Skip to content

v0.5.0

Latest

Choose a tag to compare

@github-actions github-actions released this 25 Oct 21:33
· 2 commits to main since this release

Upgrading from 0.4: passes remembered by 0.4 are asked once more, because
passed.json now records the score and grader of each pass. grip grade no longer
takes --passing-score; the pass mark comes from the configuration. The Keep A Grip
commands moved under grip platform, and their old names still work for now.

Added

  • retry_questions option: same (the default) keeps reusing a diff's questions and
    board on a retry; new forgets them when a quiz, a whiteboard defense or grip grade
    fails, so the next try asks new ones. Grading feedback now says where to look again
    and what kind of point is missing, instead of naming the rubric point, so a failed
    quiz can no longer be passed by pasting its feedback back.
  • [[paths]] tables in .grip.toml (or [[tool.grip.paths]] in pyproject.toml) set
    a passing_score, a difficulty or skip = true for the files that match their
    match globs. A diff takes the strictest pass mark and the hardest difficulty of the
    files it touches, and a diff made only of skipped files is not quizzed.
  • A GitHub Action (uses: guilyx/grip@...): on each pull request it writes five
    questions about the diff since the merge base and posts them as one comment, updated on
    every push, for the author or a reviewer to answer in review. Nothing is graded in CI.
    export-board: true also uploads the whiteboard as a workflow artifact and links it.
  • Diffs with nothing to explain are skipped, with the reason printed: only renames or mode
    changes, only whitespace (a re-indent still counts), only paths in the new skip_paths
    option (e.g. ["docs/**", "*.md"]), or fewer added and removed lines than the new
    min_changed_lines option (off by default). grip check, the agent push gate and
    grip status agree with the hook; grip quiz --force quizzes such a diff anyway.
  • The model reads the messages of the commits being quizzed (pushes, --unpushed,
    --branch, --range), up to 4 KB, as delimited data next to the diff, so questions can
    ask why and grading can weigh what the developer said they meant. Rewording a commit gets
    new questions. include_commit_messages = false sends the diff alone.
  • grip appeal <question> "<why my answer was right>" has one question of the last graded
    quiz graded again by the same provider, with the justification as data. It never lowers
    a grade, allows one appeal per question per quiz, is saved in the report and the history
    and shown by grip last, and records a pass when the new score reaches the pass mark.
  • grip measures what a quiz costs. Each graded quiz records the wall time of every model
    request and, where the provider reports it (the Anthropic and OpenAI-compatible APIs,
    not the coding-agent CLIs), the tokens used; the result ends with
    took 9.8 s · 3,140 tokens, grip last shows it per request, grip status averages the
    last 20 quizzes (an appealed quiz counts once), and grip grade and grip last --json
    include it. A grip appeal request is added to its quiz as an appeal call. The FAQ
    explains how to turn tokens into a cost with your provider's prices.

