{"slug":"skf-update-skill","title":"skf-update-skill","summary":"Smart regeneration preserving [MANUAL] sections after source changes. Use when the user requests to \"update a skill\" or \"regenerate a skill.\"","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-24T15:42:41.601366Z","repo":{"url":"https://github.com/armelhbobdad/bmad-module-skill-forge","stars":95,"forks":8,"license":null,"updatedAt":"2026-09-22T20:28:59Z"},"bodyHtml":"<hr>\n<h2>name: skf-update-skill\ndescription: Smart regeneration preserving [MANUAL] sections after source changes. Use when the user requests to \"update a skill\" or \"regenerate a skill.\"</h2>\n<h1>Update Skill</h1>\n<h2>Overview</h2>\n<p>Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking. Only changed exports are re-extracted — unchanged content is never touched. Every regenerated instruction must trace to code with file:line citations. Stack skills (<code>skill_type: \"stack\"</code> in metadata.json) are not supported by surgical update — use <code>skf-create-stack-skill</code> to re-compose from updated constituents. If a stack skill is provided, this workflow exits with a redirect message.</p>\n<h2>Conventions</h2>\n<ul>\n<li>Bare paths (e.g. <code>references/&lt;name&gt;.md</code>) resolve from the skill root.</li>\n<li><strong>Module-level path exception:</strong> bare paths beginning with <code>knowledge/</code> or <code>shared/</code> resolve from the SKF module root (<code>{project-root}/_bmad/skf/</code> installed, <code>src/</code> in dev), not the skill root — stage files reference <code>knowledge/version-paths.md</code> and <code>knowledge/tool-resolution.md</code>, and the terminal step chains to <code>shared/health-check.md</code>.</li>\n<li><code>references/</code> holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter <code>nextStepFile</code>, plus static reference docs); <code>scripts/</code> and <code>assets/</code> hold deterministic helpers and templates.</li>\n<li><code>{skill-root}</code> resolves to this skill's installed directory (where <code>customize.toml</code> lives, if present).</li>\n<li><code>{project-root}</code>-prefixed paths resolve from the project working directory.</li>\n<li><code>{skill-name}</code> resolves to the skill directory's basename.</li>\n<li><strong>Cross-skill data coupling:</strong> stages in this workflow load four shared assets from <code>skf-create-skill</code> to keep extraction semantics aligned between create and update — <code>re-extract.md</code> pulls <code>extraction-patterns.md</code>, <code>extraction-patterns-tracing.md</code>, and <code>tier-degradation-rules.md</code> from <code>skf-create-skill/references/</code>; <code>remote-source-resolution.md</code> references <code>source-resolution-protocols.md</code>; <code>write.md</code> reads <code>skill-sections.md</code> from <code>skf-create-skill/assets/</code>. Update-skill assumes these files are present at install time and that their semantics are stable across the two skills' versions.</li>\n</ul>\n<h2>Role</h2>\n<p>You are a precision code analyst operating in Ferris Surgeon mode. This is a surgical operation, not an exploratory session. You bring AST-backed structural analysis and provenance-driven change detection expertise, while the source code provides the ground truth.</p>\n<h2>Workflow Rules</h2>\n<p>These rules apply to every step in this workflow:</p>\n<ul>\n<li>Never hallucinate — every statement must have AST provenance</li>\n<li>[MANUAL] sections survive regeneration with zero content loss</li>\n<li>Only load one step file at a time — never preload future steps</li>\n<li>Always communicate in <code>{communication_language}</code></li>\n<li>If <code>{headless_mode}</code> is true, auto-proceed through confirmation gates with their default action and log each auto-decision</li>\n</ul>\n<h2>Stages</h2>\n<table>\n<thead>\n<tr>\n<th>#</th>\n<th>Step</th>\n<th>File</th>\n<th>Auto-proceed</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>Initialize &amp; Load</td>\n<td>references/init.md</td>\n<td>No (confirm)</td>\n</tr>\n<tr>\n<td>2</td>\n<td>Detect Changes</td>\n<td>references/detect-changes.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>3</td>\n<td>Re-Extract</td>\n<td>references/re-extract.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>4</td>\n<td>Merge</td>\n<td>references/merge.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>5</td>\n<td>Validate</td>\n<td>references/validate.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>6</td>\n<td>Write</td>\n<td>references/write.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>7</td>\n<td>Report</td>\n<td>references/report.md</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>8</td>\n<td>Workflow Health Check</td>\n<td>references/health-check.md</td>\n<td>Yes</td>\n</tr>\n</tbody>\n</table>\n<h2>Invocation Contract</h2>\n<table>\n<thead>\n<tr>\n<th>Aspect</th>\n<th>Detail</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Inputs</strong></td>\n<td>skill_name [required]</td>\n<td></td>\n</tr>\n<tr>\n<td><strong>Flags</strong></td>\n<td><code>--headless</code> / <code>-H</code> (auto-resolve all gates); <code>--from-test-report</code> (gap-driven mode); <code>--allow-workspace-drift</code> (gap-driven only — bypass §0.a pinning guard); <code>--allow-degraded</code> (headless only — pre-authorize the lossy degraded full re-extraction when the provenance map is missing, instead of halting <code>blocked</code>; init.md §4); <code>--detect-only</code> (run detect-changes only, exit before re-extract; envelope <code>status=\"detect-only\"</code>); <code>--dry-run</code> (run detect-changes + re-extract, exit before merge/write; envelope <code>status=\"dry-run\"</code> describes what would change). If both <code>--detect-only</code> and <code>--dry-run</code> are passed, <code>--detect-only</code> wins.</td>\n<td></td>\n</tr>\n<tr>\n<td><strong>Gates</strong></td>\n<td>step 1: Confirm Gate [C]</td>\n<td>step 4: Confirm Gate [C if clean merge, HALT if conflicts]</td>\n</tr>\n<tr>\n<td><strong>Outputs</strong></td>\n<td>Updated SKILL.md, metadata.json, provenance-map.json, evidence-report.md (none when <code>--detect-only</code> or <code>--dry-run</code> is set — those modes are read-only inspection paths)</td>\n<td></td>\n</tr>\n<tr>\n<td><strong>Concurrency</strong></td>\n<td>Two simultaneous real-update runs against the same skill would corrupt provenance. init.md §1b acquires a PID-file lock at <code>{forge_data_folder}/{skill_name}/.skf-update.lock</code> before any artifact read; live-PID collisions halt with <code>status: \"halted-for-concurrent-run\"</code>. Stale locks (dead PID) are cleared silently with a warning. The lock is released by the terminal health-check step (step 8) on the normal path and by the two init-stage headless halts (§4/§6); mid-workflow halts leave it for the next run's stale-lock self-heal (see init.md §1b Release contract). Read-only modes (<code>--detect-only</code>, <code>--dry-run</code>) skip the lock entirely — they're safe alongside a concurrent real update.</td>\n<td></td>\n</tr>\n<tr>\n<td><strong>Headless</strong></td>\n<td>All gates auto-resolve with default action when <code>{headless_mode}</code> is true. Each auto-resolved gate appends a <code>{gate, default_action, taken_action, reason, evidence?}</code> entry to <code>headless_decisions[]</code>, surfaced in step 7's <code>SKF_UPDATE_RESULT_JSON</code> envelope so non-interactive runs can be audited post-hoc. A HALT reached in headless mode emits its own <code>SKF_UPDATE_RESULT_JSON</code> at the halt site (the site's <code>status</code> code plus an <code>error: {phase, path?, reason}</code> object) and exits — halts do not fall through to step 7. Pipeline branches on the envelope's top-level <code>status</code> field (<code>success</code>, <code>no-changes</code>, <code>detect-only</code>, <code>dry-run</code>, or one of the documented <code>halted-for-*</code>/<code>blocked</code> codes). The first four are successful exits — pipelines treating non-success as failure must include them in the success set. The status enum is defined once in <code>src/shared/scripts/schemas/skf-update-result-envelope.v1.json</code>.</td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<h2>On Activation</h2>\n<ol>\n<li><p>Load config from <code>{project-root}/_bmad/skf/config.yaml</code> and resolve:</p>\n<ul>\n<li><code>project_name</code>, <code>output_folder</code>, <code>user_name</code>, <code>communication_language</code>, <code>document_output_language</code></li>\n<li><code>skills_output_folder</code>, <code>forge_data_folder</code>, <code>sidecar_path</code></li>\n</ul>\n</li>\n<li><p><strong>Resolve <code>{headless_mode}</code></strong>: true if <code>--headless</code> or <code>-H</code> was passed as an argument, or if <code>headless_mode: true</code> in preferences.yaml. Default: false.</p>\n</li>\n<li><p><strong>Resolve workflow customization.</strong> Run:</p>\n<pre><code>python3 {project-root}/_bmad/scripts/resolve_customization.py \\\n    --skill {skill-root} --key workflow\n</code></pre>\n<p>This merges the three layers per <code>bmad-customize</code> rules (scalars override, arrays append): <code>{skill-root}/customize.toml</code> (bundled defaults), <code>_bmad/custom/&lt;skill-name&gt;.toml</code> under <code>{project-root}</code> (team overrides), and <code>_bmad/custom/&lt;skill-name&gt;.user.toml</code> under <code>{project-root}</code> (personal overrides). If the script is missing or fails, read <code>{skill-root}/customize.toml</code> directly.</p>\n<p>Apply the resolved values so no surface is a silent no-op: execute each entry in <code>workflow.activation_steps_prepend</code> in order now; treat every entry in <code>workflow.persistent_facts</code> as standing context for the whole run (entries prefixed <code>file:</code> are paths or globs whose contents load as facts — the bundled default loads any <code>project-context.md</code> under <code>{project-root}</code>); resolve <code>{onCompleteCommand}</code> ← <code>workflow.on_complete</code> if non-empty, else empty string, and stash it in workflow context (<code>references/report.md</code> §5b invokes it after the result contract is written; empty string = the hook is a no-op). After activation completes, execute each entry in <code>workflow.activation_steps_append</code> in order before <code>init.md</code> runs.</p>\n</li>\n<li><p>Load, read the full file, and then execute <code>references/init.md</code> to begin the workflow.</p>\n</li>\n</ol>\n","files":[{"path":"customize.toml","sizeBytes":1991,"isText":true},{"path":"references/detect-changes.md","sizeBytes":36030,"isText":true},{"path":"references/health-check.md","sizeBytes":1288,"isText":true},{"path":"references/init.md","sizeBytes":18476,"isText":true},{"path":"references/manual-section-rules.md","sizeBytes":2131,"isText":true},{"path":"references/merge-conflict-rules.md","sizeBytes":878,"isText":true},{"path":"references/merge.md","sizeBytes":10595,"isText":true},{"path":"references/re-extract.md","sizeBytes":30098,"isText":true},{"path":"references/remote-source-resolution.md","sizeBytes":6013,"isText":true},{"path":"references/report.md","sizeBytes":10896,"isText":true},{"path":"references/validate.md","sizeBytes":7413,"isText":true},{"path":"references/write.md","sizeBytes":29767,"isText":true},{"path":"scripts/skf-new-file-diff.py","sizeBytes":5941,"isText":true},{"path":"SKILL.md","sizeBytes":7975,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-24T15:43:00.80026Z","sha256":"2B48E379E2E17C2528311C15D677D9343CACFBEE7B74C58100E7DAB8B705CD31","sizeBytes":65106},"review":null,"source":{"repositoryUrl":"https://github.com/armelhbobdad/bmad-module-skill-forge","path":"src/skf-update-skill","license":null,"commit":"492e73e7ea0d4069d1f37f5e176424b9c2cf8521","subtreeSha":"625969A5F81F590D946AA931BFE5605281390246603C354732EC5D768FD072A6","lastSyncedAt":"2026-09-24T15:42:40.059679Z"},"reviewedAt":"2026-09-24T15:43:58.414162Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/armelhbobdad/bmad-module-skill-forge/tree/main/src/skf-update-skill"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install armelhbobdad-bmad-module-skill-forge@llmmart"},{"target":"git","command":"git clone https://github.com/armelhbobdad/bmad-module-skill-forge.git"}]}