A shared library of Agent Skills (agentskills.io spec) used across multiple projects.
Skills are generic and project-agnostic. Project-specific overrides live in a /skills/ directory within each project repo.
skills/
<skill-name>/ # One directory per skill variant
SKILL.md # Required. Frontmatter + instructions.
scripts/ # Executable scripts (bash, Python, etc.)
references/ # Supplementary docs loaded on demand
assets/ # Static resources (templates, schemas, etc.)
All active skills live under skills/. No other top-level layout is required by the spec.
- Skill directories use gerund form, no suffix:
reviewing-code,shipping-work,init-project-fastapi. - Names must be lowercase, hyphens only, no consecutive hyphens, max 64 chars (spec requirement).
- In practice all current skills run identically across agent providers, so the bare name is the default.
Two situations warrant a suffix:
- Agent-specific variant when a skill genuinely needs to diverge for one provider (e.g. provider-specific tool invocation, prompt-style tuning that materially affects behavior). Allowed suffixes:
-claude,-cursor,-copilot,-gemini. - Stack-specific variant when a skill diverges along a technology axis (e.g.
reviewing-code-php,shipping-work-python-fastapi). Use the language or framework as the suffix; when a single language hosts multiple genuinely-different workflows (e.g. Python FastAPI vs Python Click), include the framework in the suffix and skip the bare-language variant.
Without a sibling variant, do not add a suffix prophylactically — it adds noise without information.
When a skill needs a variant, each variant lives in its own directory:
skills/
reviewing-code/ # baseline (used when no variant matches)
reviewing-code-php/ # PHP/WordPress stack variant
reviewing-code-python-fastapi/ # Python/FastAPI stack variant
reviewing-code-python-click/ # Python/Click CLI stack variant
reviewing-code-cursor/ # Cursor-specific agent variant (hypothetical)
shipping-work/ # baseline
shipping-work-php/ # PHP/WordPress stack variant
shipping-work-python-fastapi/ # Python/FastAPI stack variant
shipping-work-python-click/ # Python/Click CLI stack variant
Variants share the same trigger phrases (documented in metadata.triggers). The runtime selects the appropriate variant. Each variant is a complete, self-contained skill — no inheritance between variants.
Projects may define a local /skills/ directory with the same skill name. The local version is a complete replacement — not an extension. There is no partial override or inheritance.
Resolution order (most specific wins):
- Project-level skill (e.g.,
my-project/skills/reviewing-code/) - Global skill (this repo, e.g.,
gregoryfoster/skills/skills/reviewing-code/)
Consequences:
- Global skills must be fully general and project-agnostic
- Project skills must be fully self-contained (they cannot assume the global version exists)
- When creating a project override, copy the global skill as a starting point
An override must declare overrides: <vendor>/<upstream-skill-name> and
override-reason: in its metadata block — the vendor prefix is what
disambiguates which parent is being replaced when two vendored sources ship the
same skill name, and should declare synced-from: (#286). A fragment the
vendor marks <!-- skill:required id=<slug> --> that genuinely cannot apply is
declared, not dropped, in omits-required: (#265). Authoring detail, the
legacy unqualified form, and the H1 suffix:
docs/CONVENTIONS.md.
Validate skills with skills-ref validate skills/<name>.
Use uv tool install (recommended — isolated, no --break-system-packages needed):
uv tool install "git+https://github.com/agentskills/agentskills#subdirectory=skills-ref"Or with pip in a venv:
python -m venv .venv && source .venv/bin/activate
pip install "git+https://github.com/agentskills/agentskills#subdirectory=skills-ref"- Required frontmatter:
name,description namemust match the directory name exactlydescriptionmax 1024 chars; write in third person; include what and whenSKILL.mdbody recommended under 500 lines; move detail toreferences/
- Be concise. Claude already knows how to use git, read Python, etc. Only add context it doesn't have.
- Match freedom to fragility. Exact scripts for dangerous/stateful ops; high-level instructions for judgment calls.
- Descriptions drive discovery. The description is how Claude decides which skill to activate from 100+ candidates. Make it specific and include trigger keywords.
- Progressive disclosure.
SKILL.mdis the overview.references/files are loaded only when needed.scripts/are executed, not loaded into context. - Test across models. Skills tuned for Opus may need more detail for Haiku.
- All scripts must be self-contained or document dependencies clearly
- Support
--helpwith usage + flag descriptions - No interactive prompts — agents run in non-interactive shells
- Use structured output (JSON, TSV) on stdout; diagnostics to stderr
- Use
set -euo pipefailin bash scripts - A write through a temp file must be checked, and a deliberate exception must
say so with
# unchecked-write-ok: <reason>— gated bytest_checked_temp_writes.py, explained in docs/STYLE.md - Pin versions when invoking tools (e.g.,
uvx ruff@0.16.6— the pin this repo's own Python gate uses, kept inrequirements-test.txt) - Must pass
shellcheck --external-sources --source-path=SCRIPTDIR --severity=style(shellcheck's own default floor — no level is exempt).TestShellcheckruns it overskills/*/scripts/,scripts/and.claude/hooks/, and skips loudly when the binary is absent or older than 0.7.0 (#140).SHELLCHECK_REQUIRED=1turns either skip into a failure. - A
# shellcheck disable=SCxxxxmust carry a reason comment on the line directly above it.TestShellcheckSuppressionsCarryReasonsenforces the pairing, so a suppression stays a documented decision rather than a silencer (#90).
These carry a full template and a rationale in docs/STYLE.md, and each is enforced:
- A repo-creating git command must scrub
GIT_DIR— it overridesgit -Cand cwd, and git exports it to every hook, so a fixture's throwaway repo writes to the real one (#189).extensions.worktreeConfigwas measured and refused. - Per-script resolution. Never write
bash scripts/X.shin a SKILL.md: the agent's cwd is the project root (#63), and resolve each script on its own (#301).TestNoBareScriptPaths. - Gate-script discipline. A script whose output drives a ship/skip decision
must never silently swallow the stderr of the tool producing that output.
TestGateScriptHardeningbinds everyshipping-work*/reviewing-code*script plus repo-rootscripts/(#318), each classified gate or reporting (#255);test_pre_ship_env_override.pyholds the wrapper-don't-fork override block across all four variants (#105).
A project configures a skill by committing a file under .skills/ instead of
forking it. Three of those resolve through the same three-step lookup —
<NAME> env var, then the file, then a built-in default: WORKTREE_ROOT /
.skills/worktree_root and PLANS_DIR / .skills/plans_dir (each a single-line
path), and SKILLS_PIN_FILE / .skills/skills-pin (one <submodule-path> <commit-ish> per line). That is the shared shape, not the inventory — the
rest use their own, and reading this section as the list is how
#261 left a repo able to
tailor a gate's watch list but not its advice. Every .skills/ file a
project may commit, what replaces or extends a default, and what each absence
means: docs/KNOBS.md, held complete by
tests/structural/test_skills_knob_inventory.py.
The per-skill defaults and resolver helpers: docs/CONVENTIONS.md.
Skills may carry supplementary references/*.md files for content exceeding the
SKILL.md body cap, loaded on demand rather than on activation. Two rules are
enforced by the structural suite:
- Every
references/<name>.mdmust be linked from its sibling SKILL.md — orphans fail tests/structural/test_references.py, which lets a doc link what it keeps in a subdirectory (#152). - Relative links resolve from the file that contains them. Every rendered
link in any
skills/**/*.md— SKILL.md and references alike — must point at a real path, or tests/structural/test_relative_links.py fails. Links inside code fences and inline code spans are skipped — they never render, and that is where a consuming repo's illustrative paths live. An illustrative link in prose needs anEXEMPT_LINKSentry naming the file, the target and the reason (#143).
Convention, not enforced: no frontmatter, lowercase-kebab.md names, and
no length cap — escaping that body cap is the point of a reference file.
Conditional-block delimiters and the assets/ equivalents:
docs/CONVENTIONS.md.
Every SKILL.md is held to a 6,000-token ratchet — the figure
curating-context enforces on a consuming repo's AGENTS.md — by
tests/structural/test_skill_self_budget.py,
which also holds every references/*.md to the 10,000-token per-doc budget,
with nothing exempt — #152
retired the one exemption by splitting the append-only log rather than excusing
it. The skills that miss it carry a named exception with its reason beside it,
and every file names its own figure in prose so the gate and the run read the
same number. A ratchet only ever comes down.
Two readings bind it, not one, and only the estimate is always on — which let three ratchets be breached past a green suite. What each reading is, how they are reconciled, anchoring a file before curating it, and the weekly exact gate: docs/BUDGETS.md.
AGENTS.md itself is gated: the context-budget-gate pre-commit hook fails any commit that puts it over .skills/context-budget (#88).
Conventional Commits style:
<type>: <description>
Common types: feat, fix, docs, refactor, chore
Example: feat: add reviewing-architecture-cursor variant
Projects vendor this repo as a git submodule at skills-vendor/<owner>-<repo>/ and
symlink individual skills into their own skills/ directory with relative paths.
Local overrides (committed directories) always win over symlinks, and
skills-vendor/ is read-only from the consuming project's side.
The pattern, the .skills/doctor.sh install and self-sync rules, and this repo's
own .claude/skills self-discovery symlink: docs/SKILLS.md.
The managing-skills skill teaches agents how to perform these operations.
Create a venv, install dependencies, and activate local git hooks (run once after cloning):
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-test.txt
pre-commit install # structural tests run on every commitHooks use .venv/ at the repo root. A worktree has none; the gate links the
main checkout's in and never re-creates it (#156).
Python is gated by ruff, pinned exactly in requirements-test.txt: bash scripts/python-lint.sh runs check + format --check (--fix applies both),
and test_python_lint.py runs the same checks inside. On a missing or
mismatched ruff the suite skips loudly (RUFF_REQUIRED=1 to fail) and the hook
refuses to run (#246).
scripts/pre-ship.sh is the ship gate — every pre-commit hook in one
command, and what shipping-work Step 1 resolves (#318):
bash scripts/pre-ship.sh # budget + ruff + suite
pytest tests/integration/ -v -m integration # billed, needs .env; never gatedPut a new structural rule in its own tests/structural/test_<rule>.py, not at
the end of test_context_surface.py. That file is the obvious default home,
which is exactly the problem: when several agents work the backlog in parallel
worktrees, appending to one shared file turns every merge into a conflict, while
a per-rule file merges clean and stays findable by filename. Extend an existing
file only when the new test belongs to the rule that file already owns.
ANTHROPIC_API_KEY lives in the gitignored .env at the repo root. Load it with
set -a && source .env && set +a; run-integration-tests.sh and
measure-context.sh --exact find it themselves.
- Create
skills/<skill-name>/SKILL.mdwith valid frontmatter - Add
scripts/andreferences/as needed - Validate:
skills-ref validate skills/<skill-name> - Commit and push
- Update project AGENTS.md files that reference this repo to include the new skill in their
<available_skills>block (if applicable) - If the skill should be listed in this repo's README.md skills table, add it there too
When an agent-specific or stack-specific divergence is needed (see "Variant strategy"):
- Copy the baseline:
cp -r skills/reviewing-code skills/reviewing-code-<suffix>(e.g.-php,-python,-cursor) - Update
name, rewritedescription:, declare inVARIANT_FAMILIES— why - Tune instructions, scripts, and references for the target stack or agent
- Validate and commit
- docs/STYLE.md — the per-script resolution template, the gate-script rules and the scripts they bind, the
GIT_DIRscrub, and the refusedextensions.worktreeConfig - docs/CONVENTIONS.md — authoring a project override, the
references/conditional-block delimiters, the env-var knobs' resolver helpers, and claims about another repo - docs/BUDGETS.md — a budget's two readings, anchoring, and the weekly exact gate
- docs/KNOBS.md — every
.skills/file a project may commit: grammar, reader, replaces-or-extends, and what absence means - docs/SKILLS.md — the submodule + symlink vendoring pattern,
.skills/doctor.sh, and self-discovery