Awesome-omni-skill portable-skills-and-rules
Defines SKILL.md structure, valid frontmatter fields, and cross-tool setup for Claude Code, Cursor, OpenCode, and Cline. ALWAYS read before creating or editing any SKILL.md file. This skill should be used when "writing a skill", "creating a skill", "editing a skill", "skill frontmatter", "SKILL.md format", "AGENTS.md", "CLAUDE.md", or setting up skills 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/tools/portable-skills-and-rules" ~/.claude/skills/diegosouzapw-awesome-omni-skill-portable-skills-and-rules && rm -rf "$T"
skills/tools/portable-skills-and-rules/SKILL.mdCross-Tool Interoperability
Write skills, rules, and commands that work across Claude Code, OpenCode, Cursor, and Cline without duplication.
Quick Start
All four tools canonically search
.claude/skills/ per the spec. However, Cursor has several bugs that require a workaround — see Cursor Bugs below.
In practice, always write new skills to
and symlink .cursor/skills/
to it:.claude/skills/
# One-time setup per project ln -sfn ../.cursor/skills .claude/skills
Skills use combined frontmatter that each tool reads selectively:
--- name: my-skill description: "Does X. Use when user asks to Y or mentions Z." user-invocable: true disable-model-invocation: false ---
Always set both invocation fields explicitly for visible defaults across all tools.
Core Strategy
Skills: Fully Shareable
The spec says
.claude/skills/ is the canonical location. In practice, Cursor bugs (see below) require the physical files to live in .cursor/skills/, with .claude/skills/ as a symlink.
Always write new skills to
. The symlink makes Claude Code and other tools pick them up automatically..cursor/skills/
Create one SKILL.md with combined frontmatter. Each tool reads what it understands, ignores the rest.
Notes:
holds the physical files — always write here.cursor/skills/
is a symlink to.claude/skills/
— never write directly to it.cursor/skills/- Cline skills require enabling in Settings → Features → Enable Skills (experimental)
- Skills can be invoked via
slash commands in Claude Code, Cursor IDE, and Cursor CLI/<skill-name>
Cursor Bugs
Cursor has three known issues that drive the
.cursor/skills/ workaround:
-
Doesn't search
— Despite the spec, Cursor IDE does not reliably read skills from.claude/skills/
. It only reliably finds skills in.claude/skills/
..cursor/skills/ -
Doesn't traverse above the open directory — Cursor only searches for skills within the directory the IDE is opened to. It won't walk up to the git root. In a monorepo where the IDE is opened to a sub-project, skills defined at the repo root are invisible. Workaround: symlink the
directory into each sub-project that needs access..cursor/ -
Skills don't survive two symlinks — If
is a symlink and the skills inside are themselves symlinks (e.g., pointing up to a parent directory), Cursor fails to read them. Skills must be physically present at the resolved path, with at most one level of symlink indirection..claude/skills/
Consequence: Skills must be physically in
.cursor/skills/. The symlink goes in the other direction: .claude/skills/ → .cursor/skills/.
Rules: Symlink Between Names
Claude Code uses
CLAUDE.md. OpenCode, Cursor, and Cline use AGENTS.md. Content is identical—only the filename differs.
# Project level: pick one as source, symlink the other ln -s AGENTS.md CLAUDE.md # or vice versa # Global level ln -s ~/dotfiles/AGENTS.md ~/.claude/CLAUDE.md ln -s ~/dotfiles/AGENTS.md ~/.config/opencode/AGENTS.md
Cline also supports a
.clinerules/ folder with multiple rule files. For portability, use AGENTS.md.
Cursor Rules Bug: .mdc
Extension Required
.mdcCursor currently only detects
.mdc files in .cursor/rules/, not .md files, despite documentation stating both formats are supported. This breaks the symlink strategy for modular rules.
Temporary workaround (until bug is fixed):
- Maintain separate
files alongside.cursor/rules/*.mdc.claude/rules/*.md - Keep content synchronized between the two (manually or via script)
- Use identical frontmatter (Claude reads
, Cursor readspaths:
, both ignore unknown keys)globs: - When Cursor fixes the bug, delete
and replace with symlink:.cursor/rules/*.mdc
→.cursor/rules/.claude/rules/
Note: This only affects modular rules in
.cursor/rules/. Root-level AGENTS.md works fine in Cursor without needing .mdc extension.
Claude Code Rules Extensions
Claude Code supports several rules features beyond basic
CLAUDE.md. These are Claude Code-only but degrade gracefully (other tools simply ignore them).
CLAUDE.local.md — Personal project-specific preferences. Auto-added to
.gitignore. Place next to CLAUDE.md for private overrides (sandbox URLs, test data, personal workflow notes).
CLAUDE.md imports — Use
@path/to/file syntax to import other files into CLAUDE.md:
See @README for project overview and @docs/git-workflow.md for git conventions.
Relative paths resolve from the importing file. Recursive imports supported (max depth 5). Other tools see
@path as literal text—harmless but not functional.
Modular rules with
— Split rules into focused files:.claude/rules/
.claude/rules/ ├── code-style.md # Unconditional: always loaded ├── testing.md └── api-design.md # Can use paths: frontmatter for file-scoped rules
All
.md files load automatically. Rules can be scoped to specific files via paths frontmatter with glob patterns. Cursor (.cursor/rules/ with globs) and Cline (.clinerules/ with paths) have similar systems but use their own directories — these are not portable across tools.
Cursor bug: Cursor currently requires
.mdc extension for rules in .cursor/rules/, not .md. See Cursor Rules Bug section.
Commands: Use Skills Instead
Claude Code has merged commands into skills —
.claude/commands/ files still work but skills take precedence if names collide. For maximum portability, write skills instead of commands. They work as:
- Slash commands in Claude Code, Cursor IDE, and Cursor CLI (
)/<skill-name> - Auto-discovered capabilities in OpenCode and Cline
Migration: Cursor 2.4+ includes
/migrate-to-skills to convert existing commands to skills with disable-model-invocation: true.
Cline has a separate "workflows" system (
.clinerules/workflows/), but skills are more portable.
OpenCode: Command Wrappers for Slash Invocation
OpenCode skills are NOT slash-invocable — they are loaded on-demand by the agent via the
skill tool. To get /skill-name slash invocation in OpenCode, create a thin command wrapper that tells the agent to load the skill.
Place command wrappers in
.opencode/commands/ (project) or ~/.config/opencode/commands/ (global):
<!-- .opencode/commands/my-skill.md --> --- description: Short description of what the skill does --- Load the `my-skill` skill and follow its instructions. $ARGUMENTS
The filename becomes the command name (e.g.,
my-skill.md → /my-skill). The agent receives the prompt, calls the skill tool to load the SKILL.md content, and follows it.
When creating a new skill, ALWAYS create a matching OpenCode command wrapper. If commands are symlinked between
~/.claude/commands/ and ~/.config/opencode/commands/, one file serves both Claude Code (as a command) and OpenCode (as a slash command).
Key differences from skills:
- Commands support
and positional args ($ARGUMENTS
,$1
)$2 - Commands support
command`` for shell output injection! - Commands support
for file content inclusion@filename - Commands can specify
andagent:
overrides in frontmattermodel:
Writing Portable Skills
Required Fields (All Tools)
| Field | Requirements |
|---|---|
| 1-64 chars, lowercase, hyphens only, must match folder name, pattern: |
| Max 1024 chars, third person, include trigger phrases |
| Always set to (Claude Code: show in slash menu) |
| Always set to (Cursor: allow auto-discovery) |
Invocation Control Fields (Required)
Always set both fields explicitly for visible defaults. All skills should be user-invokable and auto-discoverable:
user-invocable: true # Claude Code: show in slash menu disable-model-invocation: false # Cursor: allow auto-discovery
| Field | Tool | Value | Effect |
|---|---|---|---|
| Claude Code | Required | Show in slash menu, allow |
| Cursor | Required | Allow auto-discovery based on description |
Note: These fields have opposite semantics but setting both explicitly ensures consistent behavior:
- Claude Code reads
, ignoresuser-invocabledisable-model-invocation - Cursor reads
, ignoresdisable-model-invocationuser-invocable - OpenCode and Cline ignore both (auto-discover via
tool; for slash commands in OpenCode, use command wrappers)skill
Optional Fields (Include Only When Specified)
Do not add these fields by default. Only include when the user explicitly requests them:
- Restricts tool access (Claude Code, experimental in Cursor)allowed-tools
- Software license (informational, recognized by Cursor + OpenCode)license
- Author, version info (informational, recognized by Cursor + OpenCode)metadata
- Environment requirements (recognized by Cursor + OpenCode)compatibility
These fields degrade gracefully—tools ignore what they don't recognize.
Example with all possible fields (only add what you need):
--- name: review-code description: "Reviews code for quality and bugs. Use when asked to review changes." # === REQUIRED: Invocation control (always set explicitly) === user-invocable: true # Claude Code: show in slash menu disable-model-invocation: false # Cursor: allow auto-discovery # === OPTIONAL: Add only when specified === # Shared (Cursor + OpenCode + Agent Skills spec) license: MIT compatibility: "requires git" metadata: author: your-name version: 1.0.0 # Claude Code + Cursor (experimental) allowed-tools: Read, Grep, Glob # Claude Code only model: claude-sonnet-4-20250514 context: fork agent: Explore argument-hint: "[file-or-directory]" ---
File Structure
Use the same structure across all tools:
skill-name/ ├── SKILL.md # Required: instructions + combined frontmatter ├── scripts/ # Optional: executable code agents can run ├── references/ # Optional: detailed docs (loaded on-demand) ├── examples/ # Optional: usage examples └── assets/ # Optional: templates, images, data files (Cursor)
Setting Up Global Interoperability
Physical skills live in
.cursor/skills/. All other tool locations symlink to it.
# Skills: physical files in .cursor/skills mkdir -p ~/.cursor/skills # Claude Code: symlink .claude/skills → .cursor/skills ln -sfn ~/.cursor/skills ~/.claude/skills # OpenCode: symlink to .cursor/skills ln -sfn ~/.cursor/skills ~/.config/opencode/skills # Cline: symlink to .cursor/skills mkdir -p ~/.cline ln -sfn ~/.cursor/skills ~/.cline/skills # Rules: single source of truth ln -sf ~/dotfiles/AGENTS.md ~/.claude/CLAUDE.md ln -sf ~/dotfiles/AGENTS.md ~/.config/opencode/AGENTS.md
For project-level skills in a monorepo, symlink
.cursor/ into each sub-project so Cursor can find it (it won't traverse above the open directory):
# In each sub-project that needs access to skills ln -sfn ../.cursor .cursor # if sub-project is one level deep ln -sfn ../.cursor/skills .claude/skills
See scripts/setup-interop.sh for full automation.
Hard Limitations
| Limitation | Impact | Workaround |
|---|---|---|
, , | Claude Code only | Degrade gracefully |
| Claude Code + Cursor (experimental) | Degrade gracefully in OpenCode/Cline |
dynamic injection | Claude Code skills + OpenCode commands | Appears as literal text in Cursor/Cline |
expansion | Claude Code + OpenCode expand | Cursor/Cline show unexpanded |
| Positional arg indexing | Claude Code: 0-based (, ); OpenCode: 1-based (, ) | Avoid positional args in portable skills |
| Claude Code only | Other tools show unexpanded |
invocation | Claude Code + Cursor (IDE & CLI) | OpenCode: create command wrapper (see above). Cline: auto-discovery only |
imports in CLAUDE.md | Claude Code only | Other tools see literal text |
| Claude Code only | Other tools ignore it; no equivalent |
| File-scoped rules | Claude Code (), Cursor (), Cline () — each in own rule dir | Not portable across tools; use tool-specific rule dirs |
Cursor rules bug | Cursor only detects in , not | Duplicate rules as until bug fixed |
| Cline skills experimental | Must enable in settings | Toggle in Settings → Features |
Cline folder | Cline-specific rules system | Use for portability |
| Cline global skill precedence | Global overrides project skills | Use unique names across locations |
Validation Checklist
Before finalizing a portable skill:
-
is lowercase with hyphens only, matches folder namename -
is under 1024 chars, third persondescription -
includes trigger phrasesdescription -
is set explicitlyuser-invocable: true -
is set explicitlydisable-model-invocation: false - SKILL.md body uses imperative form
- No tool-specific features in core logic
- Tool-specific frontmatter clearly commented
- OpenCode command wrapper created (if slash invocation needed)
- Tested in target tools
References
Tool-Specific Documentation
- references/claude-code.md - Claude Code configuration and capabilities
- references/opencode.md - OpenCode configuration and capabilities
- references/cursor.md - Cursor configuration and capabilities
- references/cline.md - Cline configuration and capabilities
Examples and Scripts
- examples/universal-skill.md - Complete portable skill template
- scripts/setup-interop.sh - Automated setup script