agentsclimarketplace

Code health

Skill ramboz/jig/skills/code-health

A Claude Code and Codex plugin that scaffolds AI-native development practices into new projects. jig adds a repeatable spec, implementation, review, and memory workflow to AI-assisted software projects.

Install
npx -y skills add ramboz/jig --skill code-health

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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`).

SKILL.md

13.1 KB, as published. Nobody here has run it

Spec 060 introduced code-health as the static-analysis sibling of tdd-loop, under ADR-0017's "detect the language → drive its blessed tools → normalize → degrade gracefully" framing. Like tdd.py, the deterministic detection + subprocess invocation live in health.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-command override always wins and bypasses ecosystem detection entirely (honored verbatim — same semantics as tdd.py's .jig/test-command).
  • Otherwise detects the ecosystem by marker files (pyproject.toml / *.py for Python; package.json for Node) and resolves its primary linter:
    • Pythonruff on PATHuvx ruffpipx run ruff (ephemeral), invoked as ruff check --output-format=json <dir>.
    • Nodeeslint on PATHnpx eslint (ephemeral), invoked as eslint --format json <dir>.
  • 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,PLR0915 surfaces a per-function complexity signal ("complexity: N function(s) over threshold; top: …").
    • Python — type checking: an advisory pyright --outputjson probe resolves pyright on PATH, then uvx pyright, then pipx run pyright. Type diagnostics are summarized as a count + representative rules ("pyright: N type diagnostic(s); top: …"). If no type-checker resolves, it emits pyright: skipped (no type-checker) …. Like every advisory signal, it is reported, never gating.
    • Node — formatting: an advisory prettier --check probe 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 jscpd when npx is on PATH (the Node analogue of pipx run, works on any language, installs nothing), and otherwise emits duplication: 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 as file: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).
  • 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-command to disambiguate.

It installs nothinguvx / 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]
  • target defaults to . when omitted.
  • Stdout: the resolved primary linter name across ecosystems (ruff, uvx ruff, pipx run ruff, eslint, or npx eslint).
  • Exit 2 with 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 (0 clean / 1 findings / 2 no-linter) per the table above. Branch on it deterministically — exit 1 means inspect the summarized findings; exit 2 means the tool couldn't even start, no ecosystem was recognized, or a mixed project needs .jig/lint-command disambiguation — 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 runs health.py, captures the tight summary, and feeds it into the prompt via review.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 how arch_review: true gates 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 the REVIEWED transition; [nit]-tagged findings become reconciliation-log items — the same rule as the craft/arch passes. workflow.py transition requires the code-health verdict for REVIEWED/DONE iff the flag is set. Query the flag with workflow.py code-health-review-needed <spec.md> <slice>.

See skills/spec-workflow/SKILL.md § "After implementation" for the full four-pass orchestration recipe.

Gotchas

  • 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-command override 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 nor npx is 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 --threshold so jscpd itself never exits non-zero (advisory, not gating).
  • The override path runs no advisory probes (including duplication) — it honors .jig/lint-command verbatim 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) and package.json are present, check exits 2 and asks you to set .jig/lint-command to disambiguate — it never picks one for you.
  • Exit 1 vs 2. Exit 1 means the linter ran and found issues — inspect the summary. Exit 2 means 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 jscpd fetch the tool on first use. If neither the binary nor a launcher is present, the skill recommends (for the primary linter) or reports skipped (for pyright/duplication) rather than failing opaquely.
  • Tight summary, not the raw dump. check parses 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.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.