git clone + node dist/cli.js init · Node ≥ 22 · zero dependencies

Connect & Setup

Canny is not on npm. Your agent installs it from the repository; the compiled CLI is committed, so there is nothing to build. This hosted workspace cannot install hooks or guard your agent's CLI on its own: the hooks run on your machine.

01

Install by prompt

Paste into Claude Code or Codex, inside the project you want guarded (upstream's own prompt):

Install Canny (https://github.com/qkal/canny), a supervisor that checks your work through this agent's hooks, and hook it into this project.

1. Confirm `node --version` is 22 or newer. If not, stop and tell me.
2. If ~/.canny/src exists, run `git -C ~/.canny/src pull --ff-only`. Otherwise run `git clone https://github.com/qkal/canny.git ~/.canny/src`. There is nothing to build or install.
3. From the root of this project, run `node ~/.canny/src/dist/cli.js init` and show me the hook entries it wrote.
4. Run `echo canny-check`, then `node ~/.canny/src/dist/cli.js status`. If status lists a session with at least one event, the hooks are live. If it says no sessions were recorded: on Claude Code ask me to restart you; on Codex remind me to run /hooks to trust the new hooks.
5. Change nothing else. Tell me what you did in five lines or fewer.
02

Or by hand

node --version            # must be v22 or newer
git clone https://github.com/qkal/canny.git ~/.canny/src
cd /path/to/your/project
node ~/.canny/src/dist/cli.js init              # agents found on this machine
node ~/.canny/src/dist/cli.js init --claude     # only Claude Code (.claude/settings.json)
node ~/.canny/src/dist/cli.js init --codex      # only Codex CLI (.codex/hooks.json)
node ~/.canny/src/dist/cli.js init --global     # every project (~/.claude, ~/.codex)
ln -s ~/.canny/src/dist/cli.js ~/.local/bin/canny   # optional: canny on PATH

Codex: it asks you to trust new hooks once. Run /hooks inside Codex after init. Claude Code picks up its settings file as you save it (restart if status shows no sessions).

03

Everyday commands

canny status [session-file]    # latest session of this project, and hook crashes
canny sessions                 # list recorded sessions with their projects
canny replay [session-file]    # re-derive every Stop verdict; exit 1 on a mismatch
canny trust                    # accept this project's .canny.json as it stands
canny remove [--global]        # take Canny's hook entries out again
git -C ~/.canny/src pull --ff-only   # update

Without the symlink, canny means node ~/.canny/src/dist/cli.js.

Update Canny: run `git -C ~/.canny/src pull --ff-only` and tell me what changed, from its CHANGELOG.md, since the previous commit.
Remove Canny from this project: from the project root run `node ~/.canny/src/dist/cli.js remove` and show me what it took out. Leave ~/.canny alone.
04

Optional Jev

Set on your machine only; never entered here. Without a key every deterministic check works the same.

export TYPESAFE_API_KEY=…               # enables Jev
export CANNY_JEV_URL=https://api.typesafe.ai/v1/systemone
export CANNY_JEV_MODEL=jev-latest
export CANNY_JEV_TIMEOUT_MS=3000
05

Real sessions, path A: import

Drag ledgers from ~/.canny/sessions/ into the importer. They are parsed here and stored on this device only.

06

Real sessions, path B: local companion

A dependency-free Node 22 script bundled with the unmodified upstream dist/ modules. It listens on 127.0.0.1 only, prints a new access token at every start, accepts only this page's exact origin, and serves read-only GET /health, /sessions and /sessions/<name>.jsonl (bounded to 500 sessions, 10 MB each). It runs no commands and reads no other paths.

Script only needs the dist modules from a clone: CANNY_DIST=~/.canny/src/dist/ node canny-companion.mjs --origin …

unzip canny-companion.zip -d ~/canny-companion
node ~/canny-companion/canny-companion/canny-companion.mjs --origin https://YOUR-APP-ORIGIN
idle

URL and token stay in this tab's memory only and are cleared on disconnect or reload. While connected, sessions refresh every 30 s when this tab is visible. Companion sessions are not saved to this device.

If it won't connect
  • Some browsers or extensions block public pages from reaching 127.0.0.1 (Private Network Access). Fall back to .
  • 403 means --origin doesn't exactly match https://YOUR-APP-ORIGIN. 401 means the token is stale: it changes each start.
  • Requires Node 22+. The default port is 4777 (--port).