Agent-01

beta

A review widget doorman injects into any gated site, and an MCP server that hands the page the visitor is looking at to Claude or ChatGPT — live edits, then a ticket.

Agent-01

Doorman already stands in front of the site, so it is the one place that can add something to it without touching the project's code. Agent-01 is what it adds: a corner bubble the reviewer can talk through, and an MCP server that exposes the page they are looking at as tools.

Put the browser and Claude side by side. Say "the hero heading is too big". Watch it change in the tab. Then say "file that", and the change request lands with the before and after of every edit attached.

No browser extension, no code in the customer project, nothing to install.

Turn it on

Agent-01 is off until a site asks for it. PUT /sites/{slug} replaces the whole record, so read the current one, add the block, and put it back:

BASE=https://griller.kunde.example/_doorman/api/v1
AUTH="Authorization: Bearer $DOORMAN_ADMIN_TOKEN"

curl -s "$BASE/sites/griller" -H "$AUTH" \
  | jq '.widget = {enabled: true, mcp: {enabled: true}, tickets: {enabled: true}}' \
  | curl -X PUT "$BASE/sites/griller" -H "$AUTH" -H 'Content-Type: application/json' -d @-

Changes apply immediately — no restart. Reload the site. A small bubble appears in the corner, showing who the gate let in — anna@kunde.dk, and how she got there.

What the reviewer gets

  • Who am I. The identity the gate recognised, so a shared PIN and a personal magic link do not look the same.
  • Select element. A crosshair. Click the thing you mean; the widget keeps the selector, so "this button" becomes something an assistant can act on.
  • Send feedback. Title, description, and whatever is selected — filed as a ticket against the site.
  • Edits. Everything changed in this session, with one-click revert. The page is never permanently modified: the edits live in that browser and nowhere else.
  • MCP [on | off]. The toggle below.

Connecting an assistant

Switch MCP on in the widget. It shows a URL:

https://griller.kunde.example/_doorman/mcp/<token>

Add it as a custom connector in Claude or ChatGPT, or as a remote MCP server in Claude Code:

claude mcp add --transport http griller https://griller.kunde.example/_doorman/mcp/<token>

The assistant can now see and change that tab. Ask it to snapshot the page first; everything else works from the selectors that come back.

The toggle is also how you choose which tab. Only one tab is attached at a time — switch MCP on somewhere else and the first one is told it lost the session, so there is never any doubt about which page an assistant is talking to.

The URL is the credential: anyone holding it can drive that page. It expires (14 days by default), and switching MCP off and on again mints a new one.

What the assistant can do

Readsnapshot, query, get_html, get_selection
Changeset_text, set_style, set_attribute, replace_html
Interactclick, fill, navigate (same-origin only)
Undolist_edits, revert_edits
Hand backcreate_ticket

Every change is highlighted in the page as it happens — the reviewer watching is the point, not an afterthought — and every change is journalled, so nothing an assistant does is invisible or irreversible.

create_ticket asks the page for its own account of the URL, the selection and the journal rather than taking the assistant's word for it.

run_js

Off by default. Add "allowScript": true to the mcp block and the assistant also gets an arbitrary JavaScript expression in the page.

It is genuinely useful — a one-liner is often the honest answer to "why is this element three pixels off" — and it turns the connector URL into an execution credential in the reviewer's session. Enable it on your own staging, think twice on anything a customer is looking at.

Where the tickets go

Doorman stores them and hands them back; the platform that owns the customer relationship owns the UI.

GET   /_doorman/api/v1/sites/{slug}/tickets?status=open
GET   /_doorman/api/v1/sites/{slug}/tickets/{id}
PATCH /_doorman/api/v1/sites/{slug}/tickets/{id}     {"status": "closed"}

A ticket carries the title and body, who raised it and how they got in, the page URL, the selected element, and the full edit journal — selector, what kind of change, and the value it replaced. Set tickets.webhookUrl and each new one is also POSTed straight to your issue tracker, chat channel or automation.

Notes for strict sites

  • The script and the socket are same-origin — doorman serves them from the site's own hostname, so no CORS and no third-party anything.
  • If the app sends a Content-Security-Policy, doorman widens the declared script-src/connect-src/default-src by 'self' and nothing else. It never removes a directive and never adds one that was not there.
  • The widget renders in a closed shadow root, so it cannot collide with the page's own CSS or be reached by its scripts.
  • A visitor who is not through the gate gets no widget at all, and no endpoint answers them.

See also

  • Admin API — the site record, and the ticket endpoints in full
  • Quickstart — get a site behind doorman first