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.
| View | Shows | Primary actions |
|---|---|---|
| Pending | Commands awaiting a decision, one row each, segments color-coded. | a approve · d deny · Del dismiss |
| Approved | Existing allow rules across scopes, grouped and filterable. | x remove (with confirm) |
| Denied | Existing 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 · 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:
| Glyph | Decision | Meaning |
|---|---|---|
| ✓ | allow | A gate already permits this segment. No rule needed. |
| ? | ask | The segment that needs a decision. This is what a rule would cover. |
| ✗ | block | A 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.
scycles local → project → global;Sgoes 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.
| Risk | When | Approve |
|---|---|---|
| safe | One exact command, local, low-stakes program. | Single keystroke. |
| caution | Anything wider or farther-reaching, but not yet dangerous. | Single keystroke. |
| DANGER | A 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 · 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 · 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 · 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.
| Key | Action | Where |
|---|---|---|
| ↑ ↓ · j / k | Move within the active list | everywhere |
| Tab · ⇧Tab | Cycle views; 1 / 2 / 3 jump direct | everywhere |
| p | Open the project switcher | everywhere |
| ← → · h / l | Cycle the pattern (narrow ↔ broad) | Pending |
| s · S | Cycle the scope forward / back | Pending |
| [ · ] | Step between segments of a compound command | Pending |
| a · Enter | Approve the selected command (arms a confirm if dangerous) | Pending |
| d | Deny (writes a deny rule) | Pending |
| Del · x | Dismiss the row from the queue (no rule written) | Pending |
| f | Cycle the scope filter | Approved / Denied |
| x · Enter | Remove the selected rule (with confirm) | Approved / Denied |
| y | Confirm an armed action; any other key cancels | confirm prompt |
| u | Undo the last write, dismiss, or removal | everywhere |
| q · Esc | Quit | everywhere |
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.