OpenCode
OpenCode is fullsend's fourth agent runtime, opt-in per repo or per agent. It runs in the same sandbox, with the same credentials and egress policy as Claude Code and pi. Choosing between runtimes is in Agent runtimes.
Planned: sandbox tool hooks and write-capable agents (#7824). Until they land, OpenCode is experimental:
- Use it only for read-only agents (
triage,prioritize) on a disposable repo. fullsend does not enforce this, so do not select it forcodeorfix.- The harness must set
security.enabled: false. That also turns off the content scans of the agent, skills and repo context, and the secret redaction of outputs and transcripts.
Run it locally
Complete Running agents locally first. The CLI, OpenShell, credentials and the agents clone are the same. The fleet sandbox image includes the pinned OpenCode (1.19.1).
1. Write the tool policy. OpenCode reads its global config, including the tool-permission policy, from OPENCODE_CONFIG_CONTENT. A run fails before it starts when the variable is empty or has no permission block. Put it in an env file:
# fullsend-opencode.env
OPENCODE_CONFIG_CONTENT='{"provider":{"google-vertex-anthropic":{"id":"google-vertex-anthropic"}},"permission":{"*":"deny","read":"allow","glob":"allow","grep":"allow","list":"allow","skill":"allow","bash":{"*":"allow","rm *":"deny"},"write":"deny","edit":"deny","webfetch":"deny","task":"deny"}}'Allow every tool the agent needs. OpenCode runs without a TTY here, so it rejects any tool call the policy does not allow. The agent's own tools: list can narrow this policy but never widen it.
2. Set up the harness. In the agent's harness (harness/triage.yaml), turn security off and add the variable to the existing env.sandbox block:
security:
enabled: false
env:
sandbox:
# ...existing entries...
OPENCODE_CONFIG_CONTENT: ${OPENCODE_CONFIG_CONTENT}fullsend agent new --runtime opencode adds the env.sandbox entry for you.
3. Run the agent:
fullsend run triage \
--fullsend-dir /tmp/fullsend-agents/ \
--target-repo /tmp/target-repo/ \
--env-file fullsend-gcp.env \
--env-file fullsend-triage.env \
--env-file fullsend-opencode.env \
--runtime opencode \
--model google-vertex-anthropic/claude-sonnet-4-6@defaultOutput from a triage run (trimmed):
Model: google-vertex-anthropic/claude-sonnet-4-6@default (from --model flag)
Runtime: opencode (from --runtime flag)
runtime: selected "opencode" from --runtime flag
• Bootstrapping sandbox
Skill "github": uploaded to sandbox
Skill "issue-labels": uploaded to sandbox
Agent Bash allowlist (gh, curl, jq) is recorded but not enforced on opencode — ...
→ Iteration 1 of 2
→ Agent: claude-sonnet-4-6@default
⚙ bash: gh issue view 1 --repo <owner>/<repo> --json number,title,body,...
⚙ bash: gh label list --repo <owner>/<repo> --json name,description --limit 100
✓ Validation passed: Validating: output/agent-result.json against .../triage-result.schema.json
Agent exit code: 0
Validation: passedmetrics.json records runtime: opencode. To keep an agent on OpenCode without the flag, set runtime: on its agents: entry in config.yaml (see per-agent settings).
Models
A model is provider/model. The aliases resolve to ids in OpenCode's built-in model catalog:
| You give | OpenCode gets |
|---|---|
opus (default) | google-vertex-anthropic/claude-opus-5-5@default |
sonnet | google-vertex-anthropic/claude-sonnet-5-5@default |
haiku | google-vertex-anthropic/claude-haiku-5-5@default |
fable | google-vertex-anthropic/claude-fable-5-1@default |
| A bare id | the id, prefixed with FULLSEND_OPENCODE_PROVIDER (default google-vertex-anthropic) |
provider/model | unchanged |
The harness or --model wins over the agent's model: frontmatter. models.aliases in .fullsend/config.yaml can retarget an alias.
There is no fallback chain. Vertex enables models per project. On a project that does not serve 5.5, Claude Code falls back to 4.6, but OpenCode fails. Name a model your project serves, as in the example above.
At a glance
| Roles | Read-only agents (triage, prioritize) |
| Credentials | Same Vertex WIF credentials as Claude Code and pi |
| Instructions | Reads AGENTS.md; no CLAUDE.md bridge |
| Effort | --effort maps to OpenCode's --variant |
| Artifacts | output.jsonl, transcripts/<agent>-output.jsonl, metrics.json, and opencode-debug.log with --debug='*' |
| Not supported | Fallback chains, plugins:, sandbox tool hooks (#7824) |
Behaviour differences worth knowing
- Bash allowlists are not enforced.
Bash(gh:*)in the agent'stools:becomes plainbash, with a warning. To restrict commands, givebasha pattern map in the policy ("bash": {"*": "deny", "gh *": "allow"}). An agent that declares Bash gets that same map. - The agent is reset before every iteration. The runner removes agent, tool and config overrides the previous iteration could have written, re-uploads the agent, and checks that OpenCode loads it.
skills/in the config directory stays agent-writable until #7824. - Repo config is ignored. OpenCode does not load the target repo's
.opencode/config or skills.
Troubleshooting
| You see | Cause and fix |
|---|---|
OPENCODE_CONFIG_CONTENT is empty | The env file or the harness env.sandbox entry is missing (steps 1 and 2) |
OPENCODE_CONFIG_CONTENT ... invalid JSON or ... permission policy | The JSON is invalid, or its permission block is missing or invalid (step 1) |
hooks adapter not yet available | The harness still has security.enabled: true (step 2) |
ProviderModelNotFoundError | The id is not in OpenCode's built-in catalog. Use an id from the table above |
Vertex 404 NOT_FOUND for the model | Your project does not serve it. Name one it serves |
Falling back to default agent | OpenCode could not load the agent, and the iteration fails. Rerun with --debug='*' and read opencode-debug.log |
| Tool calls fail with a permission error | The policy does not allow that tool (step 1) |
See also
- Agent runtimes: choosing and selecting a runtime
- Running agents locally: the local-run setup this page builds on
- Runtime implementation: how the runtime is secured, per feature
