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 throughMeerkatMachine 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 assession_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
Rust Implementation Style
Keep Execution Semantics I/O-Neutral
The agent loop and domain contracts inmeerkat-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:Preserve Raw Provider Payloads Only Where They Are Truly Opaque
Tool arguments useBox<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: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.
