backends
Run the same ACE workflow on whichever AI coding tool your team prefers. Set the backend in ace.toml or ace.local.toml with backend = "value". Default: claude.
cli override
Override the configured backend for a single invocation without editing config. Flags are global — they work on any ace subcommand.
| Flag | Equivalent |
|---|---|
| -b, --backend <value> | any registered backend name, including custom names |
| --claude | shortcut for --backend claude |
| --codex | shortcut for --backend codex |
| --opencode | shortcut for --backend opencode |
| --pi | shortcut for --backend pi |
$ ace --codex # launch Codex for this session only $ ace --claude -- --continue # resume with Claude, passing --continue through $ ace mcp --codex # list Codex MCP servers without switching config
| Config Value | Binary | Project Dir | Instructions File |
|---|---|---|---|
| claude | claude | .claude | CLAUDE.md |
| codex | codex | .agents | AGENTS.md |
| opencode | opencode | .opencode | AGENTS.md |
| pi | pi | .pi | AGENTS.md |
custom backends
Schools, users, or projects can register additional backend entries via keyed [backends.<name>] tables; the table key is the backend's name. A custom backend aliases a built-in kind (claude, codex, opencode, or pi) and may override its launch cmd and env, and set a model and effort. The MCP, instructions file, and linked-folder behavior are inherited from the aliased kind.
# Override env on the built-in claude backend [backends.claude] env = { ANTHROPIC_BASE_URL = "https://proxy.example.com" } # Custom name aliasing claude [backends.bailer] kind = "claude" env = { ANTHROPIC_BASE_URL = "https://bailer.example.com" } # Wrap the claude binary through a process wrapper [backends.claude-wrapped] kind = "claude" cmd = ["wrapper", "claude"]
model and effort
model and effort map to each backend's native settings, for interactive sessions and one-shot ace -p runs. Both are passed through unchanged — ACE does not validate them. Unset, the backend uses its own default. A custom backend inherits the mapping of its kind. Arguments after -- come last, so they can override either value for one run.
| Kind | model | effort |
|---|---|---|
| claude | --model <v> | --effort <v> |
| codex | --model <v> | -c model_reasoning_effort=<v> |
| opencode | --model <v> | variant of the generated ace agent in sessions; --variant <v> on opencode run |
| pi | --model <v> | --thinking <v> |
# Pin the built-in claude backend's model and effort [backends.claude] model = "opus" effort = "high" $ ace config set backends.claude.model opus # same, from the CLI $ ace config explain backends.claude.model # which layer sets it
templated cmd and env
cmd[] and env values support {{ placeholder }} substitution when ACE resolves the backend. A school can provide a backend that points at a launcher script under its own clone without knowing the absolute path.
| Placeholder | Resolves to |
|---|---|
| {{ school_dir }} | Active school root. |
| {{ project_dir }} | Project working directory. |
| {{ backend_dir }} | project_dir joined with the kind's backend dir (.claude, .agents, .opencode, .pi). |
| {{ home }} | $HOME. |
# School-relative launcher script [backends.codex-ace] kind = "codex" cmd = ["{{ school_dir }}/skills/ace-connect/scripts/codex.sh"] # Path-valued env var [backends.claude-scoped] kind = "claude" env = { XDG_CONFIG_HOME = "{{ project_dir }}/.config" }
Selectable via backend = "bailer" in any config layer or -b bailer on the CLI. Layer order for merging [backends.<name>] tables is school → user → project → local; later layers may add new tables or partially override a table of the same name from an earlier layer. A custom backend cannot introduce new behavior beyond its aliased kind — that requires a source change.
linked folders
ACE links school folders into the project's backend directory. skills/ becomes a real directory with per-skill symlinks (driven by skills/include_skills/exclude_skills in ace.toml); the rest are whole-directory symlinks. Not all backends support every folder.
| Backend | skills/ | rules/ | commands/ | agents/ |
|---|---|---|---|---|
| Claude Code | yes | yes | yes | yes |
| Codex | yes | — | — | — |
| OpenCode | yes | — | yes | yes |
| Pi | yes | — | — | — |
trust modes
Trust modes request backend-specific permission behavior. default uses the backend's standard handling, while auto and yolo map to different flags where each backend supports them. Three equivalent ways to persist the mode:
| Command | Equivalent |
|---|---|
| ace auto | shortcut for ace config set trust auto |
| ace yolo | shortcut for ace config set trust yolo |
| ace config set trust <value> | accepts default, auto, or yolo |
For a single invocation without writing to disk, pass --trust <mode>, or its shortcuts --auto and --yolo.
scope
Without a scope flag, trust writes to ace.local.toml (per-machine and gitignored). Trust is personal configuration: use local scope for this project or user scope across projects, not project scope.
Omitting trust inherits the level from lower-precedence layers. An explicit trust = "default" — in a personal layer or via --trust default — overrides an inherited auto or yolo.
| Flag | Layer | File |
|---|---|---|
| --local (default for trust) | per-machine, gitignored | ace.local.toml |
| --user (alias: --global) | per-user, applies everywhere | ~/.config/ace/ace.toml |
# Per-machine yolo for the current project (default scope) $ ace yolo # User-wide auto across every project on this machine $ ace config set trust auto --user # Inspect which layer is winning and why $ ace config explain trust
per-backend mapping
| Backend | auto | yolo | CLI Flags |
|---|---|---|---|
| Claude Code | yes | yes | --permission-mode auto / --permission-mode bypassPermissions |
| Codex | yes | yes | --ask-for-approval on-request --sandbox danger-full-access / --dangerously-bypass-approvals-and-sandbox |
| OpenCode | — | — | interactive mode has no trust flags; --dangerously-skip-permissions is one-shot only |
| Pi | — | — | honours only default; with auto or yolo ACE warns and passes no flag (Pi's --approve approves resources, not tool permissions) |
MCP registration
ACE registers [[mcp]] entries from school.toml into the active backend. All entries are remote HTTP endpoints.
| Backend | Method | OAuth |
|---|---|---|
| Claude Code | CLI: claude mcp add -t http -s user | auto on 401 |
| Codex | CLI-first: codex mcp add | in-session via /mcp |
| OpenCode | writes opencode.json directly (mcpServers key) | in-session |
| Pi | writes pi-mcp-adapter's user-scope mcp-adapter.json under $PI_CODING_AGENT_DIR (default ~/.pi/agent) | in-session via /mcp-auth <name> |
readiness check
ACE checks whether the backend is authenticated before launching a session.
| Backend | Check |
|---|---|
| Claude Code | ~/.claude.json exists |
| Codex | ~/.codex/auth.json exists, or CODEX_API_KEY / OPENAI_API_KEY set |
| OpenCode | ~/.local/share/opencode/auth.json exists and is non-empty ($XDG_DATA_HOME respected) |
| Pi | none — ACE does not check Pi authentication; Pi's own login flow handles it |
quirks
| Backend | Notes |
|---|---|
| Claude Code | Default backend. Full feature support. MCP servers registered at user scope (-s user), not project scope. Auto-resume via --continue fails when no prior session exists; ACE prints a hint suggesting ace new to start fresh. |
| Codex | MCP registration is CLI-first. MCP auth and ongoing management happen inside Codex via /mcp. Only skills/ is linked. |
| OpenCode | Session prompt is written to .opencode/agents/ace.md and selected with --agent ace. ACE supports opencode.json only — an existing opencode.jsonc is rejected with a hint to rename. No structured MCP health check; ace mcp check is a no-op. |
| Pi | Only skills/ is supported; any rules/, commands/, or agents/ are still linked into .pi for future compatibility and Pi ignores them. Session prompt is written to a temp file and passed with --append-system-prompt; no generated agent file. Resume uses --continue; ace -p uses --print with the prompt on stdin. MCP needs pi-mcp-adapter 3.x (pi install npm:pi-mcp-adapter@3) for registration and checks, not for ordinary launches. ACE writes mcp-adapter.json only while ACE runs, keeps unrelated fields, and never overwrites an existing server name; --mcp-config <path> in the backend cmd selects another file. Approval happens in Pi via /mcp-adapter. ace mcp check starts a model session that asks the adapter to connect to each server and relies on the model's report, not a direct probe; Pi must run in text output mode. |