Chimera Architecture
Chimera is composed from eight phases of agent infrastructure. Each phase is
a self-contained set of modules with a defined public surface, and each of
the seven coding-agent CLIs (mink, otter, ferret, weasel, shrew,
stoat, badger) is assembled by picking from those phase primitives.
Phases are independent enough to use on their own, but they were designed
so that the dependency edges flow in one direction: a higher phase may
reach into a lower one, never the reverse.
This page is the live phase-to-code map. If you are looking for the older “8-layer stack” view (CLI / Workflows / Synthesis / Evaluation / Agent / Provider / Infrastructure / Environment), the eight phases are an orthogonal slicing of the same codebase along the agent-loop axis rather than the synthesis-pipeline axis. The two views are complementary, not competing — see the old layer view at the bottom of this page.
Why phases at all
Section titled “Why phases at all”The seven coding-agent CLIs share one library. Earlier versions of
Chimera tried to keep everything as horizontal “layers” — one giant
loop, one giant context manager, one giant permission system. That
worked while there was one CLI. Once mink and otter shipped side
by side, the seams started to show: features that needed to go into
the loop AND the session AND the permission system kept landing in
three different layers at once. The phases collect those features by
their cross-cutting concern (loop turns, sub-agent isolation,
persistence, gating, prompting, lifecycle hooks, command surface,
production wiring, snapshotting), so a feature lands in one place and
every CLI inherits it.
If you are reading this to figure out where to add code, the rule of thumb is: pick the phase whose contract your change touches, not the CLI it shows up in first.
Phase overview
Section titled “Phase overview”The nine phases form a stack: phases 1 through 7 layer downward, each building on the one below; phases 8 and 9 cross-cut the stack rather than sitting inside it. The diagram below traces the load-bearing edges — read top-down, every arrow says “depends on the layer below me at runtime.”
graph TD P7["Phase 7 — Command + Skill surface<br/>slash commands, skills, flow workflows"] P6["Phase 6 — Hook system<br/>Pre/PostToolUse, lifecycle, async registry"] P5["Phase 5 — System prompt + context<br/>layered prompts, cache-safe, tool deferral"] P4["Phase 4 — Permission system<br/>modes, rules, denial tracking, sandbox"] P3["Phase 3 — State + persistence<br/>eventlog, snapshots, content replacement"] P2["Phase 2 — Sub-agent architecture<br/>isolation tiers, spawner, task manager"] P1["Phase 1 — Core loop<br/>AgentLoop, streaming executor, recovery"]
P8["Phase 8 — Production infrastructure<br/>auth, secrets, MCP/LSP/ACP, plugins"] P9["Phase 9 — Snapshot / format / patch<br/>undo, auto-format, structured patching"]
P7 --> P6 --> P5 --> P4 --> P3 --> P2 --> P1 P8 -.threads through.-> P1 P8 -.threads through.-> P3 P8 -.threads through.-> P7 P9 -.plugs into.-> P1 P9 -.plugs into.-> P3 P9 -.plugs into.-> P4
classDef stack fill:#2563eb,stroke:#60a5fa,color:#fff classDef cross fill:#d97706,stroke:#fbbf24,color:#000 class P1,P2,P3,P4,P5,P6,P7 stack class P8,P9 crossCaption. Solid edges = load-bearing call-graph dependencies. Dotted edges = cross-cutting attachment points (phases 8 and 9 don’t sit in the stack — they thread through several layers at once).
The dependency edges are real. Phase 2 needs Phase 1’s AbortSignal
to give sub-agents linked-but-cancellable children. Phase 4’s permission
checks fire from inside Phase 1’s tool-execution phase. Phase 5’s
prompt builder feeds Phase 1’s AgentLoop.run(). And so on. Phases 8
and 9 are cross-cutting: Phase 8 wires production concerns (auth,
analytics, MCP lifecycle) into every other phase, and Phase 9 plugs
snapshot/format/patch into the loop turn boundary, the persistence
layer, and the permission gate.
Phase 1 — Core Loop
Section titled “Phase 1 — Core Loop”Purpose. Drive a tool-augmented LLM agent with streaming, concurrent tool execution, multi-stage error recovery, and cooperative cancellation. This is the engine every other phase plugs into.
Status. Shipped as the default loop in CodingAgent. The legacy
synchronous ReAct loop is preserved alongside for back-compat with
callers that still use Agent.run() directly.
Key modules.
chimera/core/agent_loop.py—AgentLoop, the async-generator core loopchimera/core/loop.py— legacy synchronousReActloop (back-compat)chimera/core/loop_events.py—LoopEvent,LoopEventType,LoopResultchimera/core/loop_state.py—LoopState,QuerySource,RETRY_POLICIESchimera/core/loop_deps.py—LoopDeps,production_deps()chimera/core/streaming_executor.py—StreamingToolExecutorwith concurrency flagschimera/core/recovery.py—ErrorRecovery,WithheldError, multi-stage recoverychimera/core/abort.py—AbortSignalwith linked childrenchimera/core/tool_executor.py— shared tool-execution path with permission/event/audit hookschimera/core/tool.py—BaseToolplus theis_concurrency_safe/is_read_only/is_destructiveflags
Public API.
from chimera.core.agent_loop import AgentLoopfrom chimera.core.abort import AbortSignalfrom chimera.core.loop_state import QuerySource
loop = AgentLoop()async for event in loop.run( messages=[...], tools=[...], provider=..., system_prompt=..., abort_signal=AbortSignal(), query_source=QuerySource.FOREGROUND,): handle(event)Tools default to is_concurrency_safe = False (fail-closed). Read-only
tools (read, glob, grep, list_files) opt in. The recovery ladder
is context-collapse → reactive-compact → escalate-output → multi-turn.
Phase 2 — Sub-Agent Architecture
Section titled “Phase 2 — Sub-Agent Architecture”Purpose. Spawn sub-agents with three-tier context isolation so a child agent cannot corrupt parent state, but infrastructure (background tasks, hooks) can still reach the root session. Every multi-agent workflow lives on top of this.
Status. Shipped. composition/ (Pipeline, Ensemble, Supervisor)
re-implements its primitives via AgentSpawner. Built-in agents
(general-purpose, explore, plan) are registered out of the box.
Key modules.
chimera/core/agent_context.py—AgentContext,IsolationLevelchimera/core/agent_spawner.py—AgentSpawner.spawn()chimera/core/agent_definition.py—AgentDefinitionand the on-disk loaderchimera/core/builtin_agents.py—BUILTIN_AGENTSchimera/core/task_manager.py—BackgroundTask,TaskManagerchimera/core/auto_background.py— auto-promote long-running foreground agentschimera/agents/—AgentConfig,AgentRegistry,AgentLoader, presetschimera/agents/dispatch/— request classifier, trigger router, force-routeschimera/composition/— Pipeline / Ensemble / Supervisor on top of the spawnerchimera/tools/agent_tool.py— the model-facingagenttoolchimera/tools/task_tools.py—TaskCreate,TaskGet,TaskList,TaskStop,TaskOutput
Public API.
from chimera.core.agent_context import AgentContext, IsolationLevelfrom chimera.core.agent_spawner import AgentSpawner
spawner = AgentSpawner(...)async for event in spawner.spawn(definition, prompt, parent_ctx, isolation=IsolationLevel.FULL): ...Sub-agents get a per-agent denial counter (so “deny three times → stop
asking” works inside a sub-agent’s own scope). The
set_app_state_for_tasks callback bypasses isolation so background bash
tasks can register with the root task manager.
Phase 3 — State + Persistence
Section titled “Phase 3 — State + Persistence”Purpose. Long conversations don’t blow up the context window, sessions resume losslessly, and prompt-cache hit rates stay high. Solved with the content-replacement state machine (large tool results spill to disk, model sees a preview), file-state caching for read deduplication, JSONL transcripts for sub-agent sidechains, and an event-sourced session store with snapshots.
Status. Shipped. The default EventSourcedSession backend has both a
JSONL-on-disk implementation and a side-car SQLite store with snapshot-driven
fast resume.
Key modules.
chimera/sessions/eventlog/— append-only event log with file locking, gap detection, crash recoverychimera/sessions/eventlog/session.py—EventSourcedSession, snapshot integration,with_sqlite()helperchimera/events/sourcing/sqlite_store.py—SqliteEventStore(SQLite + WAL + per-aggregate seq + snapshot table)chimera/events/sourcing/projector.py— projector registry and replaychimera/sessions/session.py—Session(chat / iter_chat / fork / save / resume / steer / queue / cancel)chimera/sessions/tree.py—SessionTreewith in-place branching viaparent_idchimera/sessions/storage/— Memory / File / SQLite backendschimera/core/content_replacement.py—ContentReplacementState, persisted-vs-inline decisionschimera/core/file_state_cache.py— file-state LRU for read deduplicationchimera/core/file_tracker.py—FileTrackeracross compaction boundarieschimera/core/tool_result_persister.py— disk persistence for oversized tool resultschimera/compaction/—SummaryCompaction, prune / counter / composite, threshold-based atomic compaction
Public API.
from chimera.sessions.eventlog.session import EventSourcedSession
session = EventSourcedSession.with_sqlite( sqlite_path="~/.chimera/eventlog/run.sqlite", snapshot_every_n_events=50,)Once a tool_use_id is replaced (persisted-to-disk), the decision is
frozen — this is critical for prompt-cache stability across turns.
Snapshots let resume start from snapshot.seq + 1 instead of seq=1; the
side-car mode keeps the journal authoritative and the snapshot purely
for fast-forward.
Phase 4 — Permission System
Section titled “Phase 4 — Permission System”Purpose. Gate tool execution with multi-source rules, five permission
modes, denial tracking with fallback-to-prompting, and a sandbox adapter
for shell execution. Bypass-immune safety checks make sure that even
bypass_permissions mode can’t run truly destructive operations
unannounced.
Status. Shipped. All seven CLIs honor ~/.claude/settings.json rules;
ferret adds an OS-level sandbox layer on top via --sandbox × --approval
preset composition.
Key modules.
chimera/permissions/base.py—ApprovalPolicy,PermissionPolicychimera/permissions/modes.py—PermissionModeenum (default / plan / accept_edits / bypass / dont_ask / auto)chimera/permissions/rule.py,rules.py,patterns.py—PermissionRuleValue,ToolName(content)parsingchimera/permissions/checker.py— decision algorithmchimera/permissions/loader.py— multi-source rule loading with precedencechimera/permissions/denial_tracking.py— per-agent denial counterchimera/permissions/presets.py— read-only / auto / full (ferret-style)chimera/permissions/sandbox.py— sandbox adapterchimera/permissions/risk.py— risk classifier for bash patternschimera/permissions/audit.py—AuditEntry,AuditLogchimera/permissions/interactive.py+chimera/permissions/prompt_handler.py— interactive approval handlerschimera/cli/permission_prompt.py— REPL prompt UI
Public API.
from chimera.permissions import ( PermissionMode, PermissionRuleValue, AllowList, AlwaysDeny,)rule = PermissionRuleValue.from_string("bash(git *)")policy = AllowList([rule])Settings discovery is project-root → user-global → built-in. Ferret’s
two-flag composition is implemented as the cross product of
PermissionMode (policy gate) and a sandbox adapter (OS gate); a tool
call has to pass both.
Phase 5 — System Prompt + Context
Section titled “Phase 5 — System Prompt + Context”Purpose. Layered prompt construction so the cache prefix stays stable across turns, agent-specific overrides for sub-agents, API-based token estimation with fallback, and tool deferral (lazy-load tools by name) to keep the initial prompt small even when the registry is large.
Status. Shipped. The Prompt template class is preserved for back-compat
callers; new code uses SystemPromptBuilder.
Key modules.
chimera/core/prompt.py—Promptclass with{{variable}}template substitution (legacy)chimera/core/system_prompt.py—PromptLayer,SystemPrompt,SystemPromptBuilder(cache-segmented layers)chimera/core/prompt_template.py— additional template helperschimera/core/context_assembler.py— assemble project-context layer (git status, project rules)chimera/core/cache_safe_params.py— frozen request params for forked agentschimera/core/tool_deferral.py—ToolSearchToollazy registrychimera/core/token_estimator.py— API-first, fallback-on-error token countingchimera/core/token_budget.py— budget enforcementchimera/core/context.py— conversation history managerchimera/core/memory.py—CLAUDE.md/AGENTS.mdingestion (per-CLI rules)
Public API.
from chimera.core.system_prompt import SystemPromptBuilder
prompt = (SystemPromptBuilder() .add_layer("default", DEFAULT_SYSTEM, cacheable=True) .add_layer("agent_override", AGENT_DESC, cacheable=True) .add_layer("user_append", USER_RULES, cacheable=False) .build())Each CLI ingests its own rule files (~/.claude/CLAUDE.md, AGENTS.md,
.codex/AGENTS.md, etc.) into the user-append layer; the default and
agent-override layers stay cacheable so the cache prefix doesn’t move
when a user edits a project rule file mid-session.
Phase 6 — Hook System
Section titled “Phase 6 — Hook System”Purpose. Event-driven lifecycle hooks — pre/post tool, permission events, session start/end, sub-agent start/stop, compaction boundaries, notifications — that can be implemented as shell commands, LLM prompts, or function callbacks. Hooks load from settings, plugins, and skill directories with priority ordering.
Status. Shipped with five built-in hooks plus a fully-async registry.
Key modules.
chimera/hooks/events.py—HookEventenum (27 lifecycle events)chimera/hooks/emitter.py— fire-and-collect hook event dispatcherchimera/hooks/executor.py— three executors (shell / prompt / function)chimera/hooks/async_registry.py— async hook registry with timeout / progresschimera/hooks/loader.py— multi-source hook loadingchimera/hooks/session_hooks.py— session-scoped hookschimera/hooks/hook_types.py— typed inputs and response schemaschimera/hooks/hooks.json— bundled defaultschimera/hooks/auto_test.py,auto_lint.py,validate_path.py,security_scan.py,verify_done.py,loop_detector.py,file_watcher.py— bundled hook scriptschimera/core/middleware.py—MiddlewareChain(before_model / after_model / after_agent) for in-process hooks
Public API.
from chimera.hooks.events import HookEventfrom chimera.hooks.async_registry import AsyncHookRegistry
reg = AsyncHookRegistry()reg.register(HookEvent.POST_TOOL_USE, my_callback)Hooks support updatedInput mutation: a PreToolUse hook can rewrite
the tool input before execution. Audit-trail and cwd / env inheritance
landed in M2-B.
Phase 7 — Command + Skill System
Section titled “Phase 7 — Command + Skill System”Purpose. Slash commands for the user (REPL palette), skills (markdown files with YAML frontmatter that the model can invoke), and a SkillTool bridge so the model can call commands directly. Skills support inline context (run in current loop) or forked context (spawn sub-agent).
Status. Shipped. The shared registry is in chimera/cli/slash_commands.py;
each CLI selects which subset to expose. Skills auto-discover from
<project>/skills/, ~/.chimera/skills/, and bundled defaults.
Key modules.
chimera/skills/discovery.py—discover_skills(), walks SKILL.md fileschimera/skills/loader.py—SkillLoaderchimera/skills/definition.py—SkillDefinitionchimera/skills/bundled.py— bundled built-inschimera/skills/flow.py,flow_parser.py,flow_executor.py— Mermaid flowchart workflowschimera/cli/slash_commands.py— shared REPL command registrychimera/commands/—CommandBase,PromptCommand,LocalCommand, registry, processorchimera/cli/code.py,chimera/mink/cli.py,chimera/otter/cli.py, etc. — per-CLI command surfaces
Public API.
from chimera.commands.registry import CommandRegistryfrom chimera.skills.discovery import discover_skills
skills = discover_skills(["~/.chimera/skills/", "skills/"])Each CLI shows only its slash subset (mink: 19, otter: 26, weasel: 7 on
purpose, badger: shared + /parity + /rerun, stoat: shared + /shell).
Skills can register hooks at invocation time so a skill becomes a small
bundle of “command + hooks + system prompt override” in one file.
Phase 8 — Production Infrastructure
Section titled “Phase 8 — Production Infrastructure”Purpose. The cross-cutting plumbing that turns a prototype into a production tool: feature flags for build-time elimination, analytics with PII redaction, MCP / LSP / ACP server lifecycle, IDE bridge, auth (API key, OAuth device, OAuth browser, credential store with 0o600 perms), secret detection and redaction, streaming output, plugin system with marketplace, and coordinator mode for multi-agent orchestration.
Status. Shipped piece by piece. MCP, LSP, ACP, plugins, auth, and
secrets are all wired into the default CodingAgent build.
Key modules.
chimera/auth/—manager.py,api_key.py,oauth.py,oauth_device.py,store.py(file-based, 0o600)chimera/secrets/—registry.py(env-var loading),detector.py(10 built-in patterns),redactor.py(event bus middleware)chimera/security/—risk.py,analyzer.py(rule / LLM / composite),policy.py(ConfirmationPolicyvariants)chimera/streaming/—base.py,handlers.py,loop.py,protocol.pychimera/core/feature_flags.py—FeatureFlags.enabled(), env-var overrideschimera/analytics/— analytics with PII redactionchimera/mcp/— MCP client (stdio / HTTP / SSE / WS), OAuth, lifecyclechimera/lsp/— LSP client, diagnostics, completion, renamechimera/acp/— Agent Client Protocol (JSON-RPC 2.0 over stdio)chimera/bridge/— IDE bridge protocolchimera/plugins/—BasePlugin,PluginManager,PluginExtensionRegistry,DirectoryPluginLoader, marketplacechimera/coordinator/— multi-agent coordinator modechimera/server/— HTTP+SSE server (drivesotter serve --portandferret serve --http)chimera/wire/—WireMessage, request/response, approval requests, status updateschimera/rpc/— JSON-RPC server (stdin/stdout) and command/response/event typeschimera/providers/cost.py+cost_tracker.py— per-model pricing, granular token trackingchimera/learning/— observation store (SQLite + FTS5), confidence tracking, error feedback
Public API. This phase has no single entry point — it’s the
collection of cross-cutting modules every other phase reaches into.
The clearest seam is chimera/assembly/coding_agent.CodingAgent,
which wires production infrastructure into a single buildable
agent: CodingAgent(model=..., preset='claude_code').
Feature flags read CHIMERA_FEATURE_<NAME>=1 from the environment.
Secrets pre-empt the event bus before logs / transcripts are persisted.
The plugin marketplace is a directory loader plus an HTTP-fetched index.
Phase 9 — Snapshot, Auto-Format, Structured Patch
Section titled “Phase 9 — Snapshot, Auto-Format, Structured Patch”Purpose. Three safety / quality features that span phases 1, 3, and 4:
turn-boundary file snapshots so users can undo agent edits to any prior
turn, auto-formatter integration that runs prettier / ruff / gofmt
after every file write, and a structured multi-file patch format with
fuzzy matching that handles multi-file edits in one tool call.
Status. Shipped. Snapshots integrate with the JSONL transcript so a
session can be reverted and resumed cleanly. Auto-format runs as a
PostToolUse hook on file-write tools. The structured patch parser
ships alongside the legacy edit formats (whole-file, search-replace,
diff, udiff) for callers that want the GPT-family-emitted format.
Key modules.
chimera/core/snapshot.py—SnapshotManager,Snapshot, shadow-git plumbing with file-copy fallbackchimera/checkpoints.py— high-levelCheckpointManager(create / restore_by_name / restore_by_id / undo / list)chimera/checkpoints_ghost.py— ghost-checkpoint helperschimera/core/auto_format.py—AutoFormatter, formatter detection (prettier,ruff,gofmt,rustfmt, …)chimera/core/patch_parser.py—PatchParser,FilePatch,PatchHunk, fuzzy-match passeschimera/core/proposed_edit.py—ProposedEditfor review-before-apply flowschimera/core/file_mutation_queue.py— serialize file-mutation toolschimera/tools/edit_formats.py— Aider-style edit formatschimera/transactions.py— file-transaction coordinator
Public API.
from chimera.core.snapshot import SnapshotManagerfrom chimera.checkpoints import CheckpointManager
snap = SnapshotManager(project_dir=Path.cwd())await snap.take(turn=N, modified_files=[...])await snap.revert(to_turn=N - 2)Snapshots use shadow git (a separate .git-style directory outside the
user’s repo) when git is available, falling back to direct file copies.
Auto-format runs after the file write completes but before the
POST_TOOL_USE hook fires, so downstream hooks see the formatted file.
Provider routing
Section titled “Provider routing”Phase 8 wires chimera/providers/factory.create_provider() in front of
every loop. When the caller passes only a model id (no provider_type),
the factory infers the provider family from the model-name prefix and
local environment hints. The diagram below mirrors _infer_provider() in
chimera/providers/factory.py exactly — same precedence, same fallback
chain, same env-var override.
flowchart TD Start(["model id<br/>(e.g. claude-sonnet-4, glm-5, gpt-4o)"]) Start --> Local{"prefix is<br/>vllm/* or sglang/*?"} Local -- yes --> Compat["compatible provider<br/>(local OpenAI-compat server)"] Local -- no --> EnvOverride{"ANTHROPIC_BASE_URL or<br/>ANTHROPIC_AUTH_TOKEN set?"}
EnvOverride -- yes --> NotAnth{"prefix in gpt / o1 / o3<br/>/ codex / gemini?"} NotAnth -- no --> Anth["anthropic provider<br/>(routed via env URL)"] NotAnth -- yes --> Prefix EnvOverride -- no --> Prefix{"model prefix<br/>match?"}
Prefix -- "claude-*" --> Anth Prefix -- "glm-*" --> Anth Prefix -- "kimi-* / moonshot-*" --> Anth Prefix -- "gpt-* / o1 / o3 / codex-*" --> OAI["openai provider"] Prefix -- "gemini-*" --> Google["google provider"] Prefix -- "grok-*" --> XAI["xai provider<br/>(OpenAI-compat to api.x.ai)"] Prefix -- "llama* / mistral* / qwen* / phi*" --> Ollama["ollama provider"] Prefix -- no match --> Catalog{"in default<br/>ProviderCatalog?"}
Catalog -- yes --> CatalogResult["catalog.provider_type"] Catalog -- no --> OpenAIEnv{"OPENAI_API_KEY set?"} OpenAIEnv -- yes --> OAI OpenAIEnv -- no --> Err["ValueError:<br/>cannot infer provider"]
classDef terminal fill:#15803d,stroke:#86efac,color:#fff classDef error fill:#b91c1c,stroke:#fecaca,color:#fff classDef decision fill:#1e40af,stroke:#93c5fd,color:#fff class Anth,OAI,Google,XAI,Ollama,Compat,CatalogResult terminal class Err error class Local,EnvOverride,NotAnth,Prefix,Catalog,OpenAIEnv decisionCaption. The first decision on vllm/ / sglang/ prefixes is
unconditional — those namespaces are reserved for local self-hosted
servers and short-circuit the rest of the chain. Env-var override wins
over prefix-match when both apply (so a user with an Anthropic-compat
endpoint in their environment can run glm-5, kimi-k2, and similar
through that one URL), but gpt-* / o1 / o3 / codex-* / gemini-*
prefixes are protected — they always go to their native provider
regardless of env vars, because the wire formats are incompatible.
How the seven CLIs compose from these phases
Section titled “How the seven CLIs compose from these phases”Each CLI is a thin argparse + small per-CLI defaults file over the shared library. The CLI picks which phase primitives to enable by default, which to disable, and which to override.
chimera/<cli>/cli.py ← argparse + per-CLI defaults ↓chimera/assembly/coding_agent.CodingAgent ↓chimera/core/agent_loop.AgentLoop + chimera/core/tool_group.create_default_tools(...) ↓chimera/providers/factory.create_provider(...) ↓chimera/sessions/eventlog (file locking, gap detection, crash recovery) ↓~/.chimera/eventlog/<cli>-<utc>-<uuid>/| CLI | Phase 1 (loop) | Phase 2 (sub-agents) | Phase 3 (sessions) | Phase 4 (permissions) | Phase 5 (prompt rules) | Phase 6 (hooks) | Phase 7 (commands) | Phase 8 (production) | Phase 9 (snapshot) |
|---|---|---|---|---|---|---|---|---|---|
| mink | AgentLoop, max_steps=50 | full (Task tool, agent-teams) | eventlog + sqlite | ~/.claude/settings.json rules | ~/.claude/CLAUDE.md ingest | full hook registry | 19 slash commands | full | snapshot + auto-format |
| otter | AgentLoop, max_steps=50 | full | eventlog + sqlite | ~/.claude/settings.json rules | rules + share | full | 26 slash commands | + HTTP+SSE server, ACP serve | snapshot + auto-format |
| ferret | AgentLoop, max_steps=50 | full | eventlog + sqlite | sandbox × approval presets | .codex/AGENTS.md ingest | full + sandbox hooks | otter + /sandbox, /approval, /bridge | + sandbox adapter, cloud bridge | snapshot + auto-format |
| weasel | AgentLoop, max_steps=50 | by design off | eventlog + sqlite | host-defined (no presets) | .weasel/extensions/ | restricted | 7 slash commands (sparse) | + RPC mode, embedded SDK | snapshot + auto-format |
| shrew | AgentLoop, max_steps=30 | inherited from weasel | eventlog + sqlite | weasel + restricted-tool default | chimera/shrew/skills/ + ~/.shrew/skills/ | restricted | weasel parity | + bench harness | snapshot + auto-format |
| stoat | AgentLoop, max_steps=50 | full | eventlog + sqlite | ~/.claude/settings.json | rules + Kimi tuning | full | shared + /shell (mode toggle) | + Moonshot provider chain | snapshot + auto-format |
| badger | AgentLoop, max_steps=25 | full | eventlog + sqlite | shared + harness-tight defaults | shared | full + parity hook | shared + /parity, /rerun | + parity-tracker subcommand | snapshot + auto-format |
Every CLI inherits all nine phases. The differences are in defaults (step budget, tool restriction, model chain), which slash commands are exposed, and which Phase-8 transports the CLI fronts (HTTP+SSE for otter, ACP-default for ferret, RPC + SDK for weasel, shell-mode toggle for stoat, parity tracker for badger).
The composition graph below is the same idea as the table, but read as “which Phase-8 transport does each CLI add on top of the shared nine-phase core.” All seven CLIs share phases 1, 3, 5, 6, 7, 9; phase 2 is on for six of seven (weasel disables sub-agents by design); phase 4 differs in preset (ferret adds OS sandbox); phase 8 is where each CLI plugs in its own transport surface.
graph LR Core["Shared nine-phase core<br/>(phases 1, 3, 5, 6, 7, 9)"]
Mink["mink — TUI"] Otter["otter — HTTP+SSE / ACP serve"] Ferret["ferret — sandbox × approval"] Weasel["weasel — RPC + embedded SDK"] Shrew["shrew — small-model harness"] Stoat["stoat — shell-mode toggle"] Badger["badger — parity-tracker"]
Core --> Mink Core --> Otter Core --> Ferret Core --> Weasel Core --> Shrew Core --> Stoat Core --> Badger
P2off["Phase 2 disabled<br/>(no sub-agents)"] P4sandbox["Phase 4: + sandbox adapter"] P4tight["Phase 4: harness-tight defaults"] P8http["Phase 8: HTTP+SSE server"] P8sdk["Phase 8: RPC + embedded SDK"] P8bench["Phase 8: bench harness"] P8moon["Phase 8: Moonshot chain"] P8parity["Phase 8: parity tracker"] P8sandbox["Phase 8: cloud bridge"]
Otter --> P8http Ferret --> P4sandbox Ferret --> P8sandbox Weasel --> P2off Weasel --> P8sdk Shrew --> P8bench Stoat --> P8moon Badger --> P4tight Badger --> P8parity
classDef coreBox fill:#1e40af,stroke:#93c5fd,color:#fff classDef cli fill:#7c3aed,stroke:#c4b5fd,color:#fff classDef ext fill:#d97706,stroke:#fbbf24,color:#000 class Core coreBox class Mink,Otter,Ferret,Weasel,Shrew,Stoat,Badger cli class P2off,P4sandbox,P4tight,P8http,P8sdk,P8bench,P8moon,P8parity,P8sandbox extCaption. Solid edges from Core show every CLI inheriting the shared
core. Outgoing edges from each CLI box capture the per-CLI deltas: which
phases get new defaults (P4: sandbox, P4: harness-tight), which
phases are disabled (P2: off for weasel), and which Phase-8 transports
front the CLI (HTTP+SSE, RPC+SDK, bench harness, parity tracker, etc.).
For the per-CLI quickstart and parity row, see each CLI’s docs:
- Mink quickstart — TUI-first
- Otter quickstart — server-first / multi-client
- Ferret quickstart — IDE-flagship sandbox-first
- Weasel quickstart — minimal harness, four modes
- Shrew quickstart — small-local-model
- Stoat quickstart — shell-mode toggle
- Badger quickstart — harness-rewrite discipline
For the side-by-side surface comparison and provider-chain matrix, see the Coding Agents Overview.
Appendix: the 8-layer stack
Section titled “Appendix: the 8-layer stack”For callers used to the older Chimera mental model — eight horizontal layers (CLI / Workflows / Synthesis / Evaluation / Agent / Provider / Infrastructure / Environment) — the relationship between the two views is:
- Layer 1 (Environment) maps roughly to Phase 8’s environment
abstractions (
chimera/env/), but environments are referenced by every phase that touches files or shells. - Layer 2 (Infrastructure) is split across Phases 3, 4, 6, and 8 depending on which cross-cutting concern the module addresses.
- Layer 3 (Provider) is Phase 8 (production wiring), referenced by
Phase 1 (the loop calls
provider.stream()). - Layer 4 (Agent) is the union of Phases 1, 2, and 5.
- Layer 5 (Evaluation) is its own thing:
chimera/eval/,chimera/benchmarks/, used by training-side workflows. Sits next to the phase stack rather than inside it. - Layer 6 (Synthesis) is the training pipeline (
chimera/training/,chimera/synthesize.py). Also sits next to the phase stack. - Layer 7 (Workflows) uses the phase stack from outside —
CIFixWorkflow,ReviewOrchestrator,Researcher,MigrationPlanner,DocGenerator,TestGeneratorare all built on top of Phase 1’sAgentLoopplus their own domain-specific parsing. - Layer 8 (CLI) is the seven coding-agent CLIs above, plus the
top-level
chimera synthesize / eval / bench / code / review / ci-fix / research / docs / testgen / migrate / pluginssubcommands.
When in doubt, prefer the phase view for changes that touch the agent loop / tool-execution path, and prefer the layer view for changes that touch the synthesis or evaluation pipelines.