{"slug": "show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff", "title": "Show HN: Commit-quiz – A pre-commit hook that quizzes you on your own diff", "summary": "Developer Cristopheer96 released commit-quiz, a pre-commit hook that generates 4 statements about a staged diff — 2 true and 2 plausible-but-false — and aborts the commit unless the developer correctly identifies the true ones, aimed at code written by AI agents such as Claude Code, Cursor and Codex. The hook sends the staged diff (truncated to 30 KB) only to the AI CLI the developer already uses (claude, codex or gemini), triggers only on commits with 20 or more changed lines, never on merges, rebases or cherry-picks, and is fail-open: if the LLM does not respond or no dialog backend exists, the commit proceeds with a notice. It requires Node ≥ 18, keeps zero telemetry, excludes lockfiles, *.snap and *.svg by default, and cannot yet run fully local, though the provider table in src/providers.js is designed for contributions such as an Ollama-backed CLI.", "body_md": "A `pre-commit` hook that verifies the developer **actually read their changes**\nbefore committing. Useful when AI agents (Claude Code, Cursor, Codex…) generate\nthe code and the dev just hits \"commit\" without reviewing.\n\nEvery AI code-review tool reviews the code. This one quizzes **you**.\n\n```\nnpm install -g commit-quiz\ncommit-quiz install          # in the repo you want guarded\n```\n\n1. On commit, the hook takes the staged diff (`git diff --cached` ).\n2. It sends it to an AI CLI you already have and generates **4 statements about\nthe diff: 2 true and 2 plausible-but-false** (wrong file, inverted\ncondition, different value…).\n3. The dev marks which ones are true:\n  - **In a terminal** : interactive prompt, with colors.\n  - **From the editor UI** (VS Code, Cursor — no terminal): native dialogs\n(macOS via`osascript` , Linux via`zenity` when installed), including a\n\"generating…\" heads-up and a verdict dialog with the real summary when\nthe answer is wrong.\n4. On a correct answer the commit goes through. On a wrong one the commit is\naborted and the **real summary** of the diff is shown.\n\nThe hook is **fail-open**: if the LLM does not respond, there is no network, or\nthere is no way to ask, the commit goes through with a notice. A gate that gets\nin the way ends up disabled; this one only gets in the way when it can do its\njob.\n\n**What is sent?** The staged diff (`git diff --cached`, unified context of 1\nline), truncated to 30 KB, plus a fixed instruction prompt. The diff carries\nthe paths of the changed files in its headers, as any diff does. Nothing else:\nno repo name, no git history, no author identity, no other files.\n\n**To whom?** Only to the AI provider you already use, through its own CLI and\nunder your own account: `claude` → Anthropic, `codex` → OpenAI, `gemini` →\nGoogle. The diff goes from your machine to that provider's API, the same path\nit takes when you use the CLI directly. There is no commit-quiz server, no\nshared key and no middleman. Which provider is used is yours to pin with\n`git config commit-quiz.cli`.\n\n**When?** Only on commits with 20 or more changed lines (configurable), and\nnever on merges, rebases or cherry-picks. Everything below the threshold is\nnever sent anywhere.\n\n**What does commit-quiz keep?** Nothing. There is **zero telemetry**. The\noptional debug log (off by default) records timings, the chosen channel and\nyour answers, never the diff.\n\n**What is excluded by default?** Lockfiles (`pnpm-lock.yaml`, `package-lock.json`,\n`yarn.lock`, `Gemfile.lock`, `Podfile.lock`), `*.snap` and `*.svg`.\n\n**How do I keep sensitive paths out?** Add git pathspecs, per repo or\n`--global`; the option is repeatable:\n\n```\ngit config --add commit-quiz.exclude \"config/credentials/**\"\ngit config --add commit-quiz.exclude \"*.pem\"\ngit config --add commit-quiz.exclude \"db/seeds/customers.rb\"\n```\n\nExcluded files are not sent and do not count toward the line threshold.\n\n**How do I skip it for one commit?** `COMMIT_QUIZ=0 git commit …` (or\n`--no-verify`, which skips every hook).\n\n**Can it run fully local?** Not yet. Providers are a small table in\n`src/providers.js`; a local CLI (for example one backed by Ollama) would be a\nfew lines, and contributions are welcome.\n\nIf sending diffs to your AI provider is not acceptable in your organization, do not install this tool.\n\n- Node ≥ 18.\n- Some AI CLI on the PATH: [Claude Code](https://claude.com/claude-code) (`claude` ), OpenAI Codex CLI (`codex` ) or Gemini CLI (`gemini` ). The first\none found is used, or the one set via config.\n- Native dialogs: macOS out of the box; Linux needs `zenity` . Without a dialog\nbackend, editor-UI commits fail open (terminal commits always work).\n\nOnce per machine:\n\n```\nnpm install -g commit-quiz        # once published to npm\nnpm install -g github:Cristopheer96/commit-quiz   # meanwhile, straight from GitHub\n```\n\nThen, once per repo you want guarded:\n\n```\ncd /path/to/repo\ncommit-quiz install\n```\n\nThat appends the hook line to `.husky/pre-commit` if the repo uses husky,\notherwise to `.git/hooks/pre-commit`. Idempotent. To remove it:\n\n```\ncommit-quiz uninstall\n```\n\nWhy once per repo? Git only runs hooks configured in each repository — that is\ngit's design, not the tool's. In husky repos the hook line is versioned, so\n**one teammate commits it and the whole team gets it**; each dev only needs the\none-time `npm install -g`.\n\n```\ncd /path/to/repo\ncommit-quiz --range HEAD~1..HEAD --dry-run   # quiz over the last commit, answers visible\ncommit-quiz --range HEAD~1..HEAD             # same but interactive\ncommit-quiz --diff-file changes.diff --dry-run\n```\n\nEvery option reads, in order: **environment variable → `git config` → default**.\n`git config` can be per repo or `--global`, and it also reaches hooks launched\nfrom editor UIs, where your shell environment does not.\n\n| Env var | git config key | Default | What it does | \n|---|---|---|---|\n| `COMMIT_QUIZ=0` | — | — | Skips the quiz for that commit (escape hatch) | \n| `COMMIT_QUIZ_MIN_LINES` | `commit-quiz.minlines` | `20` | Minimum changed lines to trigger the quiz | \n| `COMMIT_QUIZ_CLI` | `commit-quiz.cli` | auto | Provider: `claude` ,`codex` or`gemini` | \n| `COMMIT_QUIZ_MODEL` | `commit-quiz.model` | `haiku` (claude only) | Model that generates the quiz | \n| `COMMIT_QUIZ_LANG` | `commit-quiz.lang` | system locale | Quiz and UI language: `en` or`es` | \n| `COMMIT_QUIZ_TIMEOUT_MS` | `commit-quiz.timeoutms` | `90000` | LLM call timeout | \n| `COMMIT_QUIZ_DEBUG=1` | `commit-quiz.debug` | off | Appends a debug log in the temp dir | \n| — | `commit-quiz.exclude` (repeatable) | lockfiles, `*.snap` ,`*.svg` | Extra pathspecs kept out of the quiz | \n\nThe quiz and all messages are available in **English and Spanish** (adding a\nlanguage is one new entry in `src/i18n.js`). It also skips itself on merges,\nrebases and cherry-picks in progress.\n\nEditor-spawned hooks have no visible output. With `COMMIT_QUIZ_DEBUG=1` (or\n`git config commit-quiz.debug true`) every run appends decisions and timings to\n`commit-quiz-debug.log` in your temp dir.\n\n|  | Terminal commits | Editor-UI commits | \n|---|---|---|\n| macOS | ✅ | ✅ native dialogs | \n| Linux | ✅ | ✅ with `zenity` , fail-open without | \n| Windows | ✅ (expected; untested) | fail-open | \n\n```\nbin/commit-quiz.mjs   thin CLI entry (args + top-level flow)\nsrc/config.js         env + git config resolution\nsrc/i18n.js           all user-facing copy (en, es)\nsrc/diff.js           reading the diff out of git\nsrc/providers.js      AI CLIs (claude/codex/gemini) + quiz generation\nsrc/ui/terminal.js    terminal prompt and rendering\nsrc/ui/dialogs.js     native dialogs (osascript / zenity)\nsrc/install.js        hook install/uninstall\n```\n\nNo dependencies, no build step — plain Node ESM with JSDoc types. Releases are\ntagged `vX.Y.Z` and published to npm by the `release.yml` workflow (requires\nthe `NPM_TOKEN` repo secret); see `CHANGELOG.md`.\n\n- `git commit --no-verify` skips it, like any hook. The goal is culture, not\nsecurity.\n- Each quiz is one LLM call: ~8-15 s and some cost per commit. Hence the line threshold, the cheap default model, and thinking disabled.\n- Statements are only as good as the diff: huge diffs are truncated to ~30 KB and the quiz may fall short.", "url": "https://wpnews.pro/news/show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff", "canonical_source": "https://github.com/Cristopheer96/commit-quiz", "published_at": "2026-10-22 05:11:12+00:00", "updated_at": "2026-10-22 05:42:41.547170+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents", "ai-products"], "entities": ["commit-quiz", "Cristopheer96", "Claude Code", "Cursor", "OpenAI Codex CLI", "Gemini CLI", "Anthropic", "OpenAI"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff", "markdown": "https://wpnews.pro/news/show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff.md", "text": "https://wpnews.pro/news/show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff.txt", "jsonld": "https://wpnews.pro/news/show-hn-commit-quiz-a-pre-commit-hook-that-quizzes-you-on-your-own-diff.jsonld"}}