Skip to main content
Configuration is realm-scoped. The active realm_id determines which config file is read and written.

Realm-scoped config

Every realm has its own config file and runtime state:
  • config.toml (user settings)
  • config_state.json (generation counter for CAS)
  • realm_manifest.json (pinned backend + metadata)
The canonical location is under the active realm state root. For CLI commands, the default is project-local:
<context-root>/.rkat/realms/<realm>/
For daemon/API surfaces that do not receive a --state-root, the default state root is the platform data directory:
  • macOS: ~/Library/Application Support/meerkat/realms/<realm>/
  • Linux: ~/.local/share/meerkat/realms/<realm>/
  • Windows: %APPDATA%\meerkat\realms\<realm>\
Use realms to choose whether state is shared or isolated.

Effective precedence

For a given realm, effective persisted configuration is:
  1. Built-in defaults
  2. Realm config.toml
  3. Per-request runtime parameters (for example model/system prompt/tool toggles on create/resume calls)
Environment variables still matter, but they are primarily part of runtime credential resolution, not a general config layer that mutates the loaded realm config. In practice:
  • realm config remains the canonical persisted settings surface
  • provider credentials can still come from RKAT_* or provider-native env vars at resolve time
  • bindings and auth profiles decide how those credentials are used at runtime

Config APIs and CAS

RPC, REST, and MCP all expose the same config envelope:
  • config
  • generation
  • realm_id
  • instance_id
  • backend
Some surfaces also expose resolved_paths in diagnostic/admin contexts. Treat that field as optional rather than universal across all public config envelopes. Writes support optimistic concurrency:
  • config/set and config/patch accept optional expected_generation
  • stale writes return generation conflict
This gives deterministic behavior when multiple clients or processes update config concurrently.

Merge semantics

Meerkat uses two distinct update models:
  1. Layered config loading (defaults -> file -> runtime) uses field-wise merge:
  • scalar/option values: last non-default wins
  • section values (for example providers, store, comms, compaction): replace whole section
  • hook entries: append/extend
  1. Runtime patch APIs (config/patch, PATCH /config) use RFC 7396 JSON merge-patch semantics.
Use config/set when replacing the whole config intentionally, and config/patch for surgical updates.

CLI behavior

CLI config commands operate on the selected realm:
rkat --realm team-alpha config get --format json
rkat --realm team-alpha config get --format json --with-generation
rkat --realm team-alpha config patch --json '{"agent":{"model":"gpt-5.5"}}' --expected-generation 4
Without --realm, CLI derives a stable workspace realm (ws-...) from the current directory, or from --context-root when supplied.

What about ~/.rkat/config.toml and .rkat/config.toml?

Those files still exist for compatibility and developer ergonomics (rkat init, legacy flows, and some layered hook loading behavior), but realm config is the canonical runtime configuration for CLI/RPC/REST/MCP surfaces.

Backend and storage settings

Session backend is pinned per realm in realm_manifest.json (sqlite, jsonl, or memory). --realm-backend only matters on first creation of a realm.

Compaction settings

Compaction runtime policy is configurable in realm config:
[compaction]
auto_compact_threshold = 100000
recent_turn_budget = 4
max_summary_tokens = 4096
min_turns_between_compactions = 3
When session-compaction is enabled, AgentFactory maps these values into the runtime CompactionConfig.

Model fallback settings

The model fallback chain is realm-scoped configuration. Empty chain means “use the catalog default chain”; a non-empty chain is an explicit ordered operator policy:
[model_fallback]
enabled = true

[[model_fallback.chain]]
model = "claude-opus-4-8"
provider = "anthropic"

[[model_fallback.chain]]
model = "gpt-5.5"
provider = "openai"
auth_binding = { realm = "dev", binding = "openai_oauth" }
A fallback target is identified by model, provider, self-hosted server, and auth_binding. This means an explicit custom chain can retry the same model/provider through a different credential binding. Catalog-default chains stay inside the selected non-env auth realm and skip providers that are not registered there. Use enabled = false to disable runtime model failover. If a lower-precedence layer disabled fallback or supplied a custom chain, set use_catalog_default_chain = true in a higher-precedence layer to restore the built-in catalog chain. Fallback activation is still runtime-governed: the generated recovery authority must classify the LLM failure as recoverable, and the core run loop must decide the retry is pre-stream safe. Network/call timeouts never trigger model fallback, and cross-model fallback is suppressed after user-visible text or reasoning stream output has been emitted. On activation, Meerkat recomputes the active model’s tool capability filter and token limits before retrying.

See also