[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M79YN4HGCDQJBWY31PRSMBPE":3,"skill-same:01M79YN4HGCDQJBWY31PRSMBPE":47},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":6,"ownerHtmlUrl":29,"ownerBlogUrl":30,"ownerDescription":31,"updatedAt":32,"install":33,"resources":46},"01M79YN4HGCDQJBWY31PRSMBPE","ship-plugin",null,"Use when packaging skill files into this department plugin and shipping to GitHub, whether first-time setup or adding\u002Fupdating skills in an existing plugin. Handles intake, structuring, local checks, commit, and PR.","tonykipkemboi\u002Fskill-foundry","tonykipkemboi","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F64493665?v=4","01M79YN0PHZ9J4SBV0F5YY9NZG","Tony Kipkemboi","01M79YN0Q4VW6014NAGG8GD8CM",2,"MIT","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fship-plugin\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: ship-plugin\ndescription: Use when packaging skill files into this department plugin and shipping to GitHub, whether first-time setup or adding\u002Fupdating skills in an existing plugin. Handles intake, structuring, local checks, commit, and PR.\n---\n\n# Ship Plugin\n\nDrive the full pipeline: take loose skill files (SKILL.md, .skill archives, reference\ndocs), package them into this plugin, run all policy checks locally, and open a PR to\nthe department's GitHub repo. CI is the authoritative gate, so never push to `main`.\n\nOptimize for **accuracy over speed**: each step below guards against a known failure\nmode. Do them all, in order, even when the change looks trivial.\n\n## Two rules before you touch anything (read first)\n\nThese apply no matter which assistant runs this (Claude Code, Codex, etc.):\n\n1. **Work on a branch, never on `main`.** Before *any* commit, run\n   `git rev-parse --abbrev-ref HEAD`. If it returns `main`, **create a feature branch\n   first** (`git checkout -b add-\u003Cskill-name>`). Do not commit, edit-then-commit, or push\n   on `main` at any point. Every change ships through a branch and a PR.\n\n2. **When you need a decision, ask. Don't guess.** Whenever the next step depends on a\n   choice only the user can make, STOP and ask using the **AskUserQuestion** tool (or your\n   platform's equivalent interactive prompt) before proceeding. Examples that *require*\n   asking: new plugin vs. add-to-existing; the plugin name\u002Fslug; which existing plugin to\n   target; what the skill should be named if it's ambiguous; whether to include a skill\n   that won't work in the target runtime; the semver bump level if unclear. Never assume a\n   consequential answer.\n\n   **Make each question easy to answer well.** Use the normal terms (plugin, skill), which\n   they know, but with every question briefly say *why you're asking and what the choice\n   leads to*, and give an example of a good answer. When you can discover the options\n   yourself, present them as concrete choices instead of an open question: for example, run\n   `gh repo list YOUR-ORG` or read the existing plugins and offer them as a pick-list\n   for \"which plugin should this join?\". Invite the user to ask back if anything is\n   unclear before they answer.\n\n## Step 0: Preflight (audit the repo state before planning anything)\n\nFailure mode this prevents: a plugin rework sitting on an unmerged branch for weeks\nwhile everyone assumes it is live. Never trust the working tree or your memory of the\nrepo. Audit what is actually merged and deployed:\n\n```bash\ngh api user --jq .login          # 0a. right GitHub account? (org 404s usually mean no)\ngit fetch origin\ngit log --oneline origin\u002Fmain -3 # 0b. what is actually on main\ngh pr list --state open          # 0c. open PRs that carry prior packaging work?\ngit branch -a --no-merged origin\u002Fmain   # 0d. unmerged branches ahead of main?\n```\n\n- **0a.** If GitHub API calls or pushes return 404 on repos you know exist, the active\n  `gh` account lacks org\u002FSSO access. Switch accounts (`gh auth switch`) before blaming\n  the repo.\n- **0c\u002F0d.** If an unmerged branch or open PR already contains packaging work (version\n  bumps, skill changes), STOP and ask the user whether to build on it, merge it first, or\n  supersede it. Do not silently branch from `main` past someone's unshipped work.\n- **0e. README drift check:** `ls skills\u002F` and confirm every skill has a row in\n  `README.md` and a `dist\u002F` download link. Pre-existing drift means a prior run shipped\n  incompletely. Fix it as part of this run and tell the user.\n\nThen decide first-time vs update:\n- `grep -l 'DEPT_SLUG\\|REPO_NAME' .claude-plugin\u002Fplugin.json`: placeholders mean first-time\n- `git remote get-url origin`: pointing at the template repo itself (e.g. `skill-foundry`) means first-time\n- `ls skills\u002F`: only `example-skill\u002F` means first-time\n\n## Step 1: Intake (inspect before anything enters the repo)\n\nAsk the user where the incoming files are. Gather every `SKILL.md`, `.skill`, and\nreference doc. Unzip each `.skill` archive **into a temp directory, not the repo**, and\ninspect there first:\n\n1. **Pre-scan for PII and secrets** across ALL file types, including `.html`, `.py`,\n   `.js`, `.csv`, scripts, and data files, not just markdown. Failure mode: submitted\n   skills can carry an employee's email or chat ID baked in as config. Placeholders that\n   pass the gate: `you@your-domain.com`, `USER_ID` (never invent realistic-looking IDs, since\n   the scanners can't tell fake from real).\n2. **Name-collision guard:** for each incoming skill, check `ls skills\u002F`. If the name\n   already exists, this is an **update** (PATCH), not an add (MINOR), and silently\n   overwriting may be wrong. Confirm with the user: replace, rename, or skip.\n3. **Hardcoded-identity check:** if a skill bakes in any one person's name, email, Slack\n   ID, manager, or personal project as its config, flag it to the user. Org-wide skills\n   must derive the current user at runtime (look up \"who is running me\" via the connected\n   account \u002F employee search) instead of shipping one person's details. A skill configured\n   for one person quietly breaks for everyone else and rots when that person changes roles.\n\n4. **Bundled scripts must be stdin\u002Fstdout only.** If a skill ships helper scripts\n   (Python, Node, etc.), they must read input from stdin and write to stdout, never\n   take file paths as CLI arguments. SAST scanners flag path-taking arguments as\n   path-traversal sinks and do not accept custom sanitizers as taint barriers; the\n   only durable fix is eliminating the pattern. Shell redirects (`script \u003C in > out`)\n   preserve any file-based workflow. If an incoming script takes path arguments,\n   flag it to the author and convert it (with their sign-off) before packaging.\n\nShell note for agents: quote paths and use **arrays** for lists in loops\n(`SKILLS=(a b c)`); a plain space-separated string silently becomes one item under zsh.\n\n## Step 2: Place skills\n\nFor each skill, create `skills\u002F\u003Cname>\u002FSKILL.md` (plus `references\u002F` and any sibling files)\nfrom the inspected temp copy. Ensure the frontmatter `name` exactly matches the directory\nname (lowercase, hyphenated).\n\nIf the build later reports `name is required` for a file that visibly has a name, the\nfrontmatter is probably **invalid YAML**, usually an unquoted `description:` containing\ncolons. Convert it to a folded block scalar (`description: >`) rather than editing content.\n\n## Step 2b: Update the README (required, every time)\n\nThe plugin's `README.md` is the human-facing catalog of what it does. Keep it in sync with\n`skills\u002F` on **every** change, not just first-time:\n\n- **Skills added:** add a row to the skills table and a download link under the install\n  section for each new skill.\n- **Skill updated:** adjust its row\u002Fdescription if its behavior or trigger phrases changed.\n- **Skill removed:** delete its row and its download link.\n\nVerify mechanically instead of trusting your memory:\n\n```bash\nfor s in $(ls skills\u002F); do grep -q \"$s\" README.md || echo \"MISSING FROM README: $s\"; done\n```\n\nA skill that ships without a README entry is invisible to anyone browsing the repo. Match\nthe existing table format; do not invent a new layout. (CI also emits an advisory\n`readme-sync` finding for any skill missing from the README.)\n\n## Step 3 (first-time only): Make it yours\n\nReplace placeholders in `.claude-plugin\u002Fplugin.json` and `.claude-plugin\u002Fmarketplace.json`:\nplugin name, displayName, repo name, descriptions. Delete `skills\u002Fexample-skill\u002F`.\n**README:** the repo starts with the framework's README. Delete it, rename\n`README.plugin.md` to `README.md`, and fill in its placeholders (title, skills table,\ninstall links). That skeleton is what Step 2b keeps in sync from then on.\n\n**Naming:** set the plugin `name` (in both `plugin.json` and `marketplace.json`) to a\nshort lowercase-hyphenated slug with **no `-skills` suffix** (e.g. `acme-general`, not\n`acme-general-skills`). The name becomes the command prefix in Claude\n(`\u002Facme-general:\u003Cskill-name>`). **Also set `displayName`** in both files to the\nhuman-readable title (e.g. `\"Acme General\"`). Otherwise Claude shows the lowercase slug as\nthe plugin's visible name. `displayName` is UI-label only; the slug keeps powering\ncommands and the update key, so the slug must never change after launch.\n\n**CI action:** leave `.github\u002Fworkflows\u002Fskill-policy.yml` using the local action\n(`uses: .\u002F.github\u002Factions\u002Flint-skills`). To pull in later template policy changes, run\n`bash scripts\u002Fsync-from-template.sh` on a branch (it updates the machinery and leaves your\nskills\u002Fplugin.json\u002FREADME alone).\n\n## Step 4: Set or bump the plugin version (required)\n\nThe `version` in `.claude-plugin\u002Fplugin.json` is **not cosmetic**: Claude Code uses it\nas the cache key that decides whether members receive an update. If you don't change it,\nclicking **Update** in Claude delivers nothing. Always set or bump it, using semver:\n\n- **First-time:** leave it at `1.0.0`.\n- **Update, new skill(s) added:** bump **MINOR** (e.g. `1.0.0 -> 1.1.0`).\n- **Update, fix to an existing skill (or label\u002Fmetadata change members should see):**\n  bump **PATCH** (e.g. `1.1.0 -> 1.1.1`).\n- **Breaking change** (renamed\u002Fremoved skill, behavior users rely on): bump **MAJOR**.\n\n`plugin.json` `version` is authoritative (it wins over the marketplace entry). Add a dated\nentry to `CHANGELOG.md`. **Changelog entries state what changed, never why the bump level\nwas chosen.** A baked-in rationale (\"MAJOR because X was removed\") goes stale the moment\na decision changes, and then the history lies.\n\n## Step 5: Build and check locally\n\n```bash\nbash scripts\u002Fbuild-org-skills.sh         # validates frontmatter, rebuilds dist\u002F\nbash .github\u002Fscripts\u002Frun-checks.sh .      # same checks CI runs\n```\n\nRead the JSONL findings. **Fix every hard finding with the user** (secrets, PII, action\npins, frontmatter, workflow permissions). Surface soft suggestions but don't block on them.\n\n**Hard gate: do not chain past it.** `run-checks.sh` exits non-zero when any hard\nfinding remains. Run it as its own step and check the exit code; **do NOT run the commit,\npush, or PR steps until it exits 0.** Re-run after each fix. If a hard finding can't be\nfixed (for example a real secret the user must rotate), STOP and report. Never push a\nknown-bad branch.\n\n## Step 6: Commit on a branch\n\nNever commit on `main`. Use the operator's corporate git identity (follow your org's commit conventions):\n\n```bash\ngit checkout -b add-\u003Cskill-name>\ngit add -A\ngit -c user.name=\"\u003Cuser>\" -c user.email=\"\u003Cyou>@your-domain.com\" commit -m \"\u003Cmessage>\"\n```\n\n## Step 7: Ship via PR, and close the loop (confirm before outward actions)\n\n**First-time:** create the repo if missing, then push and open a PR:\n\n```bash\ngh repo create YOUR-ORG\u002F\u003Crepo> --private --source=. --remote=origin --push\ngh pr create --fill\n```\n\n**Update:** push to the existing repo and open a PR:\n\n```bash\ngit push -u origin add-\u003Cskill-name>\ngh pr create --fill\n```\n\n**End-state contract.** Failure mode this prevents: a PR merged minutes before the\npackager's final commit was pushed, and the stranded commit silently missed `main` for\nweeks. So:\n\n- Report the PR URL **and the head commit SHA** (`git rev-parse HEAD`) to the user.\n- If you push *anything* after opening the PR, tell the user the new head SHA and say\n  explicitly that the earlier state is stale.\n- Only when the branch is complete, state: **\"final push done, safe to merge.\"** The\n  user should not merge before hearing this.\n- After the user merges, verify the outcome: `git fetch && git show origin\u002Fmain:.claude-plugin\u002Fplugin.json | jq .version`\n  must show your bump. If it doesn't, a commit was stranded. Find it\n  (`git log origin\u002Fmain..\u003Cbranch>`) and cherry-pick it onto a fresh PR immediately.\n\n**Reading CI status:** use the JSON rollup, never column-parsed text output. Check\nnames containing spaces (\"Vendor: SAST\") break positional parsing and can silently\nmask a failure:\n\n```bash\ngh pr view \u003Cn> --json statusCheckRollup \\\n  --jq '.statusCheckRollup[] | \"\\(.name \u002F\u002F .context): \\(.conclusion \u002F\u002F .state)\"'\n```\n\n**New-repo scanner lag:** org security scanners often attach to a repository minutes\nor hours after creation, so a brand-new repo's first PR may run with no scanner checks\nat all. The debt then lands on the second PR, which may fail on first-PR code. Expect\nthis; it is not a regression in your change.\n\nRemind the user of the delivery step: existing plugin -> members click **Update**;\nbrand-new plugin -> one-time admin **Sync from GitHub** registration first.\n\n## Step 8: Run report (append to the PR description)\n\nEvery packaging PR ends with a standard self-assessment block. This is the benchmark that\nshows whether the process is getting more accurate over time. Accuracy and completeness\nare the metrics that matter; speed is recorded but secondary.\n\n```markdown\n## Run report\n- Operation: first-time | add | update | label-only\n- Skills processed: N (list)\n- Intake pre-scan: clean | N issues fixed before placement (what)\n- Local gate: exit 0 on attempt N (hard findings fixed: ...)\n- README sync verified: yes (mechanical check)\n- Version: X -> Y (bump level + why)\n- Human-caught misses this run: 0 (target) | list anything the user had to point out\n- Post-PR pushes: none | SHAs + why\n- Incidents \u002F new lessons for the skill: none | describe\n```\n\n\"Human-caught misses\" is the headline number: anything the user had to catch that this\nskill should have caught. The target is always 0. If it isn't 0, the miss belongs in the\nskill: propose the edit in the same conversation. Compare your report against the\nprevious packaging PR's report in the repo (or the runlog in\n`docs\u002Fpackaging-runlog.md` of the template) to see the trend.\n\n## Guardrails\n\n- **Never commit or push on `main`.** Check the branch first (rule 1) and branch if needed.\n- **Ask, don't assume.** Use AskUserQuestion for any consequential choice (rule 2).\n- Creating a repo and opening a PR are outward actions, so confirm with the user first.\n- The local check is a preview; CI is the source of truth.\n- Never edit the plugin `name` slug after launch; use `displayName` for label changes.\n- See `.github\u002Fskill-policy.md` for what every check means.\n","# Ship Plugin\n\nDrive the full pipeline: take loose skill files (SKILL.md, .skill archives, reference\ndocs), package them into this plugin, run all policy checks locally, and open a PR to\nthe department's GitHub repo. CI is the authoritative gate, so never push to `main`.\n\nOptimize for **accuracy over speed**: each step below guards against a known failure\nmode. Do them all, in order, even when the change looks trivial.\n\n## Two rules before you touch anything (read first)\n\nThese apply no matter which assistant runs this (Claude Code, Codex, etc.):\n\n1. **Work on a branch, never on `main`.** Before *any* commit, run\n   `git rev-parse --abbrev-ref HEAD`. If it returns `main`, **create a feature branch\n   first** (`git checkout -b add-\u003Cskill-name>`). Do not commit, edit-then-commit, or push\n   on `main` at any point. Every change ships through a branch and a PR.\n\n2. **When you need a decision, ask. Don't guess.** Whenever the next step depends on a\n   choice only the user can make, STOP and ask using the **AskUserQuestion** tool (or your\n   platform's equivalent interactive prompt) before proceeding. Examples that *require*\n   asking: new plugin vs. add-to-existing; the plugin name\u002Fslug; which existing plugin to\n   target; what the skill should be named if it's ambiguous; whether to include a skill\n   that won't work in the target runtime; the semver bump level if unclear. Never assume a\n   consequential answer.\n\n   **Make each question easy to answer well.** Use the normal terms (plugin, skill), which\n   they know, but with every question briefly say *why you're asking and what the choice\n   leads to*, and give an example of a good answer. When you can discover the options\n   yourself, present them as concrete choices instead of an open question: for example, run\n   `gh repo list YOUR-ORG` or read the existing plugins and offer them as a pick-list\n   for \"which plugin should this join?\". Invite the user to ask back if anything is\n   unclear before they answer.\n\n## Step 0: Preflight (audit the repo state before planning anything)\n\nFailure mode this prevents: a plugin rework sitting on an unmerged branch for weeks\nwhile everyone assumes it is live. Never trust the working tree or your memory of the\nrepo. Audit what is actually merged and deployed:\n\n```bash\ngh api user --jq .login          # 0a. right GitHub account? (org 404s usually mean no)\ngit fetch origin\ngit log --oneline origin\u002Fmain -3 # 0b. what is actually on main\ngh pr list --state open          # 0c. open PRs that carry prior packaging work?\ngit branch -a --no-merged origin\u002Fmain   # 0d. unmerged branches ahead of main?\n```\n\n- **0a.** If GitHub API calls or pushes return 404 on repos you know exist, the active\n  `gh` account lacks org\u002FSSO access. Switch accounts (`gh auth switch`) before blaming\n  the repo.\n- **0c\u002F0d.** If an unmerged branch or open PR already contains packaging work (version\n  bumps, skill changes), STOP and ask the user whether to build on it, merge it first, or\n  supersede it. Do not silently branch from `main` past someone's unshipped work.\n- **0e. README drift check:** `ls skills\u002F` and confirm every skill has a row in\n  `README.md` and a `dist\u002F` download link. Pre-existing drift means a prior run shipped\n  incompletely. Fix it as part of this run and tell the user.\n\nThen decide first-time vs update:\n- `grep -l 'DEPT_SLUG\\|REPO_NAME' .claude-plugin\u002Fplugin.json`: placeholders mean first-time\n- `git remote get-url origin`: pointing at the template repo itself (e.g. `skill-foundry`) means first-time\n- `ls skills\u002F`: only `example-skill\u002F` means first-time\n\n## Step 1: Intake (inspect before anything enters the repo)\n\nAsk the user where the incoming files are. Gather every `SKILL.md`, `.skill`, and\nreference doc. Unzip each `.skill` archive **into a temp directory, not the repo**, and\ninspect there first:\n\n1. **Pre-scan for PII and secrets** across ALL file types, including `.html`, `.py`,\n   `.js`, `.csv`, scripts, and data files, not just markdown. Failure mode: submitted\n   skills can carry an employee's email or chat ID baked in as config. Placeholders that\n   pass the gate: `you@your-domain.com`, `USER_ID` (never invent realistic-looking IDs, since\n   the scanners can't tell fake from real).\n2. **Name-collision guard:** for each incoming skill, check `ls skills\u002F`. If the name\n   already exists, this is an **update** (PATCH), not an add (MINOR), and silently\n   overwriting may be wrong. Confirm with the user: replace, rename, or skip.\n3. **Hardcoded-identity check:** if a skill bakes in any one person's name, email, Slack\n   ID, manager, or personal project as its config, flag it to the user. Org-wide skills\n   must derive the current user at runtime (look up \"who is running me\" via the connected\n   account \u002F employee search) instead of shipping one person's details. A skill configured\n   for one person quietly breaks for everyone else and rots when that person changes roles.\n\n4. **Bundled scripts must be stdin\u002Fstdout only.** If a skill ships helper scripts\n   (Python, Node, etc.), they must read input from stdin and write to stdout, never\n   take file paths as CLI arguments. SAST scanners flag path-taking arguments as\n   path-traversal sinks and do not accept custom sanitizers as taint barriers; the\n   only durable fix is eliminating the pattern. Shell redirects (`script \u003C in > out`)\n   preserve any file-based workflow. If an incoming script takes path arguments,\n   flag it to the author and convert it (with their sign-off) before packaging.\n\nShell note for agents: quote paths and use **arrays** for lists in loops\n(`SKILLS=(a b c)`); a plain space-separated string silently becomes one item under zsh.\n\n## Step 2: Place skills\n\nFor each skill, create `skills\u002F\u003Cname>\u002FSKILL.md` (plus `references\u002F` and any sibling files)\nfrom the inspected temp copy. Ensure the frontmatter `name` exactly matches the directory\nname (lowercase, hyphenated).\n\nIf the build later reports `name is required` for a file that visibly has a name, the\nfrontmatter is probably **invalid YAML**, usually an unquoted `description:` containing\ncolons. Convert it to a folded block scalar (`description: >`) rather than editing content.\n\n## Step 2b: Update the README (required, every time)\n\nThe plugin's `README.md` is the human-facing catalog of what it does. Keep it in sync with\n`skills\u002F` on **every** change, not just first-time:\n\n- **Skills added:** add a row to the skills table and a download link under the install\n  section for each new skill.\n- **Skill updated:** adjust its row\u002Fdescription if its behavior or trigger phrases changed.\n- **Skill removed:** delete its row and its download link.\n\nVerify mechanically instead of trusting your memory:\n\n```bash\nfor s in $(ls skills\u002F); do grep -q \"$s\" README.md || echo \"MISSING FROM README: $s\"; done\n```\n\nA skill that ships without a README entry is invisible to anyone browsing the repo. Match\nthe existing table format; do not invent a new layout. (CI also emits an advisory\n`readme-sync` finding for any skill missing from the README.)\n\n## Step 3 (first-time only): Make it yours\n\nReplace placeholders in `.claude-plugin\u002Fplugin.json` and `.claude-plugin\u002Fmarketplace.json`:\nplugin name, displayName, repo name, descriptions. Delete `skills\u002Fexample-skill\u002F`.\n**README:** the repo starts with the framework's README. Delete it, rename\n`README.plugin.md` to `README.md`, and fill in its placeholders (title, skills table,\ninstall links). That skeleton is what Step 2b keeps in sync from then on.\n\n**Naming:** set the plugin `name` (in both `plugin.json` and `marketplace.json`) to a\nshort lowercase-hyphenated slug with **no `-skills` suffix** (e.g. `acme-general`, not\n`acme-general-skills`). The name becomes the command prefix in Claude\n(`\u002Facme-general:\u003Cskill-name>`). **Also set `displayName`** in both files to the\nhuman-readable title (e.g. `\"Acme General\"`). Otherwise Claude shows the lowercase slug as\nthe plugin's visible name. `displayName` is UI-label only; the slug keeps powering\ncommands and the update key, so the slug must never change after launch.\n\n**CI action:** leave `.github\u002Fworkflows\u002Fskill-policy.yml` using the local action\n(`uses: .\u002F.github\u002Factions\u002Flint-skills`). To pull in later template policy changes, run\n`bash scripts\u002Fsync-from-template.sh` on a branch (it updates the machinery and leaves your\nskills\u002Fplugin.json\u002FREADME alone).\n\n## Step 4: Set or bump the plugin version (required)\n\nThe `version` in `.claude-plugin\u002Fplugin.json` is **not cosmetic**: Claude Code uses it\nas the cache key that decides whether members receive an update. If you don't change it,\nclicking **Update** in Claude delivers nothing. Always set or bump it, using semver:\n\n- **First-time:** leave it at `1.0.0`.\n- **Update, new skill(s) added:** bump **MINOR** (e.g. `1.0.0 -> 1.1.0`).\n- **Update, fix to an existing skill (or label\u002Fmetadata change members should see):**\n  bump **PATCH** (e.g. `1.1.0 -> 1.1.1`).\n- **Breaking change** (renamed\u002Fremoved skill, behavior users rely on): bump **MAJOR**.\n\n`plugin.json` `version` is authoritative (it wins over the marketplace entry). Add a dated\nentry to `CHANGELOG.md`. **Changelog entries state what changed, never why the bump level\nwas chosen.** A baked-in rationale (\"MAJOR because X was removed\") goes stale the moment\na decision changes, and then the history lies.\n\n## Step 5: Build and check locally\n\n```bash\nbash scripts\u002Fbuild-org-skills.sh         # validates frontmatter, rebuilds dist\u002F\nbash .github\u002Fscripts\u002Frun-checks.sh .      # same checks CI runs\n```\n\nRead the JSONL findings. **Fix every hard finding with the user** (secrets, PII, action\npins, frontmatter, workflow permissions). Surface soft suggestions but don't block on them.\n\n**Hard gate: do not chain past it.** `run-checks.sh` exits non-zero when any hard\nfinding remains. Run it as its own step and check the exit code; **do NOT run the commit,\npush, or PR steps until it exits 0.** Re-run after each fix. If a hard finding can't be\nfixed (for example a real secret the user must rotate), STOP and report. Never push a\nknown-bad branch.\n\n## Step 6: Commit on a branch\n\nNever commit on `main`. Use the operator's corporate git identity (follow your org's commit conventions):\n\n```bash\ngit checkout -b add-\u003Cskill-name>\ngit add -A\ngit -c user.name=\"\u003Cuser>\" -c user.email=\"\u003Cyou>@your-domain.com\" commit -m \"\u003Cmessage>\"\n```\n\n## Step 7: Ship via PR, and close the loop (confirm before outward actions)\n\n**First-time:** create the repo if missing, then push and open a PR:\n\n```bash\ngh repo create YOUR-ORG\u002F\u003Crepo> --private --source=. --remote=origin --push\ngh pr create --fill\n```\n\n**Update:** push to the existing repo and open a PR:\n\n```bash\ngit push -u origin add-\u003Cskill-name>\ngh pr create --fill\n```\n\n**End-state contract.** Failure mode this prevents: a PR merged minutes before the\npackager's final commit was pushed, and the stranded commit silently missed `main` for\nweeks. So:\n\n- Report the PR URL **and the head commit SHA** (`git rev-parse HEAD`) to the user.\n- If you push *anything* after opening the PR, tell the user the new head SHA and say\n  explicitly that the earlier state is stale.\n- Only when the branch is complete, state: **\"final push done, safe to merge.\"** The\n  user should not merge before hearing this.\n- After the user merges, verify the outcome: `git fetch && git show origin\u002Fmain:.claude-plugin\u002Fplugin.json | jq .version`\n  must show your bump. If it doesn't, a commit was stranded. Find it\n  (`git log origin\u002Fmain..\u003Cbranch>`) and cherry-pick it onto a fresh PR immediately.\n\n**Reading CI status:** use the JSON rollup, never column-parsed text output. Check\nnames containing spaces (\"Vendor: SAST\") break positional parsing and can silently\nmask a failure:\n\n```bash\ngh pr view \u003Cn> --json statusCheckRollup \\\n  --jq '.statusCheckRollup[] | \"\\(.name \u002F\u002F .context): \\(.conclusion \u002F\u002F .state)\"'\n```\n\n**New-repo scanner lag:** org security scanners often attach to a repository minutes\nor hours after creation, so a brand-new repo's first PR may run with no scanner checks\nat all. The debt then lands on the second PR, which may fail on first-PR code. Expect\nthis; it is not a regression in your change.\n\nRemind the user of the delivery step: existing plugin -> members click **Update**;\nbrand-new plugin -> one-time admin **Sync from GitHub** registration first.\n\n## Step 8: Run report (append to the PR description)\n\nEvery packaging PR ends with a standard self-assessment block. This is the benchmark that\nshows whether the process is getting more accurate over time. Accuracy and completeness\nare the metrics that matter; speed is recorded but secondary.\n\n```markdown\n## Run report\n- Operation: first-time | add | update | label-only\n- Skills processed: N (list)\n- Intake pre-scan: clean | N issues fixed before placement (what)\n- Local gate: exit 0 on attempt N (hard findings fixed: ...)\n- README sync verified: yes (mechanical check)\n- Version: X -> Y (bump level + why)\n- Human-caught misses this run: 0 (target) | list anything the user had to point out\n- Post-PR pushes: none | SHAs + why\n- Incidents \u002F new lessons for the skill: none | describe\n```\n\n\"Human-caught misses\" is the headline number: anything the user had to catch that this\nskill should have caught. The target is always 0. If it isn't 0, the miss belongs in the\nskill: propose the edit in the same conversation. Compare your report against the\nprevious packaging PR's report in the repo (or the runlog in\n`docs\u002Fpackaging-runlog.md` of the template) to see the trend.\n\n## Guardrails\n\n- **Never commit or push on `main`.** Check the branch first (rule 1) and branch if needed.\n- **Ask, don't assume.** Use AskUserQuestion for any consequential choice (rule 2).\n- Creating a repo and opening a PR are outward actions, so confirm with the user first.\n- The local check is a preview; CI is the source of truth.\n- Never edit the plugin `name` slug after launch; use `displayName` for label changes.\n- See `.github\u002Fskill-policy.md` for what every check means.\n",{"name":5,"description":7},"main","bea7733dee43817183fc8d6c4dbfa2cd65e582be",".claude\u002Fskills\u002Fship-plugin",1,"https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi","https:\u002F\u002Ftonykipkemboi.com","Tinkering","2026-08-18 02:12:52",{"source":8,"skillName":5,"commands":34,"prompt":44,"zipAvailable":45},[35,38,41],{"tool":36,"command":37},"npx","npx skills add tonykipkemboi\u002Fskill-foundry --skill ship-plugin",{"tool":39,"command":40},"bunx","bunx skills add tonykipkemboi\u002Fskill-foundry --skill ship-plugin",{"tool":42,"command":43},"pnpm","pnpm dlx skills add tonykipkemboi\u002Fskill-foundry --skill ship-plugin","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fship-plugin\u002FSKILL.md",true,[],[48,55,62,69,76,83],{"skillNo":49,"name":50,"nameZh":6,"description":51,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":52,"categories":53,"keywords":54,"publishedAt":19},"01M79YPBDJD5DKF3FS3D9PFTTJ","soft-channel-id","Use when testing that a Slack channel ID is flagged as advisory, not blocking.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fsoft-channel-id\u002FSKILL.md",[],[],{"skillNo":56,"name":57,"nameZh":6,"description":58,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":59,"categories":60,"keywords":61,"publishedAt":19},"01M79YP9XB9FVXSVCR701NC4DX","soft-body-too-long","Use when testing that an overly long skill body produces a soft suggestion.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fsoft-body-too-long\u002FSKILL.md",[],[],{"skillNo":63,"name":64,"nameZh":6,"description":65,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":68,"publishedAt":19},"01M79YP7WBK5RVE5BJ3XKNWHVA","claude","Use when testing that reserved names like claude or anthropic are rejected.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Freserved-name-claude\u002FSKILL.md",[],[],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":19},"01M79YP4JDKZCV52QWZDAYHV6Q","unlisted-skill","Fixture skill that is MISSING from the README, so the readme-sync advisory must flag it.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Freadme-drift\u002Fskills\u002Funlisted-skill\u002FSKILL.md",[],[],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":19},"01M79YP1KVWR8Q9JCZ6CW2M1QN","listed-skill","Fixture skill that IS listed in the README, so it must produce no readme-sync finding.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Freadme-drift\u002Fskills\u002Flisted-skill\u002FSKILL.md",[],[],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":19},"01M79YNYK8XSAE7262SH8S8D6J","pii-slack-user-id","Use when testing detection of a Slack user ID committed in a reference file.","https:\u002F\u002Fgithub.com\u002Ftonykipkemboi\u002Fskill-foundry\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fpii-slack-user-id\u002FSKILL.md",[],[]]