The Daemon
Dumb Scheduler, Not a Feature Host
The Animus daemon is a scheduler. It consumes SubjectDispatch envelopes, manages subprocess capacity, spawns workflow-runner processes, and emits execution facts. It does not contain AI logic, task policy, or business rules.
This deliberate simplicity keeps the daemon generic. Advanced behavior lives in YAML workflows executed by workflow-runner.
The Tick Loop
The daemon operates on a periodic tick (default: every 5 seconds). Each tick follows the same sequence:
Step by step
- Load dispatch queue -- Read queued
SubjectDispatchvalues, ordered by priority andrequested_at. - Check capacity -- Determine how many new workflows can be started given the current slot usage and headroom configuration.
- Dequeue -- Pop the highest-priority dispatch that fits within capacity.
- Spawn -- Start a
workflow-runnersubprocess, passing theworkflow_ref, subject identity, and input. Built-in task subjects get a managed worktree; plugin-owned task subjects run fromproject_rootunless the plugin provides its own checkout strategy. - Poll -- Check all active
workflow-runnersubprocesses for completion, telemetry, or failure. - Emit facts -- Publish execution facts (workflow started, phase completed, workflow succeeded/failed) for projectors to consume.
Capacity Management
The daemon controls concurrency through three mechanisms:
| Control | Description |
|---|---|
| Max concurrent workflows | Hard limit on how many workflow-runner subprocesses can run simultaneously. |
| Slot headroom | Reserve slots so the system is never fully saturated. Allows high-priority work to preempt. |
| Priority ordering | Dispatches are dequeued in priority order. Within the same priority, earlier requested_at wins. |
The daemon tracks active subjects to prevent duplicate dispatches for the same subject.
What the Daemon Knows vs. Does Not Know
Knows about
- Subjects -- generic
SubjectRefidentity (kind,id, optional metadata). - Dispatch envelopes --
SubjectDispatchwithworkflow_ref, priority, trigger source. - Slots and headroom -- How many workflows are running, how many can start.
- Subprocess lifecycle -- PID tracking, health checks, orphan detection on restart.
- Runner telemetry -- Phase progress, resource usage, timing.
- Workflow execution events -- Started, phase completed, succeeded, failed.
Does NOT know about
- Task status policy (backlog, ready, blocked transitions).
- Backlog promotion rules.
- Retry policy (handled by workflow-runner's rework loop).
- Requirement state transitions.
- AI logic, prompts, or model selection.
- Git workflow policy (branching, merging, PR creation).
These responsibilities belong to workflow-runner, projectors, or MCP tool surfaces.
Execution Facts and Projectors
When a workflow completes (or fails), the daemon emits execution facts. Projectors subscribe to these facts and update domain state accordingly.
The daemon emits facts; it never interprets them. This separation means adding a new projector (e.g. a Slack notifier) does not require changing the daemon.
Starting and Stopping
animus daemon start --autonomous # Start daemon in background (forks child process)
animus daemon status # Check daemon health and active workflows
animus daemon pause # Pause dispatch (running workflows continue)
animus daemon resume # Resume dispatch
animus daemon stop # Graceful shutdownWhen started with --autonomous, the daemon forks a child process. Structured runtime events are written through the active log storage backend and mirrored locally at ~/.animus/<repo-scope>/logs/events.jsonl. Use animus daemon stream for live events and animus logs tail for recent persisted entries.
Failure Recovery
- Daemon crashes -- On next startup, orphan recovery detects and cleans up stale subprocesses, but newly-started workflows get a 90-second grace window before they can be treated as orphaned.
- workflow-runner crashes -- The daemon detects the process exit and emits a failure fact.
- Phase fails inside a workflow -- Handled by workflow-runner's rework loop, not by the daemon.