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.

FlagEquivalent
-b, --backend <value>any registered backend name, including custom names
--claudeshortcut for --backend claude
--codexshortcut for --backend codex
--opencodeshortcut for --backend opencode
--pishortcut 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 ValueBinaryProject DirInstructions File
claudeclaude.claudeCLAUDE.md
codexcodex.agentsAGENTS.md
opencodeopencode.opencodeAGENTS.md
pipi.piAGENTS.md
Pi support is new in v0.10.0. Live Pi sessions — extension loading and OAuth — are not yet verified.

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"]
Releases before v0.9.3 used a [[backends]] array with a name field. That form is now rejected: move each name into its table key. Selectors such as backend = "bailer" stay the same.

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.

Kindmodeleffort
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.

PlaceholderResolves 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" }
Substitution is a closed set of named placeholders — no shell-style $VAR or ~ expansion. Unknown placeholders render to empty strings.

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.

Backendskills/rules/commands/agents/
Claude Codeyesyesyesyes
Codexyes———
OpenCodeyes—yesyes
Piyes———

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:

CommandEquivalent
ace autoshortcut for ace config set trust auto
ace yoloshortcut 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.

FlagLayerFile
--local (default for trust)per-machine, gitignoredace.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
--user, --project, and --local are mutually exclusive global flags. Trust and resume default to --local and may also be stored at user scope; other writable keys generally default to --project.

per-backend mapping

BackendautoyoloCLI Flags
Claude Codeyesyes--permission-mode auto / --permission-mode bypassPermissions
Codexyesyes--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)
Each backend maps ACE trust modes to its own CLI flags. The mappings differ between backends. When a backend cannot honour the requested level — interactive OpenCode has no approval-mode flags, and Pi honours only default — ACE announces it instead of silently claiming the level was applied.

MCP registration

ACE registers [[mcp]] entries from school.toml into the active backend. All entries are remote HTTP endpoints.

BackendMethodOAuth
Claude CodeCLI: claude mcp add -t http -s userauto on 401
CodexCLI-first: codex mcp addin-session via /mcp
OpenCodewrites opencode.json directly (mcpServers key)in-session
Piwrites 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.

BackendCheck
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)
Pinone — ACE does not check Pi authentication; Pi's own login flow handles it

quirks

BackendNotes
Claude CodeDefault 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.
CodexMCP registration is CLI-first. MCP auth and ongoing management happen inside Codex via /mcp. Only skills/ is linked.
OpenCodeSession 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.
PiOnly 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.