rkat is designed for three main workflows:
- interactive terminal use
- scripts and CI
- Unix pipes and chained command composition
The default path is prompt-first:
You can also use subcommands explicitly:
Global flags
The top-level parser exposes the same realm and convention-root flags to each
command family:
--default-model <model> persists the default agent model into the
scope-resolved config (project/user/realm resolution included) and exits when
given without a command — rkat --default-model claude-fable-5 is the
one-liner for switching what every future run talks to. The model is
validated against the catalog and configured custom models.
By default, CLI commands use the current directory as the invocation context
and derive a stable workspace realm id from that path. For project-local state,
StorageLayout walks upward to the nearest ancestor containing a .rkat
entry and stores realms under <project-root>/.rkat/realms/<realm>/. When no
ancestor contains .rkat, the context root is the project root fallback.
--context-root changes the derived workspace identity and the starting point
for that ancestor search; it does not necessarily change the project root when
both contexts are inside the same project. --state-root bypasses discovery
and changes only where realm directories are stored.
Some maintenance or host commands reject combinations that have no safe
meaning. In particular, storage verbs reject --isolated and
--default-model, and rkat mob host rejects --isolated.
Fresh prompt-first runs and rkat help are fail-soft only at the default
workspace storage boundary. If the workspace-derived realm cannot be opened,
no historical session from that realm is loaded into the fresh run, and the
explicit compatibility bridge is never invoked automatically. The ordinary
strict open may already have completed supported manifest initialization or an
earlier domain migration before a later store refuses. The CLI warns and
creates a new generated realm using durable SQLite under the same resolved
state root. The workspace’s configuration, auth policy, provider selection,
and tool policy remain in force; only persistence-owned state is isolated in
the generated realm. The warning names both realms and prints the explicit
recovery command:
An explicit --realm, --isolated, every resume form, and all session
commands remain fail-closed. Historical session access therefore stays an
explicit maintenance operation. The fresh-run fallback is never an in-memory
session and never makes a historical session from the failed workspace realm
part of the new run.
Common commands
Prompt-first usage
Examples:
Common run flags
-m, --model <MODEL>
-o, --output <text|json|html>
--json
-s, --stream
--no-stream
--no-web-search
--export-atif (write an ATIF trajectory to the realm trajectories/ directory after the turn; default off)
--resume[=<SESSION>]
--skill <BUILTIN_ID> repeatable
-d, --max-duration <DURATION>
-t, --tools <safe|workspace|full|none>
--stdin <auto|blob|lines|off>
--keep-alive
--wait-for-mcp
--mcp-auth <stored|interactive>
-v, --verbose
For the full advanced set, use:
Current CLI help labels this value PATH_OR_ID, but rkat run --skill and
resume currently construct builtin skill keys. Direct local-path preload is
therefore unsupported. rkat skill add <PATH> registers a filesystem source
but does not make this flag source-aware, and ordinary CLI sessions do not
currently advertise the skill-discovery tool set. Use typed RPC/SDK preload
fields when a host must address a source UUID directly.
rkat uses presets instead of many enable/disable booleans.
--yolo is an alias for --tools full.
Provider and structured output controls
Use --param for common tuning and --params-json as the escape hatch:
Structured output is file-friendly:
--json is a convenience alias for --output json.
HTML output asks the agent to make the final answer a standalone local HTML artifact:
--html is a convenience alias for --output html. --browser is a compact
shortcut for HTML output plus --open-in-browser. HTML output writes the file
under the active realm’s presentation/html directory and prints the path.
Template defaults live under [presentation.html]:
Per run, use --html-template <NAME> or --html-template-file <PATH>.
Config template paths are resolved relative to the active config base directory.
Streaming defaults
- In a TTY, text output streams by default.
- In pipes and scripts, streaming is off by default.
- JSON and HTML output stay non-streaming by default so stdout remains machine-friendly unless
--stream is explicitly requested.
Stdin modes and Unix pipes
rkat treats piped stdin as a first-class interface:
auto default: if stdin is piped, read it as one blob of context
blob: always read full stdin to EOF before running
lines: keep stdin open and process one line at a time
off: ignore stdin even if something is piped in
Batch blob mode:
Live line mode:
--line-format json treats each incoming line as JSON instead of plain text.
run —resume
Examples:
SESSION_ID accepts:
- a full UUID
- a short prefix
last
~N
Omitting the value means last, so rkat run --resume "keep going" and rkat run --resume last "keep going" are equivalent.
Resume supports the same stdin model as run, plus per-turn tool overlays and provider params.
Self-hosted aliases work the same way:
session
This is the human/operator session surface. CLI-internal control-plane session APIs are not exposed here.
session export-atif reads the currently available event audit/replay
projection. A slow live subscriber can receive a typed stream-truncation
marker without dropping projector input, but projection is asynchronous
best-effort derived state and export does not first drain it to the latest
committed session boundary.
Meerkat supports ordinary durable-state opens from 0.8.10 onward. For an older
SQLite realm, stop every process that can access it and run the explicit
current maintenance bridge:
The frozen importer fails closed on unsupported pre-floor shapes. Normal realm
opens remain strict. JSONL and memory realms are rejected before any database
is mutated. The maintenance transaction preserves queued and
nonterminal input rows without scheduling or replaying them. A later session
activation follows normal recovery.
blob
Without either output flag, blob get writes the decoded raw bytes to stdout.
--output writes those bytes to a file. --json prints the complete
BlobPayload (blob_id, media_type, and base64 data) instead of raw bytes. Blob
IDs are realm-scoped, so use the same realm that produced the session or
artifact reference.
realm
realm current prints the realm selected by the CLI scope. realm list and
realm show inspect manifests in the active state root. realm prune defaults
to a 24-hour age threshold. --force bypasses active-lease safety checks, so
use it only after confirming that no process still owns the target realm.
config
The positional argument is always a file path; inline payloads use --json (or --toml for set).
Examples:
auth
rkat auth login provisions the reserved global realm in the home-rooted
doc at ~/.rkat/config.toml — both the credential token and the
[realm.global] binding section. Login therefore materializes global as the
optional chain tail, after which a single sign-in is inherited by workspace
realms without a per-realm re-login. Earlier dev-realm logins are
migrated to global on the run path (one-time, idempotent, no-clobber), so an
existing sign-in keeps working without re-auth.
Credential reads inherit down the realm chain (a child realm resolves a
binding defined in a parent or in global), but credential writes are
strict-owner: the caller must explicitly target the realm that defines the
binding; a child-addressed inherited write is rejected. --realm
on profile, status, test, and refresh commands selects the realm and composes
its chain for resolution. Logout is different: its positional
[<realm>:]<binding> selects the token owner directly, and a bare binding
means global; --realm does not retarget logout.
See Realm inheritance and the
auth guide for the full model.
models
This prints the effective runtime model registry for the active realm, including configured self_hosted aliases and their server_id.
doctor
For self-hosted setups, doctor checks the normalized /v1/models endpoint for each configured server and warns when configured aliases are missing from the returned model list.
For Gemma 4, prefer chat_completions in your server config unless you have validated a specific responses path for your serving stack.
Follow Self-hosting models for the full Gemma 4 examples.
storage
Storage administration verbs. All of them dispatch before realm resolution,
so they run against the exact on-disk state they diagnose — including
split-brain realms the normal resolver refuses. Because no runtime scope is
resolved, the global --isolated and --default-model flags are rejected
as usage errors on every storage verb rather than silently ignored; scope
the sweep with --realm, --root, or --state-root instead.
Read-only and safe against a live realm: takes no leases, never changes
logical database content, and never creates a database or directory. SQLite
may create or update the -wal/-shm sidecars needed for a coherent WAL read.
Sweeps the invocation-context-local
(<context-root>/.rkat/realms) and user-global roots by default. Ordinary
runtime resolution first walks to the nearest ancestor containing .rkat, so
run the storage verb from that project root (or pass --root) to inspect the
same local candidate;
any explicit root (--state-root or repeatable --root) restricts the
sweep to exactly those roots. --realm focuses the sweep on one realm.
Reports per-root realm inventory, schema-ledger state per database,
dual-root twins, dangling session→blob references, and orphaned
lease/lock/backup artifacts. Exit 0
means no error-severity findings; exit 1 means errors were found.
migrate is dry-run by default, offline, resumable, and fail-closed. It
sweeps the same roots (and honors the same --realm filter) as storage doctor. The dry run reads each realm’s schema-ledger baseline read-only —
no fence, no store opens, no mutation. --apply acquires the realm’s
exclusive maintenance fence (--fence-wait-secs, default 10, bounds the
wait for in-flight store operations to drain), then per realm: stamps
ledgers by opening every store through its normal constructor under the
held fence and reports state-root adoption (report-only — realms are used
where they lie). Exact 0.8.10 session-state conversion is owned by each
backend’s activation transaction, which binds the released schema, key, and
source bytes before installing current store authority; storage migrate
does not bulk-adopt documents or defer conversion to ordinary reads. A realm
materialized under multiple swept roots is a fail-closed refusal unless
--apply --adopt-root <path> names the swept root whose copy to keep:
every copy is fenced first, the divergence report is recomputed under the
held fences, and archiving is gated on that comparison being conclusive
(an unreadable entry poisons it and refuses) — then every other copy is
archived read-only under the registered *.pre-<version>-<timestamp>
backup naming. Divergent data is preserved and reported, never merged.
Per-mob databases under mobs/ are report-only, and credential stores are
never read, moved, or reported. Exit 0 = clean; exit 1 = errors or
fail-closed refusals (split-brain without --adopt-root, unacquirable
maintenance fence).
--bridge-pre-0-8-10 is an explicit --apply-only maintenance lane for
SQLite realms. JSONL and memory realms are rejected before any database is
mutated. While the realm fence is held, it runs a frozen importer before the
normal store constructors. A domain is authenticated as exactly one
caller-authorized source catalog; an unknown or ambiguous catalog refuses that
domain instead of being inferred or stamped, and each domain owns its own
transaction, so a domain that committed stays committed when a later one
refuses. The same authentication answers the eligibility sentence an ordinary
open prints, so a realm the bridge recovers is never described as
unrecoverable and a realm it cannot recover is never handed this command.
Row admission is per record, not per domain. Every runtime input row is
carried forward when it decodes through the current typed contract and
re-encodes without losing a field; a row that cannot be is left with its
bytes exactly as found - never deleted, never blanked - and named in the
output with the reason and the consequence. Rows are preserved in the current
representation without being scheduled or replayed, and that includes their
ingress payloads: a rescued realm keeps the operator’s own prompt whatever
lifecycle state its input reached. A later session activation follows normal
recovery, which applies this binary’s ordinary payload retirement to rows it
writes itself. Ordinary store opens never enter this bridge.
prune owns the lifecycle of registered maintenance artifacts only —
*.pre-<version>-<timestamp> migration backups and *.corrupt-<timestamp>
index quarantines; nothing outside those naming patterns is ever touched.
The default run lists artifacts with sizes and ages; --apply deletes
those at least --older-than-days (default 30; 0 = all) days old. Age
comes from the timestamp embedded in the registered name, not filesystem
mtime — renames preserve mtime, so a long-idle file archived today would
otherwise look instantly prunable. --realm restricts eligibility to one
realm’s artifacts. Exit 0 = clean; exit 1 = deletion failures. Not to be
confused with rkat realm prune, which deletes whole realm directories.
mcp
rkat mcp is for local and project configuration only.
Examples:
Omit --scope on list or get to search all configured scopes.
HTTP OAuth is discovered when connecting, not stored in .rkat/mcp.toml.
Use rkat mcp login <NAME> to open the browser flow ahead of time, or
rkat run "..." --mcp-auth interactive to allow a TTY run to authenticate
when an HTTP MCP server first requires it. The default --mcp-auth stored
uses persisted tokens only.
mob
rkat mob is the artifact, typed callable run, and operational run-resource
surface. Runtime semantics still live in the shared mob runtime; the CLI only
binds to it.
Multi-host notes:
rkat mob host starts only the signed member-host and optional live
listeners. It uses the workspace-derived realm (or explicit --realm) and
rejects --isolated; it does not expose an RPC, REST, or MCP console.
- When enabling the host pairing branch, prefer
--pairing-password-env or
--pairing-password-file so the secret does not appear in process arguments.
The three pairing-secret options are mutually exclusive;
--pairing-password remains available for compatibility. Pairing secrets
must be at least 32 bytes and are validated before host startup effects.
Pairing is accepted only on an IP loopback listener because it returns the
one-time binding descriptor over the plaintext comms transport. Use the 0600
descriptor out-of-band for remote hosts, or tunnel a loopback listener.
rkat mob bind-host consumes the descriptor JSON written by
rkat mob host --descriptor-out; the 0600 descriptor carries a single-use
bootstrap token, and the bind report (host id, authority epoch, capability
record) prints as JSON.
grant, revoke-grant, and grants manage the closed control-scope set:
list, read_history, subscribe_events, send_command, cancel,
retire, wire_topology, live, admin_host, and admin_grants.
rkat mob live open prints the wire LiveOpenResult JSON — including the
live URL and single-use token — to stdout only; stderr carries a
token-free note. The socket it names is the input plane: there is no
live send verb.
- Member live channels are WebSocket-only in the current runtime. The shared
CLI transport enum accepts
--transport webrtc, but the member host rejects
that selection. Session-scoped JSON-RPC live/open plus
live/webrtc/answer supports WebRTC only when the caller can address the
owning session directly. Controller session/* methods do not proxy a
placed member’s host-local session in multi-host v1.
- Mob verbs exit with typed codes for the four multi-host error classes:
scope denied
45, host unavailable 46, stale cursor 47, stale fence
48, each with a one-line detail: {...} JSON rendering on stderr.
Everything else keeps the generic exit 1.
- Durable member role migration is not a CLI spawn option. The one-shot
resume_from_role declaration is restricted to trusted in-process
SpawnMemberSpec construction and the private member-host materialization
protocol. CLI helpers, public RPC/SDK spawn requests, REST, MCP, and standing
profiles cannot grant it.
Examples:
Trust policy
--trust-policy strict rejects unsigned packs and unknown signers
--trust-policy permissive allows unsigned packs with warnings but still rejects invalid signatures
Web build prerequisites
The CLI does not compile wasm32 itself. --wasm is required and must point at
the prebuilt meerkat-web-runtime artifacts — either the wasm-pack --target web
output directory (which holds meerkat_web_runtime.js +
meerkat_web_runtime_bg.wasm) or that *_bg.wasm file (the sibling .js glue
is copied alongside). mob web build copies those artifacts into its output.
wasm-pack is one way to generate the required input:
The emitted bundle is self-contained and runnable: serve the output directory and
open index.html (it includes the glue, a meerkat-bootstrap.js module, and the
mobpack). The generated page trust-verifies the package and initializes the
WASM runtime only. It does not call mob_create, spawn members, or provide a
transcript UI; integrate the package with the generated WASM glue or
@rkat/web to build those application flows.
skill
workgraph
rkat workgraph provides operator lookup plus narrow goal and attention controls for the active realm.
Agents mutate WorkGraph through workgraph_* tools. The CLI exposes only the
narrow trusted goal/attention controls above; attention continuation injection
remains runtime-host owned rather than a REST-backed CLI command.
capabilities
Shows status for compiled/runtime capabilities.
init
Creates .rkat/config.toml from the global template.