Skip to content

Providers and adapters

← Back to README

OpenCode is the default engine. Codex: --engine codex. Claude Code: --engine claude (built in). Any other tool registers with one TOML file.

Provider process ownership

Supervised task-stage providers, including core TaskRun conversations and autocode ui, require a native little-endian Linux x86_64 or aarch64 runtime, matching /proc PID namespace, and working seccomp user notifications with syscall continuation. A Linux host without them, and any other unsupported host except macOS, refuses the launch before provider spawn. The refusal identifies the unavailable boundary; it does not send a model request. There is no CLI opt-out.

macOS has no seccomp, so providers there run without this boundary (#1195): the keeper's lifeline and sampled process-group and session ownership, as for runner commands, with no kernel proof that every descendant exited. The run prints one notice on stderr, and the supervision receipt carries no session_boundary. A provider child that calls setsid() and reparents between samples can outlive the run there; use Linux when that matters.

Automatic model-access probes started by a task use the same provider boundary and retain attempt-local admission and cleanup receipts. Admission or cleanup failure pauses the task. A probe timeout remains uncertain and can be retried; it does not become a cached access pass.

Each automatic probe counts toward the run's recorded spend and active time. The runner checks the remaining money/time allowance and pending human input before each request, limits its timeout to the remaining active time, and saves its usage before admitting another probe or workflow stage. Stop is acknowledged only after the previous probe's cleanup is verified. Interrupted attempts retain their evidence and usage; they require verified cleanup before a retry. Older marker-only access passes remain readable, but their historical probe usage cannot be reconstructed from the marker.

The dashboard's separate conversation/intake transports and explicitly invoked standalone provider probes use other launch paths; this task-owned boundary does not qualify them.

The owner chose this macOS fallback in #1195 (delivered by #1204). #1265 replaced it with strict refusal on 2026-10-14; the owner restored the fallback on 2026-10-15, so local live qualification can run on macOS.

Normal detached shell tools remain allowed: the independent keeper records a prospective session before permitting setsid(). Its receipt preserves that ownership through controller or keeper loss. Cleanup is verified only when the kernel reports that no task retains the inherited boundary. Permission errors, missing receipts and unverified cleanup remain failures.

Providers inherit no_new_privs, so privilege elevation through exec is unavailable. Additional ordinary seccomp filters remain allowed, but installing a replacement notification listener is refused. Launches with permitted or effective CAP_SYS_PTRACE or CAP_SYS_ADMIN are also refused. The keeper is non-dumpable to protect its listener from same-user descriptor access. This is a process ownership boundary, not a filesystem or network sandbox.

Offline native tests cover detached spawning, thread callers, double forks, descriptor closure, owner loss and keeper loss. They do not establish live-model or provider-version conformance. This policy changes no role models or routes.

Runner-owned verification commands use their existing portable lifeline and sampled SID guard, including nested preparation workers. They do not install a provider listener or claim its kernel family-extinction proof. Commands already inside a provider family continue to inherit that family's filter. The model adapters always use the mandatory provider boundary; there is no CLI opt-out.

OpenCode adapter

The Requirements Gatherer, Planner and default Builder use the connections already configured in OpenCode. --engine opencode is accepted but is optional for new runs:

python3 tools/autocode.py "Your rough idea" --workspace /path/to/project

Override the planning roles with --requirements-model, --glm-model, and --plan-reviewer-model (plus their reasoning-effort flags). For a new task without a conversation-handoff profile, --glm-model also selects the initial Requirements model unless --requirements-model selects it separately. Conversation handoffs apply an independent profile: Requirements keeps that profile's default unless --requirements-model selects it explicitly. Resuming keeps the saved Requirements model unless --requirements-model explicitly changes it. Override execution roles with --astra-model, --terra-model, --sol-model, or --completion-model using a provider/model ID from opencode models, including openai/… with an OpenCode ChatGPT OAuth connection. Saved runs retain their original role engines and sessions; no existing run is migrated by a dashboard selection. If an account offers only one model, --single-model MODEL assigns it to all roles and permits same-model verification. The roles still run in separate sessions and all normal evidence, approval and completion gates remain active, but model-family independence is intentionally unavailable in this mode. OpenCode reasoning variants can be selected in the browser or with the existing role-specific reasoning-effort flags. New joint runs start with separate GLM requirements and planner sessions, GPT-6 Sol High for the Plan Reviewer, GLM Medium for the Builder, GPT-6 Sol High for the Validator, and a separate GPT-6 Sol Medium session for the Completion Owner. Escalation then follows the ladders and Builder retry policy documented in Models. Provider credentials remain with OpenCode: Autocode does not read its auth file or change your global configuration.

The same approval, task, independent-evidence and completion gates apply. The adapter uses OpenCode's non-interactive JSON event interface, validates the final report against the stage schema, and verifies command evidence against actual completed bash events; the runner then re-runs a passing Validator's checks itself in a clean copy (Execution). Raw events, session IDs and stage-local permission overrides are saved alongside the checkpoint. Token limits include cache reads/writes and reasoning tokens. Malformed or uncertain results pause; the runner does not automatically replay an ambiguous provider request. An explicitly retryable native APIError with ECONNRESET, ETIMEDOUT, EPIPE, or HTTP 500/502/503/504 may receive one fresh same-stage, same-model retry when its entire event stream contains only that error, its collected failed process exited normally with verified owned cleanup, and its source, Git index, task, settings and route are unchanged. The failed attempt, raw events and usage remain charged and retained. The existing run-wide automatic-recovery limit still applies; restarts, abandonment and route changes do not renew a failed chain's allowance. Session continuations, partial turns/tools/reports, uncertain cleanup, human gates, quota/auth failures and output limits keep their ordinary recovery policy. Saved attempts without the launch binding and non-native transports remain unsupported by this automatic retry. The supported native error fields follow OpenCode 1.18.33's conversion and HTTP error metadata; unknown metadata keeps the ordinary hold.

When a Validator or Completion Owner response is cut off by the output-token limit and the process exited cleanly with the source unchanged, the runner archives the attempt and queues a bounded report-only repair from the saved partial response and check evidence rather than replaying the provider request.

OpenCode has a different isolation boundary: Requirements Planner sessions and other read-only OpenCode roles have edit tools denied and their workspace snapshots checked, but OpenCode tool permissions are not an OS sandbox. Shell commands and configured external tools retain OpenCode's native permission policy. Autocode also rejects a read-only report when native OpenCode step snapshots record a workspace change during the attempt, even if the final files were restored. This check applies when loading saved reports and when reusing review evidence for report repair. Before a native OpenCode launch, the runner adds local Git exclusions for .autocode/, .autocode-ui/, __pycache__/ and *.pyc, matching its existing source-snapshot boundary and preserving other exclusion rules. This prevents runtime evidence writes from looking like source drift. The check cannot detect writes outside the workspace, ignored files, or transient changes between snapshots, and is unavailable when the transport omits snapshots. Use an OS sandbox when filesystem prevention is required. The built-in OpenCode adapter does not enable --auto or override user-level permission rules with blanket allows. A denied required operation is reported back as a blocker. See OpenCode's permission documentation.

Output cap

OpenCode derives a requested response limit from the model's listed output limit and OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX, with a 32000-token default. Provider routes can override it. On routes that honor the setting, reasoning counts against the same limit; a planning report can exceed it and stop with finish reason length and truncated JSON. AutoCode therefore launches OpenCode with OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=64000 unless you set a positive whole number yourself, which wins:

OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=100000 autocode "..."

The setting is a request, not a verified provider limit. For example, OpenCode 1.18.33's OpenAI Codex plugin clears maxOutputTokens after OpenCode derives it from this setting. A real Codex check returned responses exceeding the requested setting. Increasing this variable cannot be assumed to fix truncation on that route.

AutoCode does not default to the model's whole listed limit: OpenCode's context planning uses this setting, and some APIs refuse a request whose input plus maximum output exceeds the window. Each stage record keeps the requested setting (or OpenCode's default when absent) under output_token_cap (tokens, and set_by: operator, autocode, or opencode when the variable did not reach it). A length stop's pause distinguishes that setting from how many tokens the last response used. A collected, terminal length stop offers a route-ROLE question (PAUSED_OUTPUT_CAP): answer it with a different model on the same engine, then resume. The answer retains the incomplete attempt, work and usage; it never launches a provider. Workflow jobs also require the displayed job retry token and issue a new token for the explicit retry. On a route that honors the setting, another recovery option is to request a larger limit, set the attempt aside with --abandon-stage, and --resume-paused. Model and provider limits still apply. Automatic report repair remains bounded to the existing read-only Tester and Completion Reviewer stages; Builder and Requirements never retry an output-limit stop automatically. Ambiguous or interrupted output remains uncertain. The cap-setting rules are in tools/autocode_output_cap.py; they do not alter configured command providers' environment or token limits.

For an isolated native run paused before plan approval, an OpenCode authentication failure can also be set aside explicitly with the displayed --abandon-stage attempt. This requires a collected nonzero exit containing only one terminal 401/403 APIError, no response or report, and the original stopped supervisor, unchanged source, settings and runtime. Other uncertain output remains refused. The command preserves the failed attempt and pauses without launching a model. Refresh the provider credential before --resume-paused; resume retains the same models, review gates and time limits. An older run cannot adopt a changed runtime to gain this recovery operation.

Environment variables agents see

Every provider process, and every test command the runner executes itself, gets the runner's environment minus variables that look like credentials: a name word such as TOKEN, SECRET, PASSWORD, KEY or AUTH (GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY, SSH_AUTH_SOCK, OPENAI_API_KEY), or a URL value with an embedded password. Proxy variables and AutoCode's ordinary AUTOCODE_* settings are kept. The nine controller token variables are always withheld, including when named in AUTOCODE_PASS_ENV. Token counts are kept: a TOKEN word followed by MAX, LIMIT, COUNT or BUDGET, or after MAX, holding a whole number (OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=100000). Each stage record lists the withheld names (never values) under withheld_env. The rules are in tools/autocode_agent_env.py.

Providers sign in from their own stored logins (OpenCode, Codex and Kilo auth files, and the Claude Code login), so the default routes need none of these. If your provider or your project's tests genuinely need one, name it:

AUTOCODE_PASS_ENV=ZHIPU_API_KEY,DATABASE_URL autocode "..."

Configured providers' version, model and authentication preflights use the same filtered ambient environment as their stage processes. A check that needs an explicitly named variable therefore needs the same AUTOCODE_PASS_ENV opt-in. An authentication listing can still describe a stored route without proving the request will authenticate. When a configured stage returns a native HTTP 401 or 403 API error, AutoCode names any withheld candidates and points to the opt-in; those names do not establish which variable the provider requires. Pass only variables you intend to expose to that provider and its agents. Private controller tokens remain withheld even when listed.

Withholding variables is not a sandbox: an agent with shell access can still read files such as ~/.aws/credentials or ~/.config/gh/hosts.yml.

Resuming preserves the saved engine, models and separate role sessions. Start a new run when switching between Codex, OpenCode and Claude Code; their session IDs cannot be reused across engines. A response with an unexpected session ID pauses the run. OpenCode version or configuration drift pauses the saved run, including changes to custom config-directory files, agent definitions and local plugin/tool definitions. This adapter was live-checked with OpenCode 1.18.31. OpenCode 2.x is accepted: the stage runs in the workspace directory with --standalone, and reasoning effort is provider/model#effort rather than --variant. A saved run records the OpenCode version, so resume refuses a silent major-version change. Strict tool containment and verified visual delivery stay qualified only for OpenCode 1.18.33.

Check provider compatibility

Before relying on a new tool/model combination, run the shared provider conformance probe. It checks the same workspace, JSON report, command evidence, usage and session rules through Codex, OpenCode, KiloCode and Claude Code. Passing applies to that recorded tool/model/configuration combination.

Codex provider overrides

Pass --engine codex to start a Codex-engine run. Roles can use different Responses-compatible Codex providers in one run, e.g. planning on the ChatGPT subscription while the Validator audits and the Builder codes via another compatible provider:

python3 tools/autocode.py "Build a greeting CLI" --workspace /path/to/project \
  --engine codex \
  --astra-model gpt-6-astra \
  --sol-model audit-model --sol-provider other_provider \
  --terra-model implementation-model --terra-provider other_provider --reasoning-effort high

Each role can also have its own reasoning effort. For example, use the Astra route at extra-high (xhigh) for read-only discovery and planning:

python3 tools/autocode.py "Build a greeting CLI" --workspace /path/to/project \
  --engine codex --astra-model gpt-6-astra --astra-reasoning-effort xhigh

Role-specific effort overrides the shared --reasoning-effort value. All selected models and providers are saved in the run checkpoint, so resumed runs retain this assignment.

An interactive terminal starts in chat mode by default. The Requirements Gatherer presents a few material questions at a time; type replies directly or /default to accept a proposed default. When the build brief is displayed, type feedback to revise it, y to approve that exact revision, or /pause to save and exit. After approval the implementation, validation and review loop runs automatically within the configured limits. During questions, /feedback TEXT sends a broader correction to the Requirements Gatherer.

Use --chat to select this mode explicitly, or --no-chat for one command per turn. Non-interactive invocations default to the command-per-turn interface.

--<role>-provider is saved per role like models and is passed to Codex as a model_provider override; roles without a provider keep the local Codex login (ChatGPT auth). The named provider must implement the OpenAI Responses API. For the connected Z.ai Coding Plan, use the OpenCode engine above. Changing the global provider/auth in local Codex config still pauses a saved Codex-engine run.

A final message that is only a shell command

Some models served through a Codex transport sometimes end a stage with the arguments of a shell tool call instead of the stage's JSON report (#512):

{"cmd": "ls docs/ && wc -l docs/*.md"}

AutoCode treats this as a known provider defect, never as a report, and never runs the command. A final message counts as only a command when its keys are cmd or command (holding a command) and, at most, the other arguments of a Codex shell call (workdir, timeout_ms, yield_time_ms, max_output_tokens, shell, login, with_escalated_permissions, justification), and none of them is a field of the stage's schema. A command whose text embeds a JSON report is still a command: AutoCode does not unwrap it, though a wrapper in your provider command may before AutoCode reads the report. The stage is rejected with Provider final message is a shell command ({"cmd": ...}) instead of the JSON report; ... and then:

  1. On a transport that keeps sessions (--engine codex, OpenCode, or a tool with output = "opencode_events" and resume), the runner resumes the stage's own session once and asks for the report alone, with no command. This correction spends no report-repair attempt. It applies to every stage, planning stages included, but only when it would run on the route (engine, provider, model, effort) that started the session: a Plan Reviewer attempt that ran on its one-use fallback route goes straight to step 2.
  2. Otherwise, or when that correction fails, the usual report-only repairs run (report_repair.max_attempts, two by default), told that the rejected report is a command with nothing to repair.
  3. A stage that keeps doing it stops there, usually at PAUSED_REPEATED_FAILURE, with that reason in stop_reason. As for any stuck stage, the Investigator looks at it first.

Roles affected. Every stage's final message is checked, so every role is covered. The defect was seen (2026-10-05) on the roles one profile ran through Codex with the gocode provider: the Plan Reviewer (astra_challenge, astra_finalize) and the Tester (sol). Its Builder and Requirements ran through another tool and did not show it. No role is qualified on a route that shows the defect: if a role keeps stopping this way, run it on another model, and check a new tool/model pair with the conformance probe first.

GoCode

Register GoCode as ~/.config/autocode/providers/gocode.toml (the command wraps gocode env then codex exec). The provider sets API credentials for its own child process. Keep OPENAI_API_KEY, CODEX_API_KEY, and OPENAI_BASE_URL out of the AutoCode process itself: ambient keys trip joint-planning's billing-route gate (PAUSED_BILLING_ROUTE) even when GoCode would have supplied the right route for the child. Unset them in the shell that launches autocode or scenarios/run.py, or put them in the provider's forbid_env so AutoCode strips them before the stage.

Put -o {report} (or --output-last-message {report}) in the command list as its own argv slot, not only inside a sh -c string. When Autocode sees that slot, the stage prompt asks the model to return the JSON report as its final response (Codex persists it). If the flag is buried in a shell string, Autocode asks the model to write the report with a tool, which fails under --sandbox read-only and yields empty Requirements contracts with REPORT_WRITE blockers (docs/bugs/2026-10-12-gocode-cross-product-fixes.md).

name = "gocode"
command = [
  "sh", "-c", "eval \"$(gocode env --shell bash)\" && exec \"$@\"", "gocode",
  "codex", "exec",
  "-C", "{workspace}",
  "--sandbox", "{sandbox}",
  "--model", "{model}",
  "-c", "model_reasoning_effort=\"{effort}\"",
  "--output-schema", "{schema}",
  "-o", "{report}",
  "-",
]
prompt = "stdin"
models_command = ["gocode", "models"]
version_command = ["gocode", "--version"]

[roles]
astra = { model = "gpt-5.6-luna", effort = "high" }
terra = { model = "gpt-5.6-luna", effort = "low" }
sol = { model = "gpt-5.6-luna", effort = "high" }
completion = { model = "gpt-5.6-luna", effort = "high" }
glm = { model = "gpt-5.6-luna", effort = "low" }
plan_reviewer = { model = "gpt-5.6-luna", effort = "high" }

In ~/.codex/config.toml, under [model_providers.gocode.auth], set timeout_ms = 45000 so a slow gocode api-key-helper refresh does not end the stage as a bare exit 1. Autocode names that stop as a provider auth-helper timeout when the trailing log lines match.

The scenario harness profile gocode-cross (scenarios/harness/profiles.py) is the reliability scorecard route: Luna for requirements and planning, Terra for the Builder, Sol for the Plan Reviewer, Validator and Completion Reviewer, Astra for the Resolver. Batch the three RELIABILITY.md cases with three repeats each:

unset OPENAI_API_KEY CODEX_API_KEY OPENAI_BASE_URL
for scenario in bugfix-iso-weeks greenfield-todo-cli feature-timesheet-by-project; do
  for n in 1 2 3; do
    .venv/bin/python scenarios/run.py run "$scenario" --profile gocode-cross \
      --i-authorize-live-model-spend --out .scenario-runs/gocode-cross-scorecard
  done
done
.venv/bin/python scenarios/run.py stats --out .scenario-runs/gocode-cross-scorecard

Any FALSE_COMPLETE blocks the change under test. A drop in pass rate is investigated by re-running the same case on origin/master.

Claude Code provider

--engine claude (or --provider claude, or engine = "claude" in the project settings) runs every role through Claude Code (claude -p) with your Claude Code login: no OpenCode or Codex install, no API key. It is built in (tools/providers/claude.py); --engine claude is the OpenCode engine's facade with the provider claude, so the status view shows provider: "claude" and every route's engine opencode.

claude auth login                     # once, with a Claude subscription
autocode doctor --engine claude       # claude on PATH and logged in, in the agents' environment
autocode --engine claude "Add a --json flag to the export command"

Default routes: Sonnet (claude-sonnet-5-5) drafts requirements and plans and tests, Opus (claude-opus-5-5) reviews plans, resolves and completes, Haiku (claude-haiku-4-5-20251001) builds; every role at effort medium. A stuck Builder's stronger attempt runs Sonnet and its checkers move to Opus. The usual --*-model and --*-reasoning-effort flags take these bare ids and the efforts low, medium, high, xhigh and max.

How a stage runs. Each stage is one process: python -I tools/providers/claude_stream.py … -- claude -p --output-format stream-json … with the stage prompt on standard input. The translator inserts the report schema (--json-schema), reads Claude's stream and writes Codex-shaped events to the stage log, so sessions, usage, cost, command evidence, the idle watchdog and the output cap work as for any stage. Claude's raw rows (stream deltas left out) are kept beside the log as <stage>.claude.jsonl.

  • Sessions. Every stage starts a fresh Claude session: its stage record has expected_session: null and its command no --resume. When a role's earlier session is set aside for this, the record says so (fresh_session_reason); a role's first stage and every joint-planning stage have no earlier session to set aside. Only a same-stage correction (a report that did not parse, or a shell command returned as the report) resumes the stage's own session.
  • Reports. The report is the JSON object Claude Code's StructuredOutput tool accepted. A stage that ends without one gets the same-session format correction, then the bounded report repair. A report Claude Code rejected is never used.
  • Evidence. Every Bash call is a command_execution event with Claude Code's real exit code, cited as event:item_N; capture receipts work too. A command whose exit code Claude Code did not report (moved to the background, interrupted, timed out, denied, or an unrecognized result) has exit code null and is never evidence: run it again in the foreground.
  • Tools and permissions. The same --tools Bash,Read,Edit,Write,Glob,Grep on every stage, no MCP servers (--strict-mcp-config), no skills (--disable-slash-commands), project settings only (--setting-sources project). Edit and Write are pre-approved unless the stage's sandbox is read-only (planning stages); judging stages keep them, and the after-stage snapshot catches a judge's source edit. git commit, push, checkout, reset, stash, branch, rebase and merge are denied.
  • Login. Before every stage of a joint-planning run, after --accept-transport-change, and in doctor, claude auth status --json runs in the agents' environment and must report a first-party Claude subscription login (claude.ai or oauth_token). An API key (ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, an apiKeyHelper), Bedrock or Vertex is refused (PAUSED_BILLING_ROUTE); a variable only in your own shell is fine, because the agent scrub withholds it. auth status does not apply an untrusted project's settings, while claude -p trusts them, so before every stage, at run start and in doctor the project's .claude/settings.json is read too: one that sets apiKeyHelper, awsAuthRefresh, awsCredentialExport or gcpAuthRefresh, or an env entry for an Anthropic API key, auth token or base URL, CLAUDE_CODE_USE_* or CLAUDE_CODE_OAUTH_TOKEN, is refused, and so is one that is not valid JSON. A stage whose Claude Code still reports an API key source (apiKeySource in its first row) is stopped at once and pauses PAUSED_BILLING_ROUTE. A setup token reaches Claude Code only through AUTOCODE_PASS_ENV=CLAUDE_CODE_OAUTH_TOKEN. The account's email and organization are never stored or printed. auth status is necessary, not sufficient: the stage's own call proves it authenticates.
  • Environment. The agent environment, minus ten variables that would tie the child to a parent Claude Code session (CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_REMOTE_SESSION_ID, CLAUDE_CODE_CHILD_SESSION, CLAUDE_CODE_DEBUG, CLAUDE_CODE_DIAGNOSTICS_FILE, CLAUDE_CODE_TEE_SDK_STDOUT, CLAUDE_CODE_MESSAGING_SOCKET, CLAUDE_EFFORT, CLAUDE_AUTO_BACKGROUND_TASKS, CLAUDE_CODE_ENTRYPOINT), plus DISABLE_AUTOUPDATER=1.
  • Identity. A saved run records the launch policy (hashed), the resolved claude, its version, a hash of <workspace>/.claude/settings.json and hashes of ANTHROPIC_BASE_URL and CLAUDE_CONFIG_DIR. A change pauses it with PAUSED_TRANSPORT_CHANGED; after a claude update, autocode resume --accept-transport-change re-checks the login and continues. CLAUDE_CODE_MAX_OUTPUT_TOKENS is not part of it.
  • Cost. Each stage's reported cost is that call's share of Claude Code's total_cost_usd (list price, not your subscription's spend). Claude reports a session's total, so a resumed call subtracts what the session had already cost (a ledger under the run's claude-sessions/); when that is unknown the stage falls back to the dated price estimate.

Stops.

Claude Code says The run
Output token limit (max_output_tokens) PAUSED_OUTPUT_CAP; a truncated Tester or Completion report is repaired automatically. Raise CLAUDE_CODE_MAX_OUTPUT_TOKENS or name another model.
Context window limit PAUSED_PROVIDER_UNCERTAIN (never an output cap)
Subscription usage limit, spend limit, billing PAUSED_BUDGET (with the reset time when Claude gave one)
Rate limit (429) PAUSED_RATE_LIMIT
Overloaded (529) PAUSED_PROVIDER_CAPACITY
Refusal PAUSED_CONTENT_FILTER
Authentication (401/403) PAUSED_PROVIDER_UNCERTAIN, naming any withheld variables; run claude auth login
An API key source in its first row (apiKeySource) PAUSED_BILLING_ROUTE; Claude Code is stopped before the stage runs
Anything else, a cut stream, a start failure PAUSED_PROVIDER_UNCERTAIN, no automatic replay

The model's own words never classify a stop, and nothing is retried automatically (Claude Code retries API errors itself). Rejections of a report that did not parse read "OpenCode final message is not a JSON report" for every event-mode provider.

The name claude is reserved. --provider claude always selects the built-in provider; a user ~/.config/autocode/providers/claude.toml (the retired example) is ignored and doctor names it. A run started with that example resolves to the built-in on resume and pauses PAUSED_TRANSPORT_CHANGED at its next stage; resume it with --accept-transport-change.

Limits. No kernel tool containment (Claude Code's permission flags and the workspace snapshot checks apply); no verified visual evidence; no --task-preflight; no hybrid split by stage; no replay of recorded Claude runs; no Investigator report adoption; autocode models lists nothing for the bare ids. program, components and verify take --provider claude rather than --engine claude; tasks has neither and runs its lanes on Claude Code through AUTOCODE_PROVIDER=claude, default_provider = "claude" or the project's engine = "claude". Claude Code loads CLAUDE.md files of the workspace and its ancestors, so keep a scenario's --out outside this repository. In a root cloud container, prefix runs with setpriv --bounding-set=-sys_admin,-sys_ptrace (cloud sessions).

Add a tool

OpenCode and Claude Code are built in. Any other tool registers with one TOML file, not a Python package. --provider <name> loads ~/.config/autocode/providers/<name>.toml and, if that file is absent, the bundled example at tools/providers/configs/<name>.toml. Configs inside a project are not loaded. The names opencode and claude are reserved for the built-in providers; a user config with either name is never read. KiloCode is a worked example.

name = "kilocode"
command = ["kilo", "run", "--auto", "--dir", "{workspace}", "--model", "{model}", "--variant", "{effort}", "--format", "json"]
prompt = "stdin"                        # or "file" (uses {prompt_file})
output = "opencode_events"              # or "report_file"; see below
resume = ["--session", "{session}"]     # optional; enables saved sessions
models_command = ["kilo", "models"]     # optional; or a static list: models = [...]
version_command = ["kilo", "--version"]

[roles]
astra = { model = "openai/gpt-5.6-sol", effort = "high" }
terra = { model = "openai/gpt-5.6-terra", effort = "medium" }
sol = { model = "openai/gpt-5.6-sol", effort = "high" }
completion = { model = "openai/gpt-5.6-sol", effort = "medium" }
glm = { model = "zhipuai-coding-plan/glm-5.3", effort = "medium" }
plan_reviewer = { model = "openai/gpt-6-sol", effort = "high", light_effort = "medium" }

For clear, small tasks the Plan Reviewer may use light_effort (or one lower standard effort tier) only when a new run used an automatic/default effort. An explicit reviewer effort, including a project effort setting, wins. Saved runs without effort provenance retain their existing effort on upgrade; model pins alone do not establish effort provenance. The review-call allowance still applies independently of this effort choice.

[roles] must keep each verifier on a different model family from what it checks (Planner/Plan Reviewer, Builder/Validator, Builder/Completion Owner); a run whose roles break that pauses with PAUSED_CROSS_MODEL before any agent is launched.

Placeholders are {model}, {effort}, {workspace}, {report}, {schema}, {prompt_file}, {run_dir}, {role}, and {sandbox}. The opt-in Codex artifact adapter below adds the standalone {sandbox_args} argv splice. {sandbox} is read-only for planning, workspace-write for the builder, and workspace-write for the judging stages (Validator, Completion Owner, milestone checkpoint): their contract requires writing runner-owned operational files under .autocode/ (capture receipts, reports), which read-only forbids. Their source contract stays enforced by the runner's after-stage workspace snapshot, not by the sandbox. {effort} reaches the tool only if the command uses it. Use {{ and }} for literal braces in a command argument, such as ${{VAR}} or {{"key":1}}; single braces are reserved for placeholders. Changing the config file or the tool version pauses a saved run.

A different tool for one role

For a new run on --engine opencode --provider opencode, repeat --role-transport ROLE=PROVIDER to select an external configured tool for only those roles. ROLE is the existing CLI code name, such as sol or completion; PROVIDER names its registered TOML config, such as kilocode. Each selection requires an explicit corresponding model flag. Select its exact model ID from that tool's catalogue, including a bare ID when the tool publishes one:

autocode models --provider opencode
autocode models --provider kilocode
# Replace the placeholder with an ID actually offered by the second catalogue.
autocode "Your task" --engine opencode --provider opencode \
  --role-transport sol=kilocode --sol-model '<MODEL_FROM_KILO_CATALOGUE>' \
  --sol-reasoning-effort high

The other roles retain their routes selected by the ordinary model flags and OpenCode defaults. Roles derived mid-run (such as Analyst, Investigator, Architect, Acceptance Tester, Resolver, Stuck Investigator, or Utility) inherit the external tool transport identity bound to their source role when their own route is on that tool. A derived role whose own route stays on the run's tool, such as a Resolver given its own --resolver-model on OpenCode, inherits nothing and runs there. Keep the GLM and MiMo role flags when using a profile that assigns them requirements, planning, building, plan review or resolution; a role selection does not assign every role to the new tool. Each tool checks only its own selected models and auth routes. At build start, the model-access probe covers every tool whose config declares [auth] billing routes, including a selected tool when the run's own tool declares none. It sends each role's model only through the tool that runs that role. Before the first request, it checks the login of each of those tools that still has a model to probe; a tool whose models all passed earlier in the run is not probed again. A pass on one tool never counts for the same model on another. Independent verification and all ordinary approval, evidence and completion gates still apply.

The binding is immutable once the run starts. Do not repeat --role-transport when advancing or reattaching with TaskRun; pass it in start_options only. A missing or mismatched saved identity cannot fall back to the default tool. Changes to a bound config fingerprint, executable path or version pause rather than move its session to another tool; --accept-transport-change does not replace these bindings. This selection cannot combine with --single-model or recorded replay.

Ordinary transport compatibility does not qualify a tool for native role isolation or image acceptance. Those flows still require their exact supported native owner and independently verified containment/image transport. Registered Kilo roles remain refused by those guards until such qualification exists; a model appearing in its catalogue is insufficient. Check the concrete tool/model pair with provider conformance before relying on it.

Builder retry on a tool

A Builder that keeps failing a milestone gets one ordinary retry and then one stronger attempt (Models). By default that attempt runs GPT-6 Sol, and a checker on GPT-6 Sol moves to GLM; a tool whose model list (models or models_command) lacks GPT-6 Sol, or lacks GLM while a checker would move to it, gets only one more ordinary retry instead. A tool that serves other models names its own in an optional [builder_retry] table (the built-in claude provider uses the same policy: Sonnet, checked by Opus):

[builder_retry]
strong_model = "claude-sonnet-5-5"   # the Builder's stronger attempt
checker_model = "claude-opus-5-5"    # a Tester or Completion Reviewer on strong_model moves here
strong_effort = "xhigh"              # optional; xhigh when left out

Both models are the tool's own spelling. When the config lists models, both must be in it. strong_model must differ from the [roles] Builder's model, and checker_model must be neither strong_model nor another model of its GLM or MiMo family; a config that breaks either is refused when it loads. A new run takes the table when it is created (--builder-strong-model still wins). A Builder that already runs the strong model makes its stronger attempt on that model at strong_effort. When the stronger attempt starts, a Tester or Completion Reviewer that runs the strong model moves to checker_model until the next milestone, as does one on another model of the strong model's GLM or MiMo family. When the Builder's model has no provider/ prefix it moves only when it runs the strong model in the tool's spelling (or such a family member), is neither pinned nor on another provider, and checker_model is a model the run already routes a role to; otherwise the run pauses with PAUSED_BUILDER_RETRY_LIMIT before changing any route. A config without the table keeps the default models, and provider/model names such as KiloCode's keep the earlier rule (a checker that cannot move is left for the cross-model guard). Adding or changing the table changes the config file, so saved runs on that tool stop with PAUSED_TRANSPORT_CHANGED at their next stage: change it between runs.

Output modes

output says how the result comes back:

  • output = "report_file" (the default): the tool writes exactly one JSON object to {report}, as codex exec -o does. Every stage starts fresh. Command evidence is a capture_command receipt file, not an event: id. These tools need supported usage events for token accounting; otherwise those counts remain unknown in the usage ledger.
  • output = "opencode_events": the tool prints OpenCode-format JSON events, as opencode run --format json and kilo run --format json do. Autocode reads the final report, token usage and command exit codes from those events, and resumes each role's session with the required resume template, for example resume = ["--session", "{session}"].

Every structured handoff for these output modes includes an executable capture_command, including standalone review, design, discuss and investigation jobs. Models append --output .autocode/evidence/<unique-name>.json -- <command> to that value. It uses the public autocode.py capture entry point; the autocode_capture_command.py implementation module is not a standalone command. An existing handoff command and its explicit output mode are preserved; the supplied default inherits the runner's output-mode environment. This supplies tool context without granting additional filesystem permissions.

The runner can fill an omitted check exit code from a unique executed event or the cited, verified capture receipt before checking the unchanged report schema. It never replaces a supplied exit code, guesses from output text, or resolves ambiguous executions. The original report is retained as .reported.json, and the stage records the derived metadata. Nonzero exits remain failures. For report_file tools, capture commands must inherit AUTOCODE_CAPTURE_CONTEXT from the tool process: the capture helper records it automatically and the validator checks it against the saved attempt. Receipts from another attempt, missing capture context, or changed output hashes are rejected. Event providers continue to require their independent tool-event attestation.

A stage log holds the tool's stdout and stderr. When a tool exits with an error, AutoCode reads the provider's reason from its error and turn.failed JSON events and from the plain-text error lines (ERROR: …, Error: …) that end the log, as codex exec without --json prints them. So ERROR: exceeded retry limit, last status: 429 Too Many Requests stops the stage as a rate limit, and a used-up plan or a busy model as a quota or capacity stop (Models). Tool output earlier in the log is never read as the provider's error, even when it mentions 429.

Codex commands that write capture receipts

A registered report_file command that passes --sandbox read-only to Codex cannot create AutoCode's required capture receipts. For that command, opt in to sandbox_adapter = "codex_artifacts" and replace the legacy sandbox flag and {sandbox} value with the standalone {sandbox_args} argument:

This adapter permits -C/--cd only with the exact {workspace} binding; literal or derived destinations and other sandbox/worktree overrides are refused before launch. Config arguments must use a valid key=value override, with policy and project-trust keys reserved for the adapter. JSON blobs are not config overrides.

name = "codex_receipts"
sandbox_adapter = "codex_artifacts"
command = ["codex", "exec", "--ephemeral", "{sandbox_args}", "-C", "{workspace}", "--model", "{model}", "-c", "model_reasoning_effort=\"{effort}\"", "-c", "approval_policy=\"never\"", "-c", "forced_login_method=\"chatgpt\"", "--output-schema", "{schema}", "-o", "{report}", "--json", "-"]
prompt = "stdin"
output = "report_file"
version_command = ["codex", "--version"]

[roles]
astra = { model = "gpt-6-sol", effort = "medium" }
terra = { model = "gpt-6-luna", effort = "medium" }
sol = { model = "gpt-6-sol", effort = "medium" }
completion = { model = "gpt-6-sol", effort = "medium" }
glm = { model = "gpt-6-luna", effort = "medium" }
plan_reviewer = { model = "gpt-6-sol", effort = "medium" }

[auth]
command = ["codex", "login", "status"]
forbid_env = ["OPENAI_API_KEY", "CODEX_API_KEY", "OPENAI_BASE_URL"]
[[auth.routes]]
models = "gpt-"
pattern = "(?m)^Logged in using (ChatGPT)$"
expect = "ChatGPT"

Save this as ~/.config/autocode/providers/codex_receipts.toml, then select it with autocode "Your task" --provider codex_receipts. Choose models available to your login. Registered command providers synthesize Requirements defaults from the config's own glm model and effort. For a new provider-configured task, --glm-model overrides the model for both Planner and Requirements; --requirements-model wins for Requirements when given. The provider's Requirements reasoning default stays independent of --glm-reasoning-effort; use --requirements-reasoning-effort to change it. OpenCode keeps its separately defined Requirements defaults when neither model override is given.

An existing Requirements route keeps its saved model when --glm-model changes the Planner. Enabling joint planning at a supported migration boundary uses the same fallback only when creating a missing Requirements route. Pass --requirements-model to explicitly change that role, or --single-model on a new run to move every role.

This adapter requires Codex CLI 0.160.0 or later, checked before a model request. For planning and review it selects a named permission profile derived from :read-only, adding writes only to the workspace's .autocode/evidence/, .autocode/output/, and the exact assigned stage JSON report. The Builder keeps workspace-write. Codex's -o option saves the final JSON response; the model still runs actual capture commands to produce independently checked receipts. No permission answer automatically changes this profile.

Opting in passes --ignore-user-config to each Codex invocation. Global files are untouched and the stored login is reused, but user-level configuration, plugins, MCP servers and provider defaults are omitted. Supply any required, compatible options explicitly in the command. Managed requirements still apply. Do not combine the adapter with legacy sandbox flags, additional writable roots, configuration profiles or permission-policy overrides. The adapter rejects those combinations instead of silently overriding a policy.

Operational paths must be canonical and unaliased. Pre-existing symlinks, hard-linked files and special files in the writable operational directories are rejected before launch; AutoCode does not delete or rewrite them. A stage report must be a JSON file under the run's iterations/ directory. Existing source snapshot, receipt identity, hash, regression-proof and completion checks still apply. Language tools that need additional caches must use an allowed operational path or a separately configured provider; this adapter does not grant arbitrary cache directories.

Existing provider configs and --engine codex keep their configuration semantics. Changing a saved run's provider config triggers its existing transport-change pause; inspect and accept that change through the public recovery command. Permission-profile behavior has been exercised on macOS with Codex 0.160.0; other platform/version combinations need their own conformance check.

Auth checks

A tool can declare how its subscription login is checked. Without an [auth] table Autocode does not inspect the tool's login. With one, before an OpenAI role starts, Autocode runs command, strips terminal color codes, and requires every match of pattern to equal expect. A mismatch, a failed listing, or a variable in forbid_env pauses the run with PAUSED_BILLING_ROUTE before any model is called:

[auth]
command = ["kilo", "auth", "list"]
forbid_env = ["OPENAI_API_KEY", "CODEX_API_KEY", "OPENAI_BASE_URL"]

[[auth.routes]]
models = "openai/"
name = "OpenAI"
billing = "subscription"
pattern = "^\\s*[●•]\\s+OpenAI\\s+(\\S+)\\s*$"
expect = "oauth"

A route may also carry name (the login name the tool itself prints; defaults to the prefix) and billing ("subscription" or "pay per token"; unknown when unset). These feed automatic route selection (#1426): the discovery step reads the same listing to learn which accounts are connected and which models each one can bill, so a model no connected login serves is never offered to the selector. A command template whose {effort} arguments (like Kilo's --variant {effort}) get no reasoning level omits those arguments instead of passing an empty value, and the model uses its own default level.

A tool that reports a subscription usage limit or runs out of pay-as-you-go credit pauses the run with PAUSED_BUDGET.

KiloCode

tools/providers/configs/kilocode.toml is bundled. It runs kilo run --auto. Its default routes use ChatGPT OAuth for openai/..., Zhipu AI Coding Plan for zhipuai-coding-plan/..., and Alibaba Token Plan for alibaba-token-plan/.... Optional zai-coding-plan/... and kilo/... routes require their separate Z.AI Coding Plan api and Kilo Gateway oauth logins. Check kilo models and kilo auth list for your installed version and configured account; distinct provider names are not credential aliases. Connect the routes you select with kilo auth first. The plan reviewer is GPT-5.6 Sol here because Kilo has no Cursor ACP route:

name = "kilocode"
command = ["kilo", "run", "--auto", "--dir", "{workspace}", "--model", "{model}", "--variant", "{effort}", "--format", "json"]
prompt = "stdin"
output = "opencode_events"
resume = ["--session", "{session}"]
models_command = ["kilo", "models"]
version_command = ["kilo", "--version"]

[roles]
astra = { model = "openai/gpt-5.6-sol", effort = "high" }
terra = { model = "openai/gpt-5.6-terra", effort = "medium" }
sol = { model = "openai/gpt-5.6-sol", effort = "high" }
completion = { model = "openai/gpt-5.6-sol", effort = "medium" }
glm = { model = "zhipuai-coding-plan/glm-5.3", effort = "medium" }
plan_reviewer = { model = "openai/gpt-5.6-sol", effort = "high" }

[auth]
command = ["kilo", "auth", "list"]
forbid_env = ["OPENAI_API_KEY", "CODEX_API_KEY", "OPENAI_BASE_URL"]

[[auth.routes]]
models = "openai/"
pattern = "^\\s*[●•]\\s+OpenAI\\s+(\\S+)\\s*$"
expect = "oauth"

[[auth.routes]]
models = "alibaba-token-plan/"
pattern = "^\\s*[●•]\\s+Alibaba Token Plan\\s+(\\S+)\\s*$"
expect = "api"

# Each coding plan keeps its own login and quota; the gateway is an explicit paid route.
[[auth.routes]]
models = "zai-coding-plan/"
pattern = "^\\s*[●•]\\s+Z\\.AI Coding Plan\\s+(\\S+)\\s*$"
expect = "api"

[[auth.routes]]
models = "zhipuai-coding-plan/"
pattern = "^\\s*[●•]\\s+Zhipu AI Coding Plan\\s+(\\S+)\\s*$"
expect = "api"

[[auth.routes]]
models = "kilo/"
pattern = "^\\s*[●•]\\s+Kilo Gateway\\s+(\\S+)\\s*$"
expect = "oauth"

Copy it to ~/.config/autocode/providers/kilocode.toml to change models or reasoning levels. Select an ID published by your kilo models whose prefix is declared in [auth] and whose login passes the check. Available model prefixes and login rows depend on your Kilo installation and configured account. If a selected model matches no configured route, PAUSED_BILLING_ROUTE lists those routed prefixes before running the login check. Choose a published model with one of those prefixes; add a route only when you intend to configure it. The message lists your loaded configuration, including user-defined routes. kilo/... IDs bill the Kilo Gateway pay-as-you-go account instead of a subscription. The [auth] table above runs kilo auth list before a role on any declared route and pauses with PAUSED_BILLING_ROUTE if its own login is absent or has the wrong mode:

Model prefix Kilo login Required mode
openai/ OpenAI oauth
alibaba-token-plan/ Alibaba Token Plan api
zai-coding-plan/ Z.AI Coding Plan api
zhipuai-coding-plan/ Zhipu AI Coding Plan api
kilo/ Kilo Gateway oauth

Each coding plan uses its separate login; a gateway login does not satisfy a coding-plan route. A missing Kilo Gateway oauth row refuses Gateway calls. For these routes the check also refuses a set OPENAI_API_KEY, CODEX_API_KEY, or OPENAI_BASE_URL. When [auth] declares routes, every selected model must match a declared prefix; add an [[auth.routes]] entry for another vendor before using it.

The bundled command uses Kilo's --auto for noninteractive stages: ordinary permission requests are approved once; effective explicit deny rules in Kilo's configuration and selected agent still block the tool. AutoCode does not replace that permission configuration or enable Kilo's permission-bypass flags. Without --auto, Kilo rejects the first request and exits with an auto-rejected-permission error. If you copied an older provider config to ~/.config/autocode/providers/kilocode.toml, add --auto to its command too; the bundled update does not replace your custom file. AutoCode's plan approvals, human reviews and recovery choices still require their own user input.

This command does not establish an OS sandbox or native read-only planning policy. A read-only stage that edits source is caught afterwards by AutoCode's workspace snapshot check and pauses; use explicit Kilo permission restrictions for operations that must be blocked before execution. See Kilo's permission reference.

The alibaba-token-plan/ route serves that login's own plan rather than the Gateway: Qwen (qwen3.8-max, qwen3.7-plus, qwen3.6-flash and the rest of kilo models' alibaba-token-plan/ list), and on the same login DeepSeek, GLM, Kimi and MiniMax. Because one login reaches several vendors, a Builder and the Tester that checks it can be different model families, which is what the cross-model guard is for.

Default provider

New runs use OpenCode unless you choose otherwise. --provider <name> picks the tool for one run. To change the default for every new run and for the dashboard, set AUTOCODE_PROVIDER=kilocode or add this to ~/.config/autocode/config.toml:

default_provider = "kilocode"

A saved run keeps the provider it started with, and --engine codex runs still use Codex. autocode-dashboard --provider <name> overrides the default for the dashboard; its model pickers list that tool's models.

See also: Models · Install · CLI

Conformance matrix

Generated by python tools/provider_matrix.py --write from tools/provider-matrix.json. Do not edit by hand. A version the offline conformance suite has not been run against is untested — never guess. Run the suite with python tools/provider_conformance.py --fake (no model calls).

Engine Version Transport Containment Visual Result Date Commit Note
opencode 1.18.33 opencode qualified qualified known-good 2026-10-08 a8852cf4 The version the glm53-mimo three-case reliability sweep ran on (docs/bugs/2026-10-06-opencode-2.md).
opencode 1.18.31 opencode untested untested known-good 2026-10-01 68e89aa4 Live-checked in the 2026-10-01 glm53-openai sweep; containment/visual stay qualified only for 1.18.33.
opencode 2.0.20 opencode-standalone refused refused accepted-for-ordinary-runs 2026-10-06 9a31a8e8 Uses --standalone and a provider/model#effort id. A 2.x binary fails the containment and visual checks closed until it has its own conformance pass (docs/bugs/2026-10-06-opencode-2.md).
codex native codex n/a n/a known-good 2026-10-03 b96a633e Native Codex probes in docs/provider-conformance.md; ChatGPT login required.
kilocode registered-adapter kilocode n/a n/a known-good 2026-10-03 b96a633e Registered KiloCode adapter; see docs/provider-conformance.md.

Connection setup and company backends

autocode connections list --json lists built-in Kilo, OpenCode and Claude Code and user-registered providers. connections check --provider NAME --json checks credentials without model traffic. connections login --provider NAME opens the backend's own interactive sign-in. AutoCode does not store a second copy of keys, SSO sessions, or AWS credentials. Kilo/OpenCode login lets the backend choose its supported API-key or browser flow; existing route/billing checks still apply before a task launches.

A company GoCode adapter can keep its corporate authentication and Bedrock routing. AutoCode does not require it to go through Kilo or OpenCode. In a registered provider's user-level TOML, optionally add:

[connection]
login_command = ["your-company-cli", "its-documented-login-command"]
status_command = ["your-company-cli", "its-documented-login-status-command"]

These are argument arrays executed without a shell. Use the company's documented commands; the names above are placeholders, not GoCode commands. The status command must make no inference requests: exit 0 for credentials present, 1 for sign-in required, and another code for a failed check. Its stdout/stderr is withheld from clients. The interactive login command owns its terminal output. Without these optional commands AutoCode reports login as unchecked and offers no guessed sign-in command. Provider files are trusted user configuration; files in a project are never discovered as connection definitions.

AutoCode direct connections (issue #1493)

AutoCode includes its own text/tool runtime. It does not require Kilo, OpenCode, Codex, Claude Code, or another coding-agent executable. In VS Code open Connections → AutoCode · Direct connection → Set up AutoCode, or run:

autocode connections setup
autocode connections check --provider autocode --json
autocode "hi" --provider autocode --joint-planning --spec-first

Setup is interactive in a terminal and launches no model. Choose mimo, zai, openai, claude, or a custom compatible API. One direct provider/endpoint is selected for a connection; mixed-provider routing remains available through the existing Kilo backend.

API choice Protocol Authentication Response limit field
MiMo Chat Completions api-key max_completion_tokens
Z.ai Chat Completions Bearer key max_tokens
OpenAI / custom compatible Chat Completions Bearer key max_completion_tokens
Claude Anthropic Messages x-api-key, version 2023-06-01 max_tokens

MiMo and Z.ai require an explicit base URL, including its version path. Use the exact endpoint and matching key for your billing route: ordinary API access and Token/Coding Plan subscriptions have separate endpoints. Setup shows the API examples and requires you to choose; it never falls back to another billing route. OpenAI defaults to https://api.openai.com/v1; Claude defaults to https://api.anthropic.com/v1. Endpoint overrides require HTTPS (HTTP is allowed only for loopback fixtures). This setup accepts API keys, not ChatGPT or Claude subscription logins. Kilo continues to own its separate sign-in and routes.

MiMo/Z.ai assistant messages retain reasoning_content across tool turns. Claude uses native tool_use/tool_result blocks and replays signed thinking blocks in order. Unsupported content and incomplete responses fail closed. Nonempty Chat Completions effort overrides are sent as reasoning_effort and must be supported by that model. Claude effort overrides are currently refused; its default reasoning is used. Redirects are refused, with no automatic parameter change, retry or provider fallback. Bedrock is outside this scope.

Model IDs are those the endpoint accepts, not Kilo/OpenCode routing aliases. Setup groups Planner/Builder/Requirements and independent reviewers/testers; the existing verifier-independence rules still apply. Reopening setup with blank model answers preserves every saved role assignment. models --provider autocode lists the configured roster; unconfigured model escalation is refused.

The API key lives in a separate auth.json file, mode 0600, under $XDG_CONFIG_HOME/autocode/direct/ (default ~/.config/autocode/direct/), whose mode is 0700. This is a private local file, not an OS keychain. The credential is bound to the API endpoint: changing the endpoint requires an explicit key for that destination. Status and launch arguments never contain key values. Listing connections reads metadata only; Check setup validates local setup, not live model access. configured and setup_required are distinct. Key rotation for the same endpoint preserves transport identity; changes to the API provider, endpoint, models or runtime change it and trigger the saved run's existing drift checks. Configuration is never read from project files.

Select Use for new chats after setup. This does not replace an existing Kilo/GoCode connection or change its model routes. CLI callers explicitly pass --provider autocode; setup does not silently change the global default.

The existing supported-Linux provider supervisor owns each launch and cleanup. Model-requested commands run only through AutoCode's existing kernel shell boundary, with credentials removed, no network, protected run files, and the stage's read/write authority. Read-only execution uses the existing verification copy mechanism. There are at most 32 model responses per stage and eight tool calls per response, an 8192-token requested response cap, a 60-second HTTP read bound, and a 90-second tool bound; outer task/stage/spend limits still apply. Tool output is bounded at 65536 bytes and explicitly marked when truncated. Actual tool output and exit codes supply evidence; model prose cannot manufacture command events. Reported input/output usage is retained across requests, including failed turns; output counts include reasoning. A separate reasoning-token breakdown is not yet reported by this runtime. Missing token fields and prices remain unknown.

This initial runtime supports text and shell tools with a fresh context per stage. It does not provide native image qualification, in-process file tools, MCP tools, or external-agent session resumption. Local HTTP fixtures and supported-Linux task tests verify protocol and safety behavior; they do not establish live model access. The implementation stays draft pending live qualification with an explicitly configured connection.

Protocol references: OpenAI Chat Completions, MiMo API and Token Plan setup, MiMo Chat Completions, Z.ai Chat Completions, Z.ai thinking replay, and Claude Messages.

Automatic routes for new runs

New runs automatically select qualified models from the chosen tool's connected accounts, preferring subscriptions and preserving independent checking. No per-role model flags are needed, including with TaskRun.start(workspace, brief). Explicit model, effort and tool overrides win; saved runs keep their choices. --no-auto-select retains fixed defaults. --auto-select requires selection to succeed instead of falling back when discovery or an independent checker is unavailable. See automatic model selection for discovery, reasoning levels, bounded preflight, recovery and the read-only selection preview.