用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Morrison-Lab/ai-config --skill skill-builder命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | skill-builder |
| description | Create or update a skill. |
| user-invocable | true |
| allowed-tools | ["Bash","Read","Edit","Write"] |
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.
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.)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)" # the ai-config repo
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.
scripts/ and hooks/ alongside skills/ before
concluding that a capability does not already exist.skills/*/SKILL.md as evidence that
the capability is absent; it answers a narrower question.One directory per skill, name matching the directory:
skills/<name>/SKILL.md
---
name: <name> # MUST equal the directory name
description: "<what it does>. Use when asked to '<trigger>', '<trigger>', …"
user-invocable: true
allowed-tools: # real skill: list its tools. alias: mirror the canonical's list
- 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.# <name> — <tagline>, then ## When this fires,
## Procedure, ## Relationship to other skills, ## Anti-patterns.
Concrete commands beat prose.shared/workflow/skill-checklists.md:
add one only for repeatable, high-cost, mechanically verifiable failure
modes. If the skill is mostly judgment/exploration, skip checklist boilerplate.gi, sup, ums, dc), also create the spelled-out
alias dir (grab-issue, send-upstream, update-memories-and-skills) — and
give a memorable short alias to a spelled-out canonical where it helps. The
alias file is thin and only redirects:
---
name: <alias>
description: "Alias for `<canonical>`. <one-line>. Use when asked to '<trigger>'."
user-invocable: true
allowed-tools: # mirror the canonical's allowed-tools exactly
- Bash
- Read
- Edit
- Write
---
# <alias> (alias for `<canonical>`)
This is a spelled-out alias. Read and follow the canonical skill:
→ **[<canonical>](../<canonical>/SKILL.md)**
Keep the real content in one canonical file; aliases never duplicate it.
The alias's allowed-tools is the one exception: copy the canonical's list
verbatim so invoking the alias permits exactly what the canonical needs (an
alias redirects, so it must not be more restrictive than its target).## Relationship to other skills.skills/ (the
bootstrap symlink and the plugin root both read the directory) — adding the
directory is enough.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.
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.
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/skillssymlinks into the mainai-configcheckout, sogit -C ~/.claude/skills … rev-parse --show-toplevelreturns the main repo root — often on another session's branch. Don'tcdthere 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 ownskills/<name>/dir and run git from the worktree (it's a full checkout of the same repo). Confirm withgit branch --show-currentbefore committing.
cd "$(git -C ~/.claude/skills/skill-builder rev-parse --show-toplevel)" # ai-config root — NOTE: the MAIN checkout, NOT your worktree (see caveat above)
git fetch origin main && git checkout -b add-<name>-skill origin/main # FETCH, CREATE_BRANCH
# write skills/<name>/SKILL.md (+ alias dir, + preferences/CLAUDE.md if it's a rule)
python3 scripts/sync-codex-skill-wrappers.py # regenerate codex-skills/ wrappers — REQUIRED for every new/renamed skill
python3 scripts/semantic-line-breaks.py skills/<name>/SKILL.md # preview only; --write to apply (see caveat below)
# The `validate` CI job runs these four — run all four locally before pushing:
python3 scripts/validate-skills.py # frontmatter + wrapper-sync + manifest checks + the 8000-char skill-listing budget
python3 scripts/check-links.py # relative markdown links resolve
python3 scripts/check-vendored-drift.py # shared-fragment vendored-content drift check
npx --yes markdownlint-cli2@0.22.1 # markdown style (config in .markdownlint-cli2.jsonc)
git add skills/<name>/SKILL.md codex-skills/<name> \
skills/<alias>/SKILL.md codex-skills/<alias> \
memories/preferences.md # stage the files you
# touched (incl. the
# generated wrappers, and
# the alias dir if you made
# one) — NOT `-A`, which
# sweeps in unrelated edits
git commit -m "skills: add <name> — <summary>" # COMMIT
git push -u origin HEAD && gh pr create --fill # PUSH, CREATE_PR
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):
gh pr edit --add-reviewer <reviewer> (EDIT_PR; see
request-pr-review).ardi skill on the new PR until the verdict has
zero findings.Why
git -C … rev-parse --show-topleveloverdirname "$(readlink …)": barereadlink(no-f) resolves only a single hop and behaves inconsistently across macOS/Linux;rev-parse --show-toplevelreturns the repo root directly regardless of how the symlink chain is set up.
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.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).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).name: not matching the directory name.preferences.md.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).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).CLAUDE.md section or an "existing scale/convention" in new
skill prose without grepping to confirm it actually exists first
(check-info-quality #349).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.(Morrison-Lab/ai-config#1055 and #1056, 2026-08-02: a Step 0 pass ran
ls skills/, the skills/*/SKILL.md grep, and the branch, worktree, and
open-PR scans below, plus a wider grep over skills/, shared/,
memories/, and CLAUDE.md.
Every one came back clean, so the session filed #1055 and opened #1056 to
author a new refresh-claude-token skill.
scripts/rotate-claude-token.py had been on main since commit
18173c88, merged as #953 under issue #952, at 312 lines with a 329-line
test file beside it.
It already discovers its target repos rather than hardcoding them, previews
by default, reads the token from stdin or the environment so it never
reaches argv, and re-reads each secret's updated_at to verify the write.
It surfaced only incidentally, from a
gh search code 'CLAUDE_CODE_OAUTH_TOKEN' run made for an unrelated
reason.
scripts/ was in none of the searched paths.)
Scan EVERY branch AND every local worktree for in-flight work — you,
another CLI session, or the @claude bot may already be adding it. A
parallel CLI session usually builds its skill in an unpushed local
worktree, so a remote-only git branch -r scan misses it entirely (this
hit PR #67 — a sibling skill was caught only by a stray system-reminder, not
the scan). Scan local refs and the worktree working trees too:
git fetch origin --prune
# local + remote branches — NOT just -r; unpushed local branches count:
for b in $(git branch -a --format='%(refname:short)' | grep -v HEAD); do
git ls-tree -r --name-only "$b" | grep -iE "skills/[^/]*<keyword>" \
| sed "s|^|$b: |"
done
# uncommitted, ref-less work in sibling worktrees — list only UNTRACKED
# files, so shipped skills (committed in the main worktree) don't false-match.
# Read paths via sed + `while read` (not $(...)/awk $2) so paths with spaces
# survive:
git worktree list --porcelain | sed -n 's/^worktree //p' | while IFS= read -r wt; do
git -C "$wt" ls-files --others --exclude-standard -- 'skills/' 2>/dev/null \
| grep -iE "skills/[^/]*<keyword>" | sed "s|^|$wt: |"
done
If a branch or worktree is already building it, continue that work (check it out / extend its PR) instead of opening a colliding parallel branch.
Check open PRs too — a branch scan misses work already pushed and
opened as a PR if you never fetched it. See
check-open-prs-before-duplicating.
Decide explicitly: extend (preferred) or new. State which and why before writing a line. A new alias or section almost always beats a whole new skill.
skills.qmd if it belongs in one of the category tables, and
bump the "All N+ canonical skills" count at the bottom to the actual
directory count (ls -d skills/*/ | wc -l), not a manual +1 — main often
gains other skills while your PR is in review, so a hand-incremented count
drifts and reads as stale by the time you merge (ai-config#347).gh/git
operation not already in tool-mappings.yml (grep it to check), verify the
tool is real first (ToolSearch for it in a live session), then add it there
— id, description, cli (the CLI fallback), and github_mcp (the MCP
tool) — and rerun scripts/sync-codex-skill-wrappers.py so the Codex wrappers
can translate it.
Skip this and the @claude reviewer flags the unregistered name
as a possible hallucination — it can't tell a real-but-undocumented tool from
an invented one. (push-memory #311 hit this: mcp__github__create_branch and
mcp__github__push_files were real but unregistered, and the first review round
flagged both.)CLAUDE.md, a shared/ fragment, or an
"existing convention/scale" before writing it into new skill prose — not
only when auditing someone else's text. A skill being authored is new
content too, and the same failure purge-hallucinations catches in other
authors' text (a citation that reads as authoritative but doesn't resolve)
is just as easy to introduce while writing your own. grep -rn "<exact phrase>" CLAUDE.md shared/ before the sentence ships, especially for
"mirrors the scale already used" / "per CLAUDE.md's ..." phrasing — that
pattern claims unverified precedent. (check-info-quality #349 shipped
both: a CLAUDE.md section citation that didn't exist, and a claimed
"blocking/nit/optional" severity scale the cited doc never defined — both
caught by the @claude reviewer, not by the skill's author.)fact-check-prose) will catch the mismatch even if you
don't. (fix-forward-references / ai-config#507: the first version of
forward-references.md's heuristic required a paired reference-cue
alongside the directional word, but every one of its own cited examples
— "see below", "as discussed below", "we'll cover this later" — has no
such cue, so none of them actually matched; caught in review, not before
pushing.)diff or re-read the fragment against your test
notes before committing, not just your terminal scrollback. (ai-config#524:
both regexes were verified working in a scratch test file, but only the
first was written into informal-definitions.md — caught by the
@claude reviewer, not before pushing.)grep "^+.*<symbol>" on a diff — unanchored, it also matches
deletions and context, inverting the answer), and an absolute claim
("guarantees a conflict") is a review finding when a plain counterexample
exists (identical edits to the same passage merge cleanly — write "almost
always conflicts"). (stack-prs #577: two of the review round's three
findings were this one class, both caught by the reviewer rather than the
author's own self-review.)<angle-bracket> placeholders in command blocks — never bare ALLCAPS.
Identifiers like PATH, URL, TARGET look like shell env vars; bare PATH
looks like the $PATH env var, and path is a zsh special that mirrors
$PATH. A reader who copies the command without substituting the placeholder
runs something wrong. Use <path>, <url>, <target> instead. (See
memories/claude-code.md → "Skill command blocks".)stack-prs #359 round 1: the one step without a concrete command was
the abandoned-base-PR rebase.)stack-prs
#359 round 1: claimed ardia's stacked-PR detection reads the PR body,
when ardia/SKILL.md actually matches baseRefName against headRefName
— the body note only helps a human scanning the list.)