Skip to content

/annotate-inline

The full raw-tab session: arm through teardown. The overlay source, the port stamp, the annotate clear, and the channel protocol live in `${CLAUDE_PLUGIN_ROOT}/commands/references/annotate-overlay.md` - read it before Step 2 and hold it for the session. The capture channel is

BOOST
From plugin
craft
6871 skills27 agents71 commands7 hooks
+1
Install
> /plugin marketplace add drobins25/craft
> /plugin install craft@craft

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/annotate-inline

Context preview

What this command does when you run it.

The full raw-tab session: arm through teardown. The overlay source, the port stamp, the annotate clear, and the channel protocol live in `${CLAUDE_PLUGIN_ROOT}/commands/references/annotate-overlay.md` - read it before Step 2 and hold it for the session. The capture channel is

Command definition

annotate-inline.md

Annotate Flow

The full raw-tab session: arm through teardown. The overlay source, the port stamp, the annotate clear, and the channel protocol live in `${CLAUDE_PLUGIN_ROOT}/commands/references/annotate-overlay.md` - read it before Step 2 and hold it for the session. The capture channel is driven only through `${CLAUDE_PLUGIN_ROOT}/hooks/scripts/annotate-run.sh`.

**No question widgets anywhere in this flow - never, at any step, including every exit.** The mode is armed by invocation and steered in plain conversation.

This flow runs in the orchestrator, not a subagent: it needs the browser connection and the session's own wake-up.

**How a snippet reaches the page.** `evaluate_script` takes a function and calls it. Every snippet this flow sends to the page - the clears, the overlay source when pasted, the listener probe and the storage read - goes in as the body of `() => { <snippet> }`, with the snippet's text unchanged inside. The exceptions are the lines `loader`, `stamp`, `sheet` and `apply` print: the lines `loader`, `stamp` and `sheet` print are already functions, so each goes in verbatim, because evaluate_script calls the function it is given and returns what it returns - the loader line returns `LOADED` or `SCRIPT-BLOCKED`, the stamp line `STAMPED`, the sheet line `APPLIED`. The lines `style` and `annotate-resolve.sh" probe` print are functions too and go in verbatim. Pasted bare, a snippet that ends in `;` is refused with `Unexpected token ';'` and nothing runs. On an external page these are the only scripts that run before the user types: any other script, or one of these edited, waits for their yes.

Step 1: Connection check

The overlay reaches a tab through the chrome-devtools connection. If that connection is not available, say so in one plain line and stop - no offer, no error, no setup instructions. Otherwise list the tabs and select the one the user means (the subject, or the tab already selected when no subject was given).

Listing the tabs is the session's first browser call. Right after it run `node "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/devtools-launch.cjs" notice`; a printed line is said to the user verbatim, and nothing printed means nothing said.

**Fresh window rule.** When every listed tab is `about:blank` or a new-tab page, the window has none of the user's pages. If the subject is an address (`http://`, `https://`, `file://`), open it with `new_page`. Otherwise say exactly "This window has none of your pages open - what address should I open?" (no question widget), open the reply with `new_page`, then select it. When the notice line and this question are both spoken, they go in one message.

Step 2: Arm or reuse the session listener

The listener is lazy and per-session. It starts the first time a flow needs it and lives until the session ends. Nothing in this flow ever shuts it down. Every start, first or restart, goes through `## Starting the listener` in the overlay reference - nothing in this flow starts one any other way.

**The project folder.** When `CRAFT_PROJECT_ROOT` is set the project is set up and every script finds it; skip this paragraph. Otherwise run this once and hold the folder it prints as `<project root>`:

bash -c 'source "$1" >/dev/null 2>&1; craft_refuse_monorepo_top "an annotate session" && exit 1; craft_before_init_root' _ "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/find-workshop.sh"

When it exits 1 it printed a `nothing written:` line on stderr and no folder: say that line to the user verbatim and stop before `arm`, with nothing armed and nothing written.

**Saved runs.** Once per conversation, before anything else in this step arms or marks a page, list the runs an earlier session left cut short (leave `--root` off when `CRAFT_PROJECT_ROOT` is set):

bash "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/annotate-record.sh" cut-short --root "<project root>"

It prints one `CUT <name> PINS <n> <subject>` line per run, newest first, or nothing. Hold the lines; Step 4 says the offer. Run it before the loader marks a page: on an outside page the block holds `annotate-record.sh` commands until the user types.

  • **No session id held in this conversation:** arm one per `## Starting the listener`, passing `--root "<project root>"` when it is held:
  bash "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/annotate-run.sh" arm --background --root "<project root>"

Hold the id and the port it ends with.

  • **A session id is already held** (an earlier `/craft:annotate` or another flow in this conversation armed one): read it back, and reuse it.
  bash "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/annotate-run.sh" status --session "<id>"
  • `no such session: <id>` (typically after the conversation was resumed, when session start already filed the old run): drop the id and arm a new session with no `--session`, without a word. Never `arm --session` that id - its folder is gone and that would recreate it.
  • `PORT none`, or `CLIENTS unreachable` (the listener is not answering): run `ensure --session "<id>"` and act on its line as the read beat does.

Only ever reuse an id this conversation armed: another pane in the same project has its own session, and its listener is not yours.

Never arm a second listener while one is held.

Then mark the start of this run, whether the listener is new or reused:

bash "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/annotate-run.sh" begin --session "<id>" --subject "<subject>"

The subject is the args, else the title of the selected tab. `begin` starts the run's sheet and puts the watch at the run's start, so a set sent by an earlier flow on the same listener is never mistaken for this run's first SEND. It also files any run on this session that never reached an exit.

Step 3: Clear any dial residue, then any earlier overlay

Run the canonical dial clear on the selected tab first, unconditionally. A dial panel from an earlier session may still be on the page, and pins taken on a

Read more
Ships withcraft

Stop Vibing. Start Crafting. A Claude Code plugin that acts as an intelligent harness for your development workflow: your codebase is read-only by default, every change passes through a Write Gate as planned and approved work, and craft tracks your project's

Get the whole plugin, auto-invoked

Other commands on craft.

craft-annotate
CommandAuto-invoked

craft-annotate

Point at anything in a live browser tab - every pin gets a live attempt on the page the moment you SEND it, and the session keeps…

@drobins25@drobins25Install Command
craft-become
CommandAuto-invoked

craft-become

Agent crystallization command. Studies a tool, role, or person and produces a portable 9-section agent that inhabits the domain -…

@drobins25@drobins25Install Command
craft-bugs
CommandAuto-invoked

craft-bugs

File a bug without fixing it, from a person mid-conversation or an agent mid-run. One door, a complete record on disk, nobody…

@drobins25@drobins25Install Command