LLMSkillHub
mirroredCopied from davekilleen/Dex under MIT. davekilleen has not claimed this page, and is not affiliated with LLM SkillHub.

davekilleen / create-skill

Author a new Dex skill that actually fires and passes the quality bar. Runs a collision check, classifies the shape, writes a router-grade description, generates the real package (SKILL.md + evals), and grades it with `skill-score` before calling it done. Use when the user says 'make a skill', 'I want a /command for X', 'turn this into a skill'. A skill the user builds for themselves is saved under `.claude/skills-custom/` (protected from updates) and coached, never blocked — ask for it by its trigger phrases; do not offer `/{name}` because Claude Code does not dispatch that folder. A first-party skill under `.claude/skills/` can be `/{name}` once the host lists it. Not for connecting an external tool; use `create-mcp`. Not for grading a skill that already exists; use `skill-score`.

0
SKILL.md
11.6 KB

Create a Skill

Author a skill the way the router and a real user will experience it: it must fire when it should (the description is the router) and do the job safely and well when it fires (the body is a contract, not a how-to essay). This skill runs a real authoring sequence — collision → classify → contract → generate → validate → score — and does not declare done until skill-score has graded the package.

Slash-path honesty: Claude Code only dispatches /name for skills it loaded from .claude/skills/, ~/.claude/skills/, .claude/commands/, or a plugin (/plugin-name:skill-name). A user skill under .claude/skills-custom/ is not on that list. Never tell the user to type /{name} or /{name}-custom for a skills-custom folder. Ask them to use the trigger phrases instead.

Governing principle: hard on Core, gentle on the user's own creations. A first-party (Core) skill must pass skill-score ≥ 85 to ship — a hard gate we hold ourselves to. A skill the user writes for themselves is coached, never blocked: show the score, name the one change that would make it fire, offer to make it — but always create/keep their skill if they want it.

Compose, don't fork: anthropic-skill-creator (vendored) is the general skill-authoring guide; the Dex-specific delta lives in references/dex-skill-standard.md. Read that reference before generating the package.


Step 1 — Get intent

Ask the user for:

1. A short name (e.g. "meeting-notes", "board-update") — hyphens, no spaces
2. What it should do for you, in 1–2 sentences
3. When you'd want it to fire — the phrases you'd actually say

Point 3 is not optional — it is the raw material for the WHEN trigger. If the user only gives 1–2, ask for the trigger phrases before continuing.

Step 2 — Determine origin

  • User skill (the default in an end-user vault): the user is building this for themselves. Write it at .claude/skills-custom/{name}/. That directory is vault-owned, so updates never overwrite it. The skill is coached, never blocked. Do not put it under .claude/skills/, and do not add -custom to the folder name unless {name} already belongs to a shipped skill.
  • First-party / Core skill (authoring inside the Dex repo, to ship to everyone): authored under .claude/skills/{name}/ and held to the hard gate (skill-score ≥ 85).

Infer from context; if genuinely unsure, ask one line: "Is this just for you, or something Dex should ship to everyone?"

Step 3 — Collision check (before writing anything)

The most common failure is a skill the router can't tell apart from one that already exists. Check first — run skill-score --all (its portfolio mode lists every routing collision and the nearest neighbor of each skill; it owns and runs the scorer, so you don't re-implement it here).

Read the routing collisions list and find the nearest neighbor to the intended job. Then decide:

  • This is a genuinely new job → note the nearest neighbor; its name goes in the anti-trigger (Step 5).
  • A skill with this exact job already exists → do NOT create a duplicate. Either edit that skill in place (overwrite its SKILL.md, keep its name — never a -name-2 or -v2 fork) or, if it's a Core skill the user wants to customize, save the user's version at .claude/skills-custom/{name}-custom/ so both stay invocable, and hand off to the conflict-resolution flow. A suffixed fork of a job that already exists fragments discoverability and is not allowed.
  • A near neighbor exists but the jobs are distinct → sharpen this skill's outcome and add an anti-trigger naming that neighbor so the router can disambiguate.

If the scorer can't run (no python3), fall back to reading the descriptions in .claude/skills/*/SKILL.md and .claude/skills-custom/*/SKILL.md by hand and say you did so — never skip the collision check silently.

Step 4 — Classify the shape

Pick the shape(s) — a skill can be more than one — because it decides the contract the body must carry (see references/dex-skill-standard.md):

  • workflow — a multi-step process over the vault
  • setup / integration — connects a tool; must be idempotent + carry a re-run/repair path
  • dependent — needs a tool/feature; must detect → explain → fix-path when it's missing
  • generative — produces user-facing content; must name a quality bar + anti-slop rules + inspect real output before claiming success
  • script-bearing — ships a script; the script needs a --diagnose/--dry-run and machine-readable output
  • multi-session / stateful — state kept in a file and sized to a single session

Step 5 — Write the description (the router)

This is the highest-leverage line in the whole package. Follow the template in references/dex-skill-standard.md. It must:

  1. Lead with the outcome in plain language — what the user gets, no internal function/file names.
  2. Carry a WHEN trigger — concrete situations AND the user phrases from Step 1 ("Use when the user says…").
  3. Carry an anti-trigger — "Not for X; use Y" naming the real nearest neighbor from Step 3.

