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
- Same
realm_idmeans shared sessions, config, and runtime metadata. - Different
realm_idmeans strict isolation, even from the same folder. - Persistent backends (
sqliteorjsonl) are pinned once per realm viarealm_manifest.json;memoryis an explicit ephemeral backend for single-process runs. - Realm IDs are user-chosen stable identifiers with syntax constraints. Reuse the same value to collaborate across surfaces.
_, and -. They cannot contain whitespace or :, and UUID-like opaque values are rejected for explicit user-facing realm IDs.
Surface defaults
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.
Realm-id-first root resolution
Every surface resolves the realm identity first, then probes for that specific realm under both candidate state roots — the project-local<context-root>/.rkat/realms and the user-global data-dir root:
- an explicit
--state-rootalways wins (no probing); - a realm that already exists under exactly one candidate root is used
where it lies (so an explicit
--realmfinds its data regardless of which surface materialized it); - a realm materialized under both roots is a typed split-brain refusal
pointing at
rkat storage doctor— no surface will silently pick one and deepen the split; - a realm that exists nowhere is created under the surface’s documented default root (CLI: project-local; servers: user-global). First materialization reserves a marker in every candidate root before writing the manifest (the cross-candidate first-start reservation), so two surfaces with different default roots racing the same fresh realm cannot each mint a copy: exactly one manifest materializes, and a racer whose realm appeared under a different candidate refuses typed instead of manufacturing a twin — its next resolution finds the winner’s copy and uses it where it lies.
--context-root, which keeps their no-flags behavior unchanged.
An existing split heals offline: rkat storage doctor reports the realm’s
twin locations, rkat storage migrate (dry-run) computes their per-domain
divergence under held fences, and rkat storage migrate --apply --adopt-root <path> adopts one root while archiving the other copy
read-only under the registered backup naming — nothing is merged or
discarded. See CLI commands.
Explicit sharing
Use the same realm everywhere:Backend pinning
On first use, a realm writes a manifest with backend choice. Later opens must honor it.
After pinning, all surfaces use the manifest backend for that realm.
Realms opened through an external
RealmStorageProvider pin the provider
the same way: the manifest records the provider name (manifest format 2,
which also adds ephemeral_domains) and the backend as external:<name>.
A realm pinned to an external provider refuses opens through the built-in
disk composition — and vice versa — with a typed provider mismatch, and
readers refuse manifest formats newer than they support instead of
silently ignoring fields they do not understand.
Default backend and same-realm sharing
When SQLite support is compiled in, new persistent realms default tosqlite.
sqliteis the recommended backend for the normal Meerkat operating mode where multiple processes share one realm.jsonlremains explicitly selectable for inspectable file-based persistence. Session documents live as JSONL files; runtime authority (queued inputs, run-boundary receipts, ops snapshots) is durable in aruntime.sqlite3companion under the realm root.memoryuses in-process session/blob/artifact stores and is useful for throwaway runs that should not persist conversation state.
Config and CAS
Config is realm-scoped and generation-based.config/getreturns the core envelope fieldsconfig,generation,realm_id,instance_id, andbackend.- Some surfaces may also include diagnostic fields such as
resolved_paths, but those should be treated as optional. config/setandconfig/patchaccept optionalexpected_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
- 100 RPC servers from the same folder without
realm_iddo not collide. - 100 agents across RPC/REST/MCP/CLI with the same
realm_idsee the same state. - CLI workspace ergonomics remain simple without forcing filesystem identity onto non-CLI surfaces.
