State Management
Animus separates authored repository config from mutable runtime state. The authored side lives in the repository under .animus/; the mutable side lives outside the repository under ~/.animus/<repo-scope>/.
Project-Local .animus/
The repository keeps only the configuration you are expected to author:
.animus/
├── config.json
├── config/
│ └── skill_definitions/
├── workflows.yaml
├── workflows/
├── plugins.lock
├── skills/
└── plugins/These files define workflow behavior, skill sources, plugin lock state, and local pack or plugin overrides.
Repo-Scoped Runtime State
Runtime state lives under ~/.animus/<repo-scope>/, not in the repository:
~/.animus/<repo-scope>/
├── core-state.json
├── resume-config.json
├── workflow.db
├── config/
├── daemon/
├── chat/
├── docs/
├── logs/
├── metrics/
├── runs/
├── artifacts/
├── secrets/
├── state/
└── worktrees/Important runtime stores:
workflow.dbfor workflows, checkpoints, tasks, and requirementsconfig/for compiled workflow, agent-runtime, and state-machine documentsdaemon/for persisted daemon settings and daemon process statechat/for conversation transcripts and continuity recordslogs/for redacted structured runtime events and log-storage-backed run logsmetrics/for buffered anonymous telemetry when opt-in is enabledruns/andartifacts/for per-run execution state and outputssecrets/for the per-scope secret-name index (values stay in the OS keychain)state/for history, error, schedule, and pack-selection stateworktrees/for managed task worktreesdocs/for generated planning artifacts such asproduct-vision.md
Why the Split Exists
Keeping mutable state outside the repository gives Animus a few important properties:
- linked worktrees resolve back to one shared repo scope
- runtime files do not pollute source control
- large and frequently updated state can evolve without rewriting repo-local config
- legacy
.animus/-local state can be migrated forward without changing the authored YAML surface
Pack and Workflow Resolution
Animus still resolves workflows from layered sources:
- project pack overrides in
.animus/plugins/ - project YAML in
.animus/workflows.yamland.animus/workflows/*.yaml - installed packs in
~/.animus/packs/
State location and workflow resolution are related but different concerns:
- workflow definitions come from YAML and pack content
- execution state and operational records live under
~/.animus/<repo-scope>/
Mutation Policy
Do not hand-edit Animus-managed runtime JSON or SQLite state unless you are explicitly working on Animus persistence or migrations.
Approved mutation surfaces:
- CLI commands such as
animus subject status --kind task - Animus MCP tools such as
animus.subject.update - pack commands such as
animus pack pin
All approved surfaces funnel through service APIs, which own the writes to disk. No surface writes scoped JSON or SQLite directly:
Moving to a new machine
Use animus state export and animus state import to migrate a project's runtime state to a new machine.
Export
animus state export --out my-project.tar.zstThe archive contains, by default:
state/— workflows, tasks, requirements, history, errors, pack-selection, etc.chat/— conversation continuity records.docs/— generated planning artifacts (product-vision.md, etc.).secrets/index.json— the names of secrets registered for this project.~/.animus/principals.yaml— the RBAC principal list (if it exists).
Excluded by default (use --include-runs / --include-artifacts to add):
runs/andartifacts/— potentially large per-run execution state.daemon/runtime files (daemon.lock,daemon.log,control.sock, etc.).config/— compiled workflow, agent-runtime, and state-machine config (regenerated on first run).worktrees/— managed task worktrees are excluded because they can be large and are derivable from repository state plus queued/runtime metadata..project-root,.git-origin— machine-local paths and credentials in the remote URL; both are re-created automatically.
SECRETS ARE DELIBERATELY EXCLUDED. The archive never contains actual secret values. Values live in the OS keychain (animus:<repo-scope> service entries), which is local to each machine. The secrets/index.json file in the archive records only the key names that were registered on the source machine — use it as a checklist to re-enter values on the new machine:
# On the new machine, after importing:
animus secret list # see which KEYs are expected
animus secret set LINEAR_API_TOKEN
animus secret set ANTHROPIC_API_KEY
# or bulk-import from a temporary .env file:
animus secret import-env --file keys.envImport
animus state import my-project.tar.zstFlags:
--yes— allow overwriting an existing non-empty scope directory. A safety snapshot is taken to~/.animus/<scope>/.backup-pre-import-<ts>/before any files are replaced.--into-project <PATH>— re-scope the archive into a different project root. The new scope id is computed from the given path so you can restore onto a repo checked out at a different location.--yes-overwrite-principals— explicit opt-in to overwrite an existing~/.animus/principals.yamlwhen the archived copy differs.--yesalone never touches RBAC config; you must pass this flag separately. This is intentional: principals govern who can act on all projects on the machine, so overwriting them silently on a shared host would be dangerous.
Keychain scope mapping
Keychain entries are stored under animus:<repo-scope> (see Secrets for the full layout). When you --into-project to a different root, the repo scope changes and the old keychain entries are not automatically re-keyed. You must re-enter secrets under the new scope with animus secret set after import.
Repository Scope
The repo scope uses the canonical project path to derive a stable identifier:
<sanitized-repo-name>-<12-hex-sha256-prefix>This is what lets Animus keep one runtime home for a repository even when you invoke it from linked worktrees.