# Agent Configuration Compatibility Matrix

> [!WARNING]
> This documentation was written by an AI agent and might be inaccurate.

Last verified: 2026-05-07. Re-verify quarterly and whenever an agent version
update breaks the existing integration.

Per-agent reference for permission control, instruction delivery, and ACP
integration. See [Agent Permission Mode Architecture](developer.md#agent-permission-mode-architecture)
for how `TEROK_UNRESTRICTED` drives permission mode inside containers.

**Agent priority tiers** — Tier-1: Claude, Vibe, Blablador; Tier-2: Codex,
local LLM via OpenCode; Tier-3: Copilot.

## Unrestricted Mode

| Agent | CLI flag | Env var | Config file | ACP adapter | terok uses (per-task) |
|-------|----------|---------|-------------|-------------|----------------------|
| Claude | `--dangerously-skip-permissions` | — | `permissions.defaultMode: bypassPermissions` in settings.json | `claude-agent-acp` (npm) | `/etc/claude-code/managed-settings.json` |
| Vibe | `--agent auto-approve` | `VIBE_AUTO_APPROVE=true` | `auto_approve = true` in TOML | `vibe-acp` (bundled) | `VIBE_AUTO_APPROVE` env var |
| Blablador | (inherits OpenCode) | `OPENCODE_PERMISSION='{"*":"allow"}'` | `"permission": {"*":"allow"}` in opencode.json | needs wrapper (#410) | `OPENCODE_PERMISSION` env var |
| OpenCode | — | `OPENCODE_PERMISSION='{"*":"allow"}'` | `"permission": {"*":"allow"}` in opencode.json | `opencode acp` (native) | `OPENCODE_PERMISSION` env var |
| Codex | `--yolo` | — | `approval_policy` + `sandbox_mode` in `~/.codex/config.toml` | `codex-acp` (npm) | `--yolo` CLI flag (no env var or managed config) |
| Copilot | `--yolo` / `--allow-all` | `COPILOT_ALLOW_ALL=true` | — (unstable) | `copilot --acp` (native) | `COPILOT_ALLOW_ALL` env var |

### Design constraint: shared volumes

`~/.claude/`, `~/.codex/`, `~/.vibe/`, `~/.config/opencode/` are shared
volume mounts (for auth and session persistence). Config written there
affects ALL tasks, not just the current one. Per-task permission mode
MUST NOT use shared-volume config files.

### What terok uses

Every agent except Codex has a mechanism that is (a) per-container and
(b) read regardless of launch path (CLI wrapper, ACP, or direct invocation):

| Agent | Per-container mechanism | Why not the alternative |
|-------|------------------------|------------------------|
| Claude | `/etc/claude-code/managed-settings.json` | `~/.claude/` is shared; managed settings have highest precedence |
| Vibe | `VIBE_AUTO_APPROVE=true` env var | pydantic-settings: env var overrides all config layers (verified) |
| OpenCode | `OPENCODE_PERMISSION` env var | merged on top of all config layers |
| Blablador | `OPENCODE_PERMISSION` env var | inherits OpenCode's mechanism |
| Copilot | `COPILOT_ALLOW_ALL=true` env var | env for `--allow-all-tools` (tools only, not paths/URLs) |
| Codex | `--yolo` CLI flag (wrapper only) | no env var, no managed config in v0.114.0; only CLI flags work |

When `TEROK_UNRESTRICTED` is unset: config files are not written and env
vars are not set; agents use vendor defaults.

**Invariant**: a container's permission mode is set at creation and never
changes during its lifetime. Podman container env vars are immutable, and
the init script re-reads them on every start — no stale state is possible.

## Instruction Delivery

| Agent | terok mechanism | ACP notes |
|-------|----------------|-----------|
| Claude | `--append-system-prompt` (wrapper) | ACP: same flag via `terok-claude-acp` wrapper |
| Vibe | `AGENTS.md` / `VIBE.md` in workspace | ACP: per-task `VIBE_HOME` overlay with `AGENTS.md` |
| OpenCode | `instructions` array in opencode.json | Injected by terok on host |
| Codex | `-c model_instructions_file` (wrapper) | ACP: same flag via `terok-codex-acp` wrapper |
| Copilot | `AGENTS.md` in workspace | ACP: `COPILOT_CUSTOM_INSTRUCTIONS_DIRS` (best-effort, upstream unstable) |

## Agent-Specific Notes

### Claude

Settings precedence (highest wins): managed (`/etc/claude-code/managed-settings.json`)
→ CLI args → local project (`<cwd>/.claude/settings.local.json`) → project
(`<cwd>/.claude/settings.json`) → user (`~/.claude/settings.json`). Managed
settings cannot be overridden. `~/.claude/` is a shared volume mount, so
per-task permission mode must use managed settings or CLI flags.

Valid `permissions.defaultMode` values: `default`, `acceptEdits`, `plan`,
`dontAsk`, `bypassPermissions`. `bypassPermissions` blocked for root unless
`IS_SANDBOX` is set (terok runs as uid 1000, not affected).

### Vibe

All config fields overridable via `VIBE_<FIELD_NAME>` env vars (pydantic-settings,
case-insensitive). `vibe-acp` defaults to `auto_approve=False` (unlike `-p`
mode which auto-selects the `auto-approve` agent). Env var is the reliable
cross-path mechanism.

### OpenCode / Blablador

`OPENCODE_PERMISSION` is merged on top of all config layers. No CLI flag for
permissions. `opencode run` auto-allows most operations by default (only
`doom_loop` and `external_directory` default to `ask`). Blablador uses a
separate config path (`OPENCODE_CONFIG`); for ACP, a `blablador-acp` wrapper
is needed (#410).

### Codex

No env var or managed config (`/etc/codex/`) for permissions in v0.114.0.
`~/.codex/config.toml` is a shared volume — unusable for per-task control.
Only `--yolo` CLI flag works, injected by the shell wrapper. This means
Codex permissions only apply via CLI wrappers, not ACP. `codex-acp`
accepts `-c key=value` overrides which could be used at ACP spawn time.

#### Synthetic auth.json — required JWT claims

Codex's vault-routed credential containment writes a shared synthetic
`auth.json` (`_codex-config/auth.json`) into every task container.  The
real `access_token` and `refresh_token` are replaced with the
`CODEX_SHARED_OAUTH_MARKER` sentinel; only the `id_token` JWT carries
metadata over.  See
[`_build_codex_shared_id_token`](https://github.com/terok-ai/terok-executor/blob/master/src/terok_executor/credentials/auth.py)
in terok-executor.

The JWT must satisfy two claim-shape contracts at startup, both of which
are enforced by Codex internally — no upstream HTTP call:

| Claim | Required by | Source code |
|---|---|---|
| `email` (top-level) **or** `https://api.openai.com/profile.email` | `account/read` JSON-RPC during TUI bootstrap | `codex-rs/login/src/token_data.rs` (`parse_chatgpt_jwt_claims`), `codex-rs/app-server/src/request_processors/account_processor.rs` (`get_account_response`) |
| `https://api.openai.com/auth.chatgpt_plan_type` | same | `codex-rs/model-provider/src/provider.rs` (`account_state` returns `MissingChatgptAccountDetails` when either is absent) |

Symptom of a missing claim: `Error: account/read failed during TUI
bootstrap`.  Codex serves this from its own app-server, so the failure
is visible immediately at `codex` startup before any model call.

terok-executor's writer preserves these plus a few non-PII identifiers
(`chatgpt_user_id`, `chatgpt_account_id`, `user_id`,
`chatgpt_account_is_fedramp`) and strips everything else.  The synthetic
JWT is unsigned (`alg: "none"`) — Codex doesn't verify the signature
locally, only that `account_state()` resolves cleanly.

### Copilot

`--yolo` / `--allow-all` grants full permissions (tools + paths + URLs).
`--allow-all-tools` is a subset (tools only). `COPILOT_ALLOW_ALL` env var
also works. All flags work with `--acp` at spawn time. No per-session ACP
permission control (upstream gap #1607).

## Sources

Check these when re-verifying.

| Agent | Primary source | Key files / docs |
|-------|---------------|-----------------|
| Claude | `github.com/zed-industries/claude-code-acp` | `src/acp-agent.ts` (permissions), `src/settings.ts` (precedence); `code.claude.com/docs/en/settings` |
| Vibe | `github.com/mistralai/mistral-vibe` | `vibe/core/config/_settings.py`, `vibe/acp/acp_agent_loop.py`, `vibe/cli/entrypoint.py` |
| OpenCode | `github.com/sst/opencode` | `packages/opencode/src/config/config.ts`, `src/flag/flag.ts`, `src/cli/cmd/acp.ts` |
| Codex | `github.com/openai/codex` | `codex-rs/config/src/lib.rs`, `codex-rs/codex-acp/src/main.rs`; also `github.com/zed-industries/codex-acp` |
| Copilot | `github.com/github/copilot` | CHANGELOG.md (v0.0.397–v1.0.5); issues #179, #307, #1020, #1607 |
| terok | This repo | `headless_providers.py`, `agents.py`, `task_runners.py`, `docs/developer.md` |
