Pre-Commit Checks (Full)
SkillDev toolsPre-commit checks — lint:fix -> build -> test
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Pre-Commit Checks (Full) skill
What this skill tells your AI
The instructions your AI receives, as published by sd0xdev/sd0x-harness in skills/precommit/SKILL.md and read by ahel’s review.
Trigger
- Keywords: precommit, pre-commit, lint and test, quality gate
When NOT to Use
- Quick checks without build (use
/precommit-fast) - Verification loop without lint:fix (use
/verify) - Just running tests (run directly)
Workflow Steps
| Step | Goal | Safety | Skip if Missing |
|---|---|---|---|
| comment_blocks | Reject over-long comment blocks (@rules/docs-writing.md § Code Comments) | read-only | yes |
| lint-fix | Auto-fix code style issues | read-write | yes |
| build | Verify compilation succeeds | read-only | yes |
| test-unit | Run full test suite | read-only | yes |
Failure behavior: continue-all (run all steps, report all results)
comment_blocks is a policy step, and the asymmetry is deliberate (POLICY_STEPS in scripts/precommit-runner.js): it can FAIL the run, but it never counts as "validation ran". A run where policy was the only thing that executed still reports ⚠️ NO CHECKS RUN, so a repo whose real checks are pytest/cargo cannot bank a ✅ PASS on a passing comment scan alone. It runs first because it is static and cheap.
Task
Run pre-commit checks: lint:fix -> build -> test
Step 1: Check for runner script
Use Glob to check if .claude/scripts/precommit-runner.js exists in the project root.
- Found → run:
node .claude/scripts/precommit-runner.js --mode full --tail 80- If runner emits
## Overall: ✅ PASS, use its output and skip to the Output section. - If runner emits
## Overall: ⚠️ NO CHECKS RUN, do NOT treat it as a pass — fall through to Step 2 ecosystem detection so the project's real checks run. The marker means no project validation executed and no policy step failed — every validation step was a skip orunavailable, and any policy step (comment_blocks) either skipped or passed (a FAILING policy step is❌ FAIL, never this marker — line 30's asymmetry) — whether because the repo declares no runnable checks or because the required tools were not available to the runner (which orchestrates the ecosystem table below itself: it detects pyproject.toml/Cargo.toml/go.mod/… and runs those checks as first-class steps). The runner self-notes its own verdict (review-state.js note precommit pass|fail); on⚠️ NO CHECKS RUNit notes nothing — the slot is untouched and the reminder persists, which is the correct reading of "nothing validated". - If runner fails (
## Overall: ❌ FAIL), treat as a real precommit failure (do not silently fallback).
- If runner emits
- NOT found → Auto-install attempt (see precommit-fast for identical auto-install logic), then fallback to Step 2.
Step 2: Fallback (no runner script)
Detect the project ecosystem to run steps manually.
Ecosystem detection:
| Manifest | Ecosystem | Lint-fix | Build | Test |
|---|---|---|---|---|
package.json | Node.js | {pm} lint:fix | {pm} build | {pm} test:ci / test / test:fast / test:unit |
pyproject.toml | Python | ruff check --fix . | — | pytest tests/unit/ |
Cargo.toml | Rust | cargo clippy --fix | cargo build | cargo test |
go.mod | Go | golangci-lint run --fix | go build ./... | go test ./... |
build.gradle / build.gradle.kts | Java (Gradle) | ./gradlew spotlessApply | ./gradlew build | ./gradlew test |
pom.xml | Java (Maven) | mvn spotless:apply | mvn compile | mvn test |
Gemfile | Ruby | bundle exec rubocop -a | — | bundle exec rspec |
How the runner executes this table (WB2b): a required tool missing from the environment (ruff, pytest, cargo, go, golangci-lint, mvn, bundle, the gradle wrapper — the runner never falls back to a global
gradle) marks that stepunavailable, which blocks ✅ PASS — incomplete validation must not let a sibling check mint the receipt. A repo-declared capability absent is an ordinary skip, but only on definitive non-membership evidence — never a manifest grep, and never an ambiguous probe failure (broken build config, broken task, network-dependent resolution), which staysunavailable: Ruby rubocop/rspec membership is read fromGemfile.locktext — rspec countsrspecor its executable providerrspec-core— afterbundle checkpasses (a failingbundle checkor unreadable lockfile isunavailable); Gradle spotless skips only on Gradle's ownTask 'spotlessApply' not founddiagnostic fromgradlew help --task spotlessApply(a marker-less failure isunavailable— Gradle realizes tasks lazily, so a configured-but-broken task fails the probe exactly like an absent one); Maven spotless skips only on theNo plugin found for prefixmarker frommvn help:describe -Dplugin=spotless— any other failure isunavailable. All probes are bounded (PRECOMMIT_PROBE_TIMEOUT_MS, default 120s; output capped) and logged; a probe timeout isunavailable, never a skip. Python tests runpytest tests/unit/when that directory exists, else barepytest(config-driven discovery — a repo with no tests fails loudly on exit 5 instead of silently skipping). Clippy runs with--allow-dirty --allow-staged: precommit operates on a dirty tree by definition.
For Node.js projects, auto-detect package manager from lockfile.
| Step | package.json script | If missing |
|---|---|---|
| lint:fix | lint:fix | Skip with note |
| build | build | Skip with note |
| test | test:ci → test → test:fast → test:unit | Skip with note |
After lint:fix completes, run git diff --name-only to capture auto-fixed files.
After a conclusive fallback run, self-note the outcome — the runner cannot see a run it did not
perform, and the rounds count stays path-independent (a failure is a failure whichever engine ran
it):
CHECKER=".claude/scripts/review-state.js"; [ -f "$CHECKER" ] || CHECKER="scripts/review-state.js"
node "$CHECKER" note precommit pass # every executed check passed
node "$CHECKER" note precommit fail # the checks ran and at least one failed
An inconclusive run (the checks could not execute at all) notes nothing — exactly like the
runner's ⚠️ NO CHECKS RUN: the slot stays untouched and the reminder persists. The note is
advisory; a failed note is reported and never fails the run.
Output
## Precommit (full)
## Results
| Step | Status | Notes |
|------|--------|-------|
| lint:fix | ✅/❌/⏭️/⛔ | ⏭️ = repo opted out (skip); ⛔ = required tool unavailable (blocks PASS) |
| build | ✅/❌/⏭️/⛔ | same legend |
| test | ✅/❌/⏭️/⛔ | same legend |
## Changed Files (after lint:fix)
- <files or "(none)">
## Overall: ✅ PASS / ❌ FAIL / ⚠️ NO CHECKS RUN (no project validation executed AND no policy step failed — validation steps all skipped/unavailable, policy steps skipped or passed; fall through to Step 2, needs human if nothing runnable exists)
## Checklist
- [ ] All available checks pass
- [ ] git status reviewed
Signals
- GitHub stars
- 188
- Forks
- 24
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
precommit-sd0xdev- Source
- github.com/sd0xdev/sd0x-harness