Step 6 — Generate the package

Create the folder — .claude/skills-custom/{name}/ for a user skill (.claude/skills-custom/{name}-custom/ only when the bare name collides with a shipped skill), .claude/skills/{name}/ for a first-party skill — and write:

  • SKILL.md — the description from Step 5 + a thin body: a router + contract, not a reference essay. Name the quality bar and at least one anti-pattern. Push long procedural detail into references/. Soft cap ~200 lines.
  • evals/trigger-cases.yaml — the standard fixture every skill carries: 3 positive paraphrases (must fire), 2 negative/collision (must route to the named neighbor), 1 ambiguous (ask), 1 missing-prerequisite (degrade honestly), 1 failure-recovery (never claim false success). Copy the shape from .claude/skills/skill-score/evals/trigger-cases.yaml.
  • Optional references/ and scripts/ only if the shape needs them.
  • No README — the SKILL.md is the entry point; a second doc just drifts.

Step 7 — Validate frontmatter

Immediately after writing SKILL.md, run validators.validate_skill_frontmatter from core.utils against that exact file and show the result. If it returns errors, fix the frontmatter and re-run; do not continue until it is clean.

Step 8 — Score it (the gate)

Invoke skill-score on the new folder, passing its origin (core or user). That skill runs the deterministic scorer and completes the model-judged parts of the rubric — don't recompute the score here.

  • First-party / Core: this is a hard gate. If the verdict is REVISE or NO, fix what it flags and re-score. Do not declare the skill done, and do not ship it, until it scores ≥ 85 with no hard-gate failure.
  • User skill: advisory — coach, never block. Show the score. If it won't fire on its own, say so plainly and offer the one fix: "This won't fire unless we distinguish it from X — want me to sharpen the trigger?" If the user wants it as-is, create it anyway. Their skill is theirs.

Step 9 — Inspect, then confirm

Read the files you just wrote back before claiming success — confirm the frontmatter, the description, and the evals file are actually on disk and say what the score was. Then:

User skill:

✅ Created {name}  (score: NN/100 — {verdict})
Ask for it with the trigger phrases you gave — not /{name}.
Claude Code does not load .claude/skills-custom/ as a slash-command folder, so /{name} is not a command it can dispatch.
Protected from updates — it lives in .claude/skills-custom/, which Dex updates never overwrite.
Edit: .claude/skills-custom/{name}/SKILL.md
{if the bare name collided: the folder is .claude/skills-custom/{name}-custom/ so it does not overwrite the shipped skill. Still not a slash command.}
{if <85: the one change that would make it fire more reliably}

First-party skill:

✅ Created {name}  (score: NN/100 — SHIP)
Held to the Core hard gate: passed skill-score ≥ 85, no gate failures.
Carries evals/trigger-cases.yaml.
It lives in .claude/skills/{name}/, which Claude Code does load. /{name} works only after the host lists it (a new session, or Dex's skill-freshness injection if they already typed the name). Do not say "try /{name}" as if the slash menu already has it in this session.
To turn it off later: open /skills, highlight it, press Space until it is off, then save. That writes skillOverrides in .claude/settings.local.json. Do not write a disabledSkills field — Claude Code does not honor that key. /skill-doctor names unused skills and points at the same /skills switch. Plugin skills are turned off from /plugin, not skillOverrides.

Quality bar for this skill

A good run leaves behind a skill that fires on the user's real phrasing, routes cleanly against its nearest neighbor, and carries its own evals. A Core skill additionally clears skill-score ≥ 85.

Anti-patterns (do not do these)

  • Telling the user to type /{name} for a skill under .claude/skills-custom/. Claude Code cannot dispatch that slash path.
  • Writing disabledSkills into settings to turn a skill off. Claude Code ignores that key. Use /skills → off (skillOverrides), or /plugin for a plugin skill.
  • Writing a user skill under .claude/skills/, including a {name}-custom folder there. User skills go in .claude/skills-custom/. Origin decides the directory.
  • Appending -custom to a first-party skill, or using a -custom folder name when the bare name is free.
  • Skipping the collision check and shipping a skill the router can't tell from an existing one.
  • Forking an existing job into {name}-2 / {name}-v2 instead of editing it in place.
  • Writing the description as a mechanism ("runs the MCP that…") instead of the outcome.
  • Claiming "created / ready" without reading the files back or running skill-score.
  • Blocking a user's own skill because it scored low — coach it, then create it if they want it.
  • Emitting a second README alongside SKILL.md.

Degradation

  • No python3 → collision check and scoring fall back to reading descriptions by hand; say so and never emit a fake score.
  • skill-score unavailable → hand-score against its rubric and state that you did.

Track Usage (Silent)

Call the mark_feature_used tool on the dex-analytics MCP server with create-skill. This ticks the feature's box in System/usage_log.md, which is what /dex-level-up reads to recommend features that have not been tried. It writes locally and sends nothing, so it runs whether or not analytics is enabled.

Analytics (Silent): Call track_event with eventname `customskillcreated` and no properties (never include skill names). Fires only if the user opted into analytics; no action if it returns "analyticsdisabled".