| name | new-skill |
| description | Take a NEW Claude Code skill from idea to published-and-live, the way Felix ships them: grill the idea into a crisp skill-spec, scaffold a dedicated repo (skills/<name>/SKILL.md), author the SKILL.md, TEST that it actually triggers correctly (fires on the right prompts, stays quiet on decoys) and works end-to-end, present one review brief, then on approval publish it (gh repo create + npx skills add -g). Use when the user says "new skill: X", "make/build/create a skill that…", "author a skill", "ship a skill", or "/new-skill". This is the full authoring+testing+publishing loop — not just scaffolding, and not for editing or debugging an existing skill (that's skill-doctor). |
new-skill — idea → tested → published
Ships a new Claude Code skill end to end. The reason this beats hand-scaffolding is the
middle and the end: it tests that the skill triggers correctly and works, and it
publishes cleanly via Felix's exact convention. One human checkpoint, deferred as late
as possible (just before the irreversible publish).
Scope: brand-new skills only. Improving/debugging an existing skill → skill-doctor.
Conventions (non-negotiable):
- Layout: a dedicated repo
~/Developments/<name>/ → GitHub sunfmin/<name>, skill at
skills/<name>/SKILL.md (a skills/ subdir — NEVER repo root). Monorepo variant:
~/Developments/felix-skills/skills/<name>/ on a branch.
- Publish + install globally (
npx skills add … -g). Never hand-edit ~/.claude/skills/
— npx skills update clobbers it; the source of truth is ~/Developments/<name>.
- Need a credential? Get it via the
mytokens skill — never prompt for a raw token.
Run the phases in order. Do NOT publish (Phase 5) without the Phase 4 approval.
Phase 0 — Intake grilling → skill-spec
Grill the user one question at a time, each with a recommended answer (the loop-me /
grilling discipline). Don't scaffold until every field below is filled. Capture the answers
into a skill-spec and write it to skills/<name>/.skill-spec.md (it seeds authoring and
future skill-doctor regression tests):
| Field | What to pin down |
|---|
name | kebab-case. Collision-check it (Phase 0.1) before continuing. |
description | One-line purpose + the trigger phrasing that goes in frontmatter. |
should_fire | 3+ concrete prompts/situations where it MUST activate. |
decoys | Nearby prompts where it must NOT activate. User adds; you also derive near-misses. |
examples | 2–3 concrete invocations. |
needs | Tools / scripts / CLIs / MCP tools / assets the skill depends on. |
functional_test | ONE representative task + a checkable success condition (concrete input, and how to know the output is right). Required — Phase 3.2 runs it. |
target | dedicated repo (default) or felix-skills monorepo. |
visibility | public (default) or private. |
Phase 0.1 — Collision check
rg -q "\"$NAME\"|/$NAME\b|$NAME ->" ~/.agents/.skill-lock.json && echo "COLLISION: lockfile"
[ -e ~/Developments/$NAME ] && echo "COLLISION: ~/Developments/$NAME"
Any collision → have the user rename before proceeding.
Phase 1 — Scaffold
Create the real repo dir so the checkpoint reviews real files:
mkdir -p ~/Developments/$NAME/skills/$NAME/{scripts,references}
Write skills/$NAME/.skill-spec.md from Phase 0.
Phase 2 — Author
Write skills/$NAME/SKILL.md and any assets from the skill-spec. Follow writing-great-skills
for description shape, discoverability, and rule clarity, and reuse skill-creator patterns.
Bundle any scripts the spec's needs calls for. Keep the frontmatter description explicit
about trigger situations — that is what Phase 3.1 measures.
Phase 3 — Test (both dimensions)
3.0 Frontmatter gate — automatic, runs first
trigger_test.py now refuses to start unless SKILL.md's frontmatter parses as strict
YAML with a non-empty name/description matching --name; publish.sh re-checks before
pushing. Do not skip or work around it: npx skills add parses strictly and silently skips
a skill that fails, so the repo gets created and nothing installs — while this harness and
the agent runtime both read SKILL.md leniently and report everything green. The bug that
motivated it: a description containing : (colon-space) inside an unquoted scalar →
Nested mappings are not allowed in compact mappings, discovered only at publish time after a
7/7 trigger pass. When writing descriptions, prefer — over : .
The gate needs PyYAML, which system python3 usually lacks. Both scripts now borrow it via
uv run --no-project --with pyyaml, and publish.sh refuses to publish if no parser can
be found. Previously it printed pyyaml missing, skipping strict check and published anyway —
a gate that waves the skill through when the parser is absent is worse than no gate, because
the reassuring line hides that nothing was checked.
3.1 Trigger test (discovery) — REQUIRED
Write the spec's prompts to a cases file and run the validated harness:
echo '{"should_fire": [...], "decoys": [...]}' > /tmp/${NAME}_cases.json
python3 SKILL_DIR/scripts/trigger_test.py \
--name "$NAME" --skill-dir ~/Developments/$NAME/skills/$NAME \
--cases /tmp/${NAME}_cases.json --jobs 3
It installs the candidate as a project skill among all of Felix's real skills, runs a real
headless claude -p probe per prompt with execution tools disabled (zero side effects), and
detects whether the Skill tool fired for this candidate. Pass = every should_fire
activated AND no decoy did. A miss usually means the description needs sharpening (or a
decoy legitimately belongs to another skill — note it).
Before you rewrite a description to chase a miss, check first_tool in the output.
Probes run --max-turns 4 (was 1) because Read/Glob are not disallowed: for a prompt
like "fix the type errors in src/models.py" the model's first move is to look at the file,
and at one turn the probe ended right there and scored a miss — even though the skill loads
on turn 2. Measured on a real skill, the same prompts scored 2/6 at one turn and 6/6 at
five. Decoys run at the same limit, so the extra room cannot hide over-firing. A miss whose
first_tool is Read/Glob is a measurement artifact; one with no tool call at all is a
real description problem.
Prompts that name real files also need those files to exist, or the model burns its turns
hunting. Point --project-dir at a fixture repo for those (the candidate is symlinked in and
removed afterwards; the fixture is left untouched); the default empty throwaway project only
suits from-scratch authoring prompts.
3.2 Functional test — REQUIRED
Execute the skill on the spec's functional_test task and evaluate its success condition;
capture the output. If running it fully would cause side effects (publishing, sending,
writing to shared state), run it in the skill's own dry-run / sandbox mode. Pass = success
condition met.
Record every miss (which prompt, expected vs actual) for the brief.
Phase 4 — Brief + checkpoint (the one gate)
Present a tight brief and stop:
- name · one-line purpose · target repo · visibility;
- link to
skills/$NAME/SKILL.md + the asset list;
- test scoreboard:
trigger: fired N/N, decoys N/N clean · functional: PASS/FAIL (+output);
- the exact publish commands Phase 5 will run.
Then the user chooses:
- approve → Phase 5;
- revise → they say what to change; re-author (Phase 2) and re-test (Phase 3), present a fresh brief;
- discard →
rm -rf ~/Developments/$NAME (nothing was ever pushed).
Phase 5 — Publish (only on approve)
bash SKILL_DIR/scripts/publish.sh "$NAME" "<visibility>"
It commits, creates sunfmin/$NAME and pushes, npx skills add sunfmin/$NAME -g -y, and
verifies with skills list. On any step failing it stops loudly without half-registering.
Monorepo target instead: commit the new skills/$NAME/ folder to ~/Developments/felix-skills,
push, then npx skills update felix-skills.
Close out with one line: Published sunfmin/$NAME, installed globally, live.
Guardrails
- The publish in Phase 5 is outward-facing and hard to undo (public repo, mutates the live
skill env). Never run it before the Phase 4 approval.
SKILL_DIR above = this skill's own directory (.../skills/new-skill).
- If
mytokens is needed for a credential during a functional test, use it — don't prompt.