shima.me

Serge Shima / Work and projects

code-quality

Deterministic code quality gate for AI coding agents (Claude Code, Codex, pi): git hooks that block test tampering, hold the CRAP bar on changed functions, check diff coverage, secrets and dependencies. 12 languages, one config file. Optional Jev classifier for test hunks.

TypeScript · 20 GitHub stars · Snapshot

GitHub · Full documentation

From the project documentation

An excerpt in the original language from the README. Current instructions, requirements and license are maintained in the repository.

Code Quality **Your AI agent made the tests green. Did it fix the code, or the tests?** A quality advisor for coding agents: git hooks and Stop hooks that raise a loud red flag on test tampering, secrets and skipped hooks, and hold one complexity bar on every changed function. They never block: the agent sees the evidence and decides. 12 languages, one config file, no server. Advice, not a gate Nothing here stops the agent. No hook refuses a commit, a push, a shell command or the end of a turn. The plugin trusts the model the way a good reviewer trusts a colleague: it measures, shows its work and says plainly when something is dangerous. The agent decides, and says why. Dangerous moves are red flags, printed first in every output: Red flags: a secret in the change or in the pushed history, a deleted, skipped or weakened test, a baseline refreshed with the code, red tests on push, and a git command that skips the hooks (`--no-verify`, `commit -n`, `core.hooksPath`). Everything else (complexity, CRAP, diff coverage, cycles, dead code, clones, glossary, AI attribution, Jev) is a finding or a note in the report. What's new in 1.3 - **Advice, never a block (1.3.3).** No hook stops a commit, a push, a shell command or the end of a turn. Dangerous moves are `RED FLAG` lines, first in every output; the Stop report reaches the agent once, with its next message. - **Accept a change by its own tests.** `check --since --tests` runs every test that reaches the change through the project's imports, with coverage, and judges only the changed functions. - **Prove a test catches a bug.** `mutant` makes one exact mutation, runs the tests and restores the file byte for byte, even after Ctrl-C. - **The report is about the pushed commit.** When a push has touched tests to run, pre-push runs them only on the checked-out commit and says so otherwise. - **Calm on a shared machine.** Test runs wait for a busy machine, Ctrl-C kills the whole test group, and a copy run by hand no longer takes the machine's git hooks. Full notes: releases. The cheap way out, caught The agent | The report | ---|---| Marked the failing test `it.skip` | `tamper/test-skipped tests/queue.test.ts:12` | Dropped two assertions | `tamper/assertion-weakened tests/queue.test.ts:48` | Swapped `toEqual` for `toBeTruthy` | `tamper/assertion-weakened tests/queue.test.ts:52` | Stubbed the module under test | `note: tamper/mock-added tests/queue.test.ts:+64` | Refreshed the baseline with the code | `tamper/baseline-touched baseline.json:1` | Shipped 50 lines, 31 covered | `cov/diff: 62% (31/50 lines, minimum 80%)` | Deterministic: file and line in the report, red flags first. No model is asked for an opinion, and the commit still goes through; the agent answers the flag. How it works - **One bar.** Cyclomatic complexity 10, CRAP 30, 80% coverage of added lines, no new cycles, no new dead code, no secrets. - **Old debt is not news.** A baseline snapshot keeps existing findings as debt. Only new findings on changed lines are reported. - **Seconds, not minutes.** `check` runs in 3-19 s on a real repo. The full run with tests and coverage is a manual one: a debt measurement, not a verdict on a change. - **Acceptance on the change.** `check --since --tests` runs the change's touched tests with coverage and reports on the change with it. `check` exits 1 on findings so a script or CI can decide; no hook turns that into a stop. `mutant` proves a test catches one exact bug and always restores the file. - **Any language.** Complexity from lizard, coverage from lcov, adapters for TypeScript, Python, Go, Rust, Java, Kotlin, C#, Swift, PHP, Ruby, C/C++, Dart. Install Bun is required for the gate and the shell hooks. Install for your agent: Agent | Install | ---|---| Claude Code | `claude plugin marketplace add smixs/code-quality` then `claude plugin install code-quality@code-quality` | Codex | `codex plugin marketplace add smixs/code-quality` then `codex plugin add code-quality@code-quality`; review and trust its hooks with `/hooks` | Grok 1.0.40 | `grok plugin install smixs/code-quality --trust`, then from this repository or its installed plugin root run `bun scripts/quality.ts install-grok-hooks` | pi | `pi install git:github.com/smixs/code-quality` | omp | `omp plugin install github:smixs/code-quality` | OpenCode V1 | `bun add github:smixs/code-quality` in a project with `package.json`, then add `"plugin": ["file:./node_modules/code-quality"]` and `"skills": ["./node_modules/code-quality/skills"]` to `opencode.json` | OpenCode V2 | Add `"plugins": ["github:smixs/code-quality"]` to `opencode.json` | Skill only | `npx skills add smixs/code-quality` (does not install hooks) | Claude and Codex load Stop, UserPromptSubmit and PreToolUse hooks from the plugin. The Stop hook never holds the turn: the user sees the red flags at once, and the agent gets the full report once, with its next message (UserPromptSubmit). Grok 1.0.40 did not dispatch plugin hooks in a live check (`total_hooks=0`); `install-grok-hooks` writes `~/.grok/hooks/code-quality.json` with both commands pointing to the current plugin root; Grok drops UserPromptSubmit context, so there the Stop report reaches the user only. Run it again after moving or updating that root; `bun scripts/quality.ts uninstall-grok-hooks` removes that file. `$GROK_HOME` overrides the Grok directory. pi and omp load the package extensions: a red flag is added to the shell command's result, the Stop report goes to the next turn. OpenCode adds the red flag after the shell command and writes the Stop report into the session on idle without a reply. OpenCode V1.18.32 reads the plugin's `config.skills` value but does not discover the skill from it. Add an explicit `"skills": ["./node_modules/code-quality/skills"]` entry to `opencode.json` when using a project Bun installation. In Git repositories with `.quality.toml`, `git commit --no-verify`, `git commit -n`, `git push --no-verify`, `git -c core.hooksPath=...` and `git config core.hooksPath` run as asked and get a red flag next to their output. Set `[hooks] flag_bypass = false` in `.quality.toml` to silence it (`block_bypass`, the old name, is still read). To enable the plugin for a team repository, commit these project settings: For Codex, commit `.codex/config.toml`: Wire each Git repository with a `.quality.toml` and a baseline. From the plugin checkout or installed package root:

Source retrieved · README 6465c4b7a839

About the author

Serge Shima is co-founder and CTO of Majento in Tashkent and founder of Aimasters. He builds AI products and open-source tools for agents.

All repositories · github.com/smixs