Changed

  • An empty diff in grip quiz, grip whiteboard and grip ask says what there is
    instead and what to run, e.g. "nothing staged. 3 untracked files and 1 modified file:
    git add them first; 2 unpushed commits: try grip quiz --unpushed or --branch".
    grip ask adds the same as data in a hint field. The "Try it" line at the end of
    grip init suggests a command that has something to quiz in that repository.
  • grip init writes provider = "auto" instead of this machine's coding agent, so the
    committed .grip.toml works for teammates without that tool. It prints what auto
    means on this machine, lists auto first in its menu, and writes a concrete provider
    only when you pick one. It now also asks for the difficulty (default normal) and says
    "wrote AGENTS.md for any coding agent that reads it" instead of "for AGENTS.md
    readers". --provider auto is accepted on every command.
  • A missing API key for the anthropic or openai provider is reported before the
    quiz starts, instead of after the "reading your diff" spinner. The message lists the
    fixes: set the key variable (api_key_env, ANTHROPIC_API_KEY by default), use a
    coding agent installed on the machine, or try --provider fake. The openai provider
    no longer asks for a key when base_url points at a server of your own.
  • The quiz header names what is being quizzed in words: 3 commits on feat/x → origin
    for a push, main..HEAD as typed for --range, 2 unpushed commits on main for
    --unpushed, and everything since the first commit instead of the empty tree's hash
    for a first push. When the diff is over max_diff_bytes it also says how much the model
    saw: grip saw the first 200 KB of a 790 KB change (max_diff_bytes).
  • grip --help lists the core commands first (init, quiz, whiteboard, status, skip,
    resume, last), groups the rest, and ends with examples. The Keep A Grip commands moved
    under grip platform (grip platform login, solve, submit, …); the old top-level
    names still work and print a one-line note that they moved. hook, agent-hook,
    statusline, ask and grade are no longer listed in the help but work as before.
  • grip config shows where each value comes from (default, pyproject.toml,
    .grip.toml, env GRIP_… or a flag) and which configuration files it read, and takes
    --provider, --model, --passing-score and --difficulty to preview a run with
    those flags. grip status shows a short summary instead of the full table: provider,
    pass mark, difficulty and hook mode.
  • Docs: new pages on cost and privacy per provider, rolling grip out to a team, removing
    it, and a glossary. The FAQ, honest numbers and home page no longer say that every run
    asks new questions or that anthropic is the default provider, the README says the
    offline fake grader only checks answer length, and the Mitchell Hashimoto quote links
    to his post.
  • Whiteboard page: handing in with questions unanswered asks first ("2 unanswered will
    score 0"); answers show a counter against the 4,000-character limit; the open question
    lights up the box or arrow it is pinned to, and graded arrows take their colour; an
    answered pin gets a tick instead of turning black; a score below the pass mark comes
    with the command to run again and a Copy button. Interview mode says "Score interview"
    and shows the ticks at full contrast after scoring. Exports show the questions without
    an answer box. On a phone, a tap within 22px of a pin opens it, the question scrolls
    into view, and the legend no longer scrolls away with the drawing.

Fixed

  • --range main...HEAD (three dots) no longer fails with bad revision '.HEAD'. It diffs
    from the merge base, as git does, in grip quiz, ask, check and whiteboard.
    main.. and main... run up to HEAD, and a malformed range is rejected with the
    expected form.
  • Git failures are one plain line instead of git's command line and stderr: "not inside a
    git repository (run grip from your project)", "this repository has no commits yet",
    "unknown revision 'nope'". GRIP_DEBUG=1 also prints the full git command and output.
    grip status works in a repository with no commits yet.
  • grip quiz without an interactive terminal (grip quiz </dev/null, a script) exits 2
    and points to grip ask / grip grade or grip whiteboard, instead of skipping with
    exit 0. Hooks still skip unless require_tty is set, and the notice no longer reads
    "grip: grip needs".
  • A pasted answer that ends with an empty line ends there, instead of waiting for one
    more Enter. Empty lines between pasted paragraphs are still kept.
  • grip check without a scope flag checks what the installed hooks quiz (the unpushed
    commits for the default pre-push hook) instead of always the staged changes, which said
    ok while the push would block. It says what it checked
    (grip: ok (unpushed commits)), names a --range as typed instead of calling it "the
    staged changes", and writes "1 file". Two scope flags at once (--branch --unpushed, --range with
    --staged) are a usage error in grip quiz, ask, check and whiteboard instead of
    the last one silently winning.
  • The installed hook runs grip by the absolute path of the grip that ran grip install,
    then falls back to PATH, so a push from an IDE or GUI client whose PATH lacks grip is
    quizzed instead of skipped with "grip: not installed". When that path is gone, the hook
    says so and suggests grip install again, and grip status shows grip missing.
    Re-running grip install --append refreshes the appended block.
  • CLI paper cuts: Ctrl-C exits 130 with grip: stopped, nothing recorded. instead of
    Aborted! and exit 1; grip forget says no remembered passes when there were none;
    pause times are shown in local time with the time zone instead of UTC; a change where
    every file is binary is skipped instead of quizzed; grip status, install and
    uninstall show hook paths relative to the repository root (.git/hooks/pre-push);
    grip grade --help no longer lists --fresh and --difficulty, and grading uses the
    difficulty grip ask wrote the questions at; a retry that reuses cached questions no
    longer shows a "reading your diff" spinner.
  • A remembered pass can no longer be faked. .git/grip/passed.json now stores each pass's
    score, pass mark, provider and model, and the hooks, grip check and the agent push
    gate only accept it if the score reaches the current pass mark and, unless fake is
    the configured provider, it was not graded by fake. grip grade no longer takes
    --passing-score, and grip status says when a pass does not count and why. Passes
    recorded by older versions are asked again once.
  • The Claude Code push gate honours GRIP_SKIP=1 git push typed in the command, as its
    message promised; before, it only read its own environment and denied the push anyway.
    The /grip skill no longer tells the agent where the rubrics are stored, every skill
    and the agent rules say not to read .git/grip/, and the docs say plainly that the
    rubrics are on disk there and that an agent with file access could read them.
  • Whiteboard answers are no longer lost when grip stops. The open page pings grip every
    minute, so a long think no longer hits the 20-minute idle timeout; answers are kept as
    a draft in the tab and survive a reload; and if grip is gone at hand-in, the page says
    "grip stopped: your answers are below, copy them" with a Copy answers button.
  • The whiteboard works from the keyboard and with a screen reader. Boxes, pins and
    buttons show a focus ring, focus no longer drops to the top of the page when it
    redraws, arrow keys move between pins, 1 to 5 open a question and Esc goes back,
    and a skip link jumps to the questions. Pins say whether they are answered or how they
    scored, the score is announced, and the panel no longer re-reads itself on every click.
  • The whiteboard is readable on real changes. The board is drawn at full size or larger in
    a window you can drag, scroll and zoom (Ctrl + scroll, pinch, or the buttons; Fit
    shows it all), and takes the height of the screen on a desktop. Box labels wrap onto two
    lines and boxes grow to fit, arrows bow around boxes instead of running through them,
    edge labels sit on a patch of board and move apart instead of overlapping, and changed
    boxes are tinted. The page now loads its fonts (Archivo, Instrument Sans, JetBrains
    Mono), which ship with grip under the SIL Open Font License; an export embeds them.

Install

pipx install grip-hook==0.5.0    # or: uv tool install grip-hook==0.5.0

On PyPI: https://pypi.org/project/grip-hook/0.5.0/