One terminal to rule all your Claude Code sessions.
When you run multiple Claude Code sessions across terminals or IDE windows, each one asks for permission in its own terminal. Gatekeeper intercepts every request and routes them to a single dashboard — you approve, deny, or auto-approve without switching windows.
Left pane — all active Claude sessions with status badges ([auto] = auto-approve enabled)
Middle pane — pending permission requests with age timer
Right pane — full request detail, danger warnings, and a numbered approval menu
- Unified approval terminal — all Claude sessions route here regardless of where they run
- Claude Code-style numbered menu —
1allow once,2always allow (saves rule),3deny;↑/↓to move cursor,Enterto confirm - Persistent allow (option 2) — saves a rule to Gatekeeper config so the command skips the queue next time
- Sessions shown immediately — reads
~/.claude/sessions/on startup, no waiting for a hook call - Auto-approve per session — mark trusted sessions to silently pass routine tool calls
- Hard safety rules —
rm,ssh,sudo,--force, SQL mutations, writes to/etc/always require manual approval, even on auto sessions - Sole permission gate —
bypassPermissionsmode disables Claude Code's own dialogs; Gatekeeper is the only checkpoint - Message injection — type a message in Gatekeeper and it appears in the target Claude terminal as keyboard input
- Window linking — link each session to its terminal tab so messages go to exactly the right window
- Daily logs + stats — every decision is recorded;
gatekeeper statsshows rates by day and session - Terminal fallback — if Gatekeeper is not running, a
Y/nprompt appears in the Claude terminal so nothing hangs
- Linux with X11 (
echo $DISPLAYshould show:0or similar) - Python 3.11+
- Claude Code CLI
- Any X11 terminal emulator (gnome-terminal, Kitty, Alacritty, etc.)
git clone https://github.com/Btocode/gatekeeper
cd gatekeeper
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
bash install.shinstall.sh does four things:
- Installs wrapper scripts in
~/.claude/bin/ - Registers a
PreToolUsehook in~/.claude/settings.json— Claude Code calls this before every tool use - Adds blanket
permissions.allowrules (Bash(**),Read(**),Write(**),Edit(**), …) using**to match path separators - Sets
permissions.defaultMode = "bypassPermissions"— disables Claude Code's built-in permission dialogs entirely so Gatekeeper is the sole approval gate (Claude Code's hardcoded sensitive-path prompts for/proc/,/sys/,~/.bashrc, etc. only suppress in this mode)
Open a dedicated terminal and run:
gatekeeperStart your Claude Code sessions anywhere — other terminals, VS Code, JetBrains, anywhere. Every Bash, Edit, Write, or Agent call will appear in Gatekeeper.
By default the hook waits up to 5 minutes for Gatekeeper to respond, then falls back to a Y/n prompt directly in the Claude terminal. This means:
| Situation | What happens |
|---|---|
| Gatekeeper running | Request appears in dashboard — approve with A / D |
| Gatekeeper not running | [Permission required] Y/n prompt appears in Claude terminal |
| Gatekeeper running, no response in 5 min | Hook times out, falls back to Y/n in Claude terminal |
To approve from the Claude terminal immediately (skip Gatekeeper for a session):
# Set timeout to 0 — always use terminal prompt, ignore daemon
GATEKEEPER_TIMEOUT=0 claude
# Or set a short timeout (e.g. 10 seconds)
GATEKEEPER_TIMEOUT=10 claudeTo permanently prefer terminal prompts, add to ~/.zshrc:
export GATEKEEPER_TIMEOUT=0To stop Gatekeeper entirely, press Q in the dashboard — subsequent hook calls fall back to the terminal prompt automatically.
| Key | Pane | Action |
|---|---|---|
Tab |
any | Switch focus between Sessions and Queue |
j / k |
any | Navigate queue items or sessions |
↑ / ↓ |
Queue | Move the approval cursor (1 / 2 / 3) |
1 |
Queue | Yes — allow this request |
2 |
Queue | Yes, for this session only — allows without saving permanently |
3 |
Queue | No — deny this request |
Enter |
Queue | Confirm highlighted option |
A |
Queue | Yes — allow (shortcut) |
D |
Queue | No — deny (shortcut) |
A |
Sessions | Toggle auto-approve for the selected session |
M |
any | Send a message to the selected session |
L |
Sessions | Link the session to a terminal window |
U |
Sessions | Unlink the session from its terminal window |
S |
any | Open settings (tool types, bash categories, custom patterns) |
Q |
any | Quit |
Mark a session (A in the Sessions pane) to silently allow all its tool calls. The session shows [auto] — you only see requests that need your attention.
No matter what, these always require manual approval:
| Category | What's blocked |
|---|---|
| File deletion | rm, rmdir, shred |
| Remote access | ssh, scp, rsync, sftp |
| Privilege escalation | sudo, su |
| Service control | systemctl stop/disable, service stop |
| Containers | docker rm/kill/prune, kubectl delete |
| Infrastructure | terraform apply/destroy |
| Destructive git | push --force, reset --hard, clean -f |
| Sensitive paths | Writes to /etc/, /usr/, ~/.ssh/, ~/.aws/ |
| Disk ops | dd, mkfs, fdisk |
Read-only commands — grep, find, ls, cat, git status, npm install, SELECT queries — always pass through auto-approve freely.
Linking maps a Claude session to its terminal window so the M (message) key knows exactly where to send input.
Tabto the Sessions pane, navigate to a session- Press
L— an overlay appears - Switch to the Claude terminal tab (alt+tab, click, etc.)
- Gatekeeper detects the focus change and links automatically — session shows
[linked]
Links persist in ~/.claude/perm-window-map.json.
Press M, type your message, press Enter. Gatekeeper injects the text into the linked Claude terminal using X11 XTEST — it appears and submits automatically, exactly as if you typed it and pressed Enter there. No need to switch to that terminal.
Useful for:
- Answering Claude's mid-task questions (
A / B / C?) without switching windows - Explaining why you denied a request
- Redirecting Claude to a different approach while it waits
Requires the session to be linked first (L key).
Message injection works when each Claude session runs in its own terminal window. If multiple sessions share one window as tabs, all tabs have the same X11 window ID — Gatekeeper cannot distinguish between them.
| Setup | Message injection |
|---|---|
| Each session in its own window | ✅ Works |
| Sessions as tabs in one window | ❌ Cannot target specific tab |
Workaround: open each Claude session in a new terminal window instead of a new tab (kitty, gnome-terminal --window, etc.).
gatekeeper stats # today
gatekeeper stats 7 # last 7 days
gatekeeper stats all # all time====================================================
GATEKEEPER STATS
====================================================
Total decisions : 177
Auto-approved : 16 ( 9%)
Manual reviewed : 161 ( 90%)
allowed : 161
denied : 0
Auto-approved by session:
b73f7ccc 7 calls
a8ed1d57 5 calls
Auto-approved by tool:
Bash 11
Edit 5
====================================================
Logs live in ~/.claude/perm-logs/YYYY-MM-DD.log, one file per day, kept indefinitely.
Claude session A Claude session B Claude session C
(any terminal/IDE) (any terminal/IDE) (any terminal/IDE)
│ │ │
PreToolUse hook PreToolUse hook PreToolUse hook
(blocks Claude) (blocks Claude) (blocks Claude)
└────────────────────────┼────────────────────────┘
│ Unix socket
▼
┌────── Gatekeeper daemon ──────┐
│ blessed TUI │
│ asyncio socket server │
│ session registry │
└───────────────────────────────┘
(your terminal)
A PreToolUse hook fires before every tool call in every Claude session. It connects to Gatekeeper's Unix socket at /tmp/claude-perm-$USER.sock, sends the request, and waits. Gatekeeper shows the request in the UI. When you press A or D, the decision travels back through the socket — Claude proceeds or stops.
Sessions are discovered at startup by reading ~/.claude/sessions/*.json (the same files used by claude /resume), so all running sessions appear immediately.
If Gatekeeper is not running, the hook falls back to a Y/n prompt in the Claude terminal — nothing hangs.
| Path | Purpose |
|---|---|
~/.claude/bin/gatekeeper |
Gatekeeper daemon |
~/.claude/bin/gatekeeper-hook |
Hook called by Claude Code |
~/.claude/bin/gatekeeper-stats |
Stats backend (gatekeeper stats) |
~/.claude/perm-logs/YYYY-MM-DD.log |
Daily decision logs |
~/.claude/perm-window-map.json |
Session → window links |
~/.claude/perm-auto-approve.json |
Auto-approve session list |
gatekeeper uninstallRemoves the hook, blanket allow rules, and wrapper scripts. Claude Code's own permission dialogs are restored automatically.
MIT
