[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DEP1NQ3928A3E7T6WC5DNG":3,"skill-same:01M6DEP1NQ3928A3E7T6WC5DNG":68},{"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":30,"linkOnly":31,"markdownContent":32,"markdownBody":33,"frontMatter":34,"refName":37,"commitSha":38,"skillDirectory":39,"forksCount":14,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":42,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M6DEP1NQ3928A3E7T6WC5DNG","source-pattern-scanner",null,"Analyzes source code patterns to identify languages, frameworks, and conventions.","iamsteveholmes\u002Fmomentum","iamsteveholmes","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F92353?v=4","01M6DENK56DRSF72CJ6FJQ4RT1","Steve Holmes","01M6DENK9KCZRYFFEB0M689F7D",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fagent-guidelines\u002Fsub-skills\u002Fsource-pattern-scanner\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29],"scanner","pattern","source pattern scanner","source","code","patterns","frameworks","conventions","code patterns","true","source code","2026-11-10 10:12:30",false,"---\nname: ci-audit-triggers\ndescription: \"Audit a GitHub Actions\u002FGitLab CI workflow for attacker-influenceable triggers (pull_request_target, issue_comment, workflow_run) — pwn-request issues: fork head-ref checkout, ${{ }} injection, author_association gaps. Analysis-only; harden via ci-harden-workflow.\"\n---\n# Security-Review a CI Workflow on Untrusted Triggers\n\nGeneric source→sink review (`security-review-diff`) and `mcp-audit` miss CI-specific\nescalations: the sink is a runner holding the **base repo's secrets**, the substitution happens in the\nrunner's own `${{ }}`\u002Fshell semantics, and the attacker controls a fork PR's code or a comment's text while a\nprivileged trigger runs in base-repo context. Apply this whenever a `.github\u002Fworkflows\u002F*.yml` (or\n`.gitlab-ci.yml`) fires on events an outsider can influence, or exposes `secrets.*`. To *build or lock down*\nsuch a workflow (CODEOWNERS, branch protection, environments), use `ci-harden-workflow`.\n\n### Step 0: Detect platform\n\n**Pasted input takes precedence.** If the user pasted workflow YAML (or quoted a workflow in the\nprompt), detect the platform from that content first — `on:` + `jobs:` + `runs-on:`\u002F`uses:` → GitHub\nActions; `stages:`\u002F`rules:`\u002F`workflow:`\u002F`script:`\u002F`$CI_*` → GitLab CI — and apply the matching branch\nbelow to the pasted text, even when the current checkout is a different platform. Run the script\nonly when no workflow was supplied.\n\nRun `..\u002F..\u002Fruntime\u002Fbin\u002Fci_platform.sh` relative to this skill directory. The shared audit method below (classify\ntrigger trust → enumerate attacker-controlled inputs → trace the ref\u002Fcode the job\noperates on → hunt injection → audit secret reach → check cheap hardening) applies on\neither platform — only the vocabulary changes:\n\n- `github-actions` → the trigger\u002Fvariable\u002Finjection vocabulary in steps 1-9 below\n  applies as written.\n- `gitlab-ci` → load `..\u002F..\u002Fruntime\u002Freferences\u002Fci\u002Fgitlab-ci-triggers.md` for the real GitLab\n  equivalents (pipelines for merge requests from forks, `CI_MERGE_REQUEST_*`\n  variables, `$[[ inputs.* ]]` interpolation, protected variables\u002Fbranches in place of\n  `author_association`) and apply the same method through that vocabulary instead.\n- `none` → report that no CI configuration was detected and stop; don't guess at a\n  platform or invent generic advice.\n\nIf the script cannot run (read-only session, no shell), skip it and use the same\ncontent-based detection on the CI files you can read.\n\n1. **Classify the trigger's trust level.** `pull_request_target`, `issue_comment`, `issues`, `workflow_run`,\n   and `discussion_comment` run with the **base repo's secrets and a writable token**, and are reachable by\n   untrusted actors (any commenter, any fork-PR author). Plain `pull_request` from a fork runs **without**\n   secrets and with a read-only token *by default* (a repo can opt to send secrets\u002Fwrite tokens to fork PRs;\n   same-repo `pull_request` does get them). State which untrusted inputs the chosen trigger exposes; flag\n   every secret-using job on the privileged triggers.\n2. **Enumerate attacker-controlled inputs.** Treat each as hostile: `github.event.comment.body`,\n   `issue.title`\u002F`issue.body`, `pull_request.title`\u002F`body`\u002F`head.ref`\u002F`head.label`\u002F`head.sha`, and\n   branch\u002Ftag names.\n3. **Check what the `if:` gate actually authenticates.** `author_association ∈ {OWNER, MEMBER, COLLABORATOR}`\n   is server-set and non-spoofable, but it has two gaps: (a) it gates the **commenter\u002Factor — not the code\u002FPR\n   author** (a trusted maintainer commenting on an outsider's fork PR still passes the gate while the job\n   points at fork-controlled content); and (b) it is **not a write-access check** — `COLLABORATOR` includes\n   read-\u002Ftriage-only collaborators and `MEMBER` is any org member, so a gate on this set can admit principals\n   with no write access. For a privileged trigger, confirm the real permission level (e.g. `gh api\n   repos\u002F{owner}\u002F{repo}\u002Fcollaborators\u002F{user}\u002Fpermission` → `admin`\u002F`write`) rather than `author_association`\n   alone. Verify the gate covers the principal whose *code or data* the job consumes, not just who typed the\n   trigger phrase.\n4. **Trace the ref\u002Fcode the job operates on (pwn-request).** Look for a checkout or operation on\n   `pull_request.head.ref`\u002F`head.sha`. If a secret-bearing step (deploy, publish, an agent CLI with an API\n   key, `gh` with a PAT, `npm install` running fork postinstall) acts on that fork-controlled tree (Makefile,\n   postinstall, git filters, lint\u002FCI configs) → **pwn-request, high severity**: attacker code executes with\n   secrets in scope. Require `head.repo.full_name == base.repo.full_name` (or explicitly refuse fork PRs)\n   before any checkout\u002Foperate step.\n5. **Hunt `${{ }}` expression injection.** Any `github.event.*` value interpolated directly into a `run:`\n   block or a `with:`\u002F`github-script` input is substituted into the YAML\u002Fshell **before** execution; a `\"`,\n   backtick, `$(...)`, or newline breaks quoting and can bleed into adjacent keys or execute commands. The fix\n   is the distinction that matters: **bind the value to `env:` and reference the quoted `\"$VAR\"` inside\n   `run:`** — once it arrives through the environment the `${{ }}` expansion never touches the script text, so\n   it is data, not code (for `with:`\u002F`github-script` inputs, read it from `process.env`\u002F`core.getInput`, don't\n   inline `${{ }}`). Flag the inline interpolation, not the env-bound passing. **Caveat — a `with:` input is\n   only data if the *receiving* action doesn't shell-template it.** A composite action can re-introduce the\n   injection by inline-templating an input into its own `run:` (e.g. `jq --arg x \"${{ inputs.x }}\"`), so an\n   attacker-controlled value you hand off via `with:` (e.g. a fork PR's `head.ref` as a `starting_branch`\n   input) still detonates inside the action. Fetch the action's metadata at the pinned SHA and read its\n   `runs:` steps — the file is `action.yml` (GitHub's preferred name) or `action.yaml`, and a subdirectory\n   action (`owner\u002Frepo\u002Fpath@sha`) keeps it under that path, so derive the path from `uses:` and try both\n   names: `gh api repos\u002FOWNER\u002FREPO\u002Fcontents\u002FPATH\u002Faction.yml?ref=SHA --jq .content | base64 -d` (retry with\n   `action.yaml` on 404). Confirm each untrusted input it receives is env-bound, not interpolated —\n   SHA-pinning fixes the version, not this. When in doubt, sanitize the value (strict allowlist, e.g. a ref\n   against `^[A-Za-z0-9._\u002F-]+$`) before the hand-off.\n6. **Audit `permissions:` and secret reach.** Demand least privilege (`contents: read` unless writes are\n   needed); identify exactly which steps see `secrets.*`. A secret-bearing step gated only on untrusted input\n   is the escalation target — narrow the gate or move the secret behind a manual approval \u002F GitHub Environment.\n7. **Check the cheap hardening.** Trigger `types: [created]` only (no `edited` replay of an approved-looking\n   comment), bot exclusion (`github.event.comment.user.type != 'Bot'` to stop self-trigger loops), and\n   third-party actions pinned to a **full commit SHA**, not a mutable tag.\n8. **Prefer the structural remedy over a smarter gate.** Either refuse fork PRs before any secret is exposed\n   (`head.repo.fork == true` → fail), or **split into two jobs**: an unprivileged job that builds\u002Ftests the\n   fork code with no secrets, and a privileged job (triggered via `workflow_run` or gated on same-repo) that\n   never checks out fork code. Don't rely on the author gate alone.\n9. **Report only findings with a concrete attacker path.** Rank pwn-request and secret-exfil as high; rank\n   pure expression-injection without a secret\u002Fcommand sink as medium. For each, name the trigger, the\n   untrusted input, and the sink it reaches.\n\n## Sub-agent dispatch\n\nFollow the [CI audit dispatch rules](references\u002Fci-audit-triggers-dispatch.md)\nand the [shared dispatch contract](..\u002F..\u002Fruntime\u002Freferences\u002Fsub-agent-dispatch.md).\nWhen at least three workflow files need auditing, assign one\n`security-reviewer` unit per workflow. The parent merges cited attacker-path\nevidence under this skill's severity rules; below the threshold, audit inline.\n","# Security-Review a CI Workflow on Untrusted Triggers\n\nGeneric source→sink review (`security-review-diff`) and `mcp-audit` miss CI-specific\nescalations: the sink is a runner holding the **base repo's secrets**, the substitution happens in the\nrunner's own `${{ }}`\u002Fshell semantics, and the attacker controls a fork PR's code or a comment's text while a\nprivileged trigger runs in base-repo context. Apply this whenever a `.github\u002Fworkflows\u002F*.yml` (or\n`.gitlab-ci.yml`) fires on events an outsider can influence, or exposes `secrets.*`. To *build or lock down*\nsuch a workflow (CODEOWNERS, branch protection, environments), use `ci-harden-workflow`.\n\n### Step 0: Detect platform\n\n**Pasted input takes precedence.** If the user pasted workflow YAML (or quoted a workflow in the\nprompt), detect the platform from that content first — `on:` + `jobs:` + `runs-on:`\u002F`uses:` → GitHub\nActions; `stages:`\u002F`rules:`\u002F`workflow:`\u002F`script:`\u002F`$CI_*` → GitLab CI — and apply the matching branch\nbelow to the pasted text, even when the current checkout is a different platform. Run the script\nonly when no workflow was supplied.\n\nRun `..\u002F..\u002Fruntime\u002Fbin\u002Fci_platform.sh` relative to this skill directory. The shared audit method below (classify\ntrigger trust → enumerate attacker-controlled inputs → trace the ref\u002Fcode the job\noperates on → hunt injection → audit secret reach → check cheap hardening) applies on\neither platform — only the vocabulary changes:\n\n- `github-actions` → the trigger\u002Fvariable\u002Finjection vocabulary in steps 1-9 below\n  applies as written.\n- `gitlab-ci` → load `..\u002F..\u002Fruntime\u002Freferences\u002Fci\u002Fgitlab-ci-triggers.md` for the real GitLab\n  equivalents (pipelines for merge requests from forks, `CI_MERGE_REQUEST_*`\n  variables, `$[[ inputs.* ]]` interpolation, protected variables\u002Fbranches in place of\n  `author_association`) and apply the same method through that vocabulary instead.\n- `none` → report that no CI configuration was detected and stop; don't guess at a\n  platform or invent generic advice.\n\nIf the script cannot run (read-only session, no shell), skip it and use the same\ncontent-based detection on the CI files you can read.\n\n1. **Classify the trigger's trust level.** `pull_request_target`, `issue_comment`, `issues`, `workflow_run`,\n   and `discussion_comment` run with the **base repo's secrets and a writable token**, and are reachable by\n   untrusted actors (any commenter, any fork-PR author). Plain `pull_request` from a fork runs **without**\n   secrets and with a read-only token *by default* (a repo can opt to send secrets\u002Fwrite tokens to fork PRs;\n   same-repo `pull_request` does get them). State which untrusted inputs the chosen trigger exposes; flag\n   every secret-using job on the privileged triggers.\n2. **Enumerate attacker-controlled inputs.** Treat each as hostile: `github.event.comment.body`,\n   `issue.title`\u002F`issue.body`, `pull_request.title`\u002F`body`\u002F`head.ref`\u002F`head.label`\u002F`head.sha`, and\n   branch\u002Ftag names.\n3. **Check what the `if:` gate actually authenticates.** `author_association ∈ {OWNER, MEMBER, COLLABORATOR}`\n   is server-set and non-spoofable, but it has two gaps: (a) it gates the **commenter\u002Factor — not the code\u002FPR\n   author** (a trusted maintainer commenting on an outsider's fork PR still passes the gate while the job\n   points at fork-controlled content); and (b) it is **not a write-access check** — `COLLABORATOR` includes\n   read-\u002Ftriage-only collaborators and `MEMBER` is any org member, so a gate on this set can admit principals\n   with no write access. For a privileged trigger, confirm the real permission level (e.g. `gh api\n   repos\u002F{owner}\u002F{repo}\u002Fcollaborators\u002F{user}\u002Fpermission` → `admin`\u002F`write`) rather than `author_association`\n   alone. Verify the gate covers the principal whose *code or data* the job consumes, not just who typed the\n   trigger phrase.\n4. **Trace the ref\u002Fcode the job operates on (pwn-request).** Look for a checkout or operation on\n   `pull_request.head.ref`\u002F`head.sha`. If a secret-bearing step (deploy, publish, an agent CLI with an API\n   key, `gh` with a PAT, `npm install` running fork postinstall) acts on that fork-controlled tree (Makefile,\n   postinstall, git filters, lint\u002FCI configs) → **pwn-request, high severity**: attacker code executes with\n   secrets in scope. Require `head.repo.full_name == base.repo.full_name` (or explicitly refuse fork PRs)\n   before any checkout\u002Foperate step.\n5. **Hunt `${{ }}` expression injection.** Any `github.event.*` value interpolated directly into a `run:`\n   block or a `with:`\u002F`github-script` input is substituted into the YAML\u002Fshell **before** execution; a `\"`,\n   backtick, `$(...)`, or newline breaks quoting and can bleed into adjacent keys or execute commands. The fix\n   is the distinction that matters: **bind the value to `env:` and reference the quoted `\"$VAR\"` inside\n   `run:`** — once it arrives through the environment the `${{ }}` expansion never touches the script text, so\n   it is data, not code (for `with:`\u002F`github-script` inputs, read it from `process.env`\u002F`core.getInput`, don't\n   inline `${{ }}`). Flag the inline interpolation, not the env-bound passing. **Caveat — a `with:` input is\n   only data if the *receiving* action doesn't shell-template it.** A composite action can re-introduce the\n   injection by inline-templating an input into its own `run:` (e.g. `jq --arg x \"${{ inputs.x }}\"`), so an\n   attacker-controlled value you hand off via `with:` (e.g. a fork PR's `head.ref` as a `starting_branch`\n   input) still detonates inside the action. Fetch the action's metadata at the pinned SHA and read its\n   `runs:` steps — the file is `action.yml` (GitHub's preferred name) or `action.yaml`, and a subdirectory\n   action (`owner\u002Frepo\u002Fpath@sha`) keeps it under that path, so derive the path from `uses:` and try both\n   names: `gh api repos\u002FOWNER\u002FREPO\u002Fcontents\u002FPATH\u002Faction.yml?ref=SHA --jq .content | base64 -d` (retry with\n   `action.yaml` on 404). Confirm each untrusted input it receives is env-bound, not interpolated —\n   SHA-pinning fixes the version, not this. When in doubt, sanitize the value (strict allowlist, e.g. a ref\n   against `^[A-Za-z0-9._\u002F-]+$`) before the hand-off.\n6. **Audit `permissions:` and secret reach.** Demand least privilege (`contents: read` unless writes are\n   needed); identify exactly which steps see `secrets.*`. A secret-bearing step gated only on untrusted input\n   is the escalation target — narrow the gate or move the secret behind a manual approval \u002F GitHub Environment.\n7. **Check the cheap hardening.** Trigger `types: [created]` only (no `edited` replay of an approved-looking\n   comment), bot exclusion (`github.event.comment.user.type != 'Bot'` to stop self-trigger loops), and\n   third-party actions pinned to a **full commit SHA**, not a mutable tag.\n8. **Prefer the structural remedy over a smarter gate.** Either refuse fork PRs before any secret is exposed\n   (`head.repo.fork == true` → fail), or **split into two jobs**: an unprivileged job that builds\u002Ftests the\n   fork code with no secrets, and a privileged job (triggered via `workflow_run` or gated on same-repo) that\n   never checks out fork code. Don't rely on the author gate alone.\n9. **Report only findings with a concrete attacker path.** Rank pwn-request and secret-exfil as high; rank\n   pure expression-injection without a secret\u002Fcommand sink as medium. For each, name the trigger, the\n   untrusted input, and the sink it reaches.\n\n## Sub-agent dispatch\n\nFollow the [CI audit dispatch rules](references\u002Fci-audit-triggers-dispatch.md)\nand the [shared dispatch contract](..\u002F..\u002Fruntime\u002Freferences\u002Fsub-agent-dispatch.md).\nWhen at least three workflow files need auditing, assign one\n`security-reviewer` unit per workflow. The parent merges cited attacker-path\nevidence under this skill's severity rules; below the threshold, audit inline.\n",{"name":35,"description":36},"ci-audit-triggers","Audit a GitHub Actions\u002FGitLab CI workflow for attacker-influenceable triggers (pull_request_target, issue_comment, workflow_run) — pwn-request issues: fork head-ref checkout, ${{ }} injection, author_association gaps. Analysis-only; harden via ci-harden-workflow.","main","1cb705536db26c557b919c204aeea2cfd0658ac1","skills\u002Fmomentum\u002Fskills\u002Fagent-guidelines\u002Fsub-skills\u002Fsource-pattern-scanner","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes","http:\u002F\u002Fcapitalcodemonkey.blogspot.com","2026-11-09 05:58:39",{"source":8,"skillName":35,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add iamsteveholmes\u002Fmomentum --skill ci-audit-triggers",{"tool":50,"command":51},"bunx","bunx skills add iamsteveholmes\u002Fmomentum --skill ci-audit-triggers",{"tool":53,"command":54},"pnpm","pnpm dlx skills add iamsteveholmes\u002Fmomentum --skill ci-audit-triggers","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fagent-guidelines\u002Fsub-skills\u002Fsource-pattern-scanner\u002FSKILL.md",true,[58,64],{"path":59,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":62,"sourceHtmlUrl":63},"agents\u002Fopenai.yaml","REFERENCE","参考文档",43,"https:\u002F\u002Fgithub.com\u002FRB-chrismandich\u002FManifest\u002Fblob\u002Fmain\u002Fplugins\u002Fmanifest-security\u002Fskills\u002Fci-audit-triggers\u002Fagents\u002Fopenai.yaml",{"path":65,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":66,"sourceHtmlUrl":67},"references\u002Fci-audit-triggers-dispatch.md",525,"https:\u002F\u002Fgithub.com\u002FRB-chrismandich\u002FManifest\u002Fblob\u002Fmain\u002Fplugins\u002Fmanifest-security\u002Fskills\u002Fci-audit-triggers\u002Freferences\u002Fci-audit-triggers-dispatch.md",[69,90,108,130,147,165],{"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":30},"01M6DES6J0HGT27SEJJWF316FV","upstream-fix","Traces quality failures upstream to spec, rule, or workflow root cause. Proposes fixes at the right level.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fupstream-fix\u002FSKILL.md",[],[76,77,78,79,80,81,82,83,84,85,86,87,88,89],"upstream","upstream fix","fix","to spec","root cause","traces","fixes","at","high","root","rule","quality","workflow","spec",{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":30},"01M6DES4A08NFWQM0AJBR2RRX5","triage","Dedup gate + batch-classify observations into five classes, enrich ARTIFACTs, batch-approve, delegate to intake\u002Fdecision or queue.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Ftriage\u002FSKILL.md",[],[92,97,98,99,100,101,102,103,84,104,105,106,107],"batch","intake","artifacts","decision","queue","delegate","approve","observations","enrich","classify","gate",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":30},"01M6DERYX8W6Z9Z4RM5V6E9HED","sprint-planning","Sprint planning — story selection, team composition, Gherkin specs, and visual companion plan gate for developer sign-off.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fsprint-planning\u002FSKILL.md",[],[115,116,117,84,118,119,120,121,122,123,124,125,126,127,128,129,107],"planning","sprint","sprint planning","visual companion","plan gate","for","companion","sign","visual","selection","Composition","Story","plan","team","developer",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":30},"01M6DERWCP7Y0WDY5KG6109RQB","sprint-manager","Sole writer of stories\u002Findex.json and sprints\u002Findex.json — validates state transitions, activates sprints, manages epic membership.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fsprint-manager\u002FSKILL.md",[],[137,116,138,139,140,141,142,143,144,145,146],"sprint manager","manager","writer","stories","sprints","EPIC","transitions","json","index","state",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":30},"01M6DERS7B4QHAH5GZHHBA4AHB","sprint-dev","Sprint execution — dependency-driven story development, post-merge AVFL, and team review.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fsprint-dev\u002FSKILL.md",[],[154,155,116,128,156,157,158,159,160,161,84,162,163,164,126],"dev","sprint dev","execution","team review","development","merge","review","dependency","post","avfl","driven",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":171,"publishedAt":30},"01M6DERP0A271FYSAXCV85GF04","retro","Sprint retrospective — transcript audit engine (dynamic Workflow), story verification, findings document, and sprint closure.","https:\u002F\u002Fgithub.com\u002Fiamsteveholmes\u002Fmomentum\u002Fblob\u002Fmain\u002Fskills\u002Fmomentum\u002Fskills\u002Fretro\u002FSKILL.md",[],[167,172,173,84,174,116,175,126,176,177,178,179,180,88],"sprint retrospective","closure","dynamic workflow","document","engine","audit","verification","transcript","retrospective"]