Only 1 of 36 plugin repos (decision-flow) runs claudecode-linter in CI at all #7
Notifications
Total Time Spent: 14 minutes
oleks
14 minutes
No due date set.
Dependencies
No dependencies set.
Reference: oleks/claude-plugin-cicd-insights#7
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Origin
kotkan/claude-plugin-decision-flow#76 (closed) — same fleet-wide CI audit as the sibling issue filed alongside this one (path-filter exclusion finding). This is a separate finding: different affected repos, different remedy — keeping them apart on purpose.
Context
claudecode-linter(CCL) enforcesskill-md/description-max-length(1024 chars) andskill-md/valid-frontmatteron Claude Code plugin artifacts. A SKILL.md whose frontmatter breaks silently stops loading — no error. On decision-flow this class already caused real damage: a 1065-char description sat undetected onmain, a later edit took it to 1230, and the pre-push CCL hook then rejected EVERY push to that repo including a branch deletion.Finding
Read-only audit of all 36 subdirectories of
~/projects/claude-plugins/(2026-08-14): 3 repos (anxious,inference-arbitrage,worktree-discipline) have atest.yamlpipeline with NO path filter, so they DO fire on skill/agent changes — but no pipeline in any of them invokesclaudecode-linter. Net effect matches the sibling path-filter-exclusion finding (skill changes go unlinted), but the fix differs: these need a lint step added to an existing pipeline, not a new pipeline.kotkan/claude-plugin-decision-flowis currently the ONLY repo in the fleet with any CCL coverage in CI at all (.woodpecker/lint.yml, v0.33.2, commitsa532841/5c3e5c1— verified: Woodpecker pipeline #7 on a skills-only commit ran that workflow alone, exit 0, 18s). Its step:npx --yes claudecode-linter@2.1.232 --ignore 'tests/plugin-fixtures/**' .in anode:22-slimimage, filtered toskills/**,commands/**,agents/**,.claude-plugin/**,hooks/hooks.json. CCL exits non-zero only on ERROR-severity findings, so adopting repos should expect warnings to be non-fatal.Scope note
Sibling finding (filed alongside this one, same title prefix) covers 9 repos whose CI path filters actively exclude the skills tree — a missing-pipeline problem. This issue is the 3 repos that already have an unfiltered pipeline but simply never call CCL — an add-a-step problem.
Not filed as a finding, context only: 23 further plugin repos have no
.woodpecker/directory whatsoever — weaker/possibly intentional, noting so it isn't re-derived.Done — all 3 repos now invoke CCL in their existing pipeline, each verified by a real run
Audit re-verified on disk first (2026-08-14):
anxious,inference-arbitrageandworktree-disciplineeach confirmed to have atest.yamlwith nopath:filter, andgrep -rl claudecode-linter .woodpecker/returned nothing in any of them. Accurate as filed. (anxiousalso carries ahooks-release.yml, which doesn't change the remedy.)What shipped
A
claudecode-linterstep appended to each existingtest.yaml— an added step, not a new pipeline, exactly as this issue scoped it. Pinned toclaudecode-linter@2.1.232(confirmed still current on npm),node:22-slim, not piped.One design decision worth stating: the step is gated
Without it, Woodpecker skips later steps once an earlier one fails, so a broken SKILL.md would land unnoticed behind an unrelated red step — the lint would be present and not running, which is the exact failure shape this issue exists to close.
anxiousalready uses this pattern for itsgo-paritystep, with the same rationale.That gating was then confirmed in practice rather than assumed — see worktree-discipline below.
The step would have landed RED on 1 of 3
Ran CCL locally against all three first. One genuine ERROR-severity finding, fixed in the same commit:
inference-arbitrage—skill-md/description-no-angle-brackets:skills/offload-audit/SKILL.md's description contained a literal<plugin>placeholder. The rule permits angle brackets only inside HTML comments (the fleet'sROUTING TRIGGERSsentinels), not in prose. Reworded to "a plugin", preserving the trigger phrase. Also excludedtests/fixtures/**, which holds deliberate frontmatter snapshots of other plugins — linting them would let an upstream fixture refresh fail this repo's build over a file it doesn't own.anxiouspasses at exit 0, but only because its.claudecode-lint.yamldowngrades three rules toinfo. One of those downgrades is now unnecessary and one is masking a live problem — both filed separately: oleks/claude-plugin-anxious#139 and oleks/claude-plugin-anxious#140. #140 matters to this issue's premise:skills/wip-claim/SKILL.mdcarries a 1228-character description — over the 1024 limit, and almost exactly the magnitude that broke decision-flow. The step added here will not catch it, by that repo's own deliberate config. Worth knowing that this repo's new coverage is real but not total.Verification — the step actually ran, and exited 0
claudecode-linterstepf8507b33e7413e9cae6dbworktree-discipline needs the honest note. Its pipeline is red — but the failure is the pre-existing
suitesstep, not the step added here. That repo'smainhas been red on #100, #102, #103, #104 and #105; the red predates this change by days. Root cause diagnosed from the #105 log: thesuitesstep'sapk addinstallsbash git python3 coreutilsbut notjq, so one suite self-skips (SKIPPED (needs jq)) and parity reports57 passed, 12 failed, most of those being pure JSON-whitespace artifacts of bash falling back off jq. It does not reproduce locally — the repo's own pre-push hook printedALL SUITES PASSEDon this machine. Filed with the diagnosis, along with one genuine bash-vs-Go parity bug found in the same log (bash manglesargh→rghinWTD_ISSUEname composition).That run is also the best available evidence that the
status: [success, failure]gating works as intended:shellcheckwas skipped whensuitesfailed, whileclaudecode-linterstill ran and passed. The design goal is demonstrated, not just asserted.Closing.
⏱ worked | 14-08-26 | session oleks/8752153d | +14min | session-total 14min (lane-release) | elapsed from timeline