Repository navigation
Canny 0.3.0 stops costing the agent a turn. It tells the agent at session start what a finished session needs, and fixes the one habit that got nearly every session blocked, so a guarded run takes no longer than an unguarded one. It also closes two ways a failing test could pass the done-gate, and lets a project keep its code from being sent to Jev.
Install or update as before: git -C ~/.canny/src pull --ff-only, or the prompt in the README. There is nothing to build.
Before you update
- Run
canny initagain in each guarded project (orcanny init --global) to add the newSessionStarthook. Without it the rest of this release still works, but the agent learns the done-gate rule from its first blocked Stop instead of up front. ! npm testandtrue # npm testno longer count as a passing check. The first exits 0 when the tests fail, and the second runs none."allow": ["rules"]andignorepaths now keep edits from being sent to Jev, and both wait forcanny trust, like every field that loosens the guard.
Faster sessions
- A
SessionStarthook tells the agent what the done-gate asks for and names the project's test command, read frompackage.json, ajustfile, aMakefile,Cargo.toml, orgo.mod. - A Bash check piped into
tail(npm test 2>&1 | tail -20) is rewritten to run behindset -o pipefail, so it counts when it passes and reports its failure when it fails. On Claude Code the rewritten command still goes through your permission rules; Codex takes a rewrite only with an "allow" and asks for approval separately. - Measured with
bench/, Opus 5, 25 pairs: no blocked Stops where every earlier guarded run had one, 25 of 25 passes with and without Canny, the same turns and cost, and the guarded arm 1.6 ± 3.4 s faster, down from 4.5 s slower. No measurable overhead; also no measured change in outcome, since both arms pass every task.
The done-gate
- A negated check and a check named only in a comment no longer count, and a
#after an escaped space no longer hides a pipe intotail. - Under pipefail, the last
set -oorset +o pipefailin a command decides, and a check pattern in.canny.jsonsuch as^npm test$is matched against the command that feeds the pipe. - A shell command that rewrites a test file goes through the test-removal check, a
;inside quotes no longer splits a statement past the secret check, and a leadingcdthat goes nowhere keeps a git-ignored.envwritable.
Privacy
- The Jev rule check can be turned off with
"allow": ["rules"]and skips the paths inignore, so part or all of a project's code can stay off TypeSafe's API without unsetting the key. ignorepatterns match a path however the agent spells it (./x,a/../x), for the done-gate as well.
Development
bench/run.mjsgives five tasks to a headless Claude Code or Codex with and without Canny, judges them by hidden checks, and records turns, cost, and model time per run.- The test suite strips git's environment, so committing from a linked worktree no longer marks the main checkout bare. CI runs the tests on Node 22, 24, and 26 plus macOS, with CodeQL.
Full changelog: https://github.com/qkal/canny/blob/v0.3.0/CHANGELOG.md · v0.2.0...v0.3.0