Pinta Documentation

Pinta is a Chrome extension and companion server that hands visual UI annotations to a coding agent — Claude Code, Cursor, Aider, or any MCP-compatible tool — which edits your source files. This guide covers the mental model, every module, the multi-agent workflow, and a troubleshooting reference.


What is Pinta

Pinta closes the loop between "I see what's wrong on this page" and "the agent edits the right file." You annotate the running app — pick an element, draw on a screenshot, drop a pin, type a comment — and hit Submit. The agent reads your annotation, finds the source file, makes the change, and reports back. No screenshots pasted into chat, no manually grepping for selectors, no copy-paste round trips.

Three pieces work together:

ComponentRole
ExtensionChrome side panel + on-page overlay. Where you draw and submit.
CompanionNode server on 127.0.0.1:7878+. Receives your submission, persists the session.
AgentClaude Code (or compatible) running the /pinta skill. Reads the session, edits source files.

The mental model

Pinta is opinionated about the verbs you use to talk to your codebase. Today there are three:

Each verb is a Pinta module. Enable the ones you want in Settings; ignore the rest. The extension's UI is just the surface; the wire protocol and agent skill stay narrow.

Why does this matter? Every module reuses the same session lifecycle — discover companion, claim, edit / answer, done. Once you understand one, you understand them all. The differences live in the agent's instructions per module, not in new infrastructure.

Install & first run

1. Install the Chrome extension

Get it from the Chrome Web Store (search for "Pinta"), or load it unpacked from the GitHub repo if you want the unreleased build.

An unpacked build has its own extension id, so the companion refuses it until you trust it once, from a terminal (copy the id from chrome://extensions):

npx pinta-companion trust <extension-id>
# undo: npx pinta-companion untrust <extension-id>   list: npx pinta-companion trust --list

2. Start the companion in your project

npx pinta-companion .

# Or, if you cloned the repo for Pinta dev:
node ~/.claude/skills/pinta/start-companion.js .

The companion binds the first free port in 7878-7898 and registers itself in ~/.pinta/registry.json so the extension + agent skill can find it.

3. Install the /pinta skill

The /pinta slash command is a Claude Code skill — it is not installed by npx pinta-companion. Install it once (no clone needed), then fully restart Claude Code (skills load at startup; /clear is not enough):

npx pinta-companion@0.10.0 install-skill

The @0.5.0 is deliberate — npx may have an older pinta-companion cached, and the install-skill subcommand only exists in 0.5.0+. Prefer a plugin? /plugin marketplace add kevzlou7979/pinta then /plugin install pinta@pinta (invoked as /pinta:pinta, auto-updates).

4. Run /pinta in Claude Code

Open a Claude Code terminal in your project root and type /pinta. The skill discovers the companion via the registry, opens a long-lived SSE stream, and waits for sessions. It will say something like:

"Companion is up on port 7878 for /path/to/your/project.
Open the Pinta Chrome extension, annotate the page you want
changed, and hit Submit. I'll wait."

5. Open the side panel

Click the Pinta icon in your Chrome toolbar (or pin it first). The side panel opens on the right; the project picker at the top should say Connected · your-project.

Your first annotation

  1. Open the page you want to change in any tab.
  2. In the side panel, click Select (the cursor icon) and click any element on the page. A pink halo appears; the element gets a pin badge.
  3. Type a comment in the popup: "make this button match the brand color".
  4. Hit Submit in the panel.
  5. Your /pinta terminal lights up: the agent reads the annotation, finds the source file, shows you the plan, and waits for confirmation.
  6. Reply "go" (or just confirm) and the edit happens. Refresh the page to see it — or rely on HMR / auto-reload if your dev server supports it.
Tip: Auto-apply is off by default. If you tick Auto-apply (no agent confirmation) in the submit footer (it stays ticked for later submits), the agent skips the wait-for-go step and applies directly. The plan is still shown briefly so you can see what's happening.

Annotate always on

The core verb. Three annotation shapes:

Inline editor

On select mode, the popup has tabs for Content (edit text in place), Font / Sizing / Spacing (CSS pickers populated from getComputedStyle), and CSS (free-form). Edits apply to the DOM live so you see the result before submitting. The diff is captured and shipped to the agent verbatim.

Hotkeys

On the page (the overlay ignores INPUT / TEXTAREA / contenteditable so typing into your app never triggers these):

Side panel (not while typing in a field):

Inline element editor + comment popover:

Chat input (Test Pilot per-row, global, Just Ask):

Settings → Keyboard shortcuts lists the same set inside the side panel for quick reference.

GitLab Issues module

Tick Create GitLab issues in the submit footer and the agent files one issue per annotation after the source edits land. Auth is delegated to your glab CLI (run glab auth login --scopes api,write_repository once); Pinta never sees the token.

Each issue carries the annotation's selector, source-file pointer, page URL, the full-page screenshot (uploaded to your project's uploads endpoint), and a footer linking back to the Pinta session, with a summary / Root cause / Fix direction / Repro body. The gear next to Create GitLab issues sets the Assignee and Labels (default domain:client, bug) applied to every issue — the agent files straight away, no chat prompt. Blank labels means no labels.

