A structured guide to aligning skill definitions, tool protocols, and shared context between two AI coding agents — so they amplify each other instead of colliding.
Why sync at all?
Opencode and Claude Code are both terminal-first AI coding agents, but they live in different runtime contexts. Opencode (by SST) is an open-source, model-agnostic CLI that reads project-level context files. Claude Code is Anthropic’s agentic environment that interprets CLAUDE.md files and skill definitions injected via system prompts or MCP servers.
When you run both in the same monorepo or multi-agent pipeline, skill drift is the first thing to kill your workflow. One agent enforces a TypeScript strict rule; the other ignores it. One uses a bash tool to scaffold; the other regenerates the same file. Synchronisation isn’t optional — it’s the load-bearing wall of any serious agentic setup.
02 — repository structure
The canonical skill tree
The simplest synchronisation strategy is a shared skills directory at repo root. Both agents are pointed at the same tree — opencode via its opencode.config.ts context paths, Claude Code via its CLAUDE.md skill references.
project-root/
├── .skills/ # canonical skill store (shared)
│ ├── SKILL_INDEX.md # master registry, read by both agents
│ ├── core/
│ │ ├── typescript-strict.md # oc: enforced on all .ts files
│ │ ├── error-handling.md # cc: wrap with Result types
│ │ └── naming-conventions.md
│ ├── agents/
│ │ ├── opencode-manifest.yaml # oc-specific overrides
│ │ ├── claudecode-manifest.yaml # cc-specific overrides
│ │ └── sync-bridge.yaml # shared invariants
│ ├── tools/
│ │ ├── bash/
│ │ │ ├── scaffold.md
│ │ │ └── test-runner.md
│ │ ├── mcp/
│ │ │ ├── filesystem-skill.md
│ │ │ ├── github-skill.md
│ │ │ └── postgres-skill.md
│ │ └── search/
│ │ └── web-search-skill.md
│ └── workflows/
│ ├── pr-review.md
│ ├── feature-scaffold.md
│ └── bug-triage.md
├── CLAUDE.md # cc entry: imports .skills/
├── opencode.config.ts # oc entry: mounts .skills/
├── mcp.json # shared MCP server registry
└── src/
├── agents/
│ ├── opencode-runner.ts
│ └── claudecode-runner.ts
└── ...
03 — skill anatomy
What a skill file must contain
For both agents to parse a skill consistently, every .md skill file must follow a shared frontmatter schema. Neither agent should rely on agent-specific fields in the canonical layer — those belong in the agent manifests.
--- # required YAML frontmatter ---
name: typescript-strict
version: 1.2.0
triggers:
- *.ts
- *.tsx
scope: file # file | project | session
priority: mandatory # mandatory | recommended | optional
agents:
- opencode
- claude-code
conflicts: []
depends:
- naming-conventions
---
# body: human + machine readable instructions
## trigger
Always enabled when editing TypeScript files.
## behaviour
- noImplicitAny: true
- strictNullChecks: true
- never use `any` unless wrapped in a branded type
## verification
Run `tsc --noEmit` before marking task complete.
04 — agent entry points
Wiring each agent to the shared tree
opencode.config.ts
Use the context array to mount .skills/**/*.md. Opencode prepends all matched files into the model context window automatically.
CLAUDE.md
Use the @path import syntax to pull skill files. Claude Code’s skill loader respects the frontmatter priority field — mandatory skills are injected first.
// opencode.config.ts
export default defineConfig({
context: [
'.skills/SKILL_INDEX.md',
'.skills/core/**/*.md',
'.skills/agents/opencode-manifest.yaml',
'.skills/tools/mcp/*.md',
'.skills/workflows/*.md',
],
model: 'anthropic:claude-sonnet-4-5',
mcpServers: import('./mcp.json'),
})
// CLAUDE.md (top of file)
# project skills
@.skills/SKILL_INDEX.md
@.skills/core/typescript-strict.md
@.skills/core/error-handling.md
@.skills/agents/claudecode-manifest.yaml
@.skills/tools/mcp/filesystem-skill.md
@.skills/workflows/feature-scaffold.md
05 — mandatory skill classes
The six mandatory skills for agentic workflows
Not every skill is optional. These six classes must be loaded by both agents on every session. Without them, agents make conflicting assumptions that compound across long tasks.
| skill class | purpose | key invariant | agent |
|---|---|---|---|
| code-conventions | Shared style rules, naming patterns, file layout | Neither agent renames or restructures without reading this first | |
| tool-registry | Which tools are available, their call signatures | Agents never invent tool calls outside the registry | |
| file-authority | Which agent owns which paths | No two agents write to the same file without a handoff protocol | |
| test-contract | Test coverage rules, assertion style, test runner commands | Task is never “done” until tests pass per this contract | |
| error-taxonomy | Canonical error types, Result wrapping, logging format | Agents never swallow errors silently; always propagate per taxonomy | |
| handoff-protocol | How agents transfer state, context, and partial work | All inter-agent hand-offs use a structured HANDOFF.md file |
06 — handoff protocol
The handoff skill: structure of inter-agent state
The most overlooked mandatory skill is the handoff protocol. When Opencode delegates to Claude Code (or vice versa), it must write a machine-parseable HANDOFF.md to a well-known path. The receiving agent reads this before acting.
// .skills/workflows/handoff-protocol.md
---
name: handoff-protocol
priority: mandatory
agents: [opencode, claude-code]
---
## HANDOFF.md schema (written by delegating agent)
task_id: string # unique task identifier
from_agent: opencode|cc # sender
to_agent: opencode|cc # receiver
status: partial|blocked # state at delegation
completed:
- action: "created src/auth/jwt.ts"
- action: "wrote 14 unit tests"
remaining:
- action: "integrate with express middleware"
- action: "run e2e suite"
context_files:
- src/auth/jwt.ts
- src/middleware/auth.ts
skills_active:
- typescript-strict
- error-taxonomy
blockers: [] # list or empty
## receiving agent behaviour
1. Read HANDOFF.md before any file edits
2. Load every file in context_files
3. Activate every skill in skills_active
4. Continue from "remaining" list only
5. Overwrite HANDOFF.md with updated status on done
07 — mcp bridge
MCP as the synchronisation bus
Model Context Protocol servers are the cleanest synchronisation bus available to both agents. Both Opencode and Claude Code can mount the same mcp.json file. Shared tools — filesystem, GitHub, search — are declared once and available to either agent without duplication.
// mcp.json (project root — loaded by both agents)
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres",
"${DATABASE_URL}"]
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": { "BRAVE_API_KEY": "${BRAVE_API_KEY}" }
}
}
}
.skills/tools/mcp/ that describes its usage contract — when to call it, what to do if it fails, and which agent is allowed to call it destructively (write vs. read-only access).
08 — agentic workflow
Full agentic workflow: feature scaffold example
Here is the complete orchestration loop for a typical “scaffold a new API feature” task, with both agents participating and all mandatory skills active throughout.
// .skills/workflows/feature-scaffold.md
---
name: feature-scaffold
priority: mandatory
agents: [opencode, claude-code]
---
## opencode responsibilities (steps 1–3)
- Parse task description; extract entity name, route, method
- Load: typescript-strict, naming-conventions, file-authority
- Create directory structure under src/{feature}/
├── {feature}.router.ts # route declarations only
├── {feature}.service.ts # business logic stub
├── {feature}.schema.ts # Zod validation schema
└── {feature}.test.ts # test file shell
- Write HANDOFF.md to .agent/handoff/{task_id}.md
## claude code responsibilities (steps 5–7)
- Read HANDOFF.md; load context_files
- Implement service methods with full error-taxonomy wrapping
- Fill test file using test-contract skill (vitest, 80% branch cov)
- Run: pnpm test --run src/{feature}
- Verify: tsc --noEmit (typescript-strict compliance)
## shared invariants (both agents)
- Never import from outside src/{feature}/ without file-authority check
- Never use console.log — use structured logger per error-taxonomy
- Git commit message must reference task_id from HANDOFF
09 — skill versioning
Keeping skills in sync: versioning and drift prevention
Skills drift the same way code does — silently, across commits, until two agents have fundamentally different understandings of the same rule. Version your skills like you version your API.
Common drift causes
Agent-specific manifests overriding shared skills without bumping the version field. Skill files edited without updating dependents listed in depends:.
Lint the skill tree
Add a pre-commit hook that validates all frontmatter fields, checks version bumps, and verifies that no agent manifest references a skill version older than what’s in SKILL_INDEX.md.
// scripts/lint-skills.ts (run in pre-commit)
const index = parseSkillIndex('.skills/SKILL_INDEX.md')
const manifests = [
'.skills/agents/opencode-manifest.yaml',
'.skills/agents/claudecode-manifest.yaml',
]
for (const m of manifests) {
const manifest = parseManifest(m)
for (const ref of manifest.skills) {
const canonical = index[ref.name]
if (!canonical)
throw new Error(`unknown skill: ${ref.name}`)
if (semver.lt(ref.version, canonical.version))
throw new Error(`${m} uses stale ${ref.name}@${ref.version}`)
}
}
console.log('skill tree: all agents in sync')
10 — summary
The minimal viable sync checklist
Before you ship an agentic pipeline that uses both agents, verify every item below. This checklist lives at .skills/SKILL_INDEX.md and is read by both agents as their first loaded file on every session start.
SKILL_INDEX.md — mandatory sync checklist
[ ] shared skill directory .skills/ exists at repo root
[ ] canonical frontmatter all skills have name/version/agents
[ ] opencode mount context[] in opencode.config.ts
[ ] claude code import @path imports in CLAUDE.md
[ ] mcp.json at root single MCP registry for both agents
[ ] skill lint hook pre-commit checks version drift
[ ] code-conventions loaded priority: mandatory, agents: both
[ ] tool-registry loaded priority: mandatory, agents: both
[ ] file-authority loaded defines write ownership per path
[ ] test-contract loaded defines done condition for both
[ ] error-taxonomy loaded propagation rules for both agents
[ ] handoff-protocol loaded HANDOFF.md schema enforced