Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Review TUI

tool-gates review is where ask decisions become permanent rules. Every command you clicked through lands in a queue; the TUI lets you promote, deny, or dismiss each one, and manage the allow/deny rules already in your settings.json. It is keyboard-first, color-and-symbol coded, and biased toward the safe choice: the wider a rule reaches, the more friction it asks for.

Launch

One command, current project by default.

$ tool-gates review          # pending + rules for the current project
$ tool-gates review --all    # span every project on this machine

The header names the active project and the machine-wide pending total. Everything below is reachable without leaving the keyboard; the mouse can click rows and tabs too.

Views

Three tabs: a queue and two rule managers.

Press Tab to cycle, or 1 / 2 / 3 to jump. The active tab is underlined.

ViewShowsPrimary actions
PendingCommands awaiting a decision, one row each, segments color-coded.a approve · d deny · Del dismiss
ApprovedExisting allow rules across scopes, grouped and filterable.x remove (with confirm)
DeniedExisting deny rules across scopes.x remove (with confirm)

Pending

Make a decision.

The list stays quiet; the Decision panel below it is the focal surface and carries the accent border. Selecting a row fills the panel with the exact rule you are about to write.

tool-gates review
 tool-gates · proj    1 pending across 1 project(s)
 Pending 1    Approved 0    Denied 0
┌ Pending · proj ──────────────────────────────────────────────────────────────────────────────────┐
│ › ? rm -rf target  &&   cargo build   1×                                                        │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌ Decision ────────────────────────────────────────────────────────────────────────────────────────┐
│ ‹? rm -rf target›  &&   cargo build                                                             │
│   Recursively force-deletes <path>.                                                              │
│                                                                                                  │
│ Pattern   All "rm" commands   rm:*                                                               │
│ Scope     ‹ This project · shared ›                                                              │
│           → /home/u/proj/.claude/settings.json                                                   │
│ Blast radius  reach   ▰▰▱ everyone on this project                                               │
│               breadth ▰▰▰ every subcommand  DANGER                                               │
│ i Approving covers the whole command since "cargo" already allowed.                              │
│  a Approve (confirm)     d Deny     Del dismiss                                                  │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
 ↑↓ move  ←→ pattern  s scope  [ ] seg  a approve  d deny  Del dismiss  Tab view  p project  q quit

Each segment of a command is prefixed with a glyph and colored by its decision, so the encoding survives a no-color terminal or color blindness:

GlyphDecisionMeaning
allowA gate already permits this segment. No rule needed.
?askThe segment that needs a decision. This is what a rule would cover.
blockA hard safety-floor deny. Cannot be approved here.

For a compound command (&&, ||, |, ;) the panel shows every segment and underlines the one in focus; [ and ] step between the actionable ones. The rows beneath are the rule itself:

  • Pattern: the settings.json pattern that would be written. / cycle from the narrowest form (this exact command) out to the broadest the gate considers safe to suggest. High-stakes programs deliberately offer only the narrow forms.
  • Scope: where the rule lives. s cycles local → project → global; S goes back. The resolved settings-file path is shown beneath, and the global choice is drawn in red because it touches every project on the machine.
  • Blast radius: the two-axis meter described below.

Blast radius

The wider the rule, the louder the panel.

Two meters score the rule you are about to write. Reach is the scope (just you → the team → the whole machine); breadth is the pattern width (one command → a family → an entire program). Both fill and redden together, and their combination sets the risk level.

RiskWhenApprove
safeOne exact command, local, low-stakes program.Single keystroke.
cautionAnything wider or farther-reaching, but not yet dangerous.Single keystroke.
DANGERA wide rule applied to every project, a high-stakes tool reaching the whole team, or a whole-program glob over network / exec / destructive commands.Requires an explicit y confirm.

Only DANGER writes demand confirmation. The approve button relabels itself to a Approve (confirm) and pressing a arms an inline prompt; y commits, any other key cancels. This is the anti-rubber-stamp guard: you cannot widen trust to the whole machine by leaning on one key.

Approved & Denied

Manage the rules you already have.

The two rule tabs read your settings files directly. Each row is a live allow or deny rule with its scope; the detail panel explains what removing it does.

tool-gates review · Approved
 tool-gates · proj    1 pending across 1 project(s)
 Pending 1    Approved 2    Denied 0
