| name | skill-builder |
| description | Create or update a skill. |
| user-invocable | true |
| allowed-tools | ["Bash","Read","Edit","Write"] |
skill-builder — author a new skill (extend-first)
Create — or, preferably, extend — an ai-config skill following the repo's
conventions. The prime directive: don't create a new skill until you've
confirmed no existing one should be extended instead, and that no other
branch is already building it.
When this fires
- "build a skill", "create a skill", "make a new skill", "add a skill",
"skill-builder"
- Creating an alias for an existing skill — "add an alias for X", "make X
an alias for Y", "should this be an alias for Y" — is a skill-builder task
too, not a raw
Write of a stub file. Hand-writing an alias SKILL.md
skips the codex-wrapper regeneration (the required step below) and trips the
validate CI check, and skips the self-review pass that catches errors in
the stub's own prose. (ai-config#569: a hand-written giardia→gia alias
stub failed validate on the missing wrapper and needed a review round to
fix a reversed phase-order description — both avoidable by routing here.)
- Any time a repeatable multi-step workflow emerges that's worth codifying —
proactively suggest capturing it as a skill.
Step 0 — Extend before you create (do this FIRST, always)
Rule out extending an existing skill before scaffolding anything:
-
Search the whole corpus, not only skills/, for something that already
owns (or is adjacent to) this concern:
cd "$(git -C ~/.claude/skills/skill-builder rev-parse --show-toplevel)"
ls skills/ scripts/ hooks/
grep -ril "<keywords>" skills/ scripts/ hooks/ shared/ memories/ CLAUDE.md
If a skill already covers it, extend that skill (a new alias, a new
section, an extra trigger phrase) rather than adding a near-duplicate.
If a script or hook already performs it, the skill you were about to
author is a wrapper around that instrument, so document the instrument
instead of restating its procedure as prose.
scripts/ and hooks/ are the paths most often left out of this search,
and they are where prior art for a procedural skill is likeliest to sit.
A skill describing a procedure is frequently a wrapper around an instrument
that already exists, because
deterministic-tools
pushes every recurring judgment task toward a script.
So an instrument in scripts/ is prior art for a skill exactly as another
skill is.
A search confined to skills/*/SKILL.md answers the narrower question
"does a skill exist", rather than the one actually being asked, "does this
capability exist".
Omitting them produces the failure shape
grep-is-not-coverage
describes: a real command, a real null result, and a conclusion wider than
the paths that were searched.
So report the paths you covered alongside the step 4 decision below, rather
than reporting the decision alone.
- Do: search
scripts/ and hooks/ alongside skills/ before
concluding that a capability does not already exist.
- Do: name the paths the search covered when stating the
extend-or-create decision.
- Don't: read a clean grep over
skills/*/SKILL.md as evidence that
the capability is absent; it answers a narrower question.
- Don't: author a skill describing a procedure without first checking
whether an instrument already performs it.
Anatomy of a skill
One directory per skill, name matching the directory:
skills/<name>/SKILL.md
---
name: <name>
description: "<what it does>. Use when asked to '<trigger>', '<trigger>', …"
user-invocable: true
allowed-tools:
- Bash
- Read
- Edit
- Write
---
description is how the skill gets discovered. Pack it with what it
does AND the natural-language triggers (Use when asked to '…'). The matcher
reads this — be generous with trigger phrasings.
- Body shape:
# <name> — <tagline>, then ## When this fires,
## Procedure, ## Relationship to other skills, ## Anti-patterns.
Concrete commands beat prose.
Conventions (match the existing family)
If the skill fans out to subagents
When a skill's procedure spawns subagents (to parallelize per-item work, e.g.
pr-status-all runs one subagent per PR), write the subagent prompt as if the
skill file doesn't exist — because for the subagent it doesn't. A spawned
subagent starts fresh: it sees only the prompt the orchestrator hands it, not
this skill's text. Any discipline the work depends on (the exact query, the
bot-login wording, how to resolve owner/repo, "read the LATEST review") has to be
restated inside the subagent prompt, not assumed inherited. Keep the cheap,
once-per-run setup in the orchestrator — enumerate the work items there, and pass
down the per-item data the orchestrator already holds so each subagent doesn't
re-fetch it. pr-status-all is the worked example.
If the same worker persona would be spawned by more than one call site, or the
fan-out step needs a harness-enforced tool boundary an inline prompt can't
guarantee (e.g. a detection pass that must never be able to write), promote it
to a persistent .claude/agents/<name>.md subagent instead of an inline
prompt — hand off to agent-builder for that. dependency-auditor,
hallucination-detector, and community-demand-scout are the worked examples.
If the skill encodes a standing rule
When the skill codifies general guidance or a preference (not just a one-off
procedure), also update memories/preferences.md, and for top-level
workflow policy add a CLAUDE.md section. Standing rule: update BOTH the
skill AND preferences — the skill encodes the behavior, preferences make it
persist and fire across all contexts even when the skill isn't invoked.
Ship it
Skills and memories all live in the ai-config repo — never leave changes
local-only. Commit via a branch + PR (not direct to main), request
the repository owner as reviewer, then ARDI to clean.
In a worktree session, the repo toplevel below is the MAIN checkout, not
your worktree. ~/.claude/skills symlinks into the main ai-config
checkout, so git -C ~/.claude/skills … rev-parse --show-toplevel returns the
main repo root — often on another session's branch. Don't cd there and don't
pass that path to Write/Edit: the skill files (and git commits) would land in
the main checkout, clobbering another session's working tree. Instead author
the files in your worktree's own skills/<name>/ dir and run git from the
worktree (it's a full checkout of the same repo). Confirm with
git branch --show-current before committing.
cd "$(git -C ~/.claude/skills/skill-builder rev-parse --show-toplevel)"
git fetch origin main && git checkout -b add-<name>-skill origin/main
python3 scripts/sync-codex-skill-wrappers.py
python3 scripts/semantic-line-breaks.py skills/<name>/SKILL.md
python3 scripts/validate-skills.py
python3 scripts/check-links.py
python3 scripts/check-vendored-drift.py
npx --yes markdownlint-cli2@0.22.1
git add skills/<name>/SKILL.md codex-skills/<name> \
skills/<alias>/SKILL.md codex-skills/<alias> \
memories/preferences.md
git commit -m "skills: add <name> — <summary>"
git push -u origin HEAD && gh pr create --fill
Regenerate the Codex wrappers — every new or renamed skill needs them.
codex-skills/ is a generated tree of thin Codex-compatible wrappers, one per
skills/<name>/, and the validate CI job fails if it's out of sync (the red
log reads Codex skill wrappers are out of sync:). After writing the skill (and
any alias dir), run
python3 scripts/sync-codex-skill-wrappers.py, then git add the new
codex-skills/<name>/ (and codex-skills/<alias>/) alongside the source.
The validate CI job runs four checks — scripts/validate-skills.py
(frontmatter + wrapper sync + manifests), scripts/check-links.py (relative
markdown links), scripts/check-vendored-drift.py (shared-fragment drift), and
markdownlint-cli2 (markdown style). Run all four before pushing to catch a
stale wrapper, broken link, drift, or lint violation without a red-CI
round-trip. Markdownlint lints every SKILL.md; the corpus disabled the
rules its legacy files already violate (see .markdownlint-cli2.jsonc), so a
new skill still has to pass the rest — e.g. unique headings (MD024) and blank
lines around tables (MD058).
A fifth CI gate isn't among those four, and it fires on the new file's own prose: check-new-line-breaks, a separate workflow that rejects a line you add which packs more than one sentence, or which reaches 80 characters and carries a mid-line semicolon.
Its scope is Markdown only (globs: '*.md'), minus the paths-ignore set --- codex-skills/**, docs/**, _site/**, .quarto/**.
So it scans every .md the skill touches, and it never scans the generated wrappers, which must not be hand-edited to satisfy a gate that does not read them.
scripts/semantic-line-breaks.py is not that gate.
As of ai-config#2085 it loads the same checker the gate pins, so --write
splits a mid-line semicolon the gate would flag rather than manufacturing
one.
The script is still a reformatter of named files, not the diff-scoped job:
take the verdict from the real check, whose runnable command is in
semantic-line-breaks.
The gate only flags lines this branch actually changed against origin/main,
so run the reformatter against every file the skill touches, not just the new
SKILL.md.
Add --write to apply once you've confirmed the diff is what you expect.
Don't reach for --all by default --- it widens the reformat to the whole file, and on a file with pre-existing hard-wrapped (but otherwise CI-clean) prose it can rewrite hundreds of untouched lines into a large, unrelated-looking diff.
Prefer the scoped mode, and if it under-fixes a paragraph (a same-sentence line shows up as "still would change" on a second scoped run even though git diff origin/main shows that region untouched), just fix that one paragraph by hand instead of widening scope.
The 8000-char skill-listing budget lives inside validate-skills.py, not a separate script.
Adding a skill grows two catalogs at once --- skills/ (this repo's own routing prompt) and codex-skills/ (the Codex-wrapper mirror) --- and validate-skills.py reports both totals even when neither is over budget, so a passing run still tells you your margin.
If either is over, shorten this skill's own description field rather than editing an unrelated skill's frontmatter to make room.
Re-run sync-codex-skill-wrappers.py after any frontmatter edit, since the Codex listing is derived from it.
Then, as their own explicit steps (don't leave them buried in a comment):
- Request the reviewer:
gh pr edit --add-reviewer <reviewer> (EDIT_PR; see
request-pr-review).
- Drive to clean: run the
ardi skill on the new PR until the verdict has
zero findings.
Why git -C … rev-parse --show-toplevel over dirname "$(readlink …)":
bare readlink (no -f) resolves only a single hop and behaves
inconsistently across macOS/Linux; rev-parse --show-toplevel returns the
repo root directly regardless of how the symlink chain is set up.
Relationship to other skills
spot-skill-opportunities — the recognition step that runs before this
one: it notices, continuously and in the moment, that a pattern is
skill-shaped and hands off here to build it. ums / record-learnings
route through it too rather than judging recurrence themselves.
ums / record-learnings — when a session reveals a workflow worth
codifying, they hand off to this skill to build it.
memorize / remember — for a one-line fact or preference (not a
procedure), write a memory instead of a skill.
request-pr-review, ardi — used to ship and clean the new skill's PR.
simplify / tidy — when extending, prefer collapsing into an existing
skill over proliferating near-duplicates.
consolidate-skills — when you discover a near-duplicate that already
shipped (two real skills for one workflow), hand the cleanup there: it merges
them into one canonical skill plus alias stubs.
decompose-skill — when Step 0 finds the closest existing skill to
extend is actually two concerns wearing one name, hand the cleanup there
instead of bolting a third concern on.
heal-skill — the repair counterpart: this skill authors a skill,
heal-skill fixes one that misfired after it shipped.
agent-builder — the subagent-file counterpart: this skill authors
user-invocable workflows in skills/; agent-builder authors the
persistent, read-only fan-out worker personas a heavy skill's subagent step
can promote to .claude/agents/<name>.md.
link-skills — this skill cross-links the one skill it authors;
link-skills is the corpus-wide audit that catches cross-reference gaps a
single authoring pass missed.
config-ai — the broader router this skill is one destination for: when
a request names a capability but not a mechanism, config-ai decides
whether it's a skill (→ here), a subagent, a memory, a hook, or a gha
capability, then hands off accordingly.
Anti-patterns
- ❌ Creating a new skill when an existing one should be extended (skipping step 0).
- ❌ Searching only
skills/ in step 0 -- scripts/ and hooks/ hold the
instruments a procedural skill is likeliest to duplicate, so a clean grep
over skills/*/SKILL.md alone is not evidence the capability is missing
(#1055/#1056).
- ❌ Not scanning other branches → colliding parallel work / duplicate skills.
- ❌ Not checking open PRs → building a second draft of a skill someone already
pushed and opened a PR for, instead of redirecting to it.
- ❌ Duplicating canonical content across alias files (aliases must only redirect).
- ❌ Hand-writing an alias
SKILL.md directly (raw Write) instead of routing
through skill-builder — skips codex-wrapper regeneration (trips validate)
and the self-review pass (giardia→gia, #569).
- ❌ A thin description with no trigger phrases — the skill never gets discovered.
- ❌ In a subagent-fanning skill, writing the subagent prompt as if it inherits
this skill's text — it doesn't; restate every needed discipline in the prompt.
- ❌
name: not matching the directory name.
- ❌ Encoding a standing rule in the skill but not in
preferences.md.
- ❌ Naming a GitHub MCP tool (or
gh/git operation) the skill uses without
registering it in tool-mappings.yml — the reviewer flags the unregistered
name as a possible hallucination (push-memory #311, resolve-pr-threads #347).
- ❌ Bumping
skills.qmd's skill count by a manual +1 instead of re-deriving it
from ls -d skills/*/ | wc -l — it drifts whenever main gains other skills
mid-review (resolve-pr-threads #347).
- ❌ Citing a
CLAUDE.md section or an "existing scale/convention" in new
skill prose without grepping to confirm it actually exists first
(check-info-quality #349).
- ❌ Leaving the new skill as a local-only uncommitted file (or pushing direct to main).
- ❌ In a worktree session, writing the skill files to the
rev-parse --show-toplevel
path — it resolves to the main checkout (via the ~/.claude/skills symlink), not
your worktree, so the files land on another session's branch. Author in the
worktree's own skills/ dir.