Metadata-Version: 2.5
Name: grip-hook
Version: 0.4.1
Summary: A git hook that won't let you push code you can't explain: it quizzes you on your own diff, or makes you defend it at a whiteboard.
Project-URL: Homepage, https://github.com/guilyx/grip
Project-URL: Documentation, https://guilyx.github.io/grip/
Project-URL: Repository, https://github.com/guilyx/grip
Project-URL: Issues, https://github.com/guilyx/grip/issues
Project-URL: Changelog, https://github.com/guilyx/grip/blob/main/CHANGELOG.md
Project-URL: Releases, https://github.com/guilyx/grip/releases
Author-email: "Erwin L." <erwin.lejeune15@gmail.com>
License-Expression: BSD-3-Clause
License-File: LICENSE
Keywords: ai,claude-code,code-review,codex,cursor,developer-tools,git,git-hooks,llm,pre-commit,pre-push,quiz,whiteboard
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Version Control :: Git
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anthropic<2,>=1.0
Requires-Dist: click>=8.1
Requires-Dist: pydantic>=2.5
Requires-Dist: rich>=13.7
Provides-Extra: demo
Requires-Dist: fonttools>=4.40; extra == 'demo'
Requires-Dist: imageio-ffmpeg>=0.5; extra == 'demo'
Requires-Dist: pillow>=10.0; extra == 'demo'
Requires-Dist: pyte>=0.8; extra == 'demo'
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs<2,>=1.6; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
Description-Content-Type: text/markdown

# grip

**A git hook that won't let you push code you can't explain.**

[![CI](https://github.com/guilyx/grip/actions/workflows/ci.yml/badge.svg)](https://github.com/guilyx/grip/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/grip-hook)](https://pypi.org/project/grip-hook/)
[![Python](https://img.shields.io/pypi/pyversions/grip-hook)](https://pypi.org/project/grip-hook/)
[![Docs](https://img.shields.io/badge/docs-guilyx.github.io%2Fgrip-ff8644)](https://guilyx.github.io/grip/)
[![License: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://github.com/guilyx/grip/blob/main/LICENSE)

![grip whiteboard: the change drawn as parts and arrows, with a question about a malicious client pinned to it](https://raw.githubusercontent.com/guilyx/grip/main/docs/assets/whiteboard.png)

Before your code leaves your machine, grip reads the diff and asks you about it: why it is
built this way, where it fails, what a malicious caller could do, how you know it works.
In the terminal, or on a whiteboard of your change in the browser. A model grades your
answers out of 100. Below your team's pass mark, the push waits.

It checks the developer, not the code. Let AI write it; just be able to defend it.

> "If I ask 'why did you do X instead of Y?', 'what happens if this actor behaves
> maliciously?' [...] you should be able to answer confidently."
> Mitchell Hashimoto, on [the whiteboard defense](https://guilyx.github.io/grip/whiteboard-defense/)
> (not affiliated with grip)

## Try it in 30 seconds

No hook, no account, no API key: the `fake` provider asks scripted questions offline.

```bash
pipx install grip-hook                 # or: uv tool install grip-hook
mkdir try-grip && cd try-grip && git init -q
echo 'def add(a, b): return a + b' > math.py && git add math.py
grip quiz --provider fake              # five questions in your terminal
grip whiteboard --provider fake        # the same, drawn in your browser
```

Nothing is blocked until you install the hook with `grip init`.

## Features

- **Five questions from your diff**, graded against a hidden rubric into a Grip Score out
  of 100. Never line numbers or trivia.
- **`grip whiteboard`**: your change drawn as parts and arrows in the browser, with the
  questions pinned to it, including what a malicious actor could do. Set
  `hook_mode = "whiteboard"` and every push is defended there.
- **Works with what you have**: reuse Claude Code, Codex or Gemini CLI as the model (no
  API key), or use Anthropic, any OpenAI-compatible API, or Ollama locally.
- **Inside coding agents**: `/grip` in Claude Code, Codex, Gemini CLI, Cursor and others,
  and a gate that keeps the agent from pushing until you pass.
- **Out of the way when it should be**: a passed diff is remembered, a retry reuses its
  questions so only grading costs a call, `grip skip` lets one push through, CI and
  non-interactive runs are skipped.

## Installation

```bash
pipx install grip-hook        # or: uv tool install grip-hook
```

Python 3.11 or newer, on Linux, macOS or Windows. This installs the `grip` command and a
`git grip` alias.

## Quick start

![grip blocking a push with lazy answers, then letting it through after real ones](https://raw.githubusercontent.com/guilyx/grip/main/docs/assets/demo.gif)

```bash
cd your-repo
grip init        # writes .grip.toml, installs the pre-push hook
git push         # grip asks five questions first
```

`grip init` picks Claude Code, Codex or Gemini CLI as the model when one is installed.
Otherwise set `ANTHROPIC_API_KEY`, or see [Providers](https://guilyx.github.io/grip/providers/).

Other commands you will use:

```bash
grip quiz                  # quiz your staged changes now, no hook needed
grip quiz --branch         # quiz the whole branch since main: your pull request
grip whiteboard            # defend the change in the browser
grip quiz --provider fake  # try it offline with a scripted grader
grip skip                  # let the next push through
grip status                # hooks, last score, configuration
```

The [walkthrough](https://guilyx.github.io/grip/walkthrough/) follows one real change from
`git commit` to an accepted push.

## Configuration

`.grip.toml` at the root of the repository, committed so the team shares one bar:

```toml
passing_score = 70        # 0-100
difficulty = "normal"     # easy | normal | hard
provider = "claude-code"  # auto | anthropic | claude-code | codex | gemini | openai | ollama
```

Every option, environment variables and the pre-commit framework hook are in the
[configuration reference](https://guilyx.github.io/grip/configuration/).

## Documentation

**[guilyx.github.io/grip](https://guilyx.github.io/grip/)**: getting started, a
walkthrough, coding agents, the whiteboard, how grip works inside, and the honest numbers
on what the score does and does not measure.

## Contributing

Issues and pull requests are welcome. See [CONTRIBUTING.md](https://github.com/guilyx/grip/blob/main/CONTRIBUTING.md)
for the development setup and [SECURITY.md](https://github.com/guilyx/grip/blob/main/SECURITY.md)
for reporting vulnerabilities and what data grip sends. This project follows a
[code of conduct](https://github.com/guilyx/grip/blob/main/CODE_OF_CONDUCT.md).

## Citation

If grip is part of a study or a course, please cite it; GitHub's "Cite this repository"
button reads [CITATION.cff](https://github.com/guilyx/grip/blob/main/CITATION.cff).

## License

[BSD-3-Clause](https://github.com/guilyx/grip/blob/main/LICENSE). Copyright (c) 2026, Erwin L.
