Skip to main content

Use drwn with OpenCode

The opencode target projects the same declared harness that Claude Code and Codex receive into OpenCode's own surfaces. This page covers what a write produces, how the dedicated skills directory shifts OpenCode's cross-scope skill dedup toward the project, the residual dedup race that remains, and the diagnostics that watch it.

What a Project Write Produces

Inside a configured project with the opencode target enabled, drwn write maintains three OpenCode surfaces:

  • MCP servers — merged into opencode.json under the mcp key. Every other key in the file is user-owned configuration and passes through untouched.
  • Skills — the composed project skill set is copied into .agents/drwn/opencode-skills/ and declared project-relative in opencode.json under skills.paths.
  • Hooks — consented card hook policies compose into the .opencode/plugins/drwn-hooks.js plugin.

A projected opencode.json looks like:

{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"context7": { "type": "local", "command": ["npx", "-y", "@upstash/context7-mcp"], "enabled": true }
},
"skills": {
"paths": [".agents/drwn/opencode-skills"]
}
}

opencode.json stays user-owned: drwn records per-server field hashes plus the skills.paths entry it added, and cleanup removes only those. User-authored servers and user-added skills.paths entries are preserved — the managed path is appended, never replaced.

Why a Dedicated Skills Directory

OpenCode discovers skills from several sources at once — ~/.agents/skills/ (the drwn machine store), ~/.claude/skills/, project .claude/skills/, and project .opencode/skills/ — and dedupes same-named skills across them. Without the declaration, the machine-home copy won that dedup on every observation made against OpenCode 1.18.4: a project's customized copy of a same-named skill silently lost, and sessions read the machine bytes.

Declaring a novel directory via skills.paths is the lever that shifts this. The effect is group-level, not path-level: with the declaration in place, OpenCode resolves one of the project's copies (the declared directory or another project surface such as .claude/skills — which carry identical composed bytes) in the large majority of resolutions. Re-declaring an already-scanned path (such as .claude/skills) changes nothing, which is why drwn projects a dedicated directory under its own project home instead of reusing an existing surface.

The residual dedup race

OpenCode 1.18.4's source scan is nondeterministic. Measured over 90 probes against an identical drwn-written project, the machine-store copy still won 21 resolutions (per-run rates ranged 17–30%); the rate is condition-dependent and upstream-nondeterministic, so no fixed number can be claimed. The declaration moves the failure from every session to intermittent — a large reduction, not an elimination. If a customized skill occasionally behaves like the machine-store version in an OpenCode session, this race is the likely cause; the only full closure is removing the same-named machine-store copy itself.

.agents/drwn/opencode-skills/ is a projection of the same composed skill set written to .claude/skills/ — one composer writes both in the same step. Do not edit it; edit the card source and rerun drwn write. The directory is gitignored by default alongside the other projection surfaces (see committedSurfaces for opting in to committed projections).

Partial Writes

The skills.paths declaration carries skill-surface semantics inside the shared opencode.json ownership record:

  • drwn write maintains the directory, the declaration, and the mcp key.
  • drwn write --skills-only writes the directory and updates skills.paths, leaving the mcp key untouched.
  • drwn write --mcp-only maintains the mcp key only and retains skills.paths as recorded.

The opencode.jsonc Limitation

drwn only manages opencode.json. When an opencode.jsonc file exists, the write skips the config entirely: MCP servers and the skills.paths declaration are withheld with a warning, while the skills directory is still projected. In that state the machine-store copy keeps winning skill dedup — migrate the config to opencode.json, or declare .agents/drwn/opencode-skills in the .jsonc yourself. The shadowing diagnostic recognizes a manual declaration in opencode.jsonc (comments and trailing commas tolerated) and downgrades the warning accordingly.

The Shadowing Diagnostic

drwn doctor and drwn status report cross-scope skill shadowing per project. For each projected skill whose name also exists in ~/.agents/skills/ or ~/.claude/skills/, project status carries an OPENCODE_SKILL_SHADOWED issue under ambientCapabilities.opencodeSkillShadowing:

  • warning — the managed skills.paths declaration is absent or drifted; OpenCode resolves the machine copy and project customization does not reach sessions. Run drwn write (with opencode.jsonc, declare the directory manually).
  • advisory — the declaration is present and current: shadowing risk is reduced, not eliminated. The collision remains live and the residual dedup race can still intermittently resolve the machine copy; eliminating the same-named machine-store skill is the only full closure.

Only skills the opencode surface actually projects (shared and Claude-surface scopes) are inspected; codex-only skills cannot produce these issues. Warnings never change doctor's exit code; only error-severity issues do.

Machine Scope

drwn write --root merges machine-Worker MCP servers into ~/.config/opencode/opencode.json and composes machine hook policies into ~/.config/opencode/plugins/drwn-hooks.js. The dedicated skills directory is a project-scope surface only: machine writes do not create it, and the machine skill store remains ~/.agents/skills/.

Cross-References