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.

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
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"
manifest: skills/ai-agents/portable-agents/SKILL.md
source content

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

ScopeClaude CodeCursorOpenCodeCline
Project
.claude/agents/
.cursor/agents/
.opencode/agents/
.clinerules/agents/
User
~/.claude/agents/
~/.cursor/agents/
~/.config/opencode/agents/
N/A
PluginPlugin
agents/
dir
N/AN/AN/A

Priority (when names collide): CLI flags > project > user > plugin (Claude Code). Project > user (Cursor, OpenCode).

Frontmatter Compatibility Matrix

FieldClaude CodeCursorOpenCodeCline
name
RequiredRequiredFilename = nameFilename = name
description
RequiredRequiredRequiredRequired
model
sonnet
/
opus
/
haiku
/
inherit
Cursor model names
provider/model-id
N/A
tools
Allowlist (tool names)Not supportedBoolean mapNot supported
disallowedTools
Denylist (tool names)Not supportedNot supportedNot supported
mode
Implicit (subagent by location)Implicit
primary
/
subagent
/
all
Implicit
temperature
Not in frontmatterSupportedSupportedNot supported
maxTurns
/
steps
maxTurns
Not supported
steps
Not supported
permissionMode
6 modesNot supported
permission
(per-tool)
Not supported
skills
Preload skill contentNot supportedNot supportedNot supported
mcpServers
Scope MCP per agentNot supportedNot supportedNot supported
hooks
Full lifecycle hooksNot supportedNot supportedNot supported
memory
user
/
project
/
local
Not supportedNot supportedNot supported
color
Hex or theme colorNot supportedHex or theme colorNot supported
hidden
Not supportedNot supportedHide 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:

FeaturePortability
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

ToolModel UsedSource
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:

ToolModel FormatExample
OpenCodeFull provider/model-id
anthropic/claude-sonnet-4-20250514
CursorCursor model names
claude-sonnet-4.5
,
gpt-4o
,
o1
Claude CodeAliases
sonnet
,
opus
,
haiku
,
inherit
ClineNot supportedN/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
    model
    field, uses model from Cursor's JSON config
  • OpenCode reads markdown, finds no
    model
    field, uses model from
    opencode.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

ToolMechanismFormat
Claude Code
tools
(allowlist) or
disallowedTools
(denylist)
Comma-separated tool names:
Read, Grep, Glob
CursorNot supported in agent frontmatterN/A
OpenCode
tools
(boolean map)
tools: { write: false, edit: false, bash: false }
ClineNot supportedN/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:

  1. opencode.json
    (project config) - loaded first
  2. .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

ModePurposeInvocation
primary
Main conversation agentsTab key to cycle
subagent
Specialized task agents
@mention
or Task tool
all
Can be used as eitherBoth methods

Omit

mode
to default to
all
.

Built-in Agents

AgentModePurposeTool Access
build
primaryFull development (default)All tools enabled
plan
primaryRead-only planning/analysisFile edits = ask, bash = ask
general
subagentMulti-step executionFull access (no todo)
explore
subagentFast read-only explorationRead/search only
compaction
hiddenContext summarizationSystem agent
title
hiddenSession title generationSystem agent
summary
hiddenSession summarizationSystem 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:

ModeBehavior
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:

  1. Save location (global vs project)
  2. Agent description
  3. Tool access preferences
  4. Generates markdown file with configuration

Subagent Spawning

All four tools support subagents, but the spawning mechanism differs:

AspectClaude CodeCursorOpenCodeCline
Spawn mechanism
Task
tool
Task
tool
Task
tool /
@mention
@mention
Max concurrent10 (queues beyond)Limited by modelConfigurable per-providerLimited
NestingSubagents cannot spawn subagentsSubagents can nest (2026)Subagents cannot nestCannot nest
BackgroundYes (Ctrl+B or explicit)Yes (async subagents)Yes (
run_in_background
)
No
ResumeYes (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:

  • name
    is lowercase with hyphens, matches filename
  • description
    clearly 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
  • model
    omitted or set to
    inherit
    for portability
  • Tool restrictions expressed in prompt body (advisory) AND frontmatter (enforced) where supported
  • Tested delegation in target tools

References