---
title: "Plannotator Explained: The Visual Review Layer for AI Coding Agents"
description: "Deep dive into Plannotator: the browser visual review surface and hook layer for Claude Code, OpenCode, and Codex. Annotate plans, review diffs, and steer agents."
pubDate: "2026-11-15"
lang: "en"
slug: "plannotator-explained"
url: "https://hoangyell.com/plannotator-explained/"
author: "HoangYell"
translation_vi: "https://hoangyell.com/vi/plannotator-explained/"
categories: ["AI & Agents"]
tags: ["claude-code", "ai-agents", "developer-tools", "code-review", "mcp"]
heroImage: "https://cdn.jsdelivr.net/gh/HoangGeek/store@main/webp/ai-plannotator-explained-hero.webp"
---

If you have used Claude Code, OpenCode, or any CLI coding agent on a non-trivial project, you know this exact scenario:

You give the agent an intricate assignment: *"Refactor the auth module to support WebAuthn passkeys alongside JWT, maintaining full backwards compatibility"*.

The agent enters Plan Mode and streams a 150-line markdown plan inside your terminal. It details each file it intends to modify, each database schema change, and pauses on a single prompt:

```text
Do you want to proceed with this plan? (y/n)
```

This is where the workflow stalls. Pressing `y` without thorough review is risky: if step 3 miscalculates a Redis session lifecycle or step 6 deletes a shared helper, your codebase breaks. But pressing `n` or typing feedback into the terminal is equally frustrating. You end up drafting awkward command line instructions: *"In step 3 do not use an external dependency, rewrite the verify helper in utils.ts following the existing pattern..."*. By the time you finish typing, manually editing the code would have been faster.

