ragctl is the operator-facing control-plane CLI for AgentContextOS. It bundles
configuration, ingestion, retrieval, gateway, reliability, observability, and
governance commands into a single binary that talks to local files, an
in-process gateway, and the supporting infrastructure (Jaeger, etc.).
Most commands are self-contained, credential-free demos: they drive the
real pipeline (or a real in-process FastAPI/gRPC/MCP gateway) against the noop
SPI wiring, so every platform capability can be exercised on a laptop with no
infrastructure. That makes ragctl both the operator tool and the fastest way
to see any subsystem work end-to-end.
The surface today: 37 commands + 13 sub-command groups, all working except
three scaffolds (plugin, logs, secret) that print a notice and exit 0.
# discover the surface
ragctl --help
# print the installed version
ragctl versionRun via the workspace until the standalone PyPI package lands:
uv run ragctl <command>.
| Command | What it does |
|---|---|
parse |
Detect MIME, parse a file, print a structural summary (Step 1.3) |
ocr |
Run an OCR plugin on an image, print region-aware results (Step 1.4) |
chunk |
Parse, then chunk via HeadingAwareChunker (Step 1.5) |
enrich |
parse → chunk → enrich; print enriched metadata (Step 1.6) |
pii |
parse → chunk → enrich → PII; print detection outcomes (Step 1.7) |
embed |
The pipeline end-to-end through embedding (Step 1.8) |
ingest |
Full ingest pipeline against a folder or file (Step 1.10) |
| Command | What it does |
|---|---|
hybrid |
Hybrid RRF retrieval over an in-memory toy corpus (Step 2.5) |
understand |
QueryUnderstandingPipeline over one query (Step 2.6) |
rerank |
RerankPipeline over a tiny in-memory corpus (Step 2.7) |
pack |
ContextPacker against a toy corpus (Step 2.8) |
graphrag |
GraphRAG detect → summarize → retrieve over a toy graph (Step 2.9) |
route |
Retrieval router classifying + dispatching a query (Step 2.10) |
agent-loop |
AgentLoopV0 over a single query end-to-end (Step 2.11) |
| Command | What it does |
|---|---|
query |
Drive POST /v1/query against an in-process gateway (Step 3.1) |
grpc-query |
Drive RagService.Query against an in-process gRPC server (Step 3.2) |
mcp-serve |
Run the MCP server over stdio (Step 3.3) |
mcp-query |
Drive the MCP query tool against an in-memory server (Step 3.3) |
chat |
Drive POST /v1/chat/completions (OpenAI-compatible, Step 3.4) |
embeddings |
Drive POST /v1/embeddings (OpenAI-compatible, Step 3.4) |
agent |
Drive POST /v1/agent — agent loop over SSE (Step 3.6) |
corpus (group) |
Inspect the corpus store + exercise the corpus router (Step 3.5) |
webhooks (group) |
Exercise outbound webhook signing + delivery (Step 3.9) |
| Command | What it does |
|---|---|
fallback |
Fallback chain degrading a query gracefully (Step 4.2) |
guard |
Hallucination guard checking an answer's faithfulness (Step 4.3) |
breaker |
Circuit breaker isolating a failing backend (Step 4.4) |
quota |
Quota enforcer admitting + throttling a tenant (Step 4.5) |
perf |
Probe the in-process gateway's latency overhead (Step 4.6) |
| Command | What it does |
|---|---|
config (group) |
Validate and diff rag.yaml files (Step 0.4) |
traces (group) |
Query distributed traces from Jaeger (Step 0.7) |
eval (group) |
Run and inspect golden-set evaluations (Step 0.8 / 5.2) |
provenance |
Per-query provenance: build → sign → store → verify (Step 5.1) |
feedback |
Record explicit + implicit signals → aggregate (Step 5.4) |
drift |
Seed a reference, feed a drifted current, report (Step 5.5) |
experiments |
A/B analyzer: control + candidate samples → lift + CI (Step 5.7) |
shadow |
Shadow mode end-to-end against in-process stubs (Step 5.7b) |
ab |
A/B routing end-to-end against in-process stubs (Step 5.7c) |
| Command | What it does |
|---|---|
tenant (group) |
Inspect per-tenant config + resolve logical tenancy (Step 6.1) |
audit |
Signed WORM audit export: seed → export → verify (Step 6.6b) |
kms |
BYOK envelope encryption with an in-process key manager (Step 6.7) |
scim |
SCIM 2.0 provisioning against an in-process directory (Step 6.8) |
sso (group) |
Per-tenant SSO config + OIDC federation demo (Step 6.8) |
airgap (group) |
Build / verify / install the air-gapped bundle (Step 6.9) |
compliance (group) |
Compliance posture + data-retention / GDPR erasure demo (Step 6.10) |
| Command | What it does |
|---|---|
pilot (group) |
Onboard a design-partner pilot + report weekly KPIs (Step 7.4) |
billing |
Metering → invoice flow: meter usage, then bill it (Step 7.9) |
| Group | Planned step | What it will do |
|---|---|---|
plugin |
1.1 | Manage SPI plugin registration |
logs |
5.6 | Tail structured logs from the platform |
secret |
6.7 | Manage tenant secrets |
Scaffold commands exit 0 and print a one-line notice so operators can probe
the planned interface without surprise.
ragctl config validate path/to/rag.yaml # exits 0 on success, 1 otherwise
ragctl config validate path/to/rag.yaml --json # machine-readable result
ragctl config diff path/a.yaml path/b.yaml # show backend differencesuv run ragctl query "what is RAG?" --top-k 3Spins up the in-process FastAPI gateway against the noop wiring and runs the full understand → route → rerank → pack pipeline — the quickest end-to-end smoke test there is.
ragctl eval run tests/eval/golden/ --top-k 10 --output report.json
ragctl eval show report.json --verbose
ragctl eval run tests/eval/golden/ --ragas # optional faithfulness scoring--ragas requires the optional ragas extra:
pip install 'rag-config[eval]'ragctl traces # default service, 20 traces
ragctl traces --service gateway --limit 50
ragctl traces --url http://jaeger.observability.svc:16686 # remote Jaegerragctl version # → ragctl 0.1.0Every other command follows the same shape — run it with --help for its
flags; each prints a structured, human-readable walkthrough of its subsystem.
ragctl ships with Typer-powered completion for bash, zsh, fish, and
PowerShell:
ragctl --install-completion # install for the detected shell
ragctl --show-completion # print the completion script to stdout
ragctl --show-completion zsh > _ragctlThe CLI lives in packages/ragctl/. The Typer app
is constructed once in ragctl.main and exposed as the ragctl entry point
via [project.scripts] in pyproject.toml.
packages/ragctl/
├── pyproject.toml # rag-ragctl, depends on rag-core/config/observability + domain packages
├── README.md # short package overview
└── src/ragctl/
├── __init__.py # exports app, main, __version__
├── main.py # root Typer app + all commands and sub-command groups
└── py.typed # type marker for downstream consumers
The CLI keeps no business logic of its own. Each command is a thin adapter
over a function exported from the corresponding domain package, and the
gateway-surface commands build the same in-process app the test suite uses
(build_app with noop SPIs) — so a ragctl run exercises exactly the code
that ships.
The three remaining scaffold groups are constructed by the local helper
_scaffold_app(group, step, help_text), which prints a "delivered in
Step X.Y" notice and exits 0. This keeps the published command shape stable —
operators can script against ragctl logs ... today and the same script keeps
working when the real implementation lands.
To add a new command or sub-command group:
- Create or import the domain logic in the appropriate package
(
rag-core,rag-config, the relevantpackages/<domain>, etc.). - In
ragctl/main.py, register an@app.command()(or build atyper.Typer()sub-app and attach it withapp.add_typer(...)). - Update the Command catalog table in this file and the package README.
- Add tests under
packages/ragctl/tests/.
To replace a scaffold with a real implementation:
- Remove the
_scaffold_app(...)call for that group frommain.py. - Build the real sub-app the same way you would for a new group.
- Move the row out of the Scaffolds table in this file.
- Quickstart — getting started in 5 minutes
- Eval framework architecture — what
drives
ragctl eval - Gateway reference — the surfaces
query/chat/embeddings/agentdrive in-process