grít
- Go
- SQLite
- git
The problem
Version control keeps what changed but not why. Six months later nobody remembers why the auth layer was refactored, what a pasted block of AI code was meant to do, or what went wrong in a reverted commit. The reasoning lived in a developer's head, and it was gone by the next sprint.
grít is a command-line tool that captures that thinking at the moment it exists. It adds small, purposeful friction at the points where context is most valuable, a commit, a revert, or a long stretch in one file, and stores the answers in a SQLite file inside your repository. There is no cloud and no account.

How it fits into a workflow
grit init installs three small git hooks and creates a config file and a database under .grit/. From then on the tool works from two places: the hooks, which fire on git events, and an opt-in watcher you run in a second terminal.

Three principles shaped the design:
- It must never get in the way. Every hook exits with code 0, and a recover guard turns any internal failure into a clean exit. If there is no terminal, as in CI, the interview is skipped and recorded instead of blocking the commit.
- Your data stays yours. Everything is a local SQLite database in WAL mode, so the watcher and a commit hook can write at the same time. There is no network use by default, and data can be exported to Markdown or JSON.
- Friction should be targeted. Questions depend on what you actually changed, rather than a fixed form on every commit.
The commit interview
At each commit, the pre-commit hook reads the staged diff and chooses questions to match it. A diff over 200 lines asks whether it should be split, a new file asks what contract it owns, a test-only commit asks which edge case drove it, and a config change asks what breaks if the value is wrong. A second question comes from a configurable pool that avoids anything asked recently.

Answers can start with a tag such as [debug] or [design], which later groups them in the digest. Reverts are handled differently, with a three-question post-mortem: what went wrong, whether it was caught in review or reached production, and what would have caught it earlier. Merges, fixups, squashes, WIP commits and amends are skipped, and a snooze pauses everything for a set time without uninstalling anything.
The real-time watcher
grit watch is deliberately not a daemon. It runs when you start it, watches the repository recursively and ignores .git, node_modules and vendor. Saves are debounced for 200 ms and then analysed for signals that something is worth a question:
- Complexity. A file over the threshold prints a per-function breakdown against a running average.
- Vague names. New lines containing identifiers like
tmp,resultorhandleDataget a language-aware naming prompt. - AI assistance. Adding 15 or more lines asks whether the code was AI-assisted and what was verified.
- Paste check. Adding 30 or more lines asks whether you understand what you pasted.
- Undo spike. Deleting 20 or more lines asks whether it was a wrong turn or intentional cleanup.
- Dead time. Forty minutes in the same file without progress prompts a focus check-in.
Every threshold is configurable in .grit.yaml.
Using what it collected
Capture only matters if the data comes back out usefully.
grit logshows a timeline grouped by day, filterable by event type, date, skipped prompts, or the interview linked to a specific commit hash.grit decisionruns a four-question interview to record an architectural decision, covering the forcing constraint, the alternatives, the choice and its reasoning, and what is given up. It exports to dated ADR-style Markdown files.grit reflectis an end-of-day check with the day's counts and two rotating questions.grit statsgives a weekly summary with a streak and top tags, a complexity sparkline for a single file, a 12-week heatmap of friction density, and a digest grouped by tag.grit pushexports to Markdown or JSON for a date range.
Engineering details worth noting
- Complexity without parsers. The score is a keyword-counting heuristic: a base of 1 plus each branch or loop keyword and each
&&or||, with comments skipped. It approximates cyclomatic complexity across Go, Python, JavaScript and TypeScript, Rust and Java without a parser for each language. Function boundaries are found with per-language declaration patterns so the total can be broken down per function. - Prompts inside git hooks. Git redirects a hook's standard input, so a normal prompt cannot read the keyboard. grít checks for a terminal device directly, using
CONIN$on Windows and/dev/ttyelsewhere, and its Bubble Tea prompts read from that. The prompts work inside a hook, and skip cleanly when there is no terminal. - Hooks that coexist. Installing hooks appends to existing ones instead of replacing them, and
grit removeunregisters grít's lines without touching other hook logic. - Linking answers to commits. The pre-commit hook runs before a commit has a hash, so a post-commit hook records the hash against the interview. That makes it possible to look up why a specific commit was made.
The website
grít has its own site, built with Next.js 16, React 19 and Tailwind CSS 4. The landing page walks through the pain points, the idea of purposeful friction, how it works, the feature set and the friction signals, with a data-driven terminal demo in the hero. The documentation page renders a Markdown reference with a sticky sidebar generated from its headings.

Stack
The CLI is written in Go. Cobra provides the commands, Bubble Tea and Lip Gloss the terminal interface, fsnotify the file watching, Viper the configuration, and SQLite the storage, which needs a C compiler to build because of the CGO-based driver.
Limits
The complexity score is a heuristic that approximates cyclomatic complexity and does not replace a real analyser. Building from source needs GCC on every platform, and the first build is slow while SQLite compiles. Everything is scoped to a single repository by design, so there is no cross-project view.