# OpenCode Agent

Run OpenCode through AML's native ACP profile with portable AML capabilities.
Canonical: https://agent-markup-language.com/docs/providers/agents/opencode/
Documentation index: https://agent-markup-language.com/docs/
Complete documentation: https://agent-markup-language.com/docs/llms.txt

**OpenCode Agent — `opencodeAgent()`**

A native OpenCode ACP profile that translates AML's model, system, filesystem, shell, and network requests into a private per-evaluation OpenCode configuration.

- **Best for:** OpenCode deployments that need AML orchestration and OpenCode's coding tools.

- **Know before using:** The executable and model-provider credentials are external prerequisites. OpenCode permissions are useful policy controls, but the enclosing Sandbox remains the hard boundary.

**Built-in** **Native ACP** **Private state**

## What this provider launches

The profile starts OpenCode with an ACP server command equivalent to:

```text
opencode acp --pure --cwd <effective-sandbox-cwd> <your args>
```

`command` changes the executable; AML always supplies the ACP arguments before your additional `args`. The profile
injects `OPENCODE_CONFIG_CONTENT` with an AML-owned `aml` primary agent, then gives every acquired session private
database, cache, config, and state directories. Its data directory is private by default and may be replaced only
through an explicit `env.XDG_DATA_HOME` setting.

**Note — Native OpenCode configuration**

The `config` option is OpenCode's typed `Config` object from `@opencode-ai/sdk/v2`, not an AML-specific arbitrary bag.
AML preserves your configuration and then overlays the `aml` agent profile, `default_agent`, and effective model
needed for the session.

The XDG directories isolate OpenCode-native user state. `XDG_DATA_HOME`, which contains OpenCode's `auth.json`, is
invocation-private by default. A caller may explicitly point it at a staged data directory through `env`, while AML
still owns the invocation's session database and every other XDG directory. Prefer a dedicated request-local data
directory or an environment credential over sharing the operator's complete interactive OpenCode data directory.

OpenCode still loads project rules from `AGENTS.md`, or
`CLAUDE.md` when no project `AGENTS.md` exists. It can also fall back to `~/.claude/CLAUDE.md` because this profile does
not replace `HOME`; set `OPENCODE_DISABLE_CLAUDE_CODE_PROMPT=1` in `env` when that compatibility behavior is unwanted.
Loaded rules remain OpenCode system instructions. AML-authored System content is delivered separately as a first-turn prelude.