┌ Approved · all scopes · 2 ───────────────────────────────────────────────────────────────────────┐
│ ›  cargo:*   global                                                                             │
│    git push:*   this project                                                                    │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌ Rule ────────────────────────────────────────────────────────────────────────────────────────────┐
│  cargo:*                                                                                        │
│   Allows All "cargo" commands                                                                    │
│                                                                                                  │
│ Scope     global   → ~/.claude/settings.json                                                     │
│                                                                                                  │
│  x Remove    Removing makes these commands prompt again.                                         │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
 ↑↓ move  ↵/x remove  f scope: all scopes  Tab view  p project  q quit

f cycles the scope filter (all → global → project → local), so you can isolate, say, only the machine-wide rules. Removing a rule is gated behind the same confirm flow as a dangerous approval, so an accidental x while navigating never deletes anything:

tool-gates review · confirm remove
 tool-gates · proj    1 pending across 1 project(s)
 Pending 1    Approved 0    Denied 0
┌ Approved · all scopes · 1 ───────────────────────────────────────────────────────────────────────┐
│ ›  cargo:*   global                                                                             │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌ Rule ────────────────────────────────────────────────────────────────────────────────────────────┐
│  cargo:*                                                                                        │
│   Allows All "cargo" commands                                                                    │
│                                                                                                  │
│ Scope     global   → ~/.claude/settings.json                                                     │
│                                                                                                  │
│ ⚠ Remove approval cargo:* (global)    y confirm   any other key cancels                          │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
 y confirm    esc cancel

Removal edits real settings files. A global rule in the Approved or Denied view lives in ~/.claude/settings.json; removing it there affects every project on the machine. The confirm prompt names the scope so you see the reach before committing.

Projects

Switch without leaving the queue.

Press p for an overlay of every project with pending commands, grouped by parent directory like a folder tree. Pick one to scope the views to it, or choose All projects to see everything at once.

tool-gates review · switch project
 tool-gates · beta    3 pending across 3 project(s)
 Pending 1    Approved 0    Denied 0
┌ Pending · beta ──────────────────────────────────────────────────────────────────────────────────┐
│ › ? npm test   1×                                                                                │
│                                                                                                  │
│                                                                                                  │
│                                                                                                  │
│                                                                                                  │
│                      ┌ Switch project ────────────────────────────────────┐                      │
│                      │ /srv/projects/                                     │                      │
│                      │     alpha (1)                                      │                      │
└──────────────────────│   › beta (1)                                       │──────────────────────┘
┌ Decision ────────────│ /srv/work/                                         │──────────────────────┐
│ ? npm test           │     gamma (1)                                      │                      │
│   Recursively force-d│   ───────                                          │                      │
│                      │   All projects (3)                                 │                      │
│ Pattern   All "npm te└────────────────────────────────────────────────────┘                      │
│ Scope     ‹ This project · shared ›                                                              │
│           → /srv/projects/beta/.claude/settings.json                                             │
│ Blast radius  reach   ▰▰▱ everyone on this project                                               │
│               breadth ▰▰▱ a family of commands                                                   │
│  a Approve     d Deny     Del dismiss                                                            │
│                                                                                                  │
│                                                                                                  │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
 ↑↓ move  ←→ pattern  s scope  a approve  d deny  Del dismiss  Tab view  p project  q quit

Keys

One key, one meaning.

Arrows always move within the active list. There is no panel-focus mode to track; the same key does the same thing wherever you are.

KeyActionWhere
↑ ↓ · j / kMove within the active listeverywhere
Tab · ⇧TabCycle views; 1 / 2 / 3 jump directeverywhere
pOpen the project switchereverywhere
← → · h / lCycle the pattern (narrow ↔ broad)Pending
s · SCycle the scope forward / backPending
[ · ]Step between segments of a compound commandPending
a · EnterApprove the selected command (arms a confirm if dangerous)Pending
dDeny (writes a deny rule)Pending
Del · xDismiss the row from the queue (no rule written)Pending
fCycle the scope filterApproved / Denied
x · EnterRemove the selected rule (with confirm)Approved / Denied
yConfirm an armed action; any other key cancelsconfirm prompt
uUndo the last write, dismiss, or removaleverywhere
q · EscQuiteverywhere

Only human approvals queue. Under auto mode the classifier decides silently; nothing it approves reaches pending.jsonl. The queue stays focused on the patterns you explicitly clicked through. Prefer the command line? tool-gates pending list, tool-gates approve, and tool-gates rules remove do the same writes without the TUI. See the Approval Learning and CLI Reference pages.

tool-gates · permission gate hook for Claude Code, Codex CLI, and Antigravity CLI, with deprecated Gemini CLI support. github.com/camjac251/tool-gates

13 gates · 400+ commands · built from rules/*.toml