LeastGrant

Parsed from the agent support table in README.md at v0.2.0, wording intact.

Agent support

One profile and one set of floors, whichever agent you are using that day. Every adapter calls the same judgePre and recordPost, so there is one decision path rather than one per editor — a security story that changes depending on which editor you opened is not a security story.

Claude Code

Enforcing, tested end to end

PreToolUse decides; PostToolUse is how it learns you approved something. Read against v2.1.240's behaviour, and every hook test in the suite drives the real binary over real stdin.

Cursor

Enforcing, not yet verified against a live install

hooks.json — shell, MCP and file reads, plus the matching after* events so it can learn. Written against Cursor's published hook contract; the request and response shapes are unit-tested, including a test that the same command gets the same verdict here as under Claude Code. Nobody has run it inside a real Cursor yet.

GitHub Copilot CLI

Enforcing, tested end to end

~/.copilot/hooks/leastgrant.json. It really does speak Claude Code's wire format — snake_case fields in, hookSpecificOutput out — and it honours all three verdicts, so the same handler drives it. Verified against Copilot CLI 1.0.82 with real copilot -p runs. It is also the one agent that fails closed: if the hook errors, Copilot denies the call rather than running it.

Codex CLI

Enforcing, tested end to end

~/.codex/hooks.json — PreToolUse, PermissionRequest and PostToolUse. Codex has no ask: it parses that decision, rejects it, and runs the call anyway, so the mapping below is not the obvious one. Verified against codex-cli 0.152.0 by driving real codex exec sessions: a credential read and a write to LeastGrant's own records were both blocked, while node --version and git status ran untouched. PermissionRequest has not fired in anger — codex exec runs unattended, where by definition nothing prompts. Codex also makes you trust a hook before it runs, and re-flags it whenever its definition changes: /hooks.

Gemini CLI, others

Not yet

An adapter is a translation layer over the shared engine — the Cursor one is about 200 lines. See CONTRIBUTING.md.

What the statuses mean

The distinction is not cosmetic, so it is stated in the words the repository uses rather than flattened into "supported":

  • Enforcing, tested end to end — the hook has been driven as a real binary over real stdin, against the agent's actual behaviour.
  • Enforcing, not yet verified against a live install — written against the agent's published hook contract, with the request and response shapes unit-tested, including a test that the same command gets the same verdict as under Claude Code. Nobody has run it inside the real thing yet.
  • Installer only, unverified — the installer writes a configuration the agent is documented to read. That is a reasonable expectation, not a demonstration.
  • Not yet — no adapter, because there is no hook to attach to.
one caveat worth stating in the open

Cursor's beforeReadFile event takes allow or deny and has no "ask". An unfamiliar read is therefore allowed rather than blocked, because turning every unrecognised file read into a hard failure would make the integration unusable. A read of something LeastGrant recognises as a credential is blocked. Shell commands and MCP calls get the full allow/ask/deny.

An adapter is a translation layer over the shared engine — the Cursor one is about 180 lines. If you want one for an agent that is not here, contributing has the shape of it.