[`backnotprop/plannotator`](https://github.com/backnotprop/plannotator) targets this operational bottleneck. Rather than modifying model intelligence, it re-engineers how humans supervise agents during planning.

## TL;DR

> **Fast Breakdown:**
> - **What is Plannotator?** An open-source, local-first review layer that automatically intercepts an AI coding agent before execution, opening a web canvas for visual redlining.
> - **Mouse-Driven Plan Corrections:** Instead of typing cumbersome descriptions in terminal text, Plannotator launches a browser interface where you highlight bad assumptions, strike out unneeded steps, and attach inline comments directly to the relevant line.
> - **Non-Blocking Execution (Claude Code 2.1.287+):** Frees your terminal. The agent terminates its current conversational turn cleanly rather than freezing the subshell, letting you inspect the plan at your own pace without session timeouts.
> - **Multi-VCS & Agent Ecosystem:** Integrates with Claude Code, OpenCode, Codex, and MCP; supports Git, GitButler, Jujutsu (`jj`), and Perforce (`p4`).
> - **Repository:** [backnotprop/plannotator on GitHub](https://github.com/backnotprop/plannotator) (Apache 2.0 / MIT).

***

## The Mental Model: Terminals Stream Logs, Browsers Review Plans

The architectural mismatch is straightforward: **Terminals were built to run commands and stream log outputs. They were never designed for human beings to read, critique, and annotate complex multi-step architecture plans.**

When an autonomous agent outlines a 10-step refactoring plan touching 6 files, you need visual markup: striking out superfluous steps, flagging delicate migrations, and attaching notes inline. Keyboard navigation and monochrome terminal text cannot match that bandwidth.

Plannotator intercepts this exact handoff:

```markdy
scene duration=20 layout=LR width=1280 height=720
theme: light=doodle dark=nebula

user Dev "Developer (Reviewer)"
service Agent "Coding Agent (Claude Code / OpenCode)"
module Hook "Plannotator Hook Layer"
service Server "Local Review Server (Dynamic / :19432)"
service WebUI "Visual Annotation Canvas & Diff Editor"

beat interception "Plan Interception & Review Lifecycle":
  show $nodes stagger=50ms
  Agent -> Hook "ExitPlanMode or Diff Generation"
  Hook -> Server "Intercept plan, spin up ephemeral server"
  Server -> WebUI "Open browser tab or VS Code webview"
  WebUI -> Dev "Render interactive plan: highlight, strike, comment"
  Dev -> WebUI "Submit feedback with one click"
  WebUI -> Server "Serialize structured review annotations"
  Server -> Hook "Dispatch payload to agent environment"
  Hook -> Agent "Agent updates plan based on exact highlights"
  glow WebUI color=#22c55e
  glow Hook color=#3b82f6

player:
  playback:
    loop true
  controls:
    speed true
    speeds "0.25"
    interact true
    fullscreen true
    gif true
    theme true
  interaction:
    zoom true
    pan true
    click_to_play true
    double_click_to_reset true
    keyboard false
  chrome:
    badge true
    progress none
```

***

## Hands-On Reality: From Terminal Text to Visual Redlining

Plannotator does not modify underlying LLM weights. It hooks directly into the agent event loop.

![Image](https://cdn.jsdelivr.net/gh/HoangGeek/store@main/webp/ai-plannotator-explained-gallery-01.webp)

### 1. Intercepting `ExitPlanMode`

In Claude Code, when the model completes its analysis and prepares to apply changes to files, it triggers an internal tool named `ExitPlanMode`.

Plannotator registers a hook that catches this event:

```json
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "plannotator",
            "timeout": 345600
          }
        ]
      }
    ]
  }
}
```

The moment Claude signals an intention to leave Plan Mode, the hook takes over:
1. It reads the markdown plan from standard input (`stdin`).
2. It spins up an ephemeral local HTTP server (selecting a random port by default).
3. It launches a browser tab or an internal VS Code webview.

Instead of an unyielding `y/n` prompt, you get an interactive document:
- Want to omit step 5? Select the step and click strike-through.
- Step 7 uses the wrong schema? Highlight the phrase, type an inline note: *"Use user_id column instead of account_id"*.
- Ready? Click **Send Feedback**. Plannotator serializes your annotations into structured prompt context, injects it back to the agent, and Claude regenerates the plan accordingly without requiring manual text coordination.

### 2. Non-Blocking Execution in Claude Code 2.1.287+

Historically, when a CLI hook intercepted a command, it blocked the subshell. The agent remained locked in an active wait state. If the plan was complex and you stepped away for 15 minutes, your shell remained frozen. Any network hiccup risked dropping the session.

Beginning with Claude Code 2.1.287+, Plannotator enables an asynchronous non-blocking workflow by default (disableable via `PLANNOTATOR_CLAUDE_MOD=0`):
- **Clean Turn Termination:** Instead of freezing Claude Code in a synchronous wait loop, the hook instructs Claude to end its current conversational turn immediately.
- **Unconstrained Terminal:** Your shell is free. You can run git commands, run tests, or close your laptop.
- **Resume as Next Turn:** When you complete your review on the browser and click "Approve", Plannotator delivers your approval as the next user turn. Claude resumes, ingests the annotations, and executes without shell lockup.

### 3. Plannotator Inbox: Aggregating Multi-Agent Workflows

A major feature of the project is **Plannotator Inbox**.

When running multiple agents concurrently (such as Claude Code handling backend refactoring while OpenCode writes integration tests), running `plannotator inbox mcp` turns Plannotator into an MCP server. Any agent requiring user sign-off or diff inspection can route requests into a single local queue. You review decisions sequentially in one browser tab rather than toggling across separate terminal windows.

***

## Production Gotchas & Operational Traps

Deploying Plannotator in real workflows reveals two operational traps and one critical security consideration:

![Image](https://cdn.jsdelivr.net/gh/HoangGeek/store@main/webp/ai-plannotator-explained-gallery-02.webp)

### 1. SECURITY ADVISORY: Remote Mode Over SSH and Docker

When developing on a remote VM or inside a headless Docker container without a display server, the default browser opener (`xdg-open` or `open`) fails. You can switch to remote mode:

```bash
export PLANNOTATOR_REMOTE=1
export PLANNOTATOR_PORT=19432
export PLANNOTATOR_BROWSER=none
```

> **CRITICAL SECURITY REQUIREMENT:**  
> When `PLANNOTATOR_REMOTE=1` is set, Plannotator binds to `0.0.0.0` with **zero authentication**. Anyone who can route network packets to port 19432 can inspect your code plans and inject feedback directly into your agent.  
> **Mandatory Hardening:** Never expose port 19432 on a public firewall or cloud security group. Always restrict access via a local SSH tunnel:
> ```bash
> ssh -L 19432:localhost:19432 user@remote-server
> ```
> Alternatively, isolate access within a private Tailscale network.

### 2. The Over-Annotation Token Trap

An interactive visual canvas often tempts developers into micromanagement: fixing punctuation, debating variable names, or tweaking formatting.

Remember: **Every annotated comment is injected into the model context window as natural language instruction.** Leaving dozens of minor comments consumes significant context tokens and dilutes model attention away from high-stakes architectural changes. Focus your annotations on critical paths: schema integrity, migrations, security boundaries, and edge cases. Let automated linters handle code style.

***

## Setup in 2 Minutes

Install the standalone binary (the installer automatically detects Claude Code and sets up the hook):

```bash
# Install standalone binary
curl -fsSL https://plannotator.ai/install.sh | bash
```

To install manually through the Claude Code plugin manager:

```bash
/plugin marketplace add backnotprop/plannotator
/plugin install plannotator@plannotator
```

Once installed, work with Claude Code as usual. The next time a prompt triggers Plan Mode, the visual review tab launches automatically.

***

## Final Take

Tools like Plannotator highlight a key evolution in software development: **Once AI code generation crosses baseline competence, developer productivity is bounded not by model generation speed, but by the cognitive overhead of human review.**

Let the terminal execute commands and stream logs, and let a dedicated visual interface handle the high-bandwidth task of reviewing architectural plans.

***

## FAQ

### 1. Are plans and code sent to external servers?
By default, Plannotator provides optional team sharing via `room.plannotator.ai`. For proprietary codebases where external network transmission is prohibited, disable sharing entirely:
```bash
export PLANNOTATOR_SHARE=disabled
```
Additionally, note that application startup checks GitHub for new releases, URL annotations query Jina, and the "Ask AI" feature sends context to your configured LLM provider.

### 2. Can Plannotator review actual code diffs?
Yes. Beyond intercepting `ExitPlanMode` for markdown plans, Plannotator provides a side-by-side diff viewer with support for Git, GitButler, Jujutsu (`jj`), and Perforce (`p4`).

### 3. How do I reopen a previous review session?
To list previous review sessions, run:
```bash
plannotator sessions
# Or open session number N directly:
plannotator sessions --open <N>
```
Within Claude Code, `/plannotator-last` requests review of the agent's most recent message.