If you only tick GitLab Issues without Auto-apply (file-only mode): no source edits happen. The agent just files the tickets. Useful when you want a backlog item but don't want code touched yet.

Test Pilot module

Interactive UAT module in its own side-panel tab. Two ways to start:

  1. Import a hand-written markdown test spec.
  2. Generate a UAT spec from project context — the agent scans your routes / components / auth flow and writes one.

Either way you get a catalog — sections of test rows. Mark each row Pass, Fail, or leave it untested. Click the ? on any row to ask the agent for step-by-step instructions (toggle Detailed help steps in Settings for deeper technical context).

Editing the catalog (Phase 13)

Right-click the kebab on any section or row for delete / add / rename / move-up / move-down / "add test below". Drag-and-drop also works — grab a row's grip handle on the leading edge. Edits sync to .pinta/test-docs/{docId}.md on disk so the agent's ? flow works against rows you added yourself.

Auto-save status to disk

Pass / Fail marks land in a Result column in the on-disk markdown — so if browser storage gets wiped, re-importing the same spec restores your marks. Catalog structure is the source of truth.

Tester round-trip v0.10.0

Export → Tester sheet (.md / .docx) or Email hands the catalog to a human tester. Any test without steps gets them generated first (untick Generate missing steps first to export as-is). The tester imports the sheet in Pinta with no companion, marks Pass / Fail, and sends ONE file back: Results (.md) with a sign-off, or a .pinta bundle with Contents set to Annotations + test results. Importing it overlays their marks read-only on your catalog; Clear restores your own.

Smoke vs Thorough

The Smoke test / Thorough toggle in the tab (or Settings → Test Pilot → Thorough test generation) sets how much catalog import / generate produces. Smoke (default) is a quick happy-path pass; Thorough covers every feature with edge cases and negative paths — more tokens, slower.

File failed tests + Suggest Test

File failed tests in the header files every failed, not-yet-filed row in one run: a GitLab issue per test via glab (no duplicates), or entries in .pinta/tasks.md when GitLab isn't set up. Suggest Test on a section header asks the agent for missing scenarios; tick the ones you want and they join the section.

Chat module

Inquiry-mode module — one Settings toggle lights up three chat surfaces:

Replies render with light markdown (inline code, fenced blocks with syntax highlighting, > Note: callouts). The Test Pilot tier has a special affordance: when the agent suggests test scenarios in its reply, a one-click Add N to spec button appears below the bubble — adds the suggestions to the current section (or creates a new section).

Detailed responses toggle

Settings → Chat → Detailed responses. Off (default) = short, tester-friendly. On = deeper technical detail (curl, payloads, env vars, ARIA names). Affects all three chat surfaces.

AuditFlow module

Lighthouse-style audit surface in its own side-panel tab. Pick categories, run audit, get back per-category scores with actionable findings.

Categories (Phase 15b)

All categories are static analysis of your source by the agent — no browser or Lighthouse run. Add your own categories and checks, or ask for more with Suggest checks.

Fix with agent

Every finding has a Fix with agent action that fixes the source in place, with a per-row loader; a category's ⋮ menu adds Fix All. Discuss opens a chat about the finding and File issue files it to GitLab (or .pinta/tasks.md). Mark findings resolved or won't-fix — the marks survive re-runs.

Scoring

Deterministic: (pass × 1 + warn × 0.5 + fail × 0) / (pass + warn + fail) × 100. Info checks excluded from the denominator. Rating: 90+ Excellent, 70+ Good, 50+ Needs work, else Poor.

Design Variants module v0.9.0

Ask for design options without leaving your app. Pick an element (or the whole page) and the agent returns 1–5 variants that stay inside your design system, as preview cards. Enable it in Settings, then open the Design Variants tab.

Settings: optional design-system path and device presets. Agent HTML is sanitized before it reaches the panel or your page.

Code Review module v0.9.0

A game-style review of your own change. The agent reads your uncommitted diff (or the last commit when the tree is clean) and deals one card per logical change. Enable it in Settings, then open the Code Review tab.

Devices module v0.9.0

See your running app on many devices at once. Enable it in Settings, open the Devices tab, and launch the canvas — a full browser tab of live, clickable device frames. The canvas needs no agent; annotations you make inside a device go to the agent like any other.

Report module

See what you shipped. Enable it in Settings, open the Report tab and pick a range; the agent gathers git, GitHub / GitLab and Pinta activity (read-only) into day cards.


Role flags (Phase 18) multi-terminal

Run multiple /pinta Claude Code terminals against the same project and dedicate each to a workload. Each terminal declares which session kinds it claims; mismatches silently skip to other terminals.

