claude (plus a mock provider for tests).
Don’t confuse providers with tools. A tool skill like
/add-ollama-tool keeps Claude as the agent’s brain and gives it a local model to call; a provider skill replaces the brain for an entire group.How the provider is resolved
At spawn time the host resolves the provider name with a fixed precedence (src/container-runner.ts):
sessions.agent_provider— per-session overridecontainer_configs.provider— the group’s container config'claude'
~/.codex, OPENCODE_*/OPENAI_* passthrough). mock contributes nothing, and claude contributes only when setup has wired a custom Anthropic-compatible endpoint — ANTHROPIC_BASE_URL from .env plus a placeholder auth token for the vault gateway to overwrite. Inside the container, the runner reads provider from container.json — materialized fresh from the database at every spawn — and instantiates it from the in-container registry, passing the group’s model and effort through unchanged.
Every code path that creates a session on trunk writes agent_provider = null, and ncl sessions is read-only (list/get) — so the per-session override exists in the resolver, but nothing ships that sets it. In practice you switch providers per group.
Claude (default)
The Claude provider wraps the Claude Agent SDK. Itsmodel accepts an alias (sonnet, opus, haiku) or a full model ID, and effort is one of low, medium, high, xhigh, max — both optional, both falling back to the SDK default. It’s also the most capable provider: native slash-command handling, and transcript rotation that archives oversized session histories before a cold resume can wedge the container.
To point it at any Anthropic-compatible endpoint, set ANTHROPIC_BASE_URL in .env — the real token stays in the vault and is injected on the wire. See Credentials.
Two ways to run a different brain
The three provider skills split into two mechanisms:- Real provider implementations — OpenCode and Codex are TypeScript providers that live on the
providersregistry branch./add-opencodeand/add-codexcopy the files in, wire them into the host and container barrels, and rebuild the image. - No provider code at all — Ollama speaks the Anthropic API natively (
/v1/messages), so/add-ollama-providerkeeps the Claude provider and just redirects it: env overrides plus a model setting.
OpenCode (/add-opencode)
Copies opencode.ts (host and container sides) from the providers branch, appends one import line to each provider barrel, adds @opencode-ai/sdk to the agent runner, installs the opencode-ai CLI in the Dockerfile, and copies registration/Dockerfile guard tests so the wiring stays verified. The provider keeps a shared opencode serve runtime — spawned once, reused across queries, and torn down on abort or when the config changes — and routes models through OpenCode’s own config: OpenRouter, DeepSeek, OpenAI, Google, Anthropic, OpenCode Zen.
Configure via host .env: OPENCODE_PROVIDER, OPENCODE_MODEL (in provider/model form), optional OPENCODE_SMALL_MODEL, and ANTHROPIC_BASE_URL pointed at the upstream provider’s API base for non-Anthropic providers. API keys go in the OneCLI vault with a matching host pattern — never in .env. SDK and CLI versions are pinned together at 1.4.17; latest silently breaks session IDs.
Codex (/add-codex)
Copies codex.ts and codex-app-server.ts from the providers branch, wires the same barrels and guards, and installs the @openai/codex CLI in the Dockerfile (no SDK dependency — Codex is a binary). The provider spawns one codex app-server child process per query and speaks JSON-RPC over stdio, which gives it native session resume, streaming events, and MCP tools.
Auth: run codex login on the host to use a ChatGPT subscription (the host copies auth.json into a per-session ~/.codex mount), or set OPENAI_API_KEY + CODEX_MODEL in .env. An experimental third path points OPENAI_BASE_URL at any OpenAI-compatible endpoint — Groq, Together, self-hosted vLLM.
Ollama (/add-ollama-provider)
No files copied, no rebuild of provider code. The skill first checks that ContainerConfig supports the env and blockedHosts fields (patching src/container-config.ts and src/container-runner.ts if not), then writes the group’s container config:
ANTHROPIC_BASE_URL redirects the SDK to Ollama, the placeholder key satisfies it (Ollama ignores it), NO_PROXY bypasses the OneCLI credential gateway for the host hostname, and blockedHosts resolves api.anthropic.com to 0.0.0.0 so config drift can’t silently bill your account. The model is set in the group’s shared settings.json (data/v2-sessions/<group-id>/.claude-shared/settings.json) — Claude Code reads its model from there, not from env. Pick models that handle tool calls reliably; the upstream notes recommend Gemma 4 or Qwen 3 Coder over small 3B models.
What changes on a non-Claude provider
Verified against the provider sources on theproviders branch:
- Slash commands aren’t native. OpenCode and Codex declare
supportsNativeSlashCommands = false, so the poll loop formats slash commands as ordinary chat text instead of executing them. - No mid-turn input. Both queue follow-up messages and drain them between turns; the Claude provider streams them into the live turn.
- CLAUDE.md imports are emulated. Codex’s app-server doesn’t expand
@-importdirectives or auto-loadCLAUDE.local.md, so the provider resolves both itself to reconstruct the composed system prompt. - No transcript rotation. Only the Claude provider implements
maybeRotateContinuation— the guard against unresumable, oversized session transcripts.
Switching a group
Set the provider (and optionally model/effort) on the group’s container config, then restart:--provider claude (or clearing the field; the fallback is claude either way). To back the code out entirely, OpenCode and Codex each ship a REMOVE.md; Ollama needs no removal — its SKILL.md’s “Reverting to Claude” steps are just deleting the env and blockedHosts keys from the container config and the model setting from the shared settings file.
Next steps
Skills catalog
The three provider-install skills at a glance
Container config
The provider, model, and effort fields in full
Credentials
How provider API keys stay out of containers
Give agents tools
Keep Claude as the brain and add capabilities instead