Full System Architecture
This is the canonical architecture narrative for the current Animus workspace. It ties together the crate map, runtime process model, state layout, daemon, workflow execution, plugin system, control surfaces, and operational boundaries.
If this document and code disagree, trust the code. The fastest source checks are Cargo.toml, crates/orchestrator-cli/src/cli_types/root_types.rs, crates/orchestrator-core/src/config.rs, crates/orchestrator-core/src/services.rs, crates/orchestrator-daemon-runtime/src/lib.rs, and crates/animus-runtime-shared/src/lib.rs.
Architecture Goals
Animus is a Rust-only orchestration kernel for autonomous software delivery. The kernel coordinates work, state, workflows, subprocesses, and plugins. It does not embed a desktop shell, browser runtime, provider SDK, or system-of-record implementation into daemon-core.
The core goals are:
- one CLI and MCP surface over the same service and control primitives
- repo-scoped runtime state that works across linked worktrees
- workflow execution as the central unit of automation
- installed plugins for providers, subjects, triggers, transports, and web UI
- daemon scheduling that stays dumb: queue, capacity, supervision, events
- source-backed documentation that does not preserve removed crates or old command trees as current architecture
Workspace Inventory
Cargo.toml currently declares 10 workspace members.
| Group | Crates |
|---|---|
| CLI | orchestrator-cli |
| Core services | orchestrator-core (includes the v0.5.3 folded-in subject_adapter and store modules), orchestrator-config |
| Runtime | orchestrator-daemon-runtime, animus-runtime-shared |
| Plugin foundation | orchestrator-plugin-host (includes session::*, the v0.5.3 folded-in session backend bridge), animus-plugin-protocol, animus-plugin-runtime |
| Support | orchestrator-logging, animus-mcp-oauth |
The workspace also depends on external launchapp-dev/animus-protocol crates. The authoritative dependency pins live in the repo's Cargo.toml files, especially the workspace root and crates/orchestrator-cli/Cargo.toml; the current runtime pins the main protocol family (protocol, animus-config-protocol, animus-subject-protocol, animus-provider-protocol, animus-session-backend, animus-journal-protocol, and animus-actor) to v0.1.26. The CLI-specific animus-control-protocol, animus-log-storage-protocol, animus-subject-protocol-wire, and animus-workflow-runner-protocol crates are also pinned to v0.1.26, while animus-queue-protocol and the separate animus-subject-protocol-v05 compatibility line remain on v0.5.10.
The release/runtime binary set is:
| Binary | Package | Role |
|---|---|---|
animus | orchestrator-cli | User-facing CLI, MCP endpoint, operations |
animus-oai-runner | external launchapp-dev/animus-provider-oai-agent plugin | OpenAI-compatible runner launched via the runtime contract resolver from the installed plugin (v0.5.2 surface-shrink) |
animus-workflow-runner-default | external workflow_runner plugin | Preferred workflow phase execution binary launched by daemon dispatch and required by plugin preflight |
animus-runtime-shared is the in-tree shared workflow execution/runtime library. The actual workflow phase execution binary now comes from an installed workflow_runner plugin. Historical animus-workflow-runner and ao-workflow-runner binary names still exist only as fallback resolution targets for older installs.
The former agent-runner sidecar was removed in v0.5.3. Provider sessions now run through orchestrator-plugin-host::session plus installed provider plugins.
Process Topology
The daemon and CLI may both instantiate service hubs. When the daemon is running, control-aware operations prefer the daemon control socket so external surfaces see the live runtime view. Direct service operations still exist for commands that are local, bootstrap-oriented, or intentionally one-shot.
A single subject-backed CLI command (for example animus subject list --kind task) flows from clap parsing through the service hub and out to a kind-scoped plugin RPC:
Startup and Root Resolution
Every command starts in orchestrator-cli:
- Parse global flags and the selected command.
- Resolve project root:
--project-root- Git common root for the current directory or linked worktree
- current working directory
- Bootstrap project-local
.animus/files if needed. - Resolve repository scope and scoped runtime paths.
- Construct
FileServiceHub. - Dispatch into command operation, daemon runtime, MCP service, plugin host, or web plugin launcher.
Project root behavior is owned by orchestrator-core/src/config.rs. Bootstrap and state persistence are owned by orchestrator-core/src/services.rs and orchestrator-core/src/store/ (folded in from the former orchestrator-store crate in v0.5.3).
State and Configuration
State lives at three levels: project-local config committed to the repo, repo-scoped runtime state under the home directory, and global config shared across repos.
<repo-scope> is <sanitized-repo-name>-<12 hex sha256(canonical-root)>, which keeps multiple repositories and linked worktrees from sharing runtime state by accident.
Animus splits state into three levels.
Project-local config in <project>/.animus/:
config.jsonworkflows.yamlworkflows/*.yamlplugins.lock
Scoped runtime state in ~/.animus/<repo-scope>/:
core-state.jsonresume-config.jsonworkflow.dbchat/config/daemon/docs/logs/metrics/runs/artifacts/secrets/state/worktrees/
Global state in protocol::Config::global_config_dir():
- global
config.json credentials.jsondaemon-events.jsonl- CLI tracker state
runner-sessions/
<repo-scope> is <sanitized-repo-name>-<12 hex sha256(canonical-root)>. The scope is what lets multiple repositories or linked worktrees avoid sharing runtime state by accident.
Configuration Loading
Workflow and runtime configuration flow through orchestrator-config and protocol:
- project config is local to
.animus/config.json - workflow overlays come from
.animus/workflows.yamland.animus/workflows/*.yaml - packs and templates can contribute workflow definitions and runtime overlays
- compiled runtime state is written under the repo-scoped runtime directory
New architecture should not introduce separate ad hoc config roots. If a setting changes workflow behavior, it belongs in workflow config or pack/runtime config. If it changes runtime state, it belongs under the scoped state root.
ServiceHub Boundary
FileServiceHub is the service composition root for file-backed operations. The ServiceHub trait exposes service APIs for:
- daemon lifecycle and health
- tasks and task provider compatibility
- subject resolution
- workflows
- planning and requirements
- reviews
The service layer owns domain mutations and persistence. CLI/MCP/control handlers should route through services or explicit daemon control adapters instead of mutating generated JSON by hand.
Domain Model
Animus currently has these main domain concepts:
| Concept | Meaning | Primary owner |
|---|---|---|
| Subject | Generic unit of dispatchable work, routed by kind | subject backend plugins, animus-subject-protocol |
| Task | Default subject kind for local task work | animus-subject-default plugin and compatibility services |
| Requirement | Requirement subject and planning unit | requirements plugin and planning services |
| Workflow | Multi-phase automation plan | orchestrator-core, animus-runtime-shared, external workflow_runner plugins |
| Phase | One step in a workflow, command or agent backed | animus-runtime-shared, external workflow_runner plugins |
| Queue entry | Pending/held/assigned dispatch unit | orchestrator-daemon-runtime::queue |
| Trigger | Event source that can enqueue or dispatch work | trigger plugins and daemon schedule runtime |
| Execution fact | Runtime fact emitted by workflow execution | protocol, execution projection |
The long-term architecture is subject-first. Removed command trees such as animus task and animus requirements should not reappear as privileged runtime paths.
CLI, MCP, Control, and Web Surfaces
| Surface | Entry | Architecture |
|---|---|---|
| CLI | animus <command> | clap types in orchestrator-cli, operation modules in services/operations |
| MCP | animus mcp | exposes animus.* tools over the same command/service/control logic |
| Daemon control | Unix socket | JSON-RPC control protocol, routed by orchestrator-daemon-runtime::control |
| Web | animus web | launches installed transport_backend and web_ui plugins |
| Plugin call | animus plugin call | one-shot stdio plugin host request |
The web stack is outside this workspace. animus web discovers transport and UI plugins, starts them, and opens the advertised UI URL. There is no in-tree web server or bundled React app.
Daemon Runtime
orchestrator-daemon-runtime owns runtime coordination. Its public module set documents the split:
daemon: runtime loop, event log, run guard, preflight wiringqueue: dispatch queue state and operationsdispatch: ready-work planning, process manager, workflow runner command construction, completion reconciliationtick: project tick preparation, execution, summaries, and hooksschedule: cron and trigger dispatchcontrol: daemon control socket server/client/routing/streamingsubject_dispatch: subject backend plugin resolution and routinglog_storage: log storage plugin dispatchmetrics,quotas,audit: operational support
The daemon starts autonomous work only after plugin preflight passes unless the operator explicitly skips preflight. Default preflight requires:
- at least one provider plugin
- at least one subject backend plugin
- a
workflow_runnerplugin - a
queueplugin
Dispatch Loop
The high-level daemon loop is:
- Load project and daemon configuration.
- Reconcile active workflow processes and stale workflow state.
- Resolve queue and subject state.
- Apply capacity limits and schedule headroom.
- Build a ready dispatch plan.
- Spawn the resolved workflow-runner executable for selected work, preferring
animus-workflow-runner-defaultand falling back to legacy names only for older installs. - Process due triggers when capacity allows.
- Capture workflow events, completion, and terminal projection.
- Persist metrics, logs, and queue state.
The process manager owns active workflow children. Shared workflow execution details stay in animus-runtime-shared and the installed workflow_runner plugin implementation.
Workflow Runner
The installed workflow_runner plugin is the execution host for workflow phases. The shared animus-runtime-shared module split remains architectural:
workflow_execute: top-level workflow executionphase_executor: phase execution orchestrationphase_command: external command phasesphase_session: agent/provider backed phasesphase_prompt: prompt renderingphase_output: phase output persistence and completion markersphase_git: git identity, commits, pending-change checksphase_failover: failure classificationworkflow_event_emitter: event pipe back to daemon/control surfacesruntime_contract: runtime contract injection, including MCP supportskill_dispatch: skill-aware phase dispatchensure_execution_cwd: cwd safety for execution
Workflow phases emit events and persisted output. Terminal phase state projects back into workflow state and, where configured, subject state.
Provider Session Bridge
Provider-specific session behavior is not implemented directly in daemon-core. Agent and workflow execution call into the session bridge inside orchestrator-plugin-host, which owns:
- provider plugin discovery
- session backend resolution
- run, resume, and cancel routing
- provider process supervision and retry policy
- active session retention so cancel reaches the owning plugin host
- provider event streaming back into workflow execution
Provider Session Host
orchestrator-plugin-host::session resolves installed provider plugins and adapts them to the external animus-session-backend contract. It owns:
- provider plugin discovery
- reserved provider name handling
oai-runnerandanimus-oai-runneralias normalization tooaiagent/run,agent/resume, andagent/cancel- active session host retention for cancel
- death-like failure retry policy
- provider restart supervision and cooldown
There is no in-tree provider fallback. Missing providers return install instructions.
Plugin System
Plugins are standalone executables. The shared host contract is:
- Discover candidate binaries or registry entries.
- Probe
--manifestwith hardened IO limits. - Spawn with a cleared environment.
- Send
initialize. - Route JSON-RPC requests and notifications over stdin/stdout.
Plugin kinds:
providersubject_backendtrigger_backendtransport_backendweb_uilog_storage_backendcustom- legacy
task_backend
The full contract is documented in Plugin System.
Subject Architecture
Subject backends are plugins. The control surface uses generic subject verbs, but plugin calls are kind-scoped:
task/listtask/getrequirement/listlinear.issue/update- and so on
SubjectRouter maps capabilities.subject_kinds to plugin hosts. Exact kind claims win over globs; longest glob wins; duplicate exact or duplicate glob prefix claims fail setup.
Trigger, Schedule, and Queue Architecture
Triggers and schedules feed the dispatch queue or start workflow dispatch when capacity allows.
- Trigger plugins watch external systems and emit
trigger/event. - The daemon acknowledges accepted trigger events with
trigger/ack. - Queue state tracks pending, held, assigned, and terminal dispatch entries.
- Tick planning combines queue state, subject readiness, daemon capacity, and schedule headroom.
The daemon owns when work starts. Plugins own how external events are observed.
Git and Worktree Architecture
Git automation helpers (worktree create/cleanup, identity, commit detection) live inside the consumers that need them — primarily the workflow_runner plugin and the daemon dispatch path. Runtime worktree state lives under ~/.animus/<repo-scope>/worktrees/.
Workflow and daemon code should treat git operations as explicit boundary calls:
- create or use managed worktrees
- ensure git identity for commits
- detect pending changes
- commit implementation changes when phase policy requires it
- recover or surface merge conflicts instead of hiding them
Architecture changes must not add implicit destructive git cleanup.
Observability and Output
Observability spans several layers:
- daemon event log and health snapshots
- daemon control streaming
- workflow event pipe from the installed
workflow_runnerplugin via sharedanimus-runtime-sharedhelpers - runner event persistence
- output inspection via
animus output - history inspection via
animus history - logs via in-tree log files or
log_storage_backendplugins - audit events for security-sensitive operations such as plugin installs
Operational logs and output are runtime state. They should not be written into project-local config unless the user explicitly exports or commits an artifact.
Security Boundaries
Important security and safety boundaries:
- workspace is Rust-only
- no bundled desktop shell frameworks
- plugin processes run out of process
- plugin environments are scrubbed
- install lockfiles preserve approved plugin hashes
- cosign keyless verification is supported for release installs
- first-party provider names are reserved
- subject ids are opaque backend-qualified strings
- command phases execute external binaries explicitly
- agent workspaces are guarded by project root or managed worktree policy
See Plugin Signing and Plugin Host Concurrency.
Concurrency Model
| Area | Model |
|---|---|
| Daemon | tick loop plus child process supervision |
| Workflow runner plugin | phase execution with explicit event emission and persisted markers |
| Provider sessions | active session map so cancel reaches the owning plugin host |
| Plugin host | single stdout reader task, pending response map, notification broadcast |
| State writes | file-backed services and atomic store helpers |
Avoid adding cross-cutting locks around async request paths. Prefer immutable routing maps, scoped ownership, channels, and explicit child-process boundaries.
Extension Points
Preferred extension points:
- add a plugin kind or plugin method when behavior belongs outside daemon-core
- add a workflow pack when behavior is domain/workflow-specific
- add a CLI/MCP/control adapter when exposing an existing service capability
- add a service API method when a domain mutation needs one authoritative path
- add a workflow phase/runtime contract when execution semantics change
Avoid:
- hand-editing generated state JSON
- adding hidden fallback state locations for new features
- duplicating CLI, MCP, and control mutations separately
- embedding provider-specific behavior in daemon-core
- reintroducing removed command trees as privileged architecture
End-to-End Data Lifecycle
Architectural Invariants
Cargo.tomlis the source of truth for workspace membership.- CLI surface docs must follow
root_types.rsand generated reference docs. - MCP docs must follow the actual operation modules and tool registry.
- Plugin defaults must follow
orchestrator-core::plugin_registry. - State layout must follow
protocolandorchestrator-core::store. - Web behavior is plugin-hosted, not bundled.
- Provider execution is plugin-hosted, not in-tree fallback.
- Subject execution is kind-routed through plugins.
- Runtime-critical binaries must keep compiling together.
Verification Checklist
Use this checklist for architecture-affecting changes:
cargo animus-bin-check
cargo test -p orchestrator-cli
cargo test -p orchestrator-daemon-runtime
cargo test -p animus-runtime-shared
cargo test -p orchestrator-plugin-hostFor docs-only architecture changes, at minimum run:
cargo animus-bin-check
git diff --checkThen search for stale references to removed architecture:
rg 'llm-cli-wrapper|embedded web|in-tree task|14 repos|Latest:' README.md docs crates