{"id":"14643449-3b81-4759-816c-3630c2017cde","shortId":"6yB8pV","kind":"skill","title":"review-ci","tagline":"Use when the user asks for a CI review, CI/CD review, GitHub Actions review, workflow review, pipeline review, build pipeline audit, \"review the workflows\", \"review the actions\", action pinning audit, workflow permissions audit, or supply-chain review of CI configuration.","description":"# CI / Workflow Review\n\nStructured review of CI/CD pipeline configuration. Focus is on **GitHub Actions** (the dominant case); CircleCI / Buildkite / GitLab / Jenkins are noted where they share concerns but receive lighter coverage.\n\n**Out of scope** (defer to siblings):\n- Application source code → `review-code`\n- Container images and Dockerfiles → `review-infrastructure`\n- Application-level secrets and IAM → `review-security`\n\n## Workflow\n\n### 1. Scope and explore\n\n- Confirm scope with the user: full repo CI config, specific workflow(s), or changed files only (PR or branch diff).\n- **Resolve scope to a file list.** Based on what the user requested:\n  - **Changed files (PR or branch):** Run `git diff --name-only --diff-filter=d <base>...HEAD`. If the user references a PR number, use `gh pr diff <number> --name-only` instead. Filter to CI file types (see classification below).\n  - **Explicit paths:** Include all CI files under given directories.\n  - **Full repo:** Walk for CI files (default).\n- **If invoked from review-all**: receive `file_list`, `has_changes`, `base_ref`, `REVIEW_DIR`, and `pr_url` from the orchestrator. Skip your own scope confirmation.\n\n**File classification.** Detect by path and content:\n- **GitHub Actions workflows**: `.github/workflows/*.yml`, `.github/workflows/*.yaml`\n- **Composite / reusable actions**: `action.yml` or `action.yaml` files (any location, but typically `.github/actions/*/action.yml`)\n- **Dependabot / Renovate config**: `.github/dependabot.yml`, `renovate.json`, `.renovaterc*`\n- **CircleCI**: `.circleci/config.yml`\n- **Buildkite**: `.buildkite/pipeline.yml`, `.buildkite/*.yml`\n- **GitLab CI**: `.gitlab-ci.yml`\n- **Jenkins**: `Jenkinsfile`\n- **Other**: `azure-pipelines.yml`, `cloudbuild.yaml`, `bitbucket-pipelines.yml`, `wercker.yml`\n\n### 2. System overview\n\nProduce a brief pipeline summary covering:\n- Triggers in use: `push`, `pull_request`, `pull_request_target`, `workflow_dispatch`, `schedule`, `workflow_call`, `release`\n- Branches / paths gated\n- Reusable workflows or composite actions referenced\n- Self-hosted vs. GitHub-hosted runners\n- Secrets / OIDC providers in use (named, not values)\n- Deploy targets (if discernible)\n\n### 3. Launch investigation subagent\n\nLaunch a single investigation subagent (`subagent_type=\"generalPurpose\"`, `model: sonnet` per `subagent-model-routing`) with the system overview and in-scope file list.\n\nPrompt it to:\n- Read only the in-scope files.\n- Apply the GitHub Actions checklist in [reference.md](reference.md); for non-GHA platforms, apply the **cross-platform** subset.\n- Run the static analyzers below when available.\n- For each finding, search nearby files (workflow comments, `README.md`, in-repo runbooks) for existing tracking.\n- Return findings using the **CI findings** template.\n\n### 4. Run static analyzers\n\n```sh\n# GitHub Actions — syntax + best-practice lint\ncommand -v actionlint >/dev/null && actionlint <files>\n\n# GitHub Actions — supply-chain / security focused\ncommand -v zizmor    >/dev/null && zizmor --format plain <files>\n\n# Generic YAML hygiene (any platform)\ncommand -v yamllint  >/dev/null && yamllint -f parsable <files>\n```\n\nTool output is **input** to the review. The subagent must triage: `actionlint` `shellcheck` warnings inside `run:` blocks are real; some structural warnings are noisy and need filtering.\n\n### 5. Present results\n\nResolve the review output directory (same pattern as siblings):\n\n```sh\nREVIEW_DATE=$(date +%Y-%m-%d)\nREVIEW_DIR=\"reviews/${REVIEW_DATE}\"\nif [ -d \"$REVIEW_DIR\" ]; then REVIEW_DIR=\"reviews/${REVIEW_DATE}-$(date +%H%M)\"; fi\nmkdir -p \"$REVIEW_DIR\"\n```\n\nCapture run metadata (see [Run metadata header](#run-metadata-header)) and prepend the rendered block to `${REVIEW_DIR}/CI-REVIEW.md`.\n\nOutput structure:\n1. Run metadata header\n2. Pipeline overview (from step 2)\n3. Findings table\n4. Tool availability notes\n5. Recommended fix order\n\nPresent the report to the user.\n\n---\n\n## Run metadata header\n\nCapture once near `REVIEW_DIR` resolution and prepend to the output document:\n\n```sh\nRUN_DATETIME=$(date -u +\"%Y-%m-%d %H:%M UTC\")\nGIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)\nGIT_COMMIT=$(git rev-parse --short HEAD)\nGIT_COMMIT_FULL=$(git rev-parse HEAD)\nGIT_SUBJECT=$(git log -1 --pretty=%s)\n# When scope is diff-based, also: BASE_REF=<base>; BASE_COMMIT=$(git rev-parse --short \"$BASE_REF\")\n```\n\n```markdown\n> **Run:** {RUN_DATETIME}\n> **Branch:** {GIT_BRANCH} @ {GIT_COMMIT} (`{GIT_COMMIT_FULL}`)\n> **Subject:** {GIT_SUBJECT}\n> **Base:** {BASE_REF} @ {BASE_COMMIT}   <!-- omit when scope is not diff-based -->\n> **Scope:** {scope description}\n```\n\n---\n\n## Finding link wrapping (PR mode)\n\nWhen `pr_url` is set (or `gh pr view --json url -q .url 2>/dev/null` returns one for standalone runs), wrap every `path:line` reference inside the finding tables as a Markdown link:\n\n```sh\n~/.claude/scripts/pr-deeplink.sh \"$pr_url\" <path> <line>\n```\n\nThe display text stays `path:line`. Pass `L` as the fourth argument for findings about removed code (default `R`). Findings follow `terse-comments`: concrete fix, optional `bug:`/`risk:`/`nit:`/`unsure:` prefix.\n\n---\n\n## Output Templates\n\n### CI findings\n\n```markdown\n| Priority | Workflow | Finding | Impact | Effort | Tracked |\n|----------|----------|---------|--------|--------|---------|\n| P0 | release.yml | Description with code references | Impact (supply chain / security / reliability) | trivial / small / moderate / large | — |\n| P1 | ci.yml | Description with code references | Impact description | Effort estimate | #123 |\n```\n\n**Workflow column values:** filename relative to `.github/workflows/`, or `action.yml`, `dependabot.yml`, etc.\n\n### Re-evaluation table (for follow-up reviews)\n\n```markdown\n| Finding | Status | What Changed |\n|---------|--------|--------------|\n| ~~1. Description~~ | FIXED | Brief explanation of the fix |\n| 2. Description | Still applicable | No changes |\n```\n\n---\n\n## Guidelines\n\n- Search the organization's codebase (Sourcegraph, GitHub) for existing reusable workflows and centralized composite actions before recommending custom ones.\n- Treat any third-party action that is not pinned by full commit SHA as a P0 supply-chain risk unless the action is from a vendored trust list (e.g. `actions/*`, `github/*`).\n- Include effort estimates.\n- When the user asks for a follow-up review, find the most recent review directory and append the re-evaluation table.\n- For detailed framework categories, see [reference.md](reference.md).\n- **REVIEW.md integration**: If a `REVIEW.md` context section was provided by the review-all orchestrator (or exists at the repository root when running standalone), treat its rules as additional review criteria. \"Always check\" items are HIGH severity; domain-specific items (CI section) are MEDIUM severity. \"Skip\" patterns exclude matching files from review scope.\n- Findings must cite probed evidence (`path:line`, grep output, command result), not pattern-matched suspicion. Per `~/.claude/rules/probe-not-assume.md`.","tags":["review","skill","issue","paultyng","agent-skills","ai-tools","claude-code","cursor","dotfiles"],"capabilities":["skill","source-paultyng","skill-review-ci","topic-agent-skills","topic-ai-tools","topic-claude-code","topic-cursor","topic-dotfiles"],"categories":["skill-issue"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/paultyng/skill-issue/review-ci","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add paultyng/skill-issue","source_repo":"https://github.com/paultyng/skill-issue","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (7,011 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:09:01.591Z","embedding":null,"createdAt":"2026-05-18T13:21:26.815Z","updatedAt":"2026-05-18T19:09:01.591Z","lastSeenAt":"2026-05-18T19:09:01.591Z","tsv":"'-1':629 '/.claude/rules/probe-not-assume.md':980 '/.claude/scripts/pr-deeplink.sh':712 '/action.yml':248 '/ci-review.md':543 '/dev/null':427,439,451,692 '1':105,546,809 '123':783 '2':271,550,555,691,817 '3':324,556 '4':412,559 '5':482,563 'abbrev':606 'abbrev-ref':605 'action':16,30,31,58,230,238,302,366,418,430,838,848,866,874 'action.yaml':241 'action.yml':239,792 'actionlint':426,428,466 'addit':937 'also':638 'alway':940 'analyz':385,415 'append':896 'appli':363,376 'applic':82,96,820 'application-level':95 'argument':726 'ask':8,882 'audit':24,33,36 'avail':388,561 'azure-pipelines.yml':267 'base':135,207,637,639,641,648,665,666,668 'best':421 'best-practic':420 'bitbucket-pipelines.yml':269 'block':471,539 'branch':127,145,295,600,654,656 'brief':276,812 'bug':742 'build':22 'buildkit':63,257,259 'buildkite/pipeline.yml':258 'call':293 'captur':524,576 'case':61 'categori':905 'central':836 'chain':40,433,766,862 'chang':122,141,206,808,822 'check':941 'checklist':367 'ci':3,11,43,45,116,174,184,193,262,409,749,950 'ci.yml':774 'ci/cd':13,51 'circleci':62,255 'circleci/config.yml':256 'cite':965 'classif':178,223 'cloudbuild.yaml':268 'code':84,87,731,762,777 'codebas':828 'column':785 'command':424,436,448,972 'comment':396,738 'commit':610,618,642,658,660,669,855 'composit':236,301,837 'concern':71 'concret':739 'config':117,251 'configur':44,53 'confirm':109,221 'contain':88 'content':228 'context':914 'cover':279 'coverag':75 'criteria':939 'cross':379 'cross-platform':378 'custom':841 'd':155,500,507,595 'date':496,497,505,515,516,591 'datetim':590,653 'default':195,732 'defer':79 'dependabot':249 'dependabot.yml':793 'deploy':320 'descript':672,760,775,780,810,818 'detail':903 'detect':224 'diff':128,148,153,167,636 'diff-bas':635 'diff-filt':152 'dir':210,502,509,512,523,542,580 'directori':188,489,894 'discern':323 'dispatch':290 'display':716 'dockerfil':91 'document':587 'domain':947 'domain-specif':946 'domin':60 'e.g':873 'effort':756,781,877 'estim':782,878 'etc':794 'evalu':797,900 'everi':699 'evid':967 'exclud':957 'exist':403,832,925 'explan':813 'explicit':180 'explor':108 'f':453 'fi':519 'file':123,133,142,175,185,194,203,222,242,351,362,394,959 'filenam':787 'filter':154,172,481 'find':391,406,410,557,673,705,728,734,750,754,805,889,963 'fix':565,740,811,816 'focus':54,435 'follow':735,801,886 'follow-up':800,885 'format':441 'fourth':725 'framework':904 'full':114,189,619,661,854 'gate':297 'generalpurpos':335 'generic':443 'gh':165,684 'gha':374 'git':147,599,601,609,611,617,620,625,627,643,655,657,659,663 'github':15,57,229,309,365,417,429,830,875 'github-host':308 'github/actions':247 'github/dependabot.yml':252 'github/workflows':232,234,790 'gitlab':64,261 'gitlab-ci.yml':263 'given':187 'grep':970 'guidelin':823 'h':517,596 'head':156,608,616,624 'header':530,534,549,575 'high':944 'host':306,310 'hygien':445 'iam':100 'imag':89 'impact':755,764,779 'in-repo':398 'in-scop':348,359 'includ':182,876 'infrastructur':94 'input':458 'insid':469,703 'instead':171 'integr':910 'investig':326,331 'invok':197 'item':942,949 'jenkin':65,264 'jenkinsfil':265 'json':687 'l':722 'larg':772 'launch':325,328 'level':97 'lighter':74 'line':701,720,969 'link':674,710 'lint':423 'list':134,204,352,872 'locat':244 'log':628 'm':499,518,594,597 'markdown':650,709,751,804 'match':958,977 'medium':953 'metadata':526,529,533,548,574 'mkdir':520 'mode':677 'model':336,341 'moder':771 'must':464,964 'name':150,169,317 'name-on':149,168 'near':578 'nearbi':393 'need':480 'nit':744 'noisi':478 'non':373 'non-gha':372 'note':67,562 'number':163 'oidc':313 'one':694,842 'option':741 'orchestr':216,923 'order':566 'organ':826 'output':456,488,544,586,747,971 'overview':273,346,552 'p':521 'p0':758,859 'p1':773 'pars':604,614,623,646 'parsabl':454 'parti':847 'pass':721 'path':181,226,296,700,719,968 'pattern':491,956,976 'pattern-match':975 'per':338,979 'permiss':35 'pin':32,852 'pipelin':20,23,52,277,551 'plain':442 'platform':375,380,447 'pr':125,143,162,166,212,676,679,685,713 'practic':422 'prefix':746 'prepend':536,583 'present':483,567 'pretti':630 'prioriti':752 'probe':966 'produc':274 'prompt':353 'provid':314,917 'pull':284,286 'push':283 'q':689 'r':733 're':796,899 're-evalu':795,898 'read':356 'readme.md':397 'real':473 'receiv':73,202 'recent':892 'recommend':564,840 'ref':208,607,640,649,667 'refer':160,702,763,778 'referenc':303 'reference.md':369,370,907,908 'relat':788 'releas':294 'release.yml':759 'reliabl':768 'remov':730 'render':538 'renov':250 'renovate.json':253 'renovaterc':254 'repo':115,190,400 'report':569 'repositori':928 'request':140,285,287 'resolut':581 'resolv':129,485 'result':484,973 'return':405,693 'reusabl':237,298,833 'rev':603,613,622,645 'rev-pars':602,612,621,644 'review':2,12,14,17,19,21,25,28,41,47,49,86,93,102,200,209,461,487,495,501,503,504,508,511,513,514,522,541,579,803,888,893,921,938,961 'review-al':199,920 'review-ci':1 'review-cod':85 'review-infrastructur':92 'review-secur':101 'review.md':909,913 'risk':743,863 'root':929 'rout':342 'rule':935 'run':146,382,413,470,525,528,532,547,573,589,651,652,697,931 'run-metadata-head':531 'runbook':401 'runner':311 'schedul':291 'scope':78,106,110,130,220,350,361,633,670,671,962 'search':392,824 'secret':98,312 'section':915,951 'secur':103,434,767 'see':177,527,906 'self':305 'self-host':304 'set':682 'sever':945,954 'sh':416,494,588,711 'sha':856 'share':70 'shellcheck':467 'short':615,647 'sibl':81,493 'singl':330 'skill' 'skill-review-ci' 'skip':217,955 'small':770 'sonnet':337 'sourc':83 'source-paultyng' 'sourcegraph':829 'specif':118,948 'standalon':696,932 'static':384,414 'status':806 'stay':718 'step':554 'still':819 'structur':48,475,545 'subag':327,332,333,340,463 'subagent-model-rout':339 'subject':626,662,664 'subset':381 'summari':278 'suppli':39,432,765,861 'supply-chain':38,431,860 'suspicion':978 'syntax':419 'system':272,345 'tabl':558,706,798,901 'target':288,321 'templat':411,748 'ters':737 'terse-com':736 'text':717 'third':846 'third-parti':845 'tool':455,560 'topic-agent-skills' 'topic-ai-tools' 'topic-claude-code' 'topic-cursor' 'topic-dotfiles' 'track':404,757 'treat':843,933 'triag':465 'trigger':280 'trivial':769 'trust':871 'type':176,334 'typic':246 'u':592 'unless':864 'unsur':745 'url':213,680,688,690,714 'use':4,164,282,316,407 'user':7,113,139,159,572,881 'utc':598 'v':425,437,449 'valu':319,786 'vendor':870 'view':686 'vs':307 'walk':191 'warn':468,476 'wercker.yml':270 'workflow':18,27,34,46,104,119,231,289,292,299,395,753,784,834 'wrap':675,698 'y':498,593 'yaml':235,444 'yamllint':450,452 'yml':233,260 'zizmor':438,440","prices":[{"id":"2b256db3-f195-41f5-a265-d1f06bb648cf","listingId":"14643449-3b81-4759-816c-3630c2017cde","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"paultyng","category":"skill-issue","install_from":"skills.sh"},"createdAt":"2026-05-18T13:21:26.815Z"}],"sources":[{"listingId":"14643449-3b81-4759-816c-3630c2017cde","source":"github","sourceId":"paultyng/skill-issue/review-ci","sourceUrl":"https://github.com/paultyng/skill-issue/tree/main/skills/review-ci","isPrimary":false,"firstSeenAt":"2026-05-18T13:21:26.815Z","lastSeenAt":"2026-05-18T19:09:01.591Z"}],"details":{"listingId":"14643449-3b81-4759-816c-3630c2017cde","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"paultyng","slug":"review-ci","github":{"repo":"paultyng/skill-issue","stars":8,"topics":["agent-skills","ai-tools","claude-code","cursor","dotfiles"],"license":"mit","html_url":"https://github.com/paultyng/skill-issue","pushed_at":"2026-05-18T18:26:54Z","description":"Personal Claude Code / Cursor agent skills, rules, and config","skill_md_sha":"46c1b91eea71294a7cf7920265842230dc410cb1","skill_md_path":"skills/review-ci/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/paultyng/skill-issue/tree/main/skills/review-ci"},"layout":"multi","source":"github","category":"skill-issue","frontmatter":{"name":"review-ci","description":"Use when the user asks for a CI review, CI/CD review, GitHub Actions review, workflow review, pipeline review, build pipeline audit, \"review the workflows\", \"review the actions\", action pinning audit, workflow permissions audit, or supply-chain review of CI configuration."},"skills_sh_url":"https://skills.sh/paultyng/skill-issue/review-ci"},"updatedAt":"2026-05-18T19:09:01.591Z"}}