FlagClaims sessions where…
--annotatemodules[] contains none of test-pilot, audit-flow, chat, design-variants, code-review
--test-pilotmodules[].id contains test-pilot
--auditmodules[].id contains audit-flow
--chatmodules[].id contains chat
--variantsmodules[].id contains design-variants
--reviewmodules[].id contains code-review
(no flag)Claim everything — default, current behavior

Flags stack: /pinta --test-pilot --audit claims both kinds. Typical 4-terminal setup:

Terminal 1: /pinta --annotate     # source-edit work
Terminal 2: /pinta --test-pilot   # UAT runs + per-row chat
Terminal 3: /pinta --audit        # audit runs, low traffic
Terminal 4: /pinta --chat         # Just-Ask + global chat

The companion enforces roles: a terminal that tries to claim a session outside its role gets a 403.

Coverage matters. At least one terminal in the project must accept each kind in use. If you start all 4 specialized terminals but submit a regular annotation, the session sits unclaimed — the side panel will warn you after 10s: "No /pinta terminal is claiming annotation sessions. Run /pinta in your project's Claude Code terminal (or /pinta --annotate)."

Multi-project setup

One companion runs per project. The extension's project picker (top of side panel) shows every running companion. When you switch tabs, Pinta auto-routes to the companion whose URL patterns match — annotations made on localhost:5173 go to one project, annotations on localhost:3000 go to another, all without you re-picking.

Add URL patterns by clicking the project name in the picker, or by editing .pinta.json in your project root:

{
  "urlPatterns": [
    "http://localhost:5173/**",
    "https://staging.example.com/**"
  ]
}

Settings

Click the gear icon in the side-panel header. Modules are listed; tick to enable. Each enabled module exposes its own settings:

Visual feedback

Settings → Visual feedback → Processing pulse enables a pulsing colored glow around the page edges while the agent is applying changes. Off by default; cosmetic only.

Standalone mode

Pinta works without a companion. Useful for testers hitting deployed URLs who don't have the project on disk: the side panel falls into Standalone mode, sessions live in browser IndexedDB, and you can Copy (markdown to clipboard) or Download instead of Submit.

Standalone is also useful for trying Pinta before you've installed the companion — the annotation UX works fully; only the agent-edit loop is gated on having a companion + /pinta running.

Share files (.pinta)

Click the download icon in the panel header to export a session as a .pinta file: a self-contained JSON document with the annotations, screenshots inline, and your manifest (title, author, accent color, description). Send it to a teammate; they open Pinta and pick Import .pinta.

Imported sessions are read-only in the viewer. Two follow-up paths:

Module settings (e.g. GitLab tokens) are stripped from share files. Each recipient uses their own configured modules.

Troubleshooting

Side panel says "No companion is running"

Start the companion in your project root:

npx pinta-companion .

If it complains about another companion already on the port, check ~/.pinta/registry.json — stale entries from crashed companions can linger.

Side panel says the companion refuses this extension

The companion only talks to the Web Store build, ids in PINTA_EXTENSION_IDS, and ids you trusted with npx pinta-companion trust <extension-id> (stored in ~/.pinta/trusted-extensions.json). Nothing is trusted automatically, so another extension can't pose as Pinta. Run the trust command only for a build you loaded yourself.

Companion is running but the agent doesn't pick up sessions

Most likely: /pinta isn't running in a Claude Code terminal for this project. Start one. If you're using role flags, make sure at least one terminal covers the kind you're submitting (see Role flags for the matrix).

Agent edited the wrong file

Pinta uses a 3-tier locate strategy: data-source-file attributes (Phase 6 Vite plugin), then a project-wide grep for nearby text, then a route-scoped fallback. The Vite plugin gives the highest accuracy (~95%); without it, you're at grep-accuracy (~80%). If you keep hitting wrong files, install the plugin or give the agent more nearby text by typing a verbose comment.

Auto-apply edited a file but I wanted to discuss first

Auto-apply is off by default. If it's on and you want a discussion instead, untick it AND tick Just Ask — the submit button re-labels to "Ask agent" and routes to the chat sheet instead of editing source.

GitLab Issues filed but no screenshot embedded

Your glab token likely lacks api / write_repository scope. Re-auth:

glab auth logout
glab auth login --scopes api,write_repository

Chat says "Agent returned an empty response"

Usually means the agent had no answer for an image-context prompt and submitted blank. Try rephrasing with more context (paste a screenshot into the chat, mention the file path), or restart /pinta if the agent seems stuck.

Sessions sitting in "Submitted" forever

After 10 seconds, the side panel surfaces a claim-warning telling you what's likely wrong (no /pinta running, or no terminal accepting the session's kind under your role flags). Most fixes: start a /pinta, or unblock a stuck agent terminal.

Privacy

Pinta sends annotation contents (selectors, comments, optional screenshots) to the agent you've configured — the same Claude Code / Cursor / etc. you'd use anyway. Pinta itself doesn't host servers, store sessions remotely, or send telemetry. The companion binds 127.0.0.1 only.

See the full Privacy Policy for the per-field breakdown.


What's next

See the Roadmap on the landing page for what's planned. Quick highlights: