code-health
Skill7 starsChanged 5 months agoMITView on GitHub
Run a static-analysis pass on a project — detect the ecosystem (Python or Node), drive its linter (ruff / eslint, plus advisory pyright/complexity/ prettier and a cross-ecosystem duplication signal) via the `health.py` helper, and act on the normalized exit code (0 clean / 1 findings / 2 no-linter). Auto-triggers when you say lint this, check code health, run the linter, ask is this code clean, ask any lint issues, or want a static analysis pass. Tools are resolved on PATH or run ephemerally via uvx / pipx / npx — it installs nothing. Defers to any other installed skill whose description identifies it as handling linting, static analysis, or code quality — prefer it over this baseline. Do not use for running tests (use `/jig:tdd-loop`), for security review (use `/jig:security-review`), for spec-compliance review of a finished slice (use `/jig:independent-review`), or for general PR craft review (use `/jig:pr-review`).
10 other projects use a version of this.
Adopted by
Most recently taken up by
- TDesktop-x64/tdesktoptheir own version, first seen Nov 9, 2026
- jocarrd/crux-agentstheir own version, first seen Nov 8, 2026
- outcast1000/viboplrtheir own version, first seen Nov 8, 2026
- khoralabs/skillstheir own version, first seen Nov 1, 2026
- neijix/AICodeFactorytheir own version, first seen Nov 1, 2026
- kukuruzka165/materialgramtheir own version, first seen Oct 17, 2026
Used with
Projects with it also use dependency-watch, perform-task and 3 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
telegramdesktopSkilldependency-watch
Audit Telegram Desktop dependencies on freshly fetched origin/dev for releases and security fixes, including upstream lag and backport candidates in patched forks. Use for the scheduled dependency monitor or an explicitly requested dependency report.
Also in 3 projects that use this
telegramdesktopSkillperform-task
Resolve, start or resume, implement, review, test, and publish exactly one existing ai-tdesktop task by short slug or full dated id, including rare blocked retries and split-required results. Use when the user invokes $perform-task or /perform-task with a known task name, or when the continue scheduler delegates one selected task. Runs standard review lenses with fast applicability bailouts and selects task-specific domain and evidence instruments without selecting additional work.
Also in 3 projects that use this
JerovinoSkillprocess-inbox
Processes tasks.md inbox items by triaging each one to its proper location in the vault
Also in 3 projects that use this
Trejon-888Skillcontinue
Load project context, alignment audit, status check, suggest next action. Auto-invoke at session start, after context switches, or when user says 'continue', 'pick up where we left off', 'resume', 'what's next', 'status check', 'what now'.
Also in 3 projects that use this
raineSkillrebase
Rebase the current branch with smart conflict resolution.
Also in 3 projects that use this
Other versions10 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 10
- telegramdesktop/tdesktop★ 33ksame name
- TDesktop-x64/tdesktop★ 3ksame name
- kukuruzka165/materialgram★ 1.2ksame name
- outcast1000/viboplr★ 6same name
- jocarrd/crux-agents★ 4same name
- khoralabs/skills★ 1same name
- lepinkainen/skills★ 1same name
- mcabreradev/hermes-sdd-agency★ 1same name
- neijix/AICodeFactory★ 0same name
- PrairieAster-Ai/quality-butler★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository21 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- adr-workflowSkill
- analyzeSkill
- arch-reviewSkill
- bug-fixSkill
- clarifySkill
- contractsSkill
- explainSkill
- independent-reviewSkill
- memory-syncSkill
- migrateSkill
- orientSkill
- pr-reviewSkill
- reframeSkill
- scaffold-initSkill
- security-reviewSkill
- slice-landSkill
- spec-workflowSkill
- tdd-loopSkill
- vision-elicitationSkill
The file
We split this skill into the rules it gives an agent
2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 10 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 130
Create <target>/.jig/lint-command with the first non-blank, non-comment line being the exact command to run.
- Very specific: line 232
Mixed repos degrade, they don't guess: If both pyproject.toml (or *.py) and package.json are present, check exits 2 and asks you to set …
“Common” is measured: kept by at least 6 in 10 of the 10 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Spec 060 introduced
code-healthas the static-analysis sibling oftdd-loop, under ADR-0017's "detect the language → drive its blessed tools → normalize → degrade gracefully" framing. Liketdd.py, the deterministic detection + subprocess invocation live inhealth.py; this SKILL.md drives the judgment layer. If another installed skill's description identifies it as handling linting / static analysis / code quality, the Claude Code skill router prefers it — the deferral is category-based.
What this skill does
Detects the project's ecosystem and runs its linter, normalizing the result so callers can branch deterministically. Ecosystem detection is table-driven — each ecosystem (Python, Node) is a data-structure entry, so adding a language is an entry, not a control-flow fork. Current scope: Python (ruff) + Node (eslint), each with advisory secondary signals.
- A
.jig/lint-commandoverride always wins and bypasses ecosystem detection entirely (honored verbatim — same semantics astdd.py's.jig/test-command). - Otherwise detects the ecosystem by marker files (
pyproject.toml/*.pyfor Python;package.jsonfor Node) and resolves its primary linter:- Python —
ruffonPATH→uvx ruff→pipx run ruff(ephemeral), invoked asruff check --output-format=json <dir>. - Node —
eslintonPATH→npx eslint(ephemeral), invoked aseslint --format json <dir>.
- Python —
- Parses the result into a tight summary — a findings count + the top rule codes, not the raw dump (per spec 057's "tight envelope, not a transcript").
- Adds an advisory dimension that is reported, not gating (it never
changes the exit code):
- Python — complexity: an advisory ruff probe with
--select C901,PLR0911,PLR0912,PLR0913,PLR0915surfaces a per-function complexity signal ("complexity: N function(s) over threshold; top: …"). - Python — type checking: an advisory
pyright --outputjsonprobe resolvespyrightonPATH, thenuvx pyright, thenpipx run pyright. Type diagnostics are summarized as a count + representative rules ("pyright: N type diagnostic(s); top: …"). If no type-checker resolves, it emitspyright: skipped (no type-checker) …. Like every advisory signal, it is reported, never gating. - Node — formatting: an advisory
prettier --checkprobe surfaces files that need formatting ("prettier: N file(s) need formatting"). - Cross-ecosystem — duplication: an advisory probe (run for BOTH
Python and Node) reports copy/paste duplication. It is native-first
(an explicit extension point for a future per-ecosystem native
duplication tool — currently empty, since no jig ecosystem ships a
distinct native detector), falls back to an ephemeral
npx jscpdwhennpxis onPATH(the Node analogue ofpipx run, works on any language, installs nothing), and otherwise emitsduplication: skipped (no detector) — install a duplication tool or Node (npx jscpd) to enable. When it runs, the summary is a tight percentage + the top clones asfile:line("duplication: 4.2% (12 clones); top: foo.py:10, bar.py:88") — never the raw jscpd log. Like the other advisory signals it is reported, never gating (it cannot change the exit code).
- Python — complexity: an advisory ruff probe with
- Normalizes the primary linter's exit code:
0— clean (no findings)1— findings exist (the linter ran and reported issues)2— no linter resolvable, no recognized ecosystem, OR the resolved tool failed to start
- Degrades gracefully (AC4), never a stack trace:
- no markers → exit
2+ "no recognized ecosystem (Python/Node) found — set .jig/lint-command to run your linter". - one ecosystem, no resolvable linter → exit
2+ an ecosystem-specific recommendation (ruff/pipx for Python; eslint/npx for Node). - mixed (2+ ecosystems) → exit
2+ a recommendation naming the detected ecosystems and pointing at.jig/lint-commandto disambiguate.
- no markers → exit
It installs nothing — uvx / pipx / npx run the tools ephemerally
only if those launchers are already on PATH.
Helper invocations
Two subcommands mirror tdd.py: detect reports which linter resolves, and
check runs it.
Detect the linter
python3 "${CLAUDE_PLUGIN_ROOT}/skills/code-health/health.py" detect [target]targetdefaults to.when omitted.- Stdout: the resolved primary linter name across ecosystems (
ruff,uvx ruff,pipx run ruff,eslint, ornpx eslint). - Exit
2with a recommendation on stderr if nothing resolves (no recognized ecosystem, no resolvable linter, or a mixed project needing disambiguation).
Run the lint pass
python3 "${CLAUDE_PLUGIN_ROOT}/skills/code-health/health.py" check [target]- Auto-resolves the ecosystem's linter via the same logic as
detect. - Prints a tight summary (count + top rule codes) to stdout, plus any advisory lines (Python complexity / Python pyright / Node prettier / cross-ecosystem duplication) — advisory lines are reported but never change the exit code.
- Exit code is normalized off the primary linter (
0clean /1findings /2no-linter) per the table above. Branch on it deterministically — exit1means inspect the summarized findings; exit2means the tool couldn't even start, no ecosystem was recognized, or a mixed project needs.jig/lint-commanddisambiguation — not "the code is clean".
Override the auto-detection
Create <target>/.jig/lint-command with the first non-blank, non-comment
line being the exact command to run. It is honored verbatim, takes
priority over all auto-detection, and bypasses ecosystem detection
entirely — the same semantics as tdd.py's .jig/test-command. Useful for
a project whose linter isn't ruff/eslint (e.g. flake8 src or pylint
mypkg), or to disambiguate a mixed Python+Node repo. (This is how jig's own
CI is unaffected — jig commits a .jig/lint-command.)
When NOT to use
- Running tests — that's
/jig:tdd-loop(tdd.py). Static analysis and the test loop are different cadences. - Security review — that's
/jig:security-review; this skill is about lint / style / correctness signals, not vulnerabilities. - Spec-compliance review of a finished slice —
/jig:independent-review. - General PR craft review —
/jig:pr-review. - Pure-documentation edits that touch no code.
Relationship to other skills
health.py is the static-analysis sibling of tdd-loop's tdd.py — same
detect → drive → normalize → degrade shape, same .jig/*-command override
idiom, same 0 / 1 / 2 exit contract. Per ADR-0002
the shared idioms (_read_text_safe / _custom_command_file /
_parse_custom_command) are inline-mirrored, not extracted into a
_common module — this is only the second helper of its kind, and the two
have independent lifecycles. The deliberate duplication is noted in
health.py's module docstring (exactly as tdd.py documents its own
duplication of scaffold.py).
The code-health review pass (slice 060-05)
Beyond the health.py runner, jig wires a distinct code-health review
pass into the post-implementation flow (alongside compliance / craft /
arch). The layering (ADR-0017):
the spine runs the tool (health.py), and a read-only reviewer
subagent judges its tight summary — rendering the judgment a static tool
can't: is reported duplication within the ADR-0002
inline-mirror budget (two callers may mirror; a third triggers an extract)?
is a flagged complex function inherent or fixable? are the lint findings
worth blocking on?
- The reviewer never runs
health.py. It is read-only (Read/Glob/Grep, no Bash). The orchestrator / CI runshealth.py, captures the tight summary, and feeds it into the prompt viareview.py code-health … --summary-file <path>(or--summary-file -to pipe it in — stdin is never read implicitly, bug 017). The reviewer judges the summary, never raw logs. - The pass is GATED, not always-on. It runs only when a slice's
frontmatter declares
code_health_review: true— exactly mirroring howarch_review: truegates the arch pass. Why gated: ADR-0017 flags the per-slice review cost (the spec 055/057 context-cost discipline — every pass adds orchestrator turns + a subagent), and recommends gating it like arch-review rather than spending it on every slice. The flag defaults off, so existing slices are unaffected; a slice author opts in when a change is duplication-/complexity-heavy enough to warrant the judgment. - Evidence + block rule. The verdict is recorded as
docs/specs/NNN-slug/reviews/slice-NN-code-health.md(ADR-0014 evidence model).[blocker]-tagged findings block theREVIEWEDtransition;[nit]-tagged findings become reconciliation-log items — the same rule as the craft/arch passes.workflow.py transitionrequires thecode-healthverdict forREVIEWED/DONEiff the flag is set. Query the flag withworkflow.py code-health-review-needed <spec.md> <slice>.
See skills/spec-workflow/SKILL.md § "After implementation" for the full
four-pass orchestration recipe.
Gotchas
- A configured
review.code_health_skill(scaffold.json) is honored only in the orchestrated code-health pass, not on interactive/jig:code-health. Spec 096-01 / ADR-0040 D1 makescode_healthone of the three extensible categories, so a project can name a richer code-health reviewer inscaffold.json; that key is read byreview.pywhen it builds the code-health pass prompt for the spec-workflow reviewer subagent (before 096-01 that builder had no richer dispatch at all). It is not consulted on this interactive invocation. Config honoring on orchestrator-invoked surfaces is a tracked follow-up (ADR-0040 OQ1). - Scope is Python (ruff, + advisory complexity and pyright) and Node
(eslint, + advisory prettier --check), plus a cross-ecosystem advisory
duplication signal (
npx jscpd). The dedicated code-health reviewer pass (slice 060-05) is now live — see "The code-health review pass" above; the Tier-2 scaffold-the-floor work (slice 060-06) is DEFERRED. An unrecognized ecosystem with no.jig/lint-commandoverride degrades to a recommendation. - Advisory ≠ gating. The complexity and pyright (Python), prettier
(Node), and duplication (cross-ecosystem) signals are reported in the
summary but never change the exit code — the exit code is driven solely by the
primary linter (ruff / eslint). A clean ruff run with complexity or
type findings still exits
0. - Duplication is honest about being unavailable. Unlike complexity /
prettier (which stay silent when their tool isn't present), the duplication
probe emits
duplication: skipped (no detector) …when neither a native tool nornpxis available — so a reader knows the dimension was not measured rather than measured clean. It writes jscpd's JSON report to a temp dir outside the project (read back, then removed) so it never pollutes your tree, and runs jscpd without--thresholdso jscpd itself never exits non-zero (advisory, not gating). - The override path runs no advisory probes (including duplication) — it
honors
.jig/lint-commandverbatim without ecosystem detection, so jig's own dogfood CI (which sets an override) is unaffected. - Mixed repos degrade, they don't guess. If both
pyproject.toml(or*.py) andpackage.jsonare present,checkexits2and asks you to set.jig/lint-commandto disambiguate — it never picks one for you. - Exit
1vs2. Exit1means the linter ran and found issues — inspect the summary. Exit2means no linter was resolvable, no ecosystem was recognized, a mixed project needs disambiguation, or the resolved tool failed to start (an environment issue) — don't conflate any of those with clean. - Ephemeral runs need a network/cache.
uvx ruff/pipx run ruff/uvx pyright/pipx run pyright/npx eslint/npx prettier/npx jscpdfetch the tool on first use. If neither the binary nor a launcher is present, the skill recommends (for the primary linter) or reportsskipped(for pyright/duplication) rather than failing opaquely. - Tight summary, not the raw dump.
checkparses the linter's JSON into a count + top codes; it does not echo the full tool output. Re-run the linter directly when you need every finding's location.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