Authored [`<Skill />`](https://agent-markup-language.com/docs/reference/primitives/skill/) packages use OpenCode's native discovery. AML preserves any configured `skills.paths` entries and appends each invocation-private staged package directory. It does not inline the Skill body or mutate the source package.

## Prerequisites

**OpenCode executable**

Install the `opencode` executable or provide an equivalent ACP-capable launcher with `command`. AML does not install
it.

**Model provider**

Configure the model provider and credentials that OpenCode expects. Pass environment values with `env` or use the
host/Sandbox environment.

**Working directory**

Use an existing Workspace or a trusted `directory`. When a Sandbox is active, its effective guest cwd wins over the
factory directory.

## Install and verify

Install OpenCode through its published CLI package, verify the executable, and configure at least one model provider:

```sh title="Terminal"
npm install --global opencode-ai@1.18.18
opencode --version
opencode auth login
opencode auth list
```

`opencode auth login` stores provider credentials in OpenCode's own data directory. `opencode auth list` also reports provider credentials discovered through environment variables. AML does not copy those credentials into a Workspace or infer which model provider you intended.

For an isolated invocation, pass the provider credential through `env` or stage the required OpenCode data into a
dedicated directory and set `env.XDG_DATA_HOME` to it. `OPENCODE_DB` remains invocation-private even when the data
directory is explicitly staged, so the Agent does not import or persist interactive session history.

The AML repository currently pins `opencode-ai@1.18.18` for its integration toolchain and `@opencode-ai/sdk@1.18.5` for the typed provider configuration. These versions are the repository's verification baseline, not a claim that every newer OpenCode release is compatible. Re-run the provider integration path when changing either side.

For container execution, the [OpenCode image variant](https://agent-markup-language.com/docs/sandbox-images/#choose-a-variant) includes this baseline. The default full image includes it too. The [alternative image guide](https://agent-markup-language.com/docs/providers/sandboxes/images/#opencode-cloudflare-sandbox) also documents Cloudflare's OpenCode-specific image.

**Caution — Install it where the Agent process runs**

A host-global installation is available to [`localSandbox()`](https://agent-markup-language.com/docs/providers/sandboxes/local/). Docker, Daytona,
Modal, or another remote Sandbox needs the executable in its own image or environment. Run `opencode --version`
through that same execution path before debugging AML configuration.

## Complete example

The example below chooses the explicit environment path for the `opencode-go` model provider; it does not depend on `opencode auth login` state. If you use native login instead, omit the key guard and `env` mapping and select a model attached to that account.

```tsx
import { Agent, AmlRuntime, Sandbox, Workspace, localSandbox, localWorkspace, opencodeAgent } from "@aml-jsx/sdk"

const apiKey = process.env.OPENCODE_API_KEY
if (!apiKey) throw new Error("OPENCODE_API_KEY is required")

const provider = opencodeAgent({
  model: "opencode-go/deepseek-v4-flash",
  // Provider-native variables are forwarded to the OpenCode process.
  env: { OPENCODE_API_KEY: apiKey },
})

const result = await new AmlRuntime({ agentProvider: provider }).evaluate(
  <Workspace
    id="opencode-review"
    provider={localWorkspace({ directory: "/absolute/path/to/repository" })}
    load={false}
    save={false}
  >
    <Sandbox provider={localSandbox()} access="read-write">
      <Agent system="Keep changes scoped to the requested review.">
        Review the repository and explain the three most important risks.
      </Agent>
    </Sandbox>
  </Workspace>
)

console.log(result)
```

Do not use an empty credential value as a production configuration. The example keeps the environment shape visible; your deployment should fail early or inject a real provider credential according to OpenCode's documentation.

## GLM models through the Z.ai Coding Plan

Z.ai officially supports OpenCode as a [GLM Coding Plan](https://docs.z.ai/devpack/overview) client, which makes this
profile the officially supported route to GLM models in AML — unlike the community
[GLM agent adapter](https://agent-markup-language.com/docs/providers/agents/glm/). Create a Coding Plan API key at z.ai and pass an OpenCode provider
configuration through the typed `config` option. The key bills against your plan quota (including free tiers), not
pay-as-you-go API credit:

```tsx
import { Agent, AmlRuntime, opencodeAgent } from "@aml-jsx/sdk"

const provider = opencodeAgent({
  config: {
    provider: {
      "zai-coding": {
        npm: "@ai-sdk/openai-compatible",
        options: {
          baseURL: "https://api.z.ai/api/coding/paas/v4",
          apiKey: "{env:Z_AI_API_KEY}",
        },
        models: {
          "glm-5.3": { name: "GLM-5.3" },
          "glm-5-turbo": { name: "GLM-5-Turbo" },
          "glm-4.7": { name: "GLM-4.7" },
        },
      },
    },
  },
  model: "zai-coding/glm-5.3",
})

const answer = await new AmlRuntime({ agentProvider: provider }).evaluate(
  <Agent system="Be concise and cite the files you inspected.">Summarize the highest-risk module.</Agent>
)
```

`Z_AI_API_KEY` must be present in the environment that launches OpenCode; the `{env:…}` reference is OpenCode's own
interpolation. Confirm the current endpoint, model ids, and key management on
[Z.ai's Coding Plan documentation](https://docs.z.ai/devpack/overview) when upgrading either side.

## Options and precedence

| Option      | Type                     | Default      | Semantics                                                                            |
| ----------- | ------------------------ | ------------ | ------------------------------------------------------------------------------------ |
| `command`   | `string`                 | `"opencode"` | OpenCode executable or launcher. Must be non-empty, trimmed, and free of null bytes. |
| `args`      | `readonly string[]`      | `[]`         | Appended after AML's `acp --pure --cwd <cwd>` arguments.                             |
| `config`    | `OpenCodeConfig`         | `{}`         | JSON-compatible OpenCode configuration captured before process acquisition.          |
| `directory` | `string`                 | —            | Fallback launch directory when no Sandbox supplies one.                              |
| `env`       | `Record<string, string>` | `{}`         | Provider credentials and environment configuration.                                  |
| `model`     | `string`                 | —            | Factory-level model fallback.                                                        |

Model precedence is:

1. `<Agent model="..." />`
2. `opencodeAgent({ model: "..." })`
3. `opencodeAgent({ config: { model: "..." } })`

AML sets `default_agent` to `aml` and merges the existing `config.agent` table, replacing the `aml` profile with the session-specific profile. This profile is `mode: "primary"` and exposes only the tools allowed by AML's normalized permission request. AML also merges its deny rules into the top-level OpenCode permission policy, which OpenCode applies to every native agent profile. Native `task` subagents therefore inherit the parent AML restrictions without disabling delegation.

OpenCode replaces its model-specific base coding prompt when a custom Agent has a non-empty `prompt`, so AML does not set that field. ACP has no system-message field; when the effective AML System text is non-empty, AML prepends it to the first user turn inside literal `<SYSTEM>` tags. Empty System content adds no prelude. This preserves OpenCode's native model-specific prompt, but the ACP protocol still carries the prelude as user-role content.

## Permission mapping

| AML permission            | OpenCode tools                      | OpenCode permissions                |
| ------------------------- | ----------------------------------- | ----------------------------------- |
| `filesystem: "read-only"` | Disables `edit` and `write`         | Denies `edit` and `write`           |
| `shell: false`            | Disables `bash`                     | Denies `bash`                       |
| `network: false`          | Disables `webfetch` and `websearch` | Denies both network tools           |
| Default permission        | Keeps tools enabled                 | Uses the AML profile's allow policy |

These mappings are provider-native controls. They do not grant access beyond the enclosing Sandbox, and an OpenCode policy cannot make a read-only Sandbox writable. Conversely, a writable host Sandbox is not made safe merely because an Agent prompt asks it to be careful.

Configured top-level permissions are preserved, but AML deny rules take precedence for a restricted evaluation. Child agents may narrow that policy further; they cannot regain filesystem, shell, or network tools denied by the parent AML request.

## State isolation and lifecycle

For each acquired session AML sets:

```text
OPENCODE_DB       <state>/opencode.db
XDG_CACHE_HOME    <state>/cache
XDG_CONFIG_HOME   <state>/config
XDG_DATA_HOME     <state>/data (default) or an explicit env.XDG_DATA_HOME
XDG_STATE_HOME    <state>/state
```

The profile creates the launch configuration after AML has resolved the effective Sandbox cwd and capabilities.
`OPENCODE_DB`, cache, config, and state always remain invocation-owned. AML then starts the ACP session, streams turns,
validates the response, and releases provider-owned state through the shared lifecycle. Do not persist these temporary
directories as a Workspace artifact unless you intentionally want OpenCode session state in your application.

## Failure modes and troubleshooting

1. **`opencode` is missing**

   Run `opencode --version` in the same host, container, or remote image that AML uses. A host installation is invisible to a remote Sandbox unless the image contains the executable.

2. **OpenCode starts but cannot select a model**

   Check the effective model identifier and the model provider's credentials. Remember the precedence order: `<Agent />` prop, factory option, then `config.model`.

3. **Network, shell, or edit operations still fail**

   Inspect both OpenCode's translated policy and the Sandbox's access. AML does not claim that the compatibility handshake verifies credentials, image utilities, model availability, network policy, or hostile-code isolation.

4. **OpenCode follows unexpected project guidance**

   Inspect the nearest project `AGENTS.md` or fallback `CLAUDE.md`, plus the operator's `~/.claude/CLAUDE.md` when Claude
   Code compatibility is enabled. Session-private XDG directories isolate OpenCode-native global rules, not repository
   rules or the home-directory Claude fallback.

5. **Configuration validation fails before launch**

   `command`, `directory`, and `model` must be normalized strings. `args` must contain strings without null bytes. `config` must contain finite JSON values without cycles.

## Provider references

- [OpenCode documentation](https://opencode.ai/docs/) — Install OpenCode, configure model providers, and manage native settings.

- [OpenCode ACP](https://opencode.ai/docs/acp/) — OpenCode's Agent Client Protocol server mode.

- [OpenCode project rules](https://opencode.ai/docs/rules/) — Project AGENTS.md and CLAUDE.md discovery, precedence, and custom instructions.

- [AML OpenCode profile source](https://github.com/we-are-singular/aml/tree/main/providers/agents/opencode/src) — Launch arguments, config overlay, and permission translation.

- [AML OpenCode tests](https://github.com/we-are-singular/aml/tree/main/providers/agents/opencode/tests) — Launch shape, permissions, precedence, and live session coverage.

## Related AML documentation

OpenCode uses the same AML capability and evaluation contracts as the other built-in ACP profiles:

- [JavaScript Tools](https://agent-markup-language.com/docs/cookbook/tools/) — Define, scope, validate, and operate an application-owned Tool.

- [Model Context Protocol](https://agent-markup-language.com/docs/cookbook/mcp/) — Declare MCP servers, transports, allowlists, and runtime requirements.

- [Runtime configuration](https://agent-markup-language.com/docs/runtime/) — Configure limits, cancellation, lifecycle events, tracing, and cleanup.

- [Agent component reference](https://agent-markup-language.com/docs/reference/primitives/agent/) — Review Agent props, resolution, capability scope, and result behavior.
