Shared skills: tested procedural capability
PLA 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.
What a governed skill program gives you
Section titled “What a governed skill program gives you”- 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.jsonversion 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.
Which procedures deserve a shared skill?
Section titled “Which procedures deserve a shared skill?”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 share | Put it in | Why |
|---|---|---|
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 skill | Loaded only when relevant, so it costs little context until used |
| A check that must run whatever the model decides | A governed hook or a CI gate | A skill is advice; the model can skip or misapply it |
| Live access to a system (tickets, feature flags, a database) | An internal MCP server | A 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.
---name: migration-reviewdescription: 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.
## Procedure1. 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:
mkdir -p .claude/skillsln -s ../../.agents/skills/migration-review .claude/skills/migration-reviewclaude plugin validate .claude/skills # fails on SKILL.md frontmatter that does not parseInvoke 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.
Codex 0.157.1 loads repository skills from .agents/skills/. Type /skills in the TUI to list what loaded, and mention $migration-review in a prompt to invoke it explicitly. For the fixtures, test the implicit trigger too: a prompt that describes the task without naming the skill.
Codex also bundles a skill-creator system skill ($skill-creator) that drafts and revises skills.
Cursor supports Agent Skills (Cursor skills docs, checked 2026-10-12), and its docs list .agents/skills/ and .cursor/skills/ as project locations; for compatibility it also loads .claude/skills/ and .codex/skills/. Confirm discovery in a fresh Agent chat with a positive and a negative fixture prompt before you count Cursor as covered. Until then, treat the Cursor adapter as advisory.
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:
| Fixture | Prompt (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 default | Skill fires; VERDICT: changes-needed |
passes-safe-change | A migration that adds a nullable column | Skill 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-input | A migration file with a syntax error | Reports the parse problem instead of inventing findings |
stale-source | A migration using a feature the rules file does not cover | Says 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:
---max_turns: 8allowed_tools: [Read, Glob, Grep, Skill]---
Can you check this migration before I merge it?
-- db/migrations/20260926_add_plan_to_accounts.sqlALTER TABLE accounts ADD COLUMN plan text NOT NULL;---type: regexpattern: 'VERDICT: changes-needed'------type: tool_usedtool: Skillinput_match: '"skill"\s*:\s*"(?:[\w-]+:)?migration-review"'min: 0max: 0arm: 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:
claude plugin validate plugins/eng-skills --strictclaude 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 20Pin --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=0for 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; fidoneexit $failedOne 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.
Add the same repository as a marketplace, pinned to a tag, then install the plugin. Codex 0.157.1 resolves a Claude-format .claude-plugin/marketplace.json:
codex plugin marketplace add acme/agent-skills --ref eng-skills--v1.4.0codex plugin add eng-skills@acme-skillscodex plugin list --marketplace acme-skillscodex plugin marketplace upgrade refreshes a Git marketplace; with a pinned --ref, a new version reaches a machine only when its ref is changed, which is the point. Which Claude-only plugin components Codex activates beyond skills was not verified for this page. The 0.157.1 binary also carries marketplace allowlist settings for the admin-managed requirements.toml (restrict_to_allowed_sources, allowed_sources); confirm the table layout in the Codex configuration reference before you roll it out.
Cursor installs plugins with /add-plugin in Agent chat, and a repository becomes a Cursor marketplace when it has .cursor-plugin/marketplace.json at its root (per Cursor’s first-party cursor/plugins repository; Cursor’s own docs could not be re-read in September 2026). Until you have tested a Cursor plugin install end to end, the simplest reliable route is the repository-scoped .agents/skills/ folder, validated with the fixture prompts in a fresh chat.
Roll out in stages and measure five things
Section titled “Roll out in stages and measure five things”- 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. - 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.
- Managed enablement. Enable the plugin through managed settings for the whole organization once the metrics below hold for two weeks.
- 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. - Quarterly review. Retire every skill whose
retire-whencondition is met, whoselast-verifieddate 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.
| Metric | Definition | Signal of trouble |
|---|---|---|
| Trigger precision and recall | From the eval suite: fired when expected ÷ should-fire cases, and silent when expected ÷ should-not-fire cases | Recall falls when descriptions overlap; precision falls when a description is too broad |
Added value (Δ) | With-skill score minus no-skill score from claude plugin eval | Near zero means the model already does this; retire the skill |
| Useful completion | Reports whose VERDICT the pull-request author or reviewer accepted ÷ all reports, sampled weekly | Falling rate means the rules drifted from what reviewers want |
| Context cost and use | Per-skill cost and invocation count from /skill-doctor (Claude Code 2.1.252 or later) and claude plugin details | High cost with few invocations; the listing budget is 1% of the context window, and overflow drops descriptions |
| Staleness | Skills whose last-verified date is older than your review interval | Rules 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-verifieddate, and aretire-whencondition. - The fixture suite passes in CI for Claude Code, and each other tool has a recorded fixture run.
- Any
allowed-toolsentry, script, or network access has a security reviewer’s approval on the pull request. - The marketplace entry pins a version, and
plugin.jsonand 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.
What breaks when a team shares skills?
Section titled “What breaks when a team shares skills?”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.
Where to go next with shared skills
Section titled “Where to go next with shared skills”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.