Skip to main content
Meerkat is realm-first. A realm_id is the only identity key for sharing or isolating state across surfaces. For task-oriented CLI behavior, filesystem layout, and troubleshooting, see the realm guide.

Core rules

  1. Same realm_id means shared sessions, config, and runtime metadata.
  2. Different realm_id means strict isolation, even from the same folder.
  3. Persistent backends (sqlite or jsonl) are pinned once per realm via realm_manifest.json; memory is an explicit ephemeral backend for single-process runs.
  4. Realm IDs are user-chosen stable identifiers with syntax constraints. Reuse the same value to collaborate across surfaces.
Realm IDs must be 1-64 characters, start with an ASCII alphanumeric character, and may contain only ASCII alphanumerics, _, and -. They cannot contain whitespace or :, and UUID-like opaque values are rejected for explicit user-facing realm IDs.

Surface defaults

SurfaceIf realm_id is not provided
CLI (rkat run, run --resume, session)Workspace-derived stable realm (ws-...)
RPC (rkat-rpc)New opaque realm (realm-...)
REST (rkat-rest)New opaque realm (realm-...)
MCP server (rkat-mcp)New opaque realm (realm-...)
Python/TypeScript SDKWhatever the spawned rkat-rpc process picks (new opaque realm unless realm_id is passed)
This means CLI is workspace-friendly by default, while non-CLI surfaces are isolated by default. The CLI workspace default uses the current directory as context_root, derives identity from that path, and stores realm runtime state under <context-root>/.rkat/realms/ unless --context-root or --state-root is provided.

Explicit sharing

Use the same realm everywhere:
rkat --realm team-alpha run "Draft release plan"
rkat --realm team-alpha session list
rkat-rpc --realm team-alpha
rkat-rest --realm team-alpha
rkat-mcp --realm team-alpha
SDKs pass the same value when connecting:
await client.connect(realm_id="team-alpha")
await client.connect({ realmId: "team-alpha" })

Backend pinning

On first use, a realm writes a manifest with backend choice. Later opens must honor it.
First openManifest pins
--realm-backend sqlitesqlite
--realm-backend jsonljsonl
--realm-backend memorymemory
No hintsqlite when compiled, otherwise jsonl
After pinning, all surfaces use the manifest backend for that realm.

Default backend and same-realm sharing

When SQLite support is compiled in, new persistent realms default to sqlite.
  • sqlite is the recommended backend for the normal Meerkat operating mode where multiple processes share one realm.
  • jsonl remains explicitly selectable for inspectable file-based persistence.
  • memory uses in-process session/blob/artifact stores and is useful for throwaway runs that should not persist conversation state.
Existing realms stay pinned to the backend recorded in their manifest. Changing the default does not migrate old realms.

Config and CAS

Config is realm-scoped and generation-based.
  • config/get returns the core envelope fields config, generation, realm_id, instance_id, and backend.
  • Some surfaces may also include diagnostic fields such as resolved_paths, but those should be treated as optional.
  • config/set and config/patch accept optional expected_generation.
  • Stale writes fail deterministically with generation conflict.
resolved_paths should be treated as a diagnostic/admin field rather than a guaranteed universal field on every public config envelope.

Why this solves multi-surface concurrency

  1. 100 RPC servers from the same folder without realm_id do not collide.
  2. 100 agents across RPC/REST/MCP/CLI with the same realm_id see the same state.
  3. CLI workspace ergonomics remain simple without forcing filesystem identity onto non-CLI surfaces.

See also