Skip to main content

fs-skill-authoring

End-to-end workflow for adding a new skill/plugin to founder-skills: scripts/add-skill.sh anatomy step-by-step, its verified hazards (manifest-schema-only validation, the rm -rf symlink swap of ~/.claude/skills/<name>, the maybe-absent ~/claude-code-plugins cross-list, the folded-description misparse), the conformance pass against the house style, and the sanitize-and-graduate gate for publishing a private skill. Use when a maintainer asks "how do I add a new skill", "scaffold a plugin", "run add-skill.sh", "publish this private skill", "graduate a skill from claude-skills", "is this safe to make public", or "why did add-skill.sh eat my skill directory".

インストールへ移動

ソース情報

リポジトリ
craigm26/founder-skills
ソースの最終更新活動
2026年7月2日 22:50
検出された SKILL.md の言語
英語
スター
0
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
2 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
fs-skill-authoring
description
End-to-end workflow for adding a new skill/plugin to founder-skills: scripts/add-skill.sh anatomy step-by-step, its verified hazards (manifest-schema-only validation, the rm -rf symlink swap of ~/.claude/skills/<name>, the maybe-absent ~/claude-code-plugins cross-list, the folded-description misparse), the conformance pass against the house style, and the sanitize-and-graduate gate for publishing a private skill. Use when a maintainer asks "how do I add a new skill", "scaffold a plugin", "run add-skill.sh", "publish this private skill", "graduate a skill from claude-skills", "is this safe to make public", or "why did add-skill.sh eat my skill directory".
# fs-skill-authoring — adding a new skill, end to end Announce at start: "Loading fs-skill-authoring — walking the add-skill.sh path with its hazards, then the conformance and sanitization gates." You are adding a plugin to `founder-skills` (public GitHub `craigm26/founder-skills`, MIT), a Claude Code marketplace (15 plugins as of 2026-07-02: 12 committed + 3 uncommitted skill-*) that **live-publishes**: every push to `master` is instantly installable by marketplace users. There is exactly one scaffolding tool, `scripts/add-skill.sh` (161 lines), and it has shipped a broken plugin once already because its validation step checks manifests, not content. This skill is the runbook that gets a new skill from idea to publish-ready without repeating that incident. All facts verified against the repo at HEAD `2e4c9dd` on 2026-07-02 unless stamped otherwise. The four hazards below were each reproduced or observed on the origin machine that day. ## When NOT to use this skill | Your job | Load instead | |---|---| | Understand what files a plugin needs, plugin.json/marketplace.json schema, .gitignore hazards in depth | `fs-plugin-anatomy` | | Write the SKILL.md *content* — frontmatter voice, phases, tables, closers | `fs-skill-style-guide` | | Get the spec/plan approved before you scaffold anything | `fs-change-control` | | Actually push to master (pre-push gate, publish sequence) | `fs-release-and-publish` | | Set up the venv / run the test suites | `fs-toolchain-and-tests` | | The no-oversell and sanitization *doctrine* and its rationale | `fs-doctrine-and-honesty` | | Full incident narratives (how build-options shipped broken and was rescued) | `fs-failure-archaeology` | | First orientation to the repo | `fs-orientation` | ## Terms (defined once) | Term | Meaning here | |---|---| | **Plugin** | A self-contained directory under `plugins/<name>/` with a `SKILL.md` and `.claude-plugin/plugin.json`, listed in the root marketplace manifest. | | **Marketplace** | The repo itself: root `.claude-plugin/marketplace.json` lists every installable plugin. | | **Cross-list** | A second registration of the same plugin in a *different* marketplace repo (`~/claude-code-plugins`, the RobotRegistryFoundation marketplace) via a `git-subdir` source pointing back at founder-skills master. | | **Graduate** | Move a skill from the private repo `claude-skills` into public founder-skills as a sanitized near-copy. | | **Sanitize-and-graduate gate** | The hard gate from `docs/superpowers/specs/2026-06-11-publish-private-six-design.md`: zero occurrences of client names, secret prefixes, personal paths, or infra layout in anything public. | | **Public-is-canonical** | Standing operator rule (2026-07-02): for graduated skills, the public copy is the source of truth; the private repo is a frozen historical archive (last commit `ab5bcb2`, 2026-06-11). Never backport. | ## Step 0 — Change control comes first Adding a skill is a publishable change to a live marketplace. Per `fs-change-control`, it needs an operator-approved spec (`docs/superpowers/specs/`, date-prefixed) and a checkbox plan before you scaffold. Do not route around this. Assistants never run mutating git commands — the script prints `git add/commit/push` lines at the end; those are **for the operator**, not for you. ## Step 1 — add-skill.sh anatomy Usage (from the script header, verified): ```bash scripts/add-skill.sh <name> [--desc "one-line description with triggers"] \ [--from <dir>] [--category <cat>] [--no-cross-list] ``` `<name>` must be a lowercase slug (`^[a-z0-9][a-z0-9-]*$`). `plugins/<name>` must not already exist (the script dies if it does — so re-runs fail early rather than double-register). What it does, in order (line numbers from the 161-line script at HEAD `2e4c9dd`): | # | Lines | Step | Detail | |---|---|---|---| | 1 | 50–57 | **Resolve source** | Three-way: `--from <dir>` (must contain `SKILL.md`) → else `~/.claude/skills/<name>` *if it is a real directory, not a symlink, with a SKILL.md* → else scaffold a stub SKILL.md you fill in. | | 2 | 59–76 | **Import or stub** | `rsync -a` the source into `plugins/<name>/`, excluding `.git`, `.pytest_cache`, `__pycache__`; any imported `.claude-plugin/` is wiped and recreated fresh. | | 3 | 79–93 | **Resolve description** | `--desc` wins; else a Python one-liner extracts the `description:` line from SKILL.md frontmatter. Dies if empty. **See Hazard 4 — this misparses folded `>-` descriptions.** | | 4 | 96–109 | **Write plugin.json** | Always `version: 0.1.0`, MIT, author Craig Merry, homepage = the GitHub repo. | | 5 | 132 | **Register locally** | Appends an entry to `.claude-plugin/marketplace.json` with source `./plugins/<name>`. Idempotent: skips if the name is already listed. | | 6 | 133–138 | **Cross-list** | If `~/claude-code-plugins/.claude-plugin/marketplace.json` exists (override path with `RRF_MARKETPLACE` env var), appends a `git-subdir` entry there too. **See Hazard 3.** | | 7 | 140–144 | **Symlink swap** | If `~/.claude/skills/<name>` is not already a symlink: `rm -rf` it, then symlink it to `plugins/<name>` ("one copy"). **See Hazard 2.** | | 8 | 146–150 | **Validate** | `claude plugin validate "$PLUGIN_DIR" --strict`, then the repo, then the cross-list repo if touched. **See Hazard 1.** | | 9 | 152–160 | **Print publish commands** | Echoes the `git add/commit/push` lines for both repos. It does NOT push for you. | Because the script runs `set -euo pipefail`, a failure at the validate step (step 8) exits **after** steps 4–7 already mutated things. Manual cleanup after a mid-run failure: `rm -rf plugins/<name>`, `git checkout -- .claude-plugin/marketplace.json`, and restore whatever was at `~/.claude/skills/<name>` from your backup (Hazard 2). ## Step 2 — The hazards ### Hazard 1 — validation is manifest-schema-only `claude plugin validate` (options: `--strict` only, verified via `--help` 2026-07-02) validates the **manifest**, not the plugin's content. It passed `build-options` while the plugin's core asset `assets/matrix.template.html` was missing from git — swallowed by a `*.html` line in the plugin's own `.gitignore` — so the plugin shipped broken and stayed broken until the 2026-07-02 rescue (full narrative: `fs-failure-archaeology`; the .gitignore mechanics: `fs-plugin-anatomy`). A green validate therefore proves almost nothing. Add these two checks for **every file your SKILL.md references** (both verified working 2026-07-02): ```bash # 1. Is the file actually tracked by git? (exits 1 + error if not) git ls-files --error-unmatch plugins/<name>/assets/<file> # 2. Which .gitignore rule, if any, would swallow files in this plugin? git check-ignore -v plugins/<name>/assets/* plugins/<name>/references/* ``` `git check-ignore -v` prints the exact `.gitignore` file and line that matches — this is the command that would have caught the `*.html` swallow before it shipped. If the plugin has executable assets, also run its tests (`fs-toolchain-and-tests`) before calling it done. ### Hazard 2 — the `rm -rf` symlink swap can destroy work Line 142: `rm -rf "$SKILLS_DIR/$NAME"; ln -s "$PLUGIN_DIR" "$SKILLS_DIR/$NAME"` — guarded only by "is it not already a symlink". Two data-loss paths: 1. **You pass `--from <dir>` while a real directory also exists at `~/.claude/skills/<name>`.** The `--from` source wins (source resolution never looks at the skills dir), so the existing real directory is `rm -rf`'d at step 7 *without ever being imported*. 2. **A real directory exists but has no `SKILL.md`** (work in progress, notes, drafts). Source resolution skips it (the elif requires `SKILL.md` to exist), the script scaffolds a stub — and then `rm -rf`s your work-in-progress directory anyway. The safe path (`~/.claude/skills/<name>` is a real dir **with** SKILL.md and you pass no `--from`) is fine: rsync copies it into the repo *before* the rm. But you cannot always know which case you are in, so: ```bash # ALWAYS back up before running, if anything exists at the target: [ -e ~/.claude/skills/<name> ] && cp -a ~/.claude/skills/<name> \ ~/.claude/skills-backup-$(date +%Y%m%d)-<name> ``` Note the inverse gotcha too: if `~/.claude/skills/<name>` is already a symlink pointing somewhere *else*, the script leaves it alone silently — your new plugin is then not the copy Claude loads. Check with `ls -l ~/.claude/skills/<name>` afterwards. These paths are environment-specific (the origin machine's home dir); the mechanism is the same anywhere the Claude Code skills dir lives. ### Hazard 3 — the cross-list repo may not exist The script cross-lists into `$HOME/claude-code-plugins` (the RobotRegistryFoundation marketplace) by default. Verified 2026-07-02: **that directory does not exist on the origin machine** — the script prints `(RRF marketplace not found at ... — skipped cross-list; set RRF_MARKETPLACE to override)` and continues harmlessly (`DID_RRF=0`). The hazard is on machines where it DOES exist: the script then mutates a **second git repo** whose new entry is a `git-subdir` source pointing at founder-skills master — meaning the cross-listed entry is broken for installers until founder-skills itself is pushed, and the second repo needs its own commit/push (the script prints that command line too). If you do not intend to maintain the cross-list, pass `--no-cross-list` explicitly rather than relying on the directory being absent. ### Hazard 4 — folded `>-` descriptions misparse to the literal string `>-` Verified 2026-07-02 by running the script's exact Python extractor against a house-style SKILL.md: when frontmatter uses the folded form the repo's own style guide mandates — ```yaml description: >- Multi-line description... ``` — the extractor's single-line regex captures `>-` and writes **`">-"` as the plugin description** into plugin.json and both marketplace entries. It is non-empty, so the script's empty-description guard does not fire; the garbage ships silently. Mitigation: **always pass `--desc "..."`** when the source SKILL.md uses a folded description (i.e., always, if you follow `fs-skill-style-guide`). After any run, eyeball the description fields in `plugins/<name>/.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`. This is an open defect candidate for a spec'd fix (route via `fs-change-control`); as of 2026-07-02 the script is unpatched. ## Step 3 — Conformance pass The script gives you a structurally registered plugin; it does nothing for quality. Before publish, check every row (detail lives in the named sibling — do not guess): | Check | Gate | Detail in | |---|---|---| | Frontmatter is EXACTLY `name` + `description`, folded `>-`, description opens with the job then "Use when …" with literal utterances | required | `fs-skill-style-guide` | | Body: imperative voice, numbered Phases/Steps, tables, house closers, `## References` list, honesty admissions ("syntax-checked only" where true) | required | `fs-skill-style-guide` | | Model style anchors: copy from the golden four only (market-validation, build-options, ecosystem-planning, fable-org-audit); NEVER from prd/tasks/tufte-viz | required | `fs-skill-style-guide` | | Directory layout, plugin.json fields, version semantics, per-plugin `.gitignore` audited for swallows | required | `fs-plugin-anatomy` | | Every referenced asset passes `git ls-files --error-unmatch`; `git check-ignore -v` on assets/references comes back clean or negated | required | this skill, Hazard 1 | | Executable assets have a `## Tests` section with exact commands, and the tests pass | required if assets exist | `fs-toolchain-and-tests` | | Per-plugin README follows the walkthrough template (Before you install / What it will ask you / What it produces / Cost / 60-second first run / Built on) | required for published plugins | `fs-plugin-anatomy` | | Every factual claim traces to a source verified this session; no oversell | required | `fs-doctrine-and-honesty` | ## Step 4 — The sanitize-and-graduate gate (publishing a private skill) Applies whenever content originates in the private repo `/home/craigm26/projects/craigm26/claude-skills` (environment-specific path; private GitHub `craigm26/claude-skills`; skills live under `skills/<name>/`) — or in ANY private context. The gate comes from the operator-approved spec `docs/superpowers/specs/2026-06-11-publish-private-six-design.md` and is a **hard gate**: zero hits, or each hit explicitly waived in a spec. ### 4a. Scripted grep scan This skill ships the scan (tested 2026-07-02: `plugins/` scans clean; planted secrets, home paths, and banned claims are all caught): ```bash .claude/skills/fs-skill-authoring/scripts/sanitize-scan.sh plugins/<name>/ # exit 0 = clean, 1 = hits (printed file:line) ``` Pattern list (mirror of the spec's hard-gate list; keep the script and this table in sync): | Pattern | Why | |---|---| | `sk_live`, `sk_test`, `cfut_`, inline `Bearer <token>` values | secret/token prefixes | | `/home/craigm26` | personal home-dir paths | | `reservoir` (case-insensitive) | real client org names — expect false positives on the English word; human-review every hit | | `parcelriskreport` | real-project example filenames → genericize | | "Anthropic('s) internal research" | banned claim class (`fs-doctrine-and-honesty`) | Grep cannot catch everything the spec bans. Manually check for: personal-machine infra layout (systemd unit paths, `/etc/` configs, venv locations), and reframe any hard third-party-tool dependency generically (the precedent: Codex became "an external executor **such as** Codex"). ### 4b. Near-copy divergence tracking Graduated skills are *near-copies*, not identical copies (sanitization changed them at birth, and v0.2.0 upgrades were public-only). Track divergence explicitly rather than assuming sync: ```bash # Per graduated skill (private path is environment-specific): diff -u /home/craigm26/projects/craigm26/claude-skills/skills/<name>/SKILL.md \ plugins/<name>/SKILL.md ``` Verified 2026-07-02: ecosystem-planning already diverges (diff exits 1) — that is expected and correct, because of: ### 4c. Public-is-canonical Standing operator rule (2026-07-02): the public founder-skills copy is canonical for all six graduated skills; private `claude-skills` is frozen as a historical archive at `ab5bcb2` (2026-06-11). Consequences: - Never edit the private copy to "keep it in sync". Never backport public changes. - When graduating a NEW skill, the private original becomes archive material the moment the sanitized copy lands on master — all future edits happen public-side only. - The divergence diff (4b) is archaeology, not a to-do list. ## Step 5 — Publish Hand off to `fs-release-and-publish` and run its full local pre-push gate (all three test suites + JSON parse + sanitization grep + URL sweep — mandatory, no CI exists to save you). The operator reviews and runs the `git add/commit/push` lines the script printed. After the push, installed users stay on their cached copy until they run `/plugin marketplace update founder-skills` — a push alone updates nobody. ## Common mistakes | Fix | Mistake | Fix |
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る