Cross-Tool Agent Interoperability
Write agent definitions that work across Claude Code, Cursor, OpenCode, and Cline without duplication.
Quick Start
All four tools define agents as markdown files with YAML frontmatter. The body is the system prompt.
---
name: code-reviewer
description: Reviews code for quality and best practices
---
You are a code reviewer. Analyze code for security, performance, and maintainability.
Store agents in tool-specific directories. Unlike skills, there is no single shared directory -- each tool has its own agent location.
Agent Directories
| Scope | Claude Code | Cursor | OpenCode | Cline |
|-------|------------|--------|----------|-------|
| Project | .claude/agents/ | .cursor/agents/ | .opencode/agents/ | .clinerules/agents/ |
| User | ~/.claude/agents/ | ~/.cursor/agents/ | ~/.config/opencode/agents/ | N/A |
| Plugin | Plugin agents/ dir | N/A | N/A | N/A |
Priority (when names collide): CLI flags > project > user > plugin (Claude Code). Project > user (Cursor, OpenCode).
Frontmatter Compatibility Matrix
| Field | Claude Code | Cursor | OpenCode | Cline |
|-------|------------|--------|----------|-------|
| name | Required | Required | Filename = name | Filename = name |
| description | Required | Required | Required | Required |
| model | sonnet/opus/haiku/inherit | Cursor model names | provider/model-id | N/A |
| tools | Allowlist (tool names) | Not supported | Boolean map | Not supported |
| disallowedTools | Denylist (tool names) | Not supported | Not supported | Not supported |
| mode | Implicit (subagent by location) | Implicit | primary/subagent/all | Implicit |
| temperature | Not in frontmatter | Supported | Supported | Not supported |
| maxTurns/steps | maxTurns | Not supported | steps | Not supported |
| permissionMode | 6 modes | Not supported | permission (per-tool) | Not supported |
| skills | Preload skill content | Not supported | Not supported | Not supported |
| mcpServers | Scope MCP per agent | Not supported | Not supported | Not supported |
| hooks | Full lifecycle hooks | Not supported | Not supported | Not supported |
| memory | user/project/local | Not supported | Not supported | Not supported |
| color | Hex or theme color | Not supported | Hex or theme color | Not supported |
| hidden | Not supported | Not supported | Hide from @ menu | Not supported |
Agent Interoperability Summary
OpenCode IS compatible with Cursor and Claude Code agent specifications at the core level. All three tools use markdown files with YAML frontmatter and support the same fundamental structure.
What Works Across All Tools
The portable subset that works in Claude Code, Cursor, OpenCode, and Cline:
---
name: my-agent # Required for Claude Code/Cursor, optional for OpenCode/Cline (uses filename)
description: What this agent does and when to use it
---
System prompt in markdown body.
This minimal format works without modification across all tools. Place the same file in each tool's agent directory via symlinks (see Cross-Tool Setup below).
What's Tool-Specific
Beyond the portable subset, each tool has unique capabilities that won't transfer:
| Feature | Portability |
|---------|-------------|
| name + description + markdown body | ✅ Works everywhere |
| Model selection syntax | ❌ Different formats per tool |
| Tool restrictions | ❌ Different mechanisms per tool |
| Permissions (bash, edit, webfetch) | ❌ OpenCode only |
| Temperature in frontmatter | ❌ OpenCode only |
| Max iterations control | ❌ Different field names |
| MCP server scoping | ❌ Claude Code only |
| Skills preloading | ❌ Claude Code only |
| Hooks | ❌ Claude Code only |
Maximizing Portability
Strategy 1: Keep it simple (Recommended)
Use only the portable subset for shared agents. Express constraints in the system prompt body:
---
name: code-reviewer
description: Reviews code for quality without making changes
---
You are a read-only code reviewer.
**CONSTRAINTS:**
- Do NOT modify files (no write, edit operations)
- Do NOT run bash commands except read-only git commands
- Focus on analysis and recommendations only
This works everywhere, though enforcement is advisory (model follows instructions) rather than technical (tool blocks execution).
Strategy 2: Tool-specific overlays
Maintain canonical agents with portable core, then add tool-specific frontmatter:
---
name: code-reviewer
description: Reviews code for quality without making changes
# OpenCode-specific
tools:
write: false
edit: false
permission:
bash:
"*": "ask"
"git diff*": "allow"
# Claude Code-specific
disallowedTools: Write, Edit
# Note: Cursor ignores tools/permissions in frontmatter
---
System prompt (portable across all tools).
OpenCode and Claude Code will enforce tool restrictions. Cursor will rely on prompt instructions only.
Portable Subset (All Tools)
The only fields guaranteed portable across all four tools:
---
name: my-agent # or use filename in OpenCode/Cline
description: What this agent does and when to use it
---
System prompt in markdown body.
Everything beyond name, description, and the markdown body is tool-specific. Write the core agent logic in the body, then add tool-specific frontmatter as needed.
Cross-Tool Setup
Recommended Strategy: Symlink portable markdown agents without model field, configure tool-specific models in each tool's JSON config. This achieves full interoperability between OpenCode and Cursor.
Canonical Setup (OpenCode + Cursor)
Step 1: Create portable agent markdown
~/.agents/code-reviewer.md:
---
name: code-reviewer
description: Reviews code for quality and best practices
mode: subagent
temperature: 0.1
# NO model field - configure per-tool in JSON
---
You are a code reviewer focusing on security, performance, and maintainability.
Step 2: Symlink to tool directories
# Symlink canonical agents to each tool
ln -sfn ~/.agents ~/.cursor/agents
ln -sfn ~/.agents ~/.config/opencode/agents
Step 3: Configure tool-specific models
Cursor config (per Cursor's configuration method):
{
"agent": {
"code-reviewer": {
"model": "claude-sonnet-4.5"
}
}
}
OpenCode config opencode.json (project-level):
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"code-reviewer": {
"model": "anthropic/claude-sonnet-4-20250514"
}
}
}
Result
| Tool | Model Used | Source |
|------|------------|--------|
| Cursor | claude-sonnet-4.5 | Cursor JSON config |
| OpenCode | anthropic/claude-sonnet-4-20250514 | OpenCode JSON config |
Both tools read the same symlinked markdown file (no model field), then apply their respective JSON configs for model selection.
Critical: Do NOT include model in YAML frontmatter when using this pattern. YAML frontmatter takes precedence over JSON config in OpenCode, which would prevent the JSON override from working.
Note: Include name in frontmatter even though OpenCode can use filename - ensures compatibility when symlinked.
Model Selection Across Tools
Each tool handles model assignment differently with incompatible formats:
| Tool | Model Format | Example |
|------|--------------|---------|
| OpenCode | Full provider/model-id | anthropic/claude-sonnet-4-20250514 |
| Cursor | Cursor model names | claude-sonnet-4.5, gpt-4o, o1 |
| Claude Code | Aliases | sonnet, opus, haiku, inherit |
| Cline | Not supported | N/A |
Achieving Interoperability (OpenCode + Cursor)
The model field uses incompatible formats - you cannot write both in the same YAML frontmatter. The solution: omit model from YAML frontmatter entirely, then specify tool-specific models in their respective JSON configs.
Portable agent markdown (works for both tools):
---
name: code-reviewer
description: Reviews code for quality
# NO model field - omit entirely for portability
---
Cursor model config (in Cursor settings or project config):
{
"agent": {
"code-reviewer": {
"model": "claude-sonnet-4.5"
}
}
}
OpenCode project config opencode.json:
{
"agent": {
"code-reviewer": {
"model": "anthropic/claude-sonnet-4-20250514"
}
}
}
Why this works:
- Cursor reads markdown, finds no
modelfield, uses model from Cursor's JSON config - OpenCode reads markdown, finds no
modelfield, uses model fromopencode.json - Same symlinked markdown file works for both tools
- Each tool's JSON config specifies tool-specific model format
Critical: If you specify model in YAML frontmatter, OpenCode will use that value and ignore the JSON config. The markdown frontmatter takes precedence over JSON config for agents loaded from .opencode/agents/ directories.
Including Claude Code
For Claude Code, also omit model from YAML and use its config:
{
"agent": {
"code-reviewer": {
"model": "sonnet"
}
}
}
Tool Restrictions Across Tools
| Tool | Mechanism | Format |
|------|-----------|--------|
| Claude Code | tools (allowlist) or disallowedTools (denylist) | Comma-separated tool names: Read, Grep, Glob |
| Cursor | Not supported in agent frontmatter | N/A |
| OpenCode | tools (boolean map) | tools: { write: false, edit: false, bash: false } |
| Cline | Not supported | N/A |
Portable approach: Express tool restrictions in the system prompt body as instructions ("Do NOT modify files. Only read and analyze."). This works everywhere, though it's advisory rather than enforced.
OpenCode Deep Dive
OpenCode provides the most comprehensive agent configuration system. This section covers OpenCode-specific features in detail.
Configuration Methods
OpenCode supports two configuration approaches. When using both methods, YAML frontmatter takes precedence over JSON config - contrary to typical config merging patterns.
Method 1: JSON Configuration (opencode.json)
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"build": {
"description": "Full development with all tools",
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.3,
"tools": {
"write": true,
"edit": true,
"bash": true
},
"permission": {
"edit": "ask",
"bash": {
"*": "ask",
"git status": "allow"
}
}
}
}
}
Method 2: Markdown Files
Place in .opencode/agents/ (project) or ~/.config/opencode/agents/ (user):
---
description: Full development with all tools
mode: primary
model: anthropic/claude-sonnet-4-20250514
temperature: 0.3
tools:
write: true
edit: true
bash: true
permission:
edit: ask
bash:
"*": ask
"git status": allow
---
System prompt in markdown body.
Filename becomes the agent name. build.md → build agent.
Merge Behavior - CRITICAL: OpenCode loads config sources in precedence order:
opencode.json(project config) - loaded first.opencode/agents/*.md(markdown files) - loaded second
YAML frontmatter takes precedence over JSON config. If a field exists in both locations, the YAML value wins. For portable agents that need tool-specific models, omit the model field from YAML entirely.
Example - Portable agent with OpenCode-specific model:
.opencode/agents/code-reviewer.md:
---
description: Reviews code for quality and best practices
mode: subagent
temperature: 0.1
# NO model field - MUST omit to allow JSON config to work
---
You are a code reviewer. Focus on security, performance, and maintainability.
opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"code-reviewer": {
"model": "anthropic/claude-sonnet-4-20250514"
}
}
}
Result: OpenCode uses the model from JSON since YAML has no model field. The markdown file remains portable (works in Cursor/Claude Code via symlinks).
Important: OpenCode is unique - Claude Code and Cursor only support markdown files with YAML frontmatter. OpenCode's dual JSON/markdown support allows tool-specific configuration, but YAML frontmatter takes precedence over JSON when fields conflict.
Agent Modes
| Mode | Purpose | Invocation |
|------|---------|------------|
| primary | Main conversation agents | Tab key to cycle |
| subagent | Specialized task agents | @mention or Task tool |
| all | Can be used as either | Both methods |
Omit mode to default to all.
Built-in Agents
| Agent | Mode | Purpose | Tool Access |
|-------|------|---------|-------------|
| build | primary | Full development (default) | All tools enabled |
| plan | primary | Read-only planning/analysis | File edits = ask, bash = ask |
| general | subagent | Multi-step execution | Full access (no todo) |
| explore | subagent | Fast read-only exploration | Read/search only |
| compaction | hidden | Context summarization | System agent |
| title | hidden | Session title generation | System agent |
| summary | hidden | Session summarization | System agent |
Model Configuration
Use the full provider/model-id format:
{
"agent": {
"plan": {
"model": "anthropic/claude-haiku-4-20250514"
},
"build": {
"model": "anthropic/claude-sonnet-4-20250514"
}
}
}
If omitted:
- Primary agents: Use globally configured model
- Subagents: Inherit from parent agent's model
Run opencode models to see available models.
Tool Control
Control tool access with boolean maps:
tools:
write: true # Enable
edit: false # Disable
bash: true
Wildcard support for MCP tools:
tools:
mymcp_*: false # Disable all tools from 'mymcp' server
write: false
edit: false
Agent-specific tools overrides global config.
Permission System
Fine-grained control over tool behavior. Three modes:
| Mode | Behavior |
|------|----------|
| allow | Execute without approval |
| ask | Prompt before execution |
| deny | Block entirely |
File Edit Permissions
{
"permission": {
"edit": "ask" // Prompt before all edits
}
}
Limitation: No path-based restrictions. Applies to all file edits.
Bash Command Permissions
Supports glob patterns for command-specific control:
{
"permission": {
"bash": {
"*": "ask", // Default: ask for all commands
"git status": "allow", // Allow specific command
"git log*": "allow", // Allow with wildcards
"grep *": "allow", // Allow command with args
"git push": "deny", // Block dangerous command
"rm -rf*": "deny" // Block destructive patterns
}
}
}
Pattern matching rules:
- Last matching rule wins
- Put
*wildcard first, then specific overrides - Patterns match full command string including arguments
Example: Safe git agent
permission:
bash:
"*": "deny" # Block everything by default
"git status*": "allow"
"git log*": "allow"
"git diff*": "allow"
"git show*": "allow"
edit: "deny"
webfetch: "deny"
WebFetch Permissions
{
"permission": {
"webfetch": "ask" // Prompt before fetching URLs
}
}
Subagent Spawning Permissions
Control which subagents an agent can invoke via Task tool:
{
"agent": {
"orchestrator": {
"permission": {
"task": {
"*": "deny", // Block all by default
"orchestrator-*": "allow", // Allow specific prefix
"code-reviewer": "ask" // Prompt for specific agent
}
}
}
}
}
When set to deny, the subagent is removed from Task tool description entirely, preventing the model from attempting invocation.
Note: Users can always invoke any subagent via @mention, regardless of task permissions.
Temperature & Top-P
Control response randomness:
temperature: 0.1 # 0.0-1.0 (lower = focused, higher = creative)
top_p: 0.9 # 0.0-1.0 (alternative to temperature)
Temperature guidelines:
- 0.0-0.2: Code analysis, planning, deterministic tasks
- 0.3-0.5: General development
- 0.6-1.0: Brainstorming, creative writing
If unspecified, defaults to model-specific values (typically 0, or 0.55 for Qwen models).
Max Steps
Limit agentic iterations:
steps: 5 # Max tool-use iterations before text-only response
When limit reached, agent receives a system prompt instructing it to summarize work and recommend remaining tasks.
Omit to allow unlimited iterations until model stops or user interrupts.
Note: Legacy maxSteps field is deprecated. Use steps.
Visual Customization
color: "#ff6b6b" # Hex color
# or
color: "accent" # Theme color: primary, secondary, accent, success, warning, error, info
Affects agent appearance in UI.
Hidden Subagents
Hide from @ autocomplete menu (subagents only):
mode: subagent
hidden: true
Still invokable via Task tool. Useful for internal helper agents.
Provider-Specific Options
Any unrecognized frontmatter fields are passed through to the provider as model options.
Example: OpenAI reasoning models
model: openai/gpt-5
reasoningEffort: high # OpenAI-specific
textVerbosity: low # OpenAI-specific
Check provider docs for available parameters.
Disabling Agents
{
"agent": {
"review": {
"disable": true
}
}
}
Custom Prompts
Reference external prompt files:
{
"agent": {
"review": {
"prompt": "{file:./prompts/code-review.txt}"
}
}
}
Path is relative to config file location (works for both global and project configs).
Complete Example: Read-Only Review Agent
Markdown approach:
.opencode/agents/review.md
---
description: Reviews code for quality without making changes. Use after implementation.
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
tools:
write: false
edit: false
permission:
bash:
"*": "ask"
"git diff*": "allow"
"git log*": "allow"
"grep *": "allow"
webfetch: "deny"
color: "warning"
---
You are a code reviewer. Focus on:
- Security vulnerabilities
- Performance issues
- Best practices violations
- Potential bugs
Provide constructive feedback without making changes.
JSON approach:
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"review": {
"description": "Reviews code for quality without making changes. Use after implementation.",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./.opencode/prompts/review.txt}",
"tools": {
"write": false,
"edit": false
},
"permission": {
"bash": {
"*": "ask",
"git diff*": "allow",
"git log*": "allow",
"grep *": "allow"
},
"webfetch": "deny"
},
"color": "warning"
}
}
}
Creating Agents via CLI
Interactive agent creation:
opencode agent create
Prompts for:
- Save location (global vs project)
- Agent description
- Tool access preferences
- Generates markdown file with configuration
Subagent Spawning
All four tools support subagents, but the spawning mechanism differs:
| Aspect | Claude Code | Cursor | OpenCode | Cline |
|--------|------------|--------|----------|-------|
| Spawn mechanism | Task tool | Task tool | Task tool / @mention | @mention |
| Max concurrent | 10 (queues beyond) | Limited by model | Configurable per-provider | Limited |
| Nesting | Subagents cannot spawn subagents | Subagents can nest (2026) | Subagents cannot nest | Cannot nest |
| Background | Yes (Ctrl+B or explicit) | Yes (async subagents) | Yes (run_in_background) | No |
| Resume | Yes (agent ID) | Yes (agent ID) | Yes (session navigation) | No |
| Restrict spawning | Task(worker, researcher) in tools | Not supported | permission.task glob patterns | Not supported |
Orchestration Patterns
Pattern 1: AGENTS.md Orchestration (Most Portable)
Put orchestration rules in AGENTS.md (read by all tools). The root agent decides when to delegate based on instructions, not config.
## Orchestration Rules
When the task involves:
- **Multiple files or modules**: Delegate to explore agent first
- **External libraries**: Delegate to librarian agent
- **Complex implementation**: Create a plan, then delegate to implementer
- **Architecture decisions**: Consult oracle agent
Pattern 2: Orchestrator Rule (Cursor-Specific)
Cursor supports .cursor/rules/*.mdc with alwaysApply: true for always-on orchestration. This is the pattern oh-my-cursor uses.
Pattern 3: Plugin Orchestration (OpenCode-Specific)
oh-my-opencode uses a plugin system with JSON config for model routing, categories, and provider fallback chains. See references/opencode-agents.md.
Validation Checklist
Before finalizing a portable agent:
- [ ]
nameis lowercase with hyphens, matches filename - [ ]
descriptionclearly states when to delegate to this agent - [ ] System prompt body uses imperative form
- [ ] No tool-specific features in core prompt logic
- [ ] Tool-specific frontmatter clearly commented
- [ ]
modelomitted or set toinheritfor portability - [ ] Tool restrictions expressed in prompt body (advisory) AND frontmatter (enforced) where supported
- [ ] Tested delegation in target tools
References
- references/claude-code-agents.md - Claude Code agent configuration and capabilities
- references/cursor-agents.md - Cursor agent configuration and capabilities
- references/opencode-agents.md - OpenCode agent configuration and capabilities
- references/agent-roster.md - Standard agent roles and their system prompts
Scan to join WeChat group