Skip to content

A shared skill is a versioned SKILL.md package that gives every engineer’s agent the same procedure for a recurring task. A shared skill earns its place only with a named owner, a narrow trigger, read-only authority by default, fixtures that prove it fires and stays silent when it should, pinned distribution, and evidence that people use it.

This page is for the tech lead or CTO who answers question 6 of the CTO Scorecard, and for the platform engineer who maintains the team’s skills. The situation it prevents: three engineers each wrote a migration-review skill, one of them fixed a lock-risk rule in theirs, and the other two kept approving migrations that took a table lock in production. Nobody knew which version any agent had loaded, because nothing recorded it.

Q6 · Shared infrastructure: Does the team share skills?

Max-score answer: versioned, reviewed skills with owners, positive, negative, and boundary fixtures, safe distribution, and usage evidence.

The Tech Lead Scorecard questions about how good workflow patterns spread across a team also land here, because a reviewed skill is how a pattern outlives the person who found it.

  • A skill contract, written as a portable SKILL.md, that a reviewer approves before the procedure spreads
  • One source directory that Claude Code, Codex, and Cursor all load
  • Eval fixtures that prove the skill fires on the right requests, stays silent on the wrong ones, and refuses work outside its boundary, without anyone reading the skill line by line
  • A team marketplace with pinned versions (a git ref in Codex, the reviewed plugin.json version in Claude Code), so the reviewed version is the one that runs
  • Five metrics with definitions, a sign-off list, and a retirement rule
  • Three copy-paste prompts: draft the contract, attack the skill, and generate the fixtures

How one developer writes a first skill is covered in agent skills as tested workflows and building custom skills. Vetting third-party skills is in skill supply-chain security. This page covers only the team layer: what becomes a shared skill, how it is proven, how it ships, and how it is retired.

A skill is instructions the agent loads when a request matches its description. It is the right container for a procedure with several steps that applies to some tasks and not others. Anything that must hold on every task, or must hold whatever the model decides, belongs somewhere else.

What you want to sharePut it inWhy
A fact true for every task in the repository (“tests run with pnpm test”)Shared agent rules (AGENTS.md, CLAUDE.md)Loaded every session; a skill might not fire
A multi-step procedure for one kind of task (review a migration, draft release notes)A shared skillLoaded only when relevant, so it costs little context until used
A check that must run whatever the model decidesA governed hook or a CI gateA skill is advice; the model can skip or misapply it
Live access to a system (tickets, feature flags, a database)An internal MCP serverA persistent, authenticated connection is a server’s job, not a document’s

Choose candidates from evidence of repetition: the same review comment on five pull requests, the same question in the team channel every week, or an incident whose fix was a checklist nobody followed. A procedure that one person ran once is not a candidate yet.

Write the skill contract as the skill itself

Section titled “Write the skill contract as the skill itself”

The Agent Skills format has been an open standard since 2025-12-18 (Anthropic, Claude blog): a folder named after the skill, holding a SKILL.md with name (at most 64 characters) and description (at most 1,024 characters), plus optional scripts/, references/, and assets/ (specification). Keep the frontmatter to the fields the specification defines, and put ownership in metadata, so the same file loads in every tool.

The example below is the contract and the skill in one file. Copy it, then replace the rules with your own.

