Plan review gate
Claude Code uses an ExitPlanMode PermissionRequest hook. Codex uses a Stop hook that reads the latest plan from the rollout transcript.
Agent safety pattern
Review agent plans and diffs in the browser with Plannotator
Plannotator does not replace the coding agent. It adds a browser checkpoint before the agent continues, so you can inspect the plan, diff, or message visually and return exact feedback.
UI Review Gate is the checkpoint pattern; Plannotator is the tool that implements it.
Plans, diffs, files, folders, URLs, and the latest agent message all open in a visual review UI.
Approve to continue, or send annotations so the agent fixes the plan or code first.
Why a visual gate
The terminal is a poor surface for reviewing a long plan: there is nowhere to mark a specific spot, and reading a dense wall of text is exhausting. A visual UI fixes both — you read it like a document and annotate exactly where the change belongs.
Long plans scroll away
A multi-step plan or large diff scrolls past in the terminal. You hold the whole thing in your head to keep track.
Reviewing a wall of text is tiring
Reading a dense wall of text with no structure is mentally draining, so real issues slip through.
Feedback is retyped from memory
There is no place to mark a specific line, so you describe the change from memory and hope the agent maps it back.
Annotate right where the fix belongs
Comment inline, on the exact line or block that needs the change. The note stays anchored to that spot.
Long plans become scannable
The plan or diff opens as a structured, navigable document, so a long review is far easier on the brain.
Precise feedback, straight to the agent
Each annotation carries its location and context, so the agent gets exact feedback instead of a vague summary.
What the gate covers
The same loop applies whether the artifact is a plan, a code diff, a rendered HTML page, a docs folder, or the agent response you just received.
The agent is paused the whole time the review is open. Nothing proceeds until you approve, so the gate is blocking by design — not a notification you can miss.
Claude Code uses an ExitPlanMode PermissionRequest hook. Codex uses a Stop hook that reads the latest plan from the rollout transcript.
The review command opens a diff review UI for current changes or a PR/MR URL, then returns feedback to the agent session.
The annotate command covers Markdown, HTML, URLs, and folders; the last command targets the latest assistant message.
Remote mode and a fixed port make the server reachable through forwarded ports, devcontainers, or tunnels.
Plan re-submissions can show diffs. Sessions can be listed, reopened by number, or cleaned when stale.
Small reviews can be shared through URL hash data. Large short links are opt-in and encrypted; sharing can be disabled for sensitive work.
Hook lifecycle
The gate is not just a UI command. Each host wires it into a specific lifecycle point, then Plannotator turns approve/feedback into the native hook response for that host.
Before Claude leaves plan mode
PermissionRequest -> ExitPlanMode tool_input.plan from stdin, opens the browser review gate, then lets Claude continue only after approval.PermissionRequest hook matching ExitPlanMode in ~/.claude/settings.json.PermissionRequest hook entry. Restart Claude Code after changing hooks.After a Codex turn stops with a plan
Stop transcript_path, extracts the latest plan or <proposed_plan>, opens review, and returns continuation feedback when annotations are sent.~/.codex exists. Manual setup uses [features] hooks = true plus a Stop hook in hooks.json.Stop hook entry, or turn hooks off for that Codex config layer when you want all Codex hooks disabled there.When the plan agent submits a plan
plan-agent submit_plan submit_plan to the plan agent by default, so planning can be gated without giving build agents the same tool.@plannotator/opencode to opencode.json and restart OpenCode. Run the installer too if you want the /plannotator-* commands.manual for commands-only mode. Use all-agents only when broad tool access is intentional.PostToolUse -> WriteReview every file the agent writes. Useful for sensitive docs, generated HTML, or files where visual copy review matters.
Stop -> annotate-lastReview the agent response at turn end. Approve closes cleanly; annotations send feedback back into the agent loop.
--hook / --gate / --json--hook makes the command gate and emit hook-native JSON. --gate adds the approval button. --json is for wrappers and logs.
PLANNOTATOR_REMOTE=1 when the browser is on another device, VM, devcontainer, or Tailscale URL. PLANNOTATOR_PORT when mobile testing needs a stable QR/link. PLANNOTATOR_BROWSER or BROWSER when the hook should open a specific browser. PLANNOTATOR_SHARE=disabled when the gate must stay local-only. Install and setup
One installer covers every agent. Run it, finish the one step your agent needs, then try a command. No deep config required.
It adds the plannotator binary, auto-detects your installed agents, and wires up their hooks, skills, and slash commands.
Run this in your terminal.
curl -fsSL https://plannotator.ai/install.sh | bash Run this in PowerShell.
irm https://plannotator.ai/install.ps1 | iex Find your agent below and do its one step. Agents marked auto need nothing after the installer.
Claude Code Add the marketplace plugin, then install plannotator@plannotator, and restart.
Codex auto Nothing. Auto via the experimental Stop hook (macOS/Linux/WSL; off on Windows). $plannotator-* skills included.
Gemini CLI auto Nothing — hook, policy, and slash commands are auto-configured. Requires Gemini CLI 0.36.0+.
OpenCode Add @plannotator/opencode@latest to the plugin list in opencode.json, then restart.
Copilot CLI Add the marketplace, install plannotator-copilot@plannotator. Plan review runs in plan mode (Shift+Tab).
Amp Copy plannotator.ts into ~/.config/amp/plugins/ and reload. Workflows live in the command palette.
Droid Add the marketplace, then install plannotator@plannotator. Commands only, no plan interception yet.
Kiro CLI auto Nothing — skills and an example agent install automatically. Try kiro-cli chat --agent plannotator.
Pi Skip the installer: pi install npm:@plannotator/pi-extension. Start with --plan or toggle /plannotator.
Use this fallback only when the Claude Code plugin path is unavailable. Merge the block into ~/.claude/settings.json, keep your existing settings, then restart Claude Code. To test it, enter the built-in plan mode and leave plan mode; Plannotator should open automatically.
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{ "type": "command", "command": "plannotator", "timeout": 345600 }
]
}
]
}
} Invoke one command yourself when needed. Automatic plan review does not apply to every plan; it only runs in flows where a Plannotator hook is already enabled. For example, in the built-in plan mode, leaving plan mode triggers the review automatically. CK plan files should be opened manually for review.
Open the latest assistant message for comments.
/plannotator-last Review your working tree like a small PR.
/plannotator-review Open a ClaudeKit plan file manually when it was saved to disk.
/plannotator-annotate plans/<plan>/plan.md Annotate Markdown, HTML, a folder, or a URL.
/plannotator-annotate report.html Mobile approval
Codex or Claude Code mobile can approve agent actions through their own remote-control path. Plannotator approval happens in a browser pointed at the Plannotator server, so the phone must be able to reach that server.
Start the review on desktop
Plannotator runs beside the agent and exposes a browser UI.
Open the reachable URL on phone
Use LAN IP on the same Wi-Fi, or a tunnel when networks differ.
Approve or comment from mobile
The decision goes back to the desktop agent session.
Host setup
Set PLANNOTATOR_REMOTE and PLANNOTATOR_PORT where your host agent reads environment variables.
~/.claude/settings.json Use user settings for every project, or .claude/settings.local.json for one repo only.
{
"env": {
"PLANNOTATOR_REMOTE": "1",
"PLANNOTATOR_PORT": "9999"
}
} ~/.codex/config.toml Use user config for every project, or .codex/config.toml inside a trusted repo. Merge into the existing table if it already exists.
[shell_environment_policy]
inherit = "core"
set = { PLANNOTATOR_REMOTE = "1", PLANNOTATOR_PORT = "9999" } After editing provider config, restart the host agent session so new Plannotator commands inherit the variables.
The phone should show the Plannotator review UI. Approve or add comments there; the decision is sent back to the desktop agent session.
Phone route
Choose the shortest route first. Same Wi-Fi is simplest; Tailscale, VPN, or a tunnel is for different networks.
Open the host LAN URL. 127.0.0.1 points to the phone itself.
Use Tailscale, VPN, or a tunnel. The link lives only while that session runs.
Same Wi-Fi
Find the host LAN IP first, then open the Plannotator URL from the phone browser.
Find the host IP
Run one command that matches the host OS.
ipconfig getifaddr en0 hostname -I | awk '{print $1}' ipconfig | findstr IPv4 Open on phone
Replace the placeholder with the IP from step 1.
http://<host-lan-ip>:9999 Different network
Use this when the phone is not on the same Wi-Fi as the agent host.
Publish the local port
Use a private route from the host machine.
tailscale ip -4
tailscale serve --bg --tcp=10000 9999 Open on phone
Use the route IP while the tunnel is active.
http://<tailscale-ip>:10000/ URL/port. Wi-Fi, firewall rules, or that Tailscale/VPN is connected on both devices. MagicDNS fails: use the raw Tailscale IP first, then fix DNS later. HTTP vs HTTPS: local Plannotator URLs are usually HTTP unless your tunnel adds TLS. plannotator sessions --clean, then open a new review. ClaudeKit fit
They do different jobs, so they pair cleanly. ClaudeKit drives the work — plan, cook, review, test. Plannotator is the human review gate: the browser surface where you inspect what CK produced and send precise feedback. Auto-blocking only happens when the host lifecycle hook fires.
Rule of thumb: Claude Code ExitPlanMode, Codex Stop, OpenCode submit_plan, and Pi plan mode can auto-open Plannotator. A normal ClaudeKit /ck:plan run is a plan-producing command, so treat Plannotator as an explicit review step.
/ck:plan → /plannotator-annotate plans/.../plan.md /ck:plan creates a CK plan artifact; it is not automatically the same as host plan mode. Open the generated plan.md file in Plannotator when you want a browser review gate.
/ck:cook → /plannotator-review Let /ck:cook handle the approved plan. Before you commit, open the diff with /plannotator-review and comment inline on the exact lines.
/plannotator-annotate ./docs Annotate Markdown, HTML, or folders such as ./docs with the same review surface, no extra setup.
After `/ck:plan` writes a plan file, open that exact `plan.md` with Plannotator. When you send feedback in the browser, annotations return to the current agent session and the agent should revise the plan before implementation starts. Ask again only if the review happened outside this session.
# 1) Ask ClaudeKit to produce the plan artifact
/ck:plan "Build the feature and save a phased implementation plan"
# 2) Use the real path printed by /ck:plan
/plannotator-annotate plans/<plan-slug>/plan.md
# 3) In the browser, comment on:
# - requirements, scope, assumptions, risks
# - phase order and acceptance criteria per phase
# - missing tests, rollback, docs impact
# - unresolved questions before implementation
# 4) Send feedback / finish the browser review
# The annotations return to this agent session.
# The agent should revise the plan from those notes before implementation. The same pattern works after cook, test, code review, or docs generation. Open the diff or artifact that needs human judgement, annotate it, then send the feedback back to the agent.
# After the approved plan, let ClaudeKit implement
/ck:cook
# Review the actual working-tree diff before commit
/plannotator-review
# Review other artifacts CK or the agent produced
/plannotator-annotate reports/<run>/test-report.md
/plannotator-annotate reports/<run>/review.md
/plannotator-annotate ./docs Keep them as separate tools. Use Plannotator beside ClaudeKit, not merged into it — that keeps CK free of a UI server and browser state, and lets each update on its own schedule.
When not to use it
References