π Cross-runtime: the problem
You write a skill for Claude Code. Works perfectly. Then your colleague uses Codex and asks: "how do I run this here?". Short answer: doesnβt run. Long answer: each agent has its own syntax β frontmatter, tool format, and permission system. Copying and pasting isn't enough.
π‘ Tip
Skills are executable documentation. The logic is the same in any runtime β what changes is the envelope: how the agent loads, activates, and calls tools. Solving the envelope is the job.
β Portable format (single source)
- βWrite once in a neutral format
- βThe build emits versions for each runtime
- βOne command propagates the change to everyone
- βTests run against the source, not copies
β Copy-paste between runtimes
- β3 copies diverge in 2 weeks
- βBug fixed in one place, forgotten in the others
- βFrontmatter broken by the wrong runtime
- βThere's no way to test consistency
π¦ polyskill β portable format
The skill polyskill (present in the repo) solves the envelope problem. You write a single source and it emits builds specific to each runtime. Think of it as "Babel for skills."
ποΈ Typical structure of a polyskill
minha-skill/
βββ source.md # fonte ΓΊnica (neutra)
βββ polyskill.config.json # mapeamento de tools
βββ claude-code/ # build pra Claude Code
β βββ SKILL.md # frontmatter + Read/Edit/Bash
βββ codex/ # build pra Codex
β βββ skill.yaml # frontmatter Codex + read_file/write_file
βββ tests/
βββ snapshot.test.ts # garante paridade entre builds
β‘ Automatic translation
O polyskill creates three essential translators:
- βFrontmatter:
name/description/toolsmapped to each runtime - βTools:
Readβread_file,Bashβshell - βActivation: Skill tool (Claude Code) vs activate_skill (Codex)
Practical advantage: you edit a paragraph in the single source, run polyskill build and both builds come out consistent. A production bug is a git diff, not a "which copy did I fix this in again?".
π Differences between Claude Code and Codex
Before porting a skill, it's worth understanding where the two differ. Spoiler: on the surface theyβre the same (Markdown + frontmatter); in the details, theyβre quite different.
| Dimension | Claude Code | Codex |
|---|---|---|
| File tools | Read, Edit, Write |
read_file, write_file, apply_patch |
| Shell execution | Bash with a permission-based sandbox |
shell with workspace-write/read |
| Skill loading | Skill tool (/skill-name) + description triggers automatically |
activate_skill explicit or prompt-triggered |
| Permissions | Allowlist in settings.json, prompt per tool |
Modes (suggest / auto-edit / full-auto) |
| MCP support | Built in, configured in ~/.claude/mcp.json |
Recent support, still evolving |
| Subagents | Yes (Task tool, parallel agents) | Limited β one session at a time |
| Slash commands | Yes, ~/.claude/commands/ |
Yes, but a different format |
The practical rule: if your skill only reads files and writes markdown, itβs trivially portable. If it orchestrates parallel subagents with hooks, will need serious adaptation β it will probably become two skills.
π Calling skills via MCP
Instead of asking the other agent to understand your skill format, wrap the skill in an MCP server. Any MCP client (Claude Code, Codex, Cursor, Cline) can call it as a tool without knowing there's a skill behind it.
π οΈ Snippet: skill as an MCP endpoint
// mcp-skills-server/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { readFileSync } from "fs";
const server = new Server({ name: "skills-bridge", version: "0.1.0" });
server.tool({
name: "grill-me",
description: "Stress-test a plan adversarially. Returns gaps and risks.",
inputSchema: {
type: "object",
properties: { plan: { type: "string" } },
required: ["plan"]
},
handler: async ({ plan }) => {
const skillBody = readFileSync("./skills/grill-me/SKILL.md", "utf8");
return runAgentLoop({ system: skillBody, user: plan });
}
});
server.start();
Use case: skills as an API. Your skill /grill-me becomes an endpoint that any agent β or even your CI β can call via HTTP/MCP. Centralizes the logic and avoids duplication.
π When to use MCP vs. polyskill
- polyskill: the skill is mainly documentation β guides the model; it doesnβt run heavy logic
- MCP server: the skill calls external APIs, maintains state, or has code you don't want to duplicate
- Hybrid: polyskill emits the documentation, the MCP server exposes the specialized tools
π€ Skills in CI/CD
Skills donβt need to be interactive. In CI/CD, you run them in batch (non-interactive, with fixed input and output to a file). Useful for automatic PR reviews, docs generation, and migration validation.
β Works in CI
- βSkills deterministic with well-defined input
- βFile output (markdown, JSON)
- βRestricted tools (Read + Write, no unrestricted Bash)
- βTimeout configured, with a fallback in case of errors
β Doesn't work in CI
- βSkills that ask the user (clarifications)
- βSkills that depend on local session state
- βSkills with interactive TUIs or prompts
- βSkills that take > 10min (runner timeout)
β οΈ Important Tip
Before running a skill in CI, test with --non-interactive locally. If it asks for input at any point, it will freeze in the runner β and GitHub Actions bills you for the 6h until timeout.
π§ͺ Practical example: /tdd in GitHub Actions
Concrete scenario: when a PR breaks tests, automatically trigger the /tdd skill. It analyzes the error, proposes a fix, and opens a commit in the PR itself. The developer wakes up the next day to a green build.
π .github/workflows/tdd-loop.yml
name: tdd-loop
on:
pull_request:
types: [opened, synchronize]
jobs:
run-tdd:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run tests (capture failure)
id: tests
run: npm test || echo "failed=true" >> $GITHUB_OUTPUT
- name: Run /tdd skill
if: steps.tests.outputs.failed == 'true'
uses: anthropics/claude-action@v1
with:
skill: tdd
input: "fix failing tests in this PR"
allowed-tools: "Read,Edit,Bash(npm test)"
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
- name: Commit fix
if: steps.tests.outputs.failed == 'true'
run: |
git config user.name "tdd-bot"
git config user.email "bot@example.com"
git add -A
git commit -m "fix: /tdd auto-repair" || exit 0
git push
Trigger in the PR
Run on each opened e synchronize (new commits)
We capture the flow from the startβwe donβt wait for the developer to ask for help.
Run tests and detect failures
Output failed=true serves as a condition for the next steps
Only activates the skill if something actually broke β doesn't waste API quota.
Invoke /tdd with restricted tools
allowed-tools limits it to Read, Edit, and Bash(npm test) β nothing else rm or curl
The allowlist is the seat belt. Without it, the skill would have too much power in an environment without human review.
Commit + push back to the PR
The fix becomes part of the PR history, attributed to the bot
The developer reviews the humanβs diff and the botβsβnot a phantom patch without context.
π§© Integration with Cursor, Aider, Continue
Cursor, Aider and Continue donβt have the native skill concept. They have rules, conventions or system prompts. The good news: a skillβs content fits these formats perfectly.
π Current portability status
- Cursor: files
.cursorrulesaccept Markdown directly from the skill (no frontmatter) - Aider: uses
CONVENTIONS.mdor--readto load context - Continue:
config.jsonallowssystemMessagewith the skill body - Cline / Roo Code: accepted
.clinerulesin markdown
π Generic adapter β emits for any agent
// scripts/sync-skills.ts
import { readFileSync, writeFileSync } from "fs";
import { stripFrontmatter } from "./utils";
const skill = readFileSync("./skills/tdd/SKILL.md", "utf8");
const body = stripFrontmatter(skill);
// Cursor
writeFileSync(".cursorrules", body);
// Aider
writeFileSync("CONVENTIONS.md", body);
// Continue
const config = JSON.parse(readFileSync(".continue/config.json", "utf8"));
config.systemMessage = body;
writeFileSync(".continue/config.json", JSON.stringify(config, null, 2));
console.log("β skill syncronized to Cursor / Aider / Continue");
Limitation: agents without The skill concept loads the content all the time (with no dynamic activation). For short skills, thatβs fine. For long skills, consider breaking them into smaller rules specific to each context.
πΌ Skills + MCP servers
The most powerful combination today: the skill orchestrates; the MCP server executes. The skill guides the model through the when e how; the MCP server provides specialized tools (DB, GitHub, Figma, Slack).
ποΈ Composition architecture
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USUΓRIO β
β "/release-notes v2.3" β
ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SKILL: /release-notes (markdown + frontmatter) β
β "Quando o user pedir release notes: β
β 1. liste commits desde a ΓΊltima tag β
β 2. agrupe por tipo (feat/fix/chore) β
β 3. publique no Slack #releases" β
ββββββββ¬ββββββββββββββββββββ¬ββββββββββββββββββββ¬ββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββ βββββββββββββββββ ββββββββββββββββ
β MCP: github β β MCP: linear β β MCP: slack β
β list-commits β β get-issues β β post-message β
ββββββββββββββββ βββββββββββββββββ ββββββββββββββββ
π― Design principle
The skill is the script; MCP is the toolbox. A roadmap without a box is theory; a box without a roadmap is chaos.
- βSkill describes when use each MCP tool
- βMCP server exposes what what each tool does and its schema
- βModel ties the two together in the how of the execution
π§ Current limitations
Cross-runtime is a work in progress. Some things already work well; others still depend on workarounds. An honest map of the landscape:
β Works well cross-runtime
- βDeclarative skills (no code)
- βBasic tools: read, write, execute
- βMCP servers (open standard)
- βShort skills (< 200 lines)
- βSync via polyskill / adapters
β Not yet / with caveats
- βParallel subagents (Claude Code only)
- βHooks (PreToolUse, PostToolUse): specific
- βSlash commands with complex arguments
- βPermission models differ considerably
- βSkills that use experimental features of a runtime
πΊοΈ Roadmap (actual status, not promises)
Matt mentioned in the repo that the goal is for "every course skill should run in at least Claude Code and Codex". Today (2026), this applies to the 80% of simpler cases. Skills that depend on parallel subagents or heavy hooks are still runtime-specific.
Trend: standardization will come from MCP, not a universal skill format. If your skill is mainly a system prompt + tools, itβs already portable today.
π Course completion
Youβve reached the end. A recap of the three tracks, one paragraph eachβto reinforce the path you took.
Track 1 β Fundamentals: the 4 problems
Why skills exist and what they solve
We showed the 4 problems that skills solve: repeated context, vague prompts, lack of a repeatable process, and no memory between sessions. From there, choosing a skill became a rational decision, not an aesthetic one.
Track 2 β About the Repo: structure and installation
How Matt Pocock's repository is organized and how to install it
We walk through the structure skills/, productivity/, engineering/, misc/, and we installed it via the Claude Code plugin. After that, every new skill finds its place without you having to ask.
Track 3 β Advanced: composition, customization, integration
How to go beyond the basics
We compose skills with one another, customize them for the project's local context, and integrate with other agents via MCP and CI/CD. Now you don't uses skills β you builds with them.
π Next steps
Theory without practice turns to dust. Next concrete step: choose a real project of yours within the next 48h and install 3 skills. Use them for a full week. Note what saves time and what fails.
After that, three paths:
- 1.Customize: adjust the frontmatter, edit the body, make your own
- 2.Compose: chain skills (e.g.,
/grill-me+/tdd) - 3.Port: use
polyskilland bring your skills to Codex / Cursor
π― What youβll know by the end
Keep learning:
- π¬ Matt Pocockβs newsletter: aihero.dev/s/skills-newsletter
- π¦ Course repository: github.com/inematds/mp-skill
- π INEMA.CLUB β Brazilian community: inema.club