[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6HTYTYDJAAYHS513AHKYCER":3,"skill-same:01M6HTYTYDJAAYHS513AHKYCER":69},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":51,"ownerHtmlUrl":52,"ownerBlogUrl":6,"ownerDescription":53,"updatedAt":54,"install":55,"resources":68},"01M6HTYTYDJAAYHS513AHKYCER","release",null,"Bump a plugin's version, write a detailed changelog entry for the upgrade skill to consume, and commit+push. Takes a plugin slug argument identifying which plugin under `plugins\u002F` to release. Use this skill whenever the user says \"release\", \"version bump\", \"cut a release\", \"changelog and push\", or finishes a set of changes and wants to ship them. Also trigger when the user says \"do the release thing\" or asks to prepare changes for hermits to pick up.","gtapps\u002Fhermitd","gtapps","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F16778396?v=4","01M6HTX8TNTPQN3NXRVA63VHTH","01M6HTX8Z23S531ZPPA5DKJVD0",84,"MIT","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Frelease\u002FSKILL.md",[],[5,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"up","when","changes","for","which","argument","trigger","cut","upgrade","version bump","do","bump","commit","version","use","write","pick","ship","SET","changelog entry","push","changelog","plugin","2026-11-10 10:12:30",false,"---\nname: release\ndescription: Bump a plugin's version, write a detailed changelog entry for the upgrade skill to consume, and commit+push. Takes a plugin slug argument identifying which plugin under `plugins\u002F` to release. Use this skill whenever the user says \"release\", \"version bump\", \"cut a release\", \"changelog and push\", or finishes a set of changes and wants to ship them. Also trigger when the user says \"do the release thing\" or asks to prepare changes for hermits to pick up.\n---\n# Release\n\nBump version, write changelog, commit, and push for a single plugin in the monorepo. The changelog entry is critical because the upgrade skill (`skills\u002Fhermit-evolve\u002FSKILL.md`) reads it to know what to tell hermits during `\u002Fhermitd:hermit-evolve`.\n\n## Usage\n\n`\u002Frelease \u003Cplugin-slug>` — release the plugin at `plugins\u002F\u003Cplugin-slug>\u002F`.\n\nExamples:\n- `\u002Frelease hermitd` — release the core plugin\n- `\u002Frelease hermitd-dev` — release the dev hermit\n- `\u002Frelease hermitd-homeassistant` — release the HA hermit\n- `\u002Frelease hermitd-laravel-forge` — release the Laravel Forge hermit\n\nIf invoked without a slug, list all `plugins\u002F\u003Cname>\u002F` directories that contain `.claude-plugin\u002Fplugin.json` and ask the operator which one via AskUserQuestion before proceeding.\n\n## Steps\n\n### 0. Identify target plugin\n\nResolve the plugin slug:\n- If the user passed `\u003Cslug>` as argument, use that.\n- Otherwise, glob `plugins\u002F*\u002F.claude-plugin\u002Fplugin.json`, collect the directory names, and ask via AskUserQuestion: \"Which plugin to release?\" with one option per slug.\n\nValidate `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` exists. If it does not, abort: `Plugin 'plugins\u002F\u003Cslug>\u002F' not found.` Suggest the available slugs.\n\nThroughout the rest of this skill, `$PLUGIN_DIR` refers to `plugins\u002F\u003Cslug>\u002F`.\n\n### 1. Pre-release validation\n\nRun before anything else. Abort the release if any step fails.\n\n1. **Run the native plugin validator (CLI form):**\n   ```bash\n   claude plugin validate plugins\u002F\u003Cslug> 2>&1\n   ```\n   Abort on any error.\n\n2. **Run test suites for the target plugin.** Detect the convention and dispatch:\n   - If `plugins\u002F\u003Cslug>\u002Ftests\u002Frun-all.sh` exists (bash entrypoint, used by dev\u002Ffitness\u002Fscribe\u002Fforge):\n     ```bash\n     bash plugins\u002F\u003Cslug>\u002Ftests\u002Frun-all.sh 2>&1\n     ```\n   - Else if any `plugins\u002F\u003Cslug>\u002Ftests\u002F*.test.ts` exists (bun entrypoint, used by core\u002FHA):\n     ```bash\n     cd plugins\u002F\u003Cslug> && bun test 2>&1\n     ```\n   - Else if a `plugins\u002F\u003Cslug>\u002Ftests\u002F` dir exists but neither marker matched: abort the release with `Plugin '\u003Cslug>' has a tests\u002F dir but no recognized convention (run-all.sh or *.test.ts) — fix the dispatch before releasing.` Do not silently skip.\n   - Else (no `tests\u002F` dir at all): skip this step and note it in the release report.\n\n   If any test fails, stop and fix before releasing.\n\n3. **Run the plugin-validator agent in `release` mode** (`plugin-validator \u003Cslug> release`) to cross-reference plugin integrity. Pass it the plugin slug explicitly so it knows which plugin to audit:\n   - Skills referenced in the plugin README or `AGENTS.md` match actual `plugins\u002F\u003Cslug>\u002Fskills\u002F` directories\n   - Agents referenced in the plugin README or `AGENTS.md` match actual `plugins\u002F\u003Cslug>\u002Fagents\u002F` files\n   - Hook scripts referenced in `plugins\u002F\u003Cslug>\u002Fhooks\u002Fhooks.json` exist in `plugins\u002F\u003Cslug>\u002Fscripts\u002F`\n   - State-template JSON files parse correctly\n   - `config.json.template` keys are in sync with `DEFAULT_CONFIG` in `plugins\u002F\u003Cslug>\u002Fscripts\u002Fhermitd-start.ts` (core only)\n\nIf the auditor reports any FAIL, fix before proceeding. WARNs are acceptable if justified. Stale-reference detection-and-fix is consolidated into Step 4 below.\n\n### 1.5. Refresh the knowledge graph\n\nThe repo carries graphify knowledge graphs (all gitignored): a root monorepo graph at `graphify-out\u002F` and one per-plugin graph at `plugins\u002F\u003Cslug>\u002Fgraphify-out\u002F`. Refresh both so they reflect the code that's shipping: the root graph (covers the whole monorepo, including this plugin's code) and this plugin's own graph. `\u002Frelease` is single-plugin, so only the target plugin's per-plugin graph is refreshed here, not the other siblings'. This runs before the fast-path branch in Step 2, so it fires on both the normal and already-bumped paths, always before either push.\n\n```bash\nROOT=\"$(git rev-parse --show-toplevel)\"\nif command -v graphify >\u002Fdev\u002Fnull; then\n  # Root monorepo graph\n  [ -f \"$ROOT\u002Fgraphify-out\u002Fgraph.json\" ] && (cd \"$ROOT\" && graphify update .)\n  # This plugin's own graph (single-plugin scope; \"if exists\")\n  [ -f \"$ROOT\u002Fplugins\u002F\u003Cslug>\u002Fgraphify-out\u002Fgraph.json\" ] && (cd \"$ROOT\" && graphify update plugins\u002F\u003Cslug>)\nfi\n```\n\nAST-only, no API cost. Each update is guarded by its graph.json existing, so it skips silently on checkouts where graphify isn't set up. Both graph dirs are gitignored, so this never affects release staging or the Step 6 `git status` check. If an update errors, warn and continue: a stale graph must not block a release.\n\n### 2. Determine version bump\n\n**Already-bumped fast-path (two-phase release flow):** Find the most recent tag for this plugin:\n\n```bash\ngit tag --list \"\u003Cslug>--v*\" | sort -V | tail -1\n```\n\nCompare its version to `plugin.json`. If `plugin.json` is already ahead (e.g. tag is `dev-hermit--v0.2.0`, plugin.json says `0.3.0`), the version was bumped on a plugin branch that has since merged to main. Skip steps 2–7 entirely — the CHANGELOG, version files, and commit are already done. Jump directly to step 8.\n\n**Normal path:** Read `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` for the current version and `plugins\u002F\u003Cslug>\u002FCHANGELOG.md` for recent entries.\n\nReview the uncommitted or recently committed changes (`git diff` and\u002For `git log` since the last `\u003Cslug>--v\u003Cversion>` tag).\n\nDecide the bump level:\n- **Patch** (0.0.X) — bug fixes, behavioral changes via updated instructions, small additions\n- **Minor** (0.X.0) — new features, new skills, structural changes, breaking config migrations\n- **Major** (X.0.0) — only if the user explicitly asks\n\nPresent the suggested version and rationale. Wait for confirmation before proceeding.\n\n### 3. Write the changelog entry\n\nPrepend a new entry to `plugins\u002F\u003Cslug>\u002FCHANGELOG.md` immediately after the `# Changelog` header, before the previous version entry. If a `[Unreleased]` section already exists, rename it to `[X.Y.Z] - YYYY-MM-DD` instead of prepending a new one — the entry has been accumulating during development.\n\n**Docs-only double-check (do this before promoting\u002Fwriting the entry).** Read every narrative bullet about to ship in this version and confirm each describes a real code\u002Fbehavior change an operator experiences. Drop any bullet whose only change is documentation (README, `docs\u002F`, instruction files, or code comments), including bullets that pair a docs correction onto an otherwise-code entry (keep the code half, cut the docs half). Docs corrections belong in the commit message and PR description, never the CHANGELOG. Cross-check against the actual diff: `git diff \u003Clast-tag>..HEAD -- plugins\u002F\u003Cslug>`; if a bullet's only backing changes are `.md` or comment edits, it should not be in the changelog. This mirrors the root `AGENTS.md` §Commits and releases rule.\n\n**Format**:\n\n```markdown\n## [X.Y.Z] - YYYY-MM-DD\n\n### Added \u002F Changed \u002F Fixed\n(use whichever sections apply — skip empty ones)\n\n- Plain sentence-case line describing the change; the header carries the category. Backticks for `commands`, `paths`, `--flags`.\n\n### Upgrade Instructions\n\nRun `\u002Fhermitd:hermit-evolve`. The evolve skill handles:\n\n1. **Imperative step title** — what to do, in one sentence.\n\nNo `config.json` changes required.\n```\n\n**Template constraints (enforce these):**\n\n1. **Narrative bullets (Added \u002F Changed \u002F Fixed)**: canonical format lives in root `AGENTS.md` §Commits and releases; enforce it here: a plain sentence-case line under the category header, no `**component:**` prefix and no leading Fixed\u002FAdded verb (the header carries the category). Backticks for commands\u002Fpaths\u002Fflags. Target 1–2 lines. If a bullet wants to grow longer, the surplus belongs in the PR description, not here.\n   - Do NOT list internal refactors, helper extractions, test scaffolding, or renamed variables — those are visible in `git diff`.\n   - **Recovery procedures, migration shell snippets, and breaking-change steps belong in `### Upgrade Instructions`, never in the narrative bullet.** Write a tight summary (\"changed default X to Y\") and let that section carry the imperative steps — `hermit-evolve` reads them step-by-step.\n\n2. **Upgrade Instructions** — strict imperative block:\n   - Every step starts with a verb (`Add`, `Replace`, `Copy`, `Run`, `Delete`, `Refresh`).\n   - Each step is a single action. No \"also do X, but only if Y, unless Z\" run-ons — split into separate numbered steps.\n   - No passive voice, no rationale clauses. If an operator needs to understand *why*, that belongs in the Changed bullet above, not here.\n   - Include what `hermit-evolve` does NOT need to touch only if omission would cause it to act destructively. Otherwise silence.\n   - Close with `No config.json changes required.` if true — it's the most common case and operators scan for it.\n\n3. **What belongs where:**\n   - Why it changed → Changed\u002FFixed bullet.\n   - What evolve executes → Upgrade Instructions (imperative, numbered).\n   - Behavior deltas that need no action but operators should know → one final line after the numbered list, prefixed `**Note:**`. Not a step.\n\n**The Upgrade Instructions section is the most important part.** The evolve skill reads this to know what actions to take for each hermit. Non-imperative steps cause evolve to misparse or skip them.\n\n### 4. Refresh references\n\nFor each new skill, agent, or hook added since the last release of this plugin, detect missing entries and add them in one pass:\n\n- Plugin README component descriptions and any affected `plugins\u002F\u003Cslug>\u002FAGENTS.md` constraints (keep inventories out of instruction files)\n- `plugins\u002F\u003Cslug>\u002Fdocs\u002Fskills.md` (if the doc exists)\n- Hook descriptions in the plugin README or relevant docs if the hook surface area changed\n\nSkip the step entirely if nothing was added. The plugin-validator (Step 1.3) covers structural integrity; this step is about narrative references.\n\n### 5. Bump version in all locations\n\nUpdate the version string in:\n- `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` → `\"version\"` field\n- `.claude-plugin\u002Fmarketplace.json` → find the entry in `plugins[]` where `\"name\" == \"\u003Cslug>\"` and update its `\"version\"` field. Other plugin entries are untouched.\n- `plugins\u002F\u003Cslug>\u002FREADME.md` → version badge if present: both the `img.shields.io` URL slug (`version-X.Y.Z-green.svg`) and the `alt` text (`Version X.Y.Z`). Confirm with `grep \"version-\" plugins\u002F\u003Cslug>\u002FREADME.md` that the new version appears and the old one does not. Skip silently if the README has no version badge. (For `hermitd`, skip this direct edit — the sync block below re-derives the whole file from root, picking up the updated badge automatically.)\n- If `\u003Cslug>` is `hermitd`: also update the root `README.md` badge — `version-OLD-green.svg` → `version-NEW-green.svg` and `Version OLD` → `Version NEW`. This is the only plugin whose version the root README tracks.\n\n**Sync plugin README from root (hermitd only):** `plugins\u002Fhermitd\u002FREADME.md` is a path-adjusted derivative of the root `README.md`. After updating version badges, re-derive it by applying these substitutions to the root README content:\n\n| In root `README.md`                              | In plugin `README.md`                          |\n|--------------------------------------------------|------------------------------------------------|\n| `href=\"LICENSE\"`                                 | `href=\"..\u002F..\u002FLICENSE\"`                         |\n| `[MIT](LICENSE)`                                 | `[MIT](..\u002F..\u002FLICENSE)`                         |\n| `href=\"plugins\u002Fhermitd\u002FCHANGELOG.md\"` | `href=\"CHANGELOG.md\"`                          |\n| `src=\"plugins\u002Fhermitd\u002Fassets\u002F`        | `src=\"assets\u002F`                                 |\n| `](plugins\u002Fhermitd\u002Fdocs\u002F`             | `](docs\u002F`                                      |\n| `](plugins\u002Fhermitd-dev\u002F`              | `](..\u002Fhermitd-dev\u002F`                 |\n| `](plugins\u002Fhermitd-homeassistant\u002F`    | `](..\u002Fhermitd-homeassistant\u002F`       |\n| `](plugins\u002Fhermitd-fitness\u002F`          | `](..\u002Fhermitd-fitness\u002F`             |\n| `](plugins\u002Fhermitd-laravel-forge\u002F`                | `](..\u002Fhermitd-laravel-forge\u002F`                   |\n\nWrite the result to `plugins\u002Fhermitd\u002FREADME.md`.\n\nAfter editing, verify the manifest and marketplace are in sync — the plugin manifest wins silently if they differ:\n```bash\njq -r '.version' plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json\njq -r --arg slug \"\u003Cslug>\" '.plugins[] | select(.name == $slug) | .version' .claude-plugin\u002Fmarketplace.json\n```\nBoth must print the same string. If they differ, fix `.claude-plugin\u002Fmarketplace.json` before continuing.\n\n### 6. Final validation\n\nSteps 3–5 only edit Markdown and JSON, so re-running the test suite is unnecessary. Confirm:\n\n```bash\njq -e . plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json > \u002Fdev\u002Fnull\njq -e . .claude-plugin\u002Fmarketplace.json > \u002Fdev\u002Fnull\ngit status --short\n```\n\nBoth `jq` checks must succeed and `git status` must show only the files this release touched (CHANGELOG, plugin.json, marketplace.json, optional CLAUDE.md \u002F README badge \u002F state-templates updates). Any unexpected entry → investigate before committing.\n\n### 7. Commit and push\n\nStage only the changed files (not `git add -A`). Commit with:\n\n```\n\u003Cslug> v\u003CX.Y.Z>: One-line summary of the release\n```\n\nPush to origin.\n\n### 8. Branch check before tagging\n\nRun `git branch --show-current` and compare to `main` (or the repo's default branch from `gh repo view --json defaultBranchRef -q .defaultBranchRef.name`).\n\n- **On `main`\u002Fdefault branch** → tag immediately (step 9).\n- **On any other branch** (e.g. `dev-hermit\u002Fv0.3.0`) → **stop**. Do not tag yet. Tagging the branch tip creates a commit SHA that `main` never carries after a regular merge (and is outright wrong after squash\u002Frebase), leaving the tag stranded on an orphan commit.\n\n  **Recommended path** (default): open a PR, merge into `main`, then re-run `\u002Frelease \u003Cslug>` from `main`. Step 2's already-bumped detection will skip straight to tagging.\n\n  If the user explicitly wants to tag now despite the risk, offer that as a secondary option. Wait for their explicit choice before proceeding.\n\n### 9. Tag and publish\n\nThe tag format is **plugin-prefixed with double-dash separator**: `\u003Cslug>--v\u003CX.Y.Z>`. This is the format Claude Code's native dependency resolver requires to find matching versions for `dependencies` entries.\n\nRun `claude plugin tag --push` from the plugin directory — it validates plugin contents, confirms `plugin.json` and `marketplace.json` versions agree, requires a clean working tree, and refuses if the tag already exists:\n\n```bash\n(cd plugins\u002F\u003Cslug> && claude plugin tag --push)\n```\n\nThen create the GitHub release pointing to the new double-dash tag. Source the release notes from the CHANGELOG section we just wrote — `--generate-notes` would otherwise interleave commits from sibling-plugin releases that landed since the last core tag.\n\n```bash\nVERSION=$(jq -r '.version' plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json)\nTAG=\"\u003Cslug>--v$VERSION\"\nNOTES_FILE=$(mktemp)\nawk -v ver=\"$VERSION\" '\n  $0 ~ \"^## \\\\[\" ver \"\\\\]\" {flag=1; next}\n  \u002F^## \\[\u002F && flag {exit}\n  flag {print}\n' plugins\u002F\u003Cslug>\u002FCHANGELOG.md > \"$NOTES_FILE\"\n[ ! -s \"$NOTES_FILE\" ] && { echo \"CHANGELOG section for $VERSION not found in plugins\u002F\u003Cslug>\u002FCHANGELOG.md — fix and retry\"; rm \"$NOTES_FILE\"; exit 1; }\ngh release create \"$TAG\" --title \"$TAG\" --notes-file \"$NOTES_FILE\"\nrm \"$NOTES_FILE\"\n```\n\n### 10. Report\n\nPrint the slug, the new version, the commit hash, the tag name, and a one-liner confirming it's pushed.\n","# Release\n\nBump version, write changelog, commit, and push for a single plugin in the monorepo. The changelog entry is critical because the upgrade skill (`skills\u002Fhermit-evolve\u002FSKILL.md`) reads it to know what to tell hermits during `\u002Fhermitd:hermit-evolve`.\n\n## Usage\n\n`\u002Frelease \u003Cplugin-slug>` — release the plugin at `plugins\u002F\u003Cplugin-slug>\u002F`.\n\nExamples:\n- `\u002Frelease hermitd` — release the core plugin\n- `\u002Frelease hermitd-dev` — release the dev hermit\n- `\u002Frelease hermitd-homeassistant` — release the HA hermit\n- `\u002Frelease hermitd-laravel-forge` — release the Laravel Forge hermit\n\nIf invoked without a slug, list all `plugins\u002F\u003Cname>\u002F` directories that contain `.claude-plugin\u002Fplugin.json` and ask the operator which one via AskUserQuestion before proceeding.\n\n## Steps\n\n### 0. Identify target plugin\n\nResolve the plugin slug:\n- If the user passed `\u003Cslug>` as argument, use that.\n- Otherwise, glob `plugins\u002F*\u002F.claude-plugin\u002Fplugin.json`, collect the directory names, and ask via AskUserQuestion: \"Which plugin to release?\" with one option per slug.\n\nValidate `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` exists. If it does not, abort: `Plugin 'plugins\u002F\u003Cslug>\u002F' not found.` Suggest the available slugs.\n\nThroughout the rest of this skill, `$PLUGIN_DIR` refers to `plugins\u002F\u003Cslug>\u002F`.\n\n### 1. Pre-release validation\n\nRun before anything else. Abort the release if any step fails.\n\n1. **Run the native plugin validator (CLI form):**\n   ```bash\n   claude plugin validate plugins\u002F\u003Cslug> 2>&1\n   ```\n   Abort on any error.\n\n2. **Run test suites for the target plugin.** Detect the convention and dispatch:\n   - If `plugins\u002F\u003Cslug>\u002Ftests\u002Frun-all.sh` exists (bash entrypoint, used by dev\u002Ffitness\u002Fscribe\u002Fforge):\n     ```bash\n     bash plugins\u002F\u003Cslug>\u002Ftests\u002Frun-all.sh 2>&1\n     ```\n   - Else if any `plugins\u002F\u003Cslug>\u002Ftests\u002F*.test.ts` exists (bun entrypoint, used by core\u002FHA):\n     ```bash\n     cd plugins\u002F\u003Cslug> && bun test 2>&1\n     ```\n   - Else if a `plugins\u002F\u003Cslug>\u002Ftests\u002F` dir exists but neither marker matched: abort the release with `Plugin '\u003Cslug>' has a tests\u002F dir but no recognized convention (run-all.sh or *.test.ts) — fix the dispatch before releasing.` Do not silently skip.\n   - Else (no `tests\u002F` dir at all): skip this step and note it in the release report.\n\n   If any test fails, stop and fix before releasing.\n\n3. **Run the plugin-validator agent in `release` mode** (`plugin-validator \u003Cslug> release`) to cross-reference plugin integrity. Pass it the plugin slug explicitly so it knows which plugin to audit:\n   - Skills referenced in the plugin README or `AGENTS.md` match actual `plugins\u002F\u003Cslug>\u002Fskills\u002F` directories\n   - Agents referenced in the plugin README or `AGENTS.md` match actual `plugins\u002F\u003Cslug>\u002Fagents\u002F` files\n   - Hook scripts referenced in `plugins\u002F\u003Cslug>\u002Fhooks\u002Fhooks.json` exist in `plugins\u002F\u003Cslug>\u002Fscripts\u002F`\n   - State-template JSON files parse correctly\n   - `config.json.template` keys are in sync with `DEFAULT_CONFIG` in `plugins\u002F\u003Cslug>\u002Fscripts\u002Fhermitd-start.ts` (core only)\n\nIf the auditor reports any FAIL, fix before proceeding. WARNs are acceptable if justified. Stale-reference detection-and-fix is consolidated into Step 4 below.\n\n### 1.5. Refresh the knowledge graph\n\nThe repo carries graphify knowledge graphs (all gitignored): a root monorepo graph at `graphify-out\u002F` and one per-plugin graph at `plugins\u002F\u003Cslug>\u002Fgraphify-out\u002F`. Refresh both so they reflect the code that's shipping: the root graph (covers the whole monorepo, including this plugin's code) and this plugin's own graph. `\u002Frelease` is single-plugin, so only the target plugin's per-plugin graph is refreshed here, not the other siblings'. This runs before the fast-path branch in Step 2, so it fires on both the normal and already-bumped paths, always before either push.\n\n```bash\nROOT=\"$(git rev-parse --show-toplevel)\"\nif command -v graphify >\u002Fdev\u002Fnull; then\n  # Root monorepo graph\n  [ -f \"$ROOT\u002Fgraphify-out\u002Fgraph.json\" ] && (cd \"$ROOT\" && graphify update .)\n  # This plugin's own graph (single-plugin scope; \"if exists\")\n  [ -f \"$ROOT\u002Fplugins\u002F\u003Cslug>\u002Fgraphify-out\u002Fgraph.json\" ] && (cd \"$ROOT\" && graphify update plugins\u002F\u003Cslug>)\nfi\n```\n\nAST-only, no API cost. Each update is guarded by its graph.json existing, so it skips silently on checkouts where graphify isn't set up. Both graph dirs are gitignored, so this never affects release staging or the Step 6 `git status` check. If an update errors, warn and continue: a stale graph must not block a release.\n\n### 2. Determine version bump\n\n**Already-bumped fast-path (two-phase release flow):** Find the most recent tag for this plugin:\n\n```bash\ngit tag --list \"\u003Cslug>--v*\" | sort -V | tail -1\n```\n\nCompare its version to `plugin.json`. If `plugin.json` is already ahead (e.g. tag is `dev-hermit--v0.2.0`, plugin.json says `0.3.0`), the version was bumped on a plugin branch that has since merged to main. Skip steps 2–7 entirely — the CHANGELOG, version files, and commit are already done. Jump directly to step 8.\n\n**Normal path:** Read `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` for the current version and `plugins\u002F\u003Cslug>\u002FCHANGELOG.md` for recent entries.\n\nReview the uncommitted or recently committed changes (`git diff` and\u002For `git log` since the last `\u003Cslug>--v\u003Cversion>` tag).\n\nDecide the bump level:\n- **Patch** (0.0.X) — bug fixes, behavioral changes via updated instructions, small additions\n- **Minor** (0.X.0) — new features, new skills, structural changes, breaking config migrations\n- **Major** (X.0.0) — only if the user explicitly asks\n\nPresent the suggested version and rationale. Wait for confirmation before proceeding.\n\n### 3. Write the changelog entry\n\nPrepend a new entry to `plugins\u002F\u003Cslug>\u002FCHANGELOG.md` immediately after the `# Changelog` header, before the previous version entry. If a `[Unreleased]` section already exists, rename it to `[X.Y.Z] - YYYY-MM-DD` instead of prepending a new one — the entry has been accumulating during development.\n\n**Docs-only double-check (do this before promoting\u002Fwriting the entry).** Read every narrative bullet about to ship in this version and confirm each describes a real code\u002Fbehavior change an operator experiences. Drop any bullet whose only change is documentation (README, `docs\u002F`, instruction files, or code comments), including bullets that pair a docs correction onto an otherwise-code entry (keep the code half, cut the docs half). Docs corrections belong in the commit message and PR description, never the CHANGELOG. Cross-check against the actual diff: `git diff \u003Clast-tag>..HEAD -- plugins\u002F\u003Cslug>`; if a bullet's only backing changes are `.md` or comment edits, it should not be in the changelog. This mirrors the root `AGENTS.md` §Commits and releases rule.\n\n**Format**:\n\n```markdown\n## [X.Y.Z] - YYYY-MM-DD\n\n### Added \u002F Changed \u002F Fixed\n(use whichever sections apply — skip empty ones)\n\n- Plain sentence-case line describing the change; the header carries the category. Backticks for `commands`, `paths`, `--flags`.\n\n### Upgrade Instructions\n\nRun `\u002Fhermitd:hermit-evolve`. The evolve skill handles:\n\n1. **Imperative step title** — what to do, in one sentence.\n\nNo `config.json` changes required.\n```\n\n**Template constraints (enforce these):**\n\n1. **Narrative bullets (Added \u002F Changed \u002F Fixed)**: canonical format lives in root `AGENTS.md` §Commits and releases; enforce it here: a plain sentence-case line under the category header, no `**component:**` prefix and no leading Fixed\u002FAdded verb (the header carries the category). Backticks for commands\u002Fpaths\u002Fflags. Target 1–2 lines. If a bullet wants to grow longer, the surplus belongs in the PR description, not here.\n   - Do NOT list internal refactors, helper extractions, test scaffolding, or renamed variables — those are visible in `git diff`.\n   - **Recovery procedures, migration shell snippets, and breaking-change steps belong in `### Upgrade Instructions`, never in the narrative bullet.** Write a tight summary (\"changed default X to Y\") and let that section carry the imperative steps — `hermit-evolve` reads them step-by-step.\n\n2. **Upgrade Instructions** — strict imperative block:\n   - Every step starts with a verb (`Add`, `Replace`, `Copy`, `Run`, `Delete`, `Refresh`).\n   - Each step is a single action. No \"also do X, but only if Y, unless Z\" run-ons — split into separate numbered steps.\n   - No passive voice, no rationale clauses. If an operator needs to understand *why*, that belongs in the Changed bullet above, not here.\n   - Include what `hermit-evolve` does NOT need to touch only if omission would cause it to act destructively. Otherwise silence.\n   - Close with `No config.json changes required.` if true — it's the most common case and operators scan for it.\n\n3. **What belongs where:**\n   - Why it changed → Changed\u002FFixed bullet.\n   - What evolve executes → Upgrade Instructions (imperative, numbered).\n   - Behavior deltas that need no action but operators should know → one final line after the numbered list, prefixed `**Note:**`. Not a step.\n\n**The Upgrade Instructions section is the most important part.** The evolve skill reads this to know what actions to take for each hermit. Non-imperative steps cause evolve to misparse or skip them.\n\n### 4. Refresh references\n\nFor each new skill, agent, or hook added since the last release of this plugin, detect missing entries and add them in one pass:\n\n- Plugin README component descriptions and any affected `plugins\u002F\u003Cslug>\u002FAGENTS.md` constraints (keep inventories out of instruction files)\n- `plugins\u002F\u003Cslug>\u002Fdocs\u002Fskills.md` (if the doc exists)\n- Hook descriptions in the plugin README or relevant docs if the hook surface area changed\n\nSkip the step entirely if nothing was added. The plugin-validator (Step 1.3) covers structural integrity; this step is about narrative references.\n\n### 5. Bump version in all locations\n\nUpdate the version string in:\n- `plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json` → `\"version\"` field\n- `.claude-plugin\u002Fmarketplace.json` → find the entry in `plugins[]` where `\"name\" == \"\u003Cslug>\"` and update its `\"version\"` field. Other plugin entries are untouched.\n- `plugins\u002F\u003Cslug>\u002FREADME.md` → version badge if present: both the `img.shields.io` URL slug (`version-X.Y.Z-green.svg`) and the `alt` text (`Version X.Y.Z`). Confirm with `grep \"version-\" plugins\u002F\u003Cslug>\u002FREADME.md` that the new version appears and the old one does not. Skip silently if the README has no version badge. (For `hermitd`, skip this direct edit — the sync block below re-derives the whole file from root, picking up the updated badge automatically.)\n- If `\u003Cslug>` is `hermitd`: also update the root `README.md` badge — `version-OLD-green.svg` → `version-NEW-green.svg` and `Version OLD` → `Version NEW`. This is the only plugin whose version the root README tracks.\n\n**Sync plugin README from root (hermitd only):** `plugins\u002Fhermitd\u002FREADME.md` is a path-adjusted derivative of the root `README.md`. After updating version badges, re-derive it by applying these substitutions to the root README content:\n\n| In root `README.md`                              | In plugin `README.md`                          |\n|--------------------------------------------------|------------------------------------------------|\n| `href=\"LICENSE\"`                                 | `href=\"..\u002F..\u002FLICENSE\"`                         |\n| `[MIT](LICENSE)`                                 | `[MIT](..\u002F..\u002FLICENSE)`                         |\n| `href=\"plugins\u002Fhermitd\u002FCHANGELOG.md\"` | `href=\"CHANGELOG.md\"`                          |\n| `src=\"plugins\u002Fhermitd\u002Fassets\u002F`        | `src=\"assets\u002F`                                 |\n| `](plugins\u002Fhermitd\u002Fdocs\u002F`             | `](docs\u002F`                                      |\n| `](plugins\u002Fhermitd-dev\u002F`              | `](..\u002Fhermitd-dev\u002F`                 |\n| `](plugins\u002Fhermitd-homeassistant\u002F`    | `](..\u002Fhermitd-homeassistant\u002F`       |\n| `](plugins\u002Fhermitd-fitness\u002F`          | `](..\u002Fhermitd-fitness\u002F`             |\n| `](plugins\u002Fhermitd-laravel-forge\u002F`                | `](..\u002Fhermitd-laravel-forge\u002F`                   |\n\nWrite the result to `plugins\u002Fhermitd\u002FREADME.md`.\n\nAfter editing, verify the manifest and marketplace are in sync — the plugin manifest wins silently if they differ:\n```bash\njq -r '.version' plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json\njq -r --arg slug \"\u003Cslug>\" '.plugins[] | select(.name == $slug) | .version' .claude-plugin\u002Fmarketplace.json\n```\nBoth must print the same string. If they differ, fix `.claude-plugin\u002Fmarketplace.json` before continuing.\n\n### 6. Final validation\n\nSteps 3–5 only edit Markdown and JSON, so re-running the test suite is unnecessary. Confirm:\n\n```bash\njq -e . plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json > \u002Fdev\u002Fnull\njq -e . .claude-plugin\u002Fmarketplace.json > \u002Fdev\u002Fnull\ngit status --short\n```\n\nBoth `jq` checks must succeed and `git status` must show only the files this release touched (CHANGELOG, plugin.json, marketplace.json, optional CLAUDE.md \u002F README badge \u002F state-templates updates). Any unexpected entry → investigate before committing.\n\n### 7. Commit and push\n\nStage only the changed files (not `git add -A`). Commit with:\n\n```\n\u003Cslug> v\u003CX.Y.Z>: One-line summary of the release\n```\n\nPush to origin.\n\n### 8. Branch check before tagging\n\nRun `git branch --show-current` and compare to `main` (or the repo's default branch from `gh repo view --json defaultBranchRef -q .defaultBranchRef.name`).\n\n- **On `main`\u002Fdefault branch** → tag immediately (step 9).\n- **On any other branch** (e.g. `dev-hermit\u002Fv0.3.0`) → **stop**. Do not tag yet. Tagging the branch tip creates a commit SHA that `main` never carries after a regular merge (and is outright wrong after squash\u002Frebase), leaving the tag stranded on an orphan commit.\n\n  **Recommended path** (default): open a PR, merge into `main`, then re-run `\u002Frelease \u003Cslug>` from `main`. Step 2's already-bumped detection will skip straight to tagging.\n\n  If the user explicitly wants to tag now despite the risk, offer that as a secondary option. Wait for their explicit choice before proceeding.\n\n### 9. Tag and publish\n\nThe tag format is **plugin-prefixed with double-dash separator**: `\u003Cslug>--v\u003CX.Y.Z>`. This is the format Claude Code's native dependency resolver requires to find matching versions for `dependencies` entries.\n\nRun `claude plugin tag --push` from the plugin directory — it validates plugin contents, confirms `plugin.json` and `marketplace.json` versions agree, requires a clean working tree, and refuses if the tag already exists:\n\n```bash\n(cd plugins\u002F\u003Cslug> && claude plugin tag --push)\n```\n\nThen create the GitHub release pointing to the new double-dash tag. Source the release notes from the CHANGELOG section we just wrote — `--generate-notes` would otherwise interleave commits from sibling-plugin releases that landed since the last core tag.\n\n```bash\nVERSION=$(jq -r '.version' plugins\u002F\u003Cslug>\u002F.claude-plugin\u002Fplugin.json)\nTAG=\"\u003Cslug>--v$VERSION\"\nNOTES_FILE=$(mktemp)\nawk -v ver=\"$VERSION\" '\n  $0 ~ \"^## \\\\[\" ver \"\\\\]\" {flag=1; next}\n  \u002F^## \\[\u002F && flag {exit}\n  flag {print}\n' plugins\u002F\u003Cslug>\u002FCHANGELOG.md > \"$NOTES_FILE\"\n[ ! -s \"$NOTES_FILE\" ] && { echo \"CHANGELOG section for $VERSION not found in plugins\u002F\u003Cslug>\u002FCHANGELOG.md — fix and retry\"; rm \"$NOTES_FILE\"; exit 1; }\ngh release create \"$TAG\" --title \"$TAG\" --notes-file \"$NOTES_FILE\"\nrm \"$NOTES_FILE\"\n```\n\n### 10. Report\n\nPrint the slug, the new version, the commit hash, the tag name, and a one-liner confirming it's pushed.\n",{"name":5,"description":7},"main","79e254360ba999b70a827541bbcfd2d4cc525992",".agents\u002Fskills\u002Frelease",16,"https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd","https:\u002F\u002Fhermitd.dev","https:\u002F\u002Fgithub.com\u002Fgtapps","Software engineer from Portugal.\r\nBuilding and deploying agents for real companies.","2026-11-12 00:14:57",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add gtapps\u002Fhermitd --skill release",{"tool":61,"command":62},"bunx","bunx skills add gtapps\u002Fhermitd --skill release",{"tool":64,"command":65},"pnpm","pnpm dlx skills add gtapps\u002Fhermitd --skill release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Frelease\u002FSKILL.md",true,[],[70,86,99,125,141,150],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":41},"01M718AB18DTYHVGXA6VF1VVR2","dream","Nightly memory maintenance from transcript ground truth. Verifies, enriches and tidies auto-memory and topic pages with snapshot validation and undo. Also handles 'undo the dream'.","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fdream\u002FSKILL.md",[],[72,77,78,79,80,81,82,83,84,85],"with","maintenance","memory","validation","snapshot","pages","auto","memory maintenance","transcript",{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":41},"01M6HVD4WX8RB5EKH49HM66M8X","when-done-switch-to","Arm a deferred model or effort switch. Use for \"when done switch to\", \"after this drop to sonnet\", or \"switch model when idle\".","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fwhen-done-switch-to\u002FSKILL.md",[],[19,93,94,95,21,96,32,97,98],"done","switch","when done switch to","model","drop","sonnet",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":41},"01M6HVD0ZA2Q1RD7CA0X8VWF3T","weekly-review","Generate the weekly review report for the current ISO week. Writes to .hermit\u002Fcompiled\u002Freview-weekly-YYYY-Www.md (dev-facing detail) and sends a plain-language channel summary (Delivered \u002F Decisions \u002F Waiting on you \u002F Spend). Runs every Sunday at 23:00 via routine.","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fweekly-review\u002FSKILL.md",[],[106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,21,121,122,123,124],"weekly review","review","weekly","hermit","plain","routine","channel","summary","report","at","generate","via","decisions","you","detail","iso","review report","dev","plain-language",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":41},"01M6HVCW8PHZXSPYAZQBZXB9DX","watch","Background events via the config watch monitor or ad-hoc Monitor tool. Quiet watches cost zero tokens.","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fwatch\u002FSKILL.md",[],[127,132,133,134,135,136,137,138,139,117,140],"monitor","ZeRO","tokens","tool","cost","ad","config","background","events",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":41},"01M6HVCRMG53K3Y63WAH59YVFJ","watch-activate","Activate the config watch monitor.","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fwatch-activate\u002FSKILL.md",[],[127,148,149,132,138],"activate","watch activate",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":161,"publishedAt":41},"01M6HVCK6782RD4D9ADQY0ENKD","voice-notes","Transcribe and respond to voice notes. Activates when any channel message carries an audio attachment, or when asked to transcribe an inbound voice message.","https:\u002F\u002Fgithub.com\u002Fgtapps\u002Fhermitd\u002Fblob\u002Fmain\u002Fplugins\u002Fhermitd\u002Fskills\u002Fvoice-notes\u002FSKILL.md",[156],{"categoryNo":157,"categoryName":158,"taxonomyType":159,"taxonomyTypeDesc":160},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",[162,163,164,36,165,166,167,168,169,170,109,19,171,172,173,174,175,176,119,18],"notes","voice","voice notes","Audio","transcribe","operator","understand","transcription","my","read","message","can","telegram","channel message","discord"]