Skip to main content
Meerkat is built as infrastructure, not as a single assistant application. The runtime should be easy to embed, strict about semantic ownership, and honest about which surface owns which behavior.

Principles

The Agent Loop Is A Primitive

The agent loop is provider-neutral. It owns messages, tool calls, streaming assembly, error evidence extraction, and transcript updates. MeerkatMachine owns recover, exhausted, fatal, and timeout verdicts. The loop does not own CLI policy, REST transport details, OAuth flows, or mob orchestration. That split lets the same loop run behind a CLI command, an RPC server, a Rust embedding, a mob member, or a browser runtime.

Surfaces Are Adapters

CLI, REST, JSON-RPC, MCP, Python, TypeScript, and Web SDKs should expose the same underlying concepts with surface-appropriate ergonomics. A surface may own transport details, but it should not create a second semantic model for sessions, tools, auth, live channels, or mobs. Runtime-backed surfaces enter through MeerkatMachine and consume SessionRuntimeBindings. Standalone embeddings use RuntimeBuildMode::StandaloneEphemeral explicitly.

One Semantic Fact, One Owner

State that changes what the system is needs a clear owner: Derived projections are allowed, but they never replace the owning store or machine as authority. The optional event projection is asynchronous, best-effort derived state; SessionStore and RuntimeStore remain session truth even when projection append later halts.

Typed Boundaries Beat String Folklore

Public APIs should expose domain handles such as session_id, AgentIdentity, blob_id, mob_id, and job_id. Internal raw identities and provider-specific handles should stay behind typed wrappers unless they are part of an explicit contract. Provider capabilities come from catalogs and profiles, not from substring matching. If a model supports realtime, images, web search, or compaction, that fact should be represented in a typed profile.

Composition Over Hidden Defaults

Optional subsystems are injected through traits and handles:
  • provider clients
  • tool dispatchers
  • session stores
  • realm storage providers
  • memory stores
  • hook engines
  • skill engines
  • comms runtimes
  • runtime bindings
  • durable job stores
  • schedule and WorkGraph services
When a subsystem is absent, the behavior should degrade explicitly. Hidden global state and implicit runtime reconstruction make recovery and testing harder.

Rust Implementation Style

Keep Execution Semantics I/O-Neutral

The agent loop and domain contracts in meerkat-core depend on traits rather than a chosen network, filesystem, database, OAuth, MCP, or model provider. Provider integrations and SQLite mechanics live in satellite crates. Core also contains bootstrap and compatibility adapters for configuration and storage, but those adapters do not become the semantic owner of a provider or backend. This keeps the execution path embeddable and lets hosts choose the concrete pieces they need.

Use Newtypes For Domain Identity

Primitive strings and UUIDs should become semantic types at boundaries:
This keeps member identity, runtime binding identity, sessions, blobs, and provider handles from being mixed accidentally.

Preserve Raw Provider Payloads Only Where They Are Truly Opaque

Tool arguments use Box<RawValue> so the runtime can pass provider-emitted JSON to the dispatcher without reparsing or reserializing it. Provider metadata that Meerkat understands should be typed instead of left as arbitrary serde_json::Value.

Prefer Explicit Runtime Modes

Runtime-backed and standalone execution are different contracts: Do not silently fall back from runtime-backed behavior to standalone behavior.

Make Generated Surfaces Checkable

Schemas, SDK wrappers, machine specs, and generated kernels are checked into the repo and verified by gates. Generated files should be reproducible, and drift should fail locally before it reaches CI.

Operational Bias

Meerkat favors boring, repeatable commands:
Cargo remains the default backend. BuildBuddy accelerates the same lanes when explicitly enabled with MEERKAT_BUILDBUDDY=1. GitHub Actions uses the Cargo lane; BuildBuddy is an optional developer and owner-selected release backend, not a required CI control plane.

See Also