Migration: v0.3.x → v0.4.0
Status (2026-05-17): Migration complete as of v0.4.2. All 8 standalone plugin repositories —
animus-protocol,animus-plugin-template,animus-subject-linear, and the five provider plugins (animus-provider-{claude,codex,gemini,opencode,oai}) — are live under launchapp-dev, each taggedv0.1.0with green CI. The CLI surfaces below (animus plugin install <owner/repo>,animus plugin new) are live in v0.4.2 of the in-tree CLI.
Animus v0.4.0 is a major release with several breaking changes that ship together intentionally. This guide walks you through every breaking change with concrete before/after examples and the exact commands to run.
TL;DR: rename
.ao/→.animus/, renameAO_*env vars →ANIMUS_*, update any.mcp.jsonfiles referencingao.task.*(or anyao.*) toanimus.*, install plugin providers from their new standalone repositories, and flip pack ids in any custom workflow YAML.
The migration is small in absolute terms because the v0.3.x install base is small. v0.4.0 is the inflection point where Animus commits to itself as an ecosystem rather than a single tool — the rename and the plugin extraction land together because both are foundational.
What's breaking
| Change | Impact |
|---|---|
Full rename to animus (no ao.* aliases) | Every .mcp.json, env var, config dir, pack id, JSON envelope reference must be updated |
Plugin discovery requires --sha256 on --url installs | animus plugin install --url <url> calls without --sha256 are rejected |
Plugin discovery $PATH scanning is opt-in | If you relied on $PATH discovery, set ANIMUS_PLUGIN_PATH or pass --include-system-path explicitly |
| Template registry commit pinning | animus init no longer silently follows main; use --update-registry to fetch latest |
Bundled YAML skills moved to animus.core-skills pack | If you referenced bundled skills like code-review directly in your overlays, ensure animus.core-skills is in your [[packs]] list |
SKILL.md frontmatter: Animus runtime fields now under animus: namespace | Custom skills using tool_policy/extra_args/env at top-level frontmatter must move them under animus: |
| Subject backend plugin model | Native animus task is one backend among many. Workflows can declare subject_type: to operate over Linear/Jira/etc. Existing workflows without subject_type: keep using the native task backend with no change |
| In-tree provider crates moved to standalone repositories | If you path-depended on crates/ao-provider-*, switch to crates.io published crates from the new standalone repos |
1. Rename .ao/ → .animus/
Per-project. Animus reads from .animus/ exclusively in v0.4.0; the old .ao/ is ignored.
# In each project repo
mv .ao .animusVerify:
ls .animus/
# Should show: config.json, workflows/, plugins/, ... (whatever was in .ao/)Commit the rename if your .ao/ was checked in:
git add -A
git commit -m "migrate: .ao/ -> .animus/ for Animus v0.4.0"2. Rename scoped runtime state
Per-machine. Animus stores per-repo runtime state under ~/.ao/<repo-scope>/ in v0.3.x and ~/.animus/<repo-scope>/ in v0.4.0.
mv ~/.ao ~/.animusIf you have multiple repos and the daemon is running, stop it first:
animus daemon stop # in each project where it's running
mv ~/.ao ~/.animus
animus daemon start --autonomous # restart in each project3. Rename environment variables AO_* → ANIMUS_*
Update your shell config:
# zsh
sed -i '' 's/AO_/ANIMUS_/g' ~/.zshrc
# bash
sed -i 's/AO_/ANIMUS_/g' ~/.bashrcThen reload:
exec $SHELLThe complete list of renamed env vars (51 total):
| v0.3.x | v0.4.0 |
|---|---|
AO_CONFIG_DIR | ANIMUS_CONFIG_DIR |
AO_PLUGIN_PATH | ANIMUS_PLUGIN_PATH |
AO_RUNNER_SCOPE | ANIMUS_RUNNER_SCOPE |
AO_RUNNER_CONFIG_DIR | ANIMUS_RUNNER_CONFIG_DIR |
AO_NOTIFY_WEBHOOK_URL | ANIMUS_NOTIFY_WEBHOOK_URL |
AO_NOTIFY_BEARER_TOKEN | ANIMUS_NOTIFY_BEARER_TOKEN |
AO_USER_ID | ANIMUS_USER_ID |
AO_ASSIGNEE_USER_ID | ANIMUS_ASSIGNEE_USER_ID |
AO_CLAUDE_BYPASS_PERMISSIONS | ANIMUS_CLAUDE_BYPASS_PERMISSIONS |
AO_SKIP_RUNNER_START | ANIMUS_SKIP_RUNNER_START |
AO_WORKFLOW_RUNNER_BIN | ANIMUS_WORKFLOW_RUNNER_BIN |
AO_MCP_SCHEMA_DRAFT | ANIMUS_MCP_SCHEMA_DRAFT |
AO_RUNNER_BUILD_ID | ANIMUS_RUNNER_BUILD_ID |
AO_TEST_ENV_CAPTURE | ANIMUS_TEST_ENV_CAPTURE |
AO_TEST_ARGS_CAPTURE | ANIMUS_TEST_ARGS_CAPTURE |
| (others — see naming-contract.md for the full list) |
Update CI: check .github/workflows/, GitLab CI YAML, Jenkinsfiles, etc. for AO_* references.
4. Update .mcp.json for the renamed MCP tools
Every MCP tool name was renamed ao.<group>.<verb> → animus.<group>.<verb>. 58 tools total.
If your .mcp.json looks like:
{
"mcpServers": {
"ao": {
"command": "ao",
"args": ["mcp", "serve"]
}
}
}Update to:
{
"mcpServers": {
"animus": {
"command": "animus",
"args": ["mcp", "serve"]
}
}
}(The CLI binary itself was already animus in v0.3.x; what changes is the server name in the config and the tool namespace your AI client calls.)
If your AI client (Claude Code, Codex, Cursor) hardcodes tool names anywhere, update them. The most common renames:
| v0.3.x | v0.4.0 |
|---|---|
ao.task.create | animus.task.create |
ao.task.list | animus.task.list |
ao.task.status | animus.task.status |
ao.workflow.run | animus.workflow.run |
ao.workflow.list | animus.workflow.list |
ao.daemon.health | animus.daemon.health |
ao.daemon.start | animus.daemon.start |
ao.daemon.events | animus.daemon.events |
ao.queue.list | animus.queue.list |
ao.queue.enqueue | animus.queue.enqueue |
ao.plugin.list | animus.plugin.list |
ao.plugin.call | animus.plugin.call |
ao.requirements.create | animus.requirements.create |
ao.memory.get | animus.memory.get |
ao.memory.append | animus.memory.append |
| ... (58 total) | ... |
The pattern: every ao.<group>.<verb> becomes animus.<group>.<verb>. Mechanical sed replace works:
# Update any .mcp.json in your home dir
find ~ -name '.mcp.json' -not -path '*/node_modules/*' -exec sed -i '' 's/"ao\./"animus./g' {} +5. Update workflow YAML pack ids
In your custom workflow YAML, pack ids ao.task, ao.review, ao.requirement become animus.task, animus.review, animus.requirement. Workflow refs follow the same pattern.
Before:
[[packs]]
id = "ao.task"
activate = true
workflows:
- id: standard-workflow
phases:
- workflow_ref: ao.task/standardAfter:
[[packs]]
id = "animus.task"
activate = true
workflows:
- id: standard-workflow
phases:
- workflow_ref: animus.task/standardThe well-known workflow refs (each animus.task/*):
| v0.3.x | v0.4.0 |
|---|---|
ao.task/standard | animus.task/standard |
ao.task/triage | animus.task/triage |
ao.task/quick-fix | animus.task/quick-fix |
ao.task/refine | animus.task/refine |
ao.task/gated | animus.task/gated |
ao.task/ui-ux | animus.task/ui-ux |
ao.requirement/plan | animus.requirement/plan |
ao.review/cycle | animus.review/cycle |
Mechanical replace:
# In each project repo, after .ao/ -> .animus/ rename
find .animus -name '*.yaml' -exec sed -i '' \
-e 's/\bao\.task\b/animus.task/g' \
-e 's/\bao\.review\b/animus.review/g' \
-e 's/\bao\.requirement\b/animus.requirement/g' \
{} +6. JSON output envelope schema
If you parse --json output, the envelope schema field renamed:
-{ "schema": "ao.cli.v1", ... }
+{ "schema": "animus.cli.v1", ... }Update any consumers asserting on the schema string.
7. Plugin install: --sha256 is now required for --url
In v0.3.x:
animus plugin install --url https://example.com/plugin/binary # worked, integrity not verifiedIn v0.4.0:
# Fails:
animus plugin install --url https://example.com/plugin/binary
# error: --sha256 is required when installing from a URL
# Works:
animus plugin install --url https://example.com/plugin/binary \
--sha256 a1b2c3d4... # 64-char lowercase hex SHA-256 of the binaryTo compute the SHA-256:
shasum -a 256 /path/to/binary
# or:
curl -sL https://example.com/plugin/binary | shasum -a 256Plugin install via --path still has optional --sha256. If you provide it, the bytes are verified before install.
8. Plugin discovery no longer scans $PATH
In v0.3.x, animus plugin list and similar commands scanned $PATH for binaries named animus-plugin-* or animus-provider-*. If a malicious binary was on your $PATH, plugin discovery would execute --manifest on it — RCE-shaped.
In v0.4.0, discovery scans only:
.animus/plugins/(project-local)$ANIMUS_PLUGIN_PATH(colon-separated dirs from this env var)
To restore the old $PATH scanning:
# Per command, opt-in:
animus plugin list --include-system-path
animus plugin info --name <name> --include-system-path
animus plugin call --name <name> --method <method> --include-system-pathOr, more typically: move your plugins from random $PATH locations into .animus/plugins/ or set ANIMUS_PLUGIN_PATH=/path/to/plugins.
9. Provider plugins moved to standalone repositories
In v0.3.x the provider crates (Claude, Codex, Gemini, OpenAI-compatible, OpenCode) lived in the Animus core workspace at crates/ao-provider-*/. In v0.4.0 they ship from independent GitHub repositories, each tagged v0.1.0 with green CI:
| v0.4.0 standalone repo | crates.io |
|---|---|
launchapp-dev/animus-provider-claude | animus-provider-claude |
launchapp-dev/animus-provider-codex | animus-provider-codex |
launchapp-dev/animus-provider-gemini | animus-provider-gemini |
launchapp-dev/animus-provider-oai | animus-provider-oai |
launchapp-dev/animus-provider-opencode | animus-provider-opencode |
The Animus daemon image bundles them pre-installed. If you build a daemon image from source, you now install providers via animus plugin install rather than building the workspace.
Install sources (v0.4.2)
animus plugin install supports four sources:
# 1. Public GitHub release (resolves latest, downloads, verifies checksum)
animus plugin install launchapp-dev/animus-provider-claude
# 2. Public GitHub release pinned to a tag
animus plugin install launchapp-dev/animus-provider-claude@v0.1.0
# or: animus plugin install launchapp-dev/animus-provider-claude --tag v0.1.0
# 3. Local binary (build it from source, install the binary)
animus plugin install --path ./target/release/animus-provider-claude
# 4. Direct HTTPS URL (--sha256 is required for supply-chain integrity)
animus plugin install \
--url https://example.com/animus-provider-claude \
--sha256 a1b2c3d4...Installed plugins land in ~/.animus/plugins/ and are registered in ~/.animus/plugins.yaml. Override either with --plugin-dir <PATH> or $ANIMUS_PLUGIN_DIR.
To scaffold a brand-new plugin from the template repository:
animus plugin new --kind subject --name jira
# writes ./animus-subject-jira/ as a buildable cargo project--kind accepts subject, provider, or trigger. --out-dir, --org, --description, --template-version, --template-repo, and --template-path (for offline use) let you customize the scaffold.
If you path-depended on crates/ao-provider-* in your own Rust code, switch to the published crate from crates.io:
-ao-provider-claude = { path = "../animus-cli/crates/ao-provider-claude" }
+animus-provider-claude = "0.1"Subject backend credentials: use ${VAR} interpolation in workflow YAML
Subject backends (animus-subject-linear, custom backends, etc.) and provider plugins configured through workflow YAML should never embed literal API tokens in .animus/workflows.yaml. Two complementary mechanisms exist in v0.4.x:
- Secrets — API tokens, passwords, OAuth keys — are read directly from the daemon's process environment by the plugin that needs them (e.g.
animus-subject-linearreadsLINEAR_API_TOKENitself). Set them where you start the daemon. - Non-secret config — team IDs, base URLs, channel allowlists, feature flags — is declared in workflow YAML and interpolated against the daemon's environment at load time.
The workflow YAML loader supports shell-style ${VAR} interpolation in every string scalar, including the :-default and :?error fallback shapes:
subjects:
- id: my-linear
backend: linear
config:
team_id: ${LINEAR_TEAM_ID:-default-team-uuid}
api_url: ${LINEAR_API_URL:-https://api.linear.app/graphql}
workspace: ${LINEAR_WORKSPACE:?set LINEAR_WORKSPACE for this workflow}Recommended pattern:
LINEAR_API_TOKEN=lin_api_... \
LINEAR_TEAM_ID=team-uuid \
animus daemon start --autonomousSee docs/reference/configuration.md for full syntax, error semantics, and the recommended secret/non-secret split.
10. Plugin protocol crates moved to animus-protocol repository
In v0.3.x the protocol types lived in crates/orchestrator-plugin-protocol/. In v0.4.0 they live in launchapp-dev/animus-protocol and publish as separate crates:
| crate | purpose |
|---|---|
animus-plugin-protocol | Wire types, RPC envelope, error codes, plugin kinds |
animus-subject-protocol | SubjectBackend trait + Subject schema |
animus-provider-protocol | ProviderBackend trait |
animus-plugin-runtime | Shared stdio loop helpers (subject_backend_main, provider_main) |
If you wrote a custom plugin in v0.3.x, your Cargo.toml changes from path-deps on the core workspace to:
[dependencies]
animus-plugin-protocol = "0.1"
animus-subject-protocol = "0.1" # if you're a subject backend
animus-plugin-runtime = "0.1"11. Bundled YAML skills moved to animus.core-skills pack
The 19 skills that previously shipped baked into the animus binary (code-review, implementation, debugging, refactoring, unit-testing, etc.) moved to the animus.core-skills installable pack in early v0.4 work. Current builds no longer auto-install that pack during animus init, and they no longer ship the legacy built-in fallback.
For most users this is invisible — the names resolve the same way. If you wrote a custom pack overlay that referenced a bundled skill name, ensure your pack's pack.toml includes:
[[depends]]
id = "animus.core-skills"12. SKILL.md frontmatter: vendor namespace animus:
In v0.3.x, custom SKILL.md files could put Animus-specific runtime fields at the top level of the YAML frontmatter:
---
name: my-skill
description: My custom skill
tool_policy:
allow: ["task.*"]
extra_args: ["--my-flag"]
mcp_servers: ["my-mcp"]
---
# Skill body...In v0.4.0 these fields move under an animus: namespace to keep SKILL.md portable across other agent hosts (Claude Code, Codex, Cursor) that don't know about Animus-specific fields:
---
name: my-skill
description: My custom skill
animus:
tool_policy:
allow: ["task.*"]
extra_args: ["--my-flag"]
mcp_servers: ["my-mcp"]
---
# Skill body...Top-level placement of these fields is no longer parsed in v0.4.0 (no deprecation warning — hard cut).
13. Template registry commit pinning
In v0.3.x, animus init cloned the default template registry (launchapp-dev/animus-project-templates) and silently followed main on every subsequent run. If the registry was hijacked or pushed a bad commit, every user got it.
In v0.4.0, the first clone captures the registry HEAD commit hash into ~/.animus/template-registries/<id>/.commit. Subsequent runs verify the local HEAD matches; if they diverge (someone fast-forwarded the cache, the registry rewrote history, etc.) the loader returns a clear error rather than silently falling through.
To re-pin to the latest commit:
animus init --template task-queue --update-registryThe --update-registry flag fetches the latest, captures the new commit hash, and proceeds with init using the new content. Without the flag, init uses whatever's pinned.
14. (Optional) Subjects are now pluggable
The native in-repo subject backend remains available for existing users, but the CLI now routes it through animus subject --kind task instead of a dedicated animus task tree. v0.4.0 also adds the option to plug in external subject sources (Linear, Jira, GitHub Issues, Notion, ...) so workflows can operate over your existing tools without migrating tasks into Animus.
The first reference subject backend, animus-subject-linear, is live (v0.1.0). Install it the same way as a provider:
animus plugin install launchapp-dev/animus-subject-linearTo add a new backend (Jira, Notion, GitHub Issues, Asana, ...), scaffold from the template:
animus plugin new --kind subject --name jira
cd animus-subject-jira
# implement the SubjectBackend trait; cargo build; shipOnce installed, wire it into a workflow:
# .animus/workflows/custom.yaml
subjects:
linear-eng:
plugin: animus-subject-linear
config:
team: ENG # non-secret config (or use ${LINEAR_TEAM:-ENG})
status_map:
ready: ["Backlog", "Todo"]
in_progress: ["In Progress"]
done: ["Done"]
workflows:
- id: linear-impl
subject_type: linear-eng # NEW: declares which backend this workflow operates over
phases: [...]Subject backend credentials
Each subject backend plugin reads its credentials directly from the daemon's process environment — they are not declared in workflow YAML. For animus-subject-linear, export LINEAR_API_TOKEN before starting the daemon. For any other plugin, see its plugin.toml [[env]] declarations or its README.
LINEAR_API_TOKEN=lin_api_... animus daemon start --autonomous${VAR} interpolation in workflow YAML is intended for non-secret, per-environment config (team IDs, base URLs, feature flags, channel allowlists). See docs/reference/configuration.md for the secrets vs. non-secret config distinction.
See the protocol design doc for the full SubjectBackend trait and JSON-RPC method set.
Operational concerns: plugin kill-switches
The v0.4.x plugin surfaces (provider plugins and trigger backend plugins) ship with two environment-variable kill-switches you can flip when an installed plugin is wedging the daemon. Use them as last-resort escape hatches while you investigate — neither one is meant for long-term operation.
ANIMUS_DAEMON_DISABLE_TRIGGERS=1— Skips the trigger plugin supervisor on daemon start and interrupts any in-progress restart backoff sleeps so the daemon stops respawning a flapping plugin immediately. Useful when a trigger plugin is panicking, flooding events, or blocking startup. Daemon restart needed to re-enable.— Removed in v0.4.12. Previously forcedANIMUS_PROVIDER_DISABLE_PLUGIN=1SessionBackendResolverto fall back to in-tree provider backends; those backends were extracted to standalone plugins, so the env var has nothing to do and is silently ignored. To quarantine a single provider plugin, uninstall it withanimus plugin uninstall --name <name>or move its binary out of discovery, then restart the daemon.
When a trigger plugin exhausts its restart budget or a provider plugin fails its handshake, the log message now points at the relevant env var so operators don't have to read the source during an incident. See docs/reference/configuration.md for the full description.
Quick smoke test after migration
Run these to verify the migration worked:
animus --version # should show v0.4.x
animus daemon health # responds successfully
animus subject list --kind task # reads from .animus/, not .ao/
animus mcp serve --help # shows MCP serve help
animus plugin list # shows installed plugins (none scanned from $PATH)
animus init --help # shows --update-registry flagIf animus subject list --kind task returns no tasks but you had tasks in v0.3.x, double-check the .ao/ → .animus/ rename completed. The daemon does not auto-migrate.
Where to ask for help
- Animus core repo: launchapp-dev/animus-cli
- Naming contract:
docs/architecture/naming-contract.md - Subject backend protocol:
docs/architecture/subject-backend-plugins.md - Skills bundle migration: launchapp-dev/animus-skills — bumped to 3.0.0 in lockstep with this release
- Template registry: launchapp-dev/animus-project-templates — content updated in lockstep