Skip to content

/annotate-overlay

The comment-mode overlay that lets someone point at a page and have Claude read what they said. It is one self-contained script, and every delivery installs this same source unchanged:

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-overlay

Context preview

What this command does when you run it.

The comment-mode overlay that lets someone point at a page and have Claude read what they said. It is one self-contained script, and every delivery installs this same source unchanged:

Command definition

annotate-overlay.md

Annotate overlay

The comment-mode overlay that lets someone point at a page and have Claude read what they said. It is one self-contained script, and every delivery installs this same source unchanged:

  • **Served by the listener** for a live inject on a project page (localhost, 127.0.0.1 or file://): `GET /overlay.js` returns the fence below, and `annotate-run.sh loader` prints the one line that loads it.
  • **Pasted** on an external page, and on any page that refuses the served script: the fence goes to `evaluate_script` as the body of `() => { ... }`.
  • **Spliced by `bake`** for a mockup round: `annotate-run.sh bake` writes the stamps and the fence into the page file.

The listener and `bake` read the fence below at run time, through one extractor, so the three deliveries are the same bytes. Nothing in the script knows which delivery it came from except two stamps the delivering flow writes into the page first (see [The stamps](#the-stamps)).

The script is the only copy. Flows reference this file and never retype, trim, or fork the block below, because a second copy drifts and a drifted overlay posts to the wrong place or leaves nodes behind.

What the overlay does

A strip with three controls sits in a corner of the page: `COMMENT MODE: OFF` / `COMMENT MODE: ON`, `CLEAR PINS`, and `SEND TO CLAUDE`, with a `MARKUP - N marks` readout. With comment mode on, a thin red proof border frames the viewport and a click on any element opens a comment box. Saving it drops a numbered pin anchored to that element. Clicking a pin opens a popover with the full comment, plus EDIT and DELETE. `SEND TO CLAUDE` posts the full current set to the session's capture channel. `CLEAR PINS` tells the channel the set is void, then wipes the page.

The page under review stays the hero. There is no tint, dim, or shadow over the page: comment mode is carried by the border, the strip, and the pins, because the people using this judge the page pixel by pixel.

Rules the source keeps, and what each protects

  • **Install guard.** The source opens with `if (window.__craftAnnotateInstalled) return;`. A page that is re-injected after navigation, or injected twice by mistake, must not grow two strips. The canonical clear deletes the flag so a deliberate re-install still works.
  • **Placement.** The style element goes in `head`; the sheet and strip go in `body` as the last children. Framework re-renders reconcile only their own root, so anything appended inside it is eventually eaten. Pins are inserted just before the strip so the strip stays last.
  • **Namespaced handles.** `ca-style`, `ca-sheet`, `ca-strip` are ids; every other real node carries `data-craft-annotate-injected`. The canonical clear is total by construction because of that attribute. The overlay never sets the marker owned by the dial flow, because dial's clear runs unconditionally on arrival, while review flows clear annotate only through `review-clear`, which leaves the page alone during an open run.
  • **No port in the source.** The channel base is `'http://127.0.0.1:' + window.__craftAnnotatePort`. Each session's listener has its own OS-assigned port, stamped into its own pages. A literal in shared source would point every page at one session. An absent stamp means SEND shows `NOT ARMED - no craft session listening` while everything else keeps working locally. A stamp that is present but a request the browser refuses to send (a page policy that does not allow 127.0.0.1) shows `BLOCKED BY PAGE - ask Claude to read pins directly`: the pins are still in the page's local storage, and the session reads them from there.
  • **Inert until asked.** An injected page makes no network request before a user gesture. The loader's one script request is the delivery itself, made by the flow and never by the overlay. Only a page stamped as baked opens the event stream, exactly once at load, and reloads itself on the `reload` event. One exception: a page stamped with a run id (see [The stamps](#the-stamps)) fetches the session sheet and holds the change stream from install, because the flow's own injection is the ask. Dial and pasted pages without that stamp stay inert. A dropped stream retries quietly with a bounded backoff, and a change stream that never opened gives up after a few tries. There is no polling.
  • **Honest confirmation.** `RETURNED` is stamped only inside the resolved-200 branch of the SEND post, and every pin in the delivered set then gains a visible sent-stamp. A non-200 reply shows `NOT ARMED - no craft session listening` and stamps nothing. A request the browser rejects outright, with the port stamped, is a refusal by the page or the browser, never a listener state: it shows `BLOCKED BY PAGE - ask Claude to read pins directly` and stamps nothing. Every other channel failure is quiet; SEND alone is loud. A stamp written from a swallowed error is a lie the user acts on.
  • **Send-only.** The only request carrying pins is the one inside the SEND handler. Unsent pins live in the page and in local storage and nowhere else, so a pin the user never sent can never reach the channel.
  • **SEND commits first.** An open comment box is saved through the normal save path before the set is collected, so a comment mid-typing is never dropped from the set it visibly belongs to.
  • **CLEAR is authoritative.** The clear post goes first, then the wipe of DOM nodes, in-memory state, the counter, and the page-path-keyed storage entry. The post does not wait on the wipe and the wipe does not wait on the post. The strip then reads `CLEARED` and `MARKUP - 0 marks`.
  • **Numbers are labels.** Deleting a pin renumbers the survivors contiguously. Nothing outside the page reasons about a pin's number as an identity.
  • **Detached pins.** A pin whose anchor no longer resolves after a live edit docks above the strip in a flagged detached state, keeping its number and comment. Pins are re-checked when the page changes, not only on the next overlay event. A comment never silently va
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