.agents/skills/migration-review/SKILL.md
---
name: migration-review
description: Review a new or changed SQL migration in db/migrations/ for lock risk, missing rollback, and unsafe defaults before merge. Use when a diff or pull request adds or edits a migration file. Do not use for application code, seed data, or running migrations.
compatibility: PostgreSQL 16 migrations in db/migrations/. Needs read access to the repository only.
metadata:
owner: platform-data (#platform-data)
version: "1.4.0"
last-verified: "2026-09-26"
retire-when: "the CI migration linter enforces every rule in references/rules.md"
---
# Migration review (v1.4.0)
## Boundary
- Read files only. Never run a migration, connect to a database, or edit files.
- If asked to apply, roll back, or run anything against a database, stop and
point to docs/runbooks/migrations.md instead.
## Procedure
1. List the migration files in the change. If there are none, reply
"No migration in this change" and stop.
2. Check each file against references/rules.md, in the order listed there.
3. Report each finding as: file:line, rule id, risk, suggested fix.
4. Start the report with "migration-review v1.4.0".
5. End with one plain-text line: "VERDICT: pass" or "VERDICT: changes-needed".

Every line in that file does governance work. The description names both the trigger and the non-trigger, which is what the agent matches against. The boundary says what the skill must refuse. The version line in the report makes each output traceable to the skill version that produced it. The fixed VERDICT: line gives the fixtures something to check without a person reading the report.

Keep one source for Claude Code, Codex, and Cursor

Section titled “Keep one source for Claude Code, Codex, and Cursor”

The format is shared, but each tool looks in its own directories. Keep the canonical copy in .agents/skills/, which Codex reads and which the skills CLI (vercel-labs/skills, npm skills 1.7.0) uses for Codex and Cursor project installs. Point Claude Code at the same folder with a symlink rather than a copy, so a fix lands everywhere at once.

Claude Code loads project skills from .claude/skills/<name>/SKILL.md, and a skill folder there “can be a symlink to a directory elsewhere on disk” (skills docs, 2.1.283). Run this in the repository root:

Terminal window
mkdir -p .claude/skills
ln -s ../../.agents/skills/migration-review .claude/skills/migration-review
claude plugin validate .claude/skills # fails on SKILL.md frontmatter that does not parse

Invoke it with /migration-review, or let Claude pick it from the description. When the skill ships inside a plugin instead, it is namespaced as /<plugin>:migration-review.

Prove the skill with fixtures, not by reading it

Section titled “Prove the skill with fixtures, not by reading it”

A reviewer should not have to read SKILL.md to know the skill works. Two things need proof, and they fail separately: whether the skill fires on the requests it should, and whether its output is right when it does. Anthropic’s docs put it plainly: “Seeing a skill trigger tells you Claude found it, not that it did what you intended.” The minimum fixture set for a shared skill:

FixturePrompt (phrased as a user would, without naming the skill)Expected
fires-on-target“Check this migration before I merge it” plus an ADD COLUMN … NOT NULL without a defaultSkill fires; VERDICT: changes-needed
passes-safe-changeA migration that adds a nullable columnSkill fires; VERDICT: pass (catches over-flagging)
silent-on-neighbour“Review this CSS change”Skill never fires
boundary-refusal“Apply this migration to production”Skill refuses and points to the runbook; no shell or database tool call
malformed-inputA migration file with a syntax errorReports the parse problem instead of inventing findings
stale-sourceA migration using a feature the rules file does not coverSays the rules do not cover it; does not guess

In Claude Code, these fixtures run as a plugin eval suite. claude plugin eval (Claude Code 2.1.269 or later) runs each case in a fresh isolated session with and without the plugin, three times by default, and exits non-zero when any case scores below --threshold. That gives you a CI gate and a measure of what the skill adds over no skill at all. Each case is a directory with a prompt.md and one file per grader:

plugins/eng-skills/evals/fires-on-target/prompt.md
---
max_turns: 8
allowed_tools: [Read, Glob, Grep, Skill]
---
Can you check this migration before I merge it?
-- db/migrations/20260926_add_plan_to_accounts.sql
ALTER TABLE accounts ADD COLUMN plan text NOT NULL;
plugins/eng-skills/evals/fires-on-target/graders/verdict.md
---
type: regex
pattern: 'VERDICT: changes-needed'
---
plugins/eng-skills/evals/silent-on-neighbour/graders/not-fired.md
---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?migration-review"'
min: 0
max: 0
arm: both
---

The arm: both line matters. By default a “skill was invoked” grader is excluded from the score in the two-arm comparison, and the docs name arm: both as the setting for a “must not invoke the skill” check. Then run the suite in CI:

Terminal window
claude plugin validate plugins/eng-skills --strict
claude plugin eval plugins/eng-skills \
--trust-plugin --threshold 0.9 --json results.json \
--model claude-opus-5-5 --judge-model claude-sonnet-5 \
--no-publish --max-cost-usd 20

Pin --model to the model your developers run, so a score change means the skill changed rather than the model. Pass --no-publish in CI, because the HTML report is published to claude.ai by default when your account supports it. Every run and judge call is billed to the credential the job uses.

For Codex, run the same prompts through codex exec in a checkout that contains .agents/skills/, and use the VERDICT: line as the skill’s fingerprint:

#!/usr/bin/env bash
# evals-codex/run.sh — each case dir holds prompt.txt and expect (fires | silent)
set -u; failed=0
for c in evals-codex/*/; do
out=$(mktemp)
codex exec --ephemeral -s read-only -o "$out" "$(cat "$c/prompt.txt")" >/dev/null 2>&1
if grep -q '^VERDICT:' "$out"; then got=fires; else got=silent; fi
want=$(cat "$c/expect")
if [ "$got" = "$want" ]; then echo "ok $(basename "$c")"
else echo "FAIL $(basename "$c"): $got, expected $want"; failed=1; fi
done
exit $failed

One run of a non-deterministic agent tells you little. Run each case at least three times before you trust a pass, as claude plugin eval does by default.

Ship skills so only the reviewed version runs

Section titled “Ship skills so only the reviewed version runs”

Where a skill is installed decides who can change it and whether it updates. Skills tied to one codebase live in that repository’s .agents/skills/ and change through its normal review. Skills used across repositories belong in a team marketplace: a repository that packages them as a plugin, with a version in plugin.json, so moving from 1.4.0 to 1.5.0 is one reviewed change and moving back is the same change reversed. The detailed build is in a private team marketplace.

acme/agent-skills
├── .claude-plugin/marketplace.json # lists the plugins; "name": "acme-skills"; Codex reads this file too
└── plugins/eng-skills/
├── .claude-plugin/plugin.json # "name": "eng-skills", "version": "1.4.0"
├── skills/migration-review/SKILL.md
└── evals/…

Register the marketplace and enable the plugin through managed settings (a managed-settings.json, MDM, or server-managed settings on Team and Enterprise), so nobody has to add it by hand:

{
"extraKnownMarketplaces": {
"acme-skills": {
"source": { "source": "github", "repo": "acme/agent-skills" },
"autoUpdate": true
}
},
"enabledPlugins": { "eng-skills@acme-skills": true },
"strictKnownMarketplaces": [
{ "source": "github", "repo": "acme/agent-skills" },
{ "source": "github", "repo": "anthropics/claude-plugins-official" }
]
}

strictKnownMarketplaces is an allowlist enforced on marketplace add and on plugin install, update, and auto-update; an empty array blocks every marketplace, including the official one. Third-party marketplaces do not auto-update unless you set autoUpdate. Updates are detected by comparing versions, so a release that does not bump version in plugin.json leaves users on the cached copy. claude plugin tag creates a {name}--v{version} git tag and checks that plugin.json and the marketplace entry agree. Run claude plugin list on a pilot machine to confirm the plugin installed.

This setup tracks the marketplace repository’s default branch, so nothing is pinned by a git ref: whatever merges there ships. On Claude Code the pin is the reviewed merge to the marketplace repository plus the version bump in plugin.json, so protect that branch and require the skill owner’s review on it.

Once every skill you need ships this way, "strictPluginOnlyCustomization": ["skills"] in managed settings stops Claude Code loading skills from ~/.claude/skills/, .claude/skills/, and claude.ai sync, and keeps plugin, bundled, and managed skills. It also switches off repository skills, so adopt it only when the repository-scoped ones have moved into plugins.

Roll out in stages and measure five things

Section titled “Roll out in stages and measure five things”
  1. One repository, one skill. Commit the skill to .agents/skills/, wire the Claude Code symlink, and get the fixture suite green three runs in a row.
  2. One volunteer team. Move the skill into the team marketplace at 1.0.0. Ask the team to report every wrong trigger in one channel, and turn each report into a fixture before changing the skill.
  3. Managed enablement. Enable the plugin through managed settings for the whole organization once the metrics below hold for two weeks.
  4. Lock the source. Add strictKnownMarketplaces (Claude Code) and, once you have confirmed the table layout in the Codex configuration reference, the Codex source allowlist, so only reviewed marketplaces install anything.
  5. Quarterly review. Retire every skill whose retire-when condition is met, whose last-verified date is more than a quarter old with no re-run, or that nobody invoked.

These are starting definitions, not benchmarks; set the thresholds from your own first month.

MetricDefinitionSignal of trouble
Trigger precision and recallFrom the eval suite: fired when expected ÷ should-fire cases, and silent when expected ÷ should-not-fire casesRecall falls when descriptions overlap; precision falls when a description is too broad
Added value (Δ)With-skill score minus no-skill score from claude plugin evalNear zero means the model already does this; retire the skill
Useful completionReports whose VERDICT the pull-request author or reviewer accepted ÷ all reports, sampled weeklyFalling rate means the rules drifted from what reviewers want
Context cost and usePer-skill cost and invocation count from /skill-doctor (Claude Code 2.1.252 or later) and claude plugin detailsHigh cost with few invocations; the listing budget is 1% of the context window, and overflow drops descriptions
StalenessSkills whose last-verified date is older than your review intervalRules that describe a stack you no longer run

Invocation count on its own is not success. A skill that fires on every request looks popular and is the most likely to be wrong.

Who signs off, and what counts as evidence?

Section titled “Who signs off, and what counts as evidence?”

Nobody approves a shared skill by reading SKILL.md alone. Approval rests on artifacts a reviewer can check in minutes:

  • The skill is merged with an owner, a version, a last-verified date, and a retire-when condition.
  • The fixture suite passes in CI for Claude Code, and each other tool has a recorded fixture run.
  • Any allowed-tools entry, script, or network access has a security reviewer’s approval on the pull request.
  • The marketplace entry pins a version, and plugin.json and the git tag agree.
  • A sample of real outputs carries the version line, so an accepted artifact can be traced to the skill that produced it.

The skill owner signs off the contract and fixtures. The platform or security lead signs off promotion to managed enablement and any grant of tools. This is the same split as for gates and guardrails: a skill guides the agent, and CI stays the gate nothing merges without.

A personal copy shadows the reviewed one. In Claude Code, a skill with the same name in ~/.claude/skills/ runs instead of the project’s, because personal outranks project. The reviewed skill is then silently unused on that machine. Recovery: ship shared skills as plugins, whose namespaced /<plugin>:<skill> names cannot collide, and once they all ship that way, lock sources with strictPluginOnlyCustomization.

A fix does not reach anyone. The owner merged a corrected rule, but version in plugin.json did not change, so clients kept the cached copy. Recovery: make a version bump part of the release check, run claude plugin validate --strict on the marketplace, and create the tag with claude plugin tag, which refuses when plugin.json and the marketplace entry disagree.

The skill fires on everything, or on nothing. A broad description catches unrelated work, and once many skills are installed the listing overflows its budget and drops descriptions, starting with the least-used skills. Recovery: add the wrongly matched prompt as a silent fixture, narrow the description, and remove unused skills that /skill-doctor flags. Keep procedures that should run only on request behind disable-model-invocation: true in Claude Code.

A skill quietly widened its own permissions. A pull request added allowed-tools: Bash(*) or a script that fetches a remote file. Recovery: require security code-owner review on allowed-tools, scripts/, and references/ paths, scan the directory as described in skill supply-chain security, and keep read-only as the default boundary.

A copied third-party skill broke. Some published skills delegate to sibling skills in the same repository, so copying one folder leaves a skill that calls something that is not there. Recovery: vendor the whole package into your marketplace at a pinned commit, run your fixtures against it, and assign an internal owner like any other skill.

The skill was treated as a control. A skill can be ignored, misapplied, or skipped when the model judges it irrelevant. Recovery: move anything that must hold every time into a governed hook, a permission rule, or a CI check, and keep the skill as the procedure that explains it.

Skills are one layer of the shared harness. Put durable repository facts in shared agent rules, enforce must-run checks with shared hooks governance, and use knowledge sharing to turn incidents into skill updates and retirements. For who owns all of this as a product, see the agent platform team.

Frequently asked questions

What makes a shared `SKILL.md` package production-ready for an engineering team?

A production-ready shared skill has a named owner, a narrow trigger description, read-only authority by default, evaluation fixtures proving it fires when relevant and stays silent otherwise, version-pinned distribution, and usage evidence.

How can one shared skill support Claude Code, Codex, and Cursor simultaneously?

Author the procedure once in a standard SKILL.md directory and distribute pinned versions through your repository or team marketplace so Claude Code, Codex, and Cursor all load the same verified source.