Awesome-omni-skill portable-agents
Defines agent configuration formats across Claude Code, Cursor, OpenCode, and Cline. Covers frontmatter fields, tool restrictions, model selection, and cross-tool portability. ALWAYS read before creating or editing agent definitions. This skill should be used when 'writing an agent', 'creating a subagent', 'porting agents between tools', 'agent frontmatter', 'agent configuration', or setting up agents across multiple AI tools.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/ai-agents/portable-agents" ~/.claude/skills/diegosouzapw-awesome-omni-skill-portable-agents && rm -rf "$T"
skills/ai-agents/portable-agents/SKILL.mdCross-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 | | | | |
| User | | | | N/A |
| Plugin | Plugin 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 |
|---|---|---|---|---|
| Required | Required | Filename = name | Filename = name |
| Required | Required | Required | Required |
| /// | Cursor model names | | N/A |
| Allowlist (tool names) | Not supported | Boolean map | Not supported |
| Denylist (tool names) | Not supported | Not supported | Not supported |
| Implicit (subagent by location) | Implicit | // | Implicit |
| Not in frontmatter | Supported | Supported | Not supported |
/ | | Not supported | | Not supported |
| 6 modes | Not supported | (per-tool) | Not supported |
| Preload skill content | Not supported | Not supported | Not supported |
| Scope MCP per agent | Not supported | Not supported | Not supported |
| Full lifecycle hooks | Not supported | Not supported | Not supported |
| // | Not supported | Not supported | Not supported |
| Hex or theme color | Not supported | Hex or theme color | Not supported |
| 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 |
|---|---|
+ + 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 | | Cursor JSON config |
| OpenCode | | 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 | |
| Cursor | Cursor model names | , , |
| Claude Code | Aliases | , , , |
| 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
from YAML frontmatter entirely, then specify tool-specific models in their respective JSON configs.model
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
field, uses model from Cursor's JSON configmodel - OpenCode reads markdown, finds no
field, uses model frommodelopencode.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 | (allowlist) or (denylist) | Comma-separated tool names: |
| Cursor | Not supported in agent frontmatter | N/A |
| OpenCode | (boolean map) | |
| 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:
(project config) - loaded firstopencode.json
(markdown files) - loaded second.opencode/agents/*.md
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
field from YAML entirely.model
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 |
|---|---|---|
| Main conversation agents | Tab key to cycle |
| Specialized task agents | or Task tool |
| Can be used as either | Both methods |
Omit
mode to default to all.
Built-in Agents
| Agent | Mode | Purpose | Tool Access |
|---|---|---|---|
| primary | Full development (default) | All tools enabled |
| primary | Read-only planning/analysis | File edits = ask, bash = ask |
| subagent | Multi-step execution | Full access (no todo) |
| subagent | Fast read-only exploration | Read/search only |
| hidden | Context summarization | System agent |
| hidden | Session title generation | System agent |
| 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 |
|---|---|
| Execute without approval |
| Prompt before execution |
| 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 | tool | tool | tool / | |
| 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 () | No |
| Resume | Yes (agent ID) | Yes (agent ID) | Yes (session navigation) | No |
| Restrict spawning | in tools | Not supported | 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:
-
is lowercase with hyphens, matches filenamename -
clearly states when to delegate to this agentdescription - System prompt body uses imperative form
- No tool-specific features in core prompt logic
- Tool-specific frontmatter clearly commented
-
omitted or set tomodel
for portabilityinherit - 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