a chrome extension for people whose coding agent just shipped the feature
point at what’s h1 > spanbroken. say what’s wrong.
Gripe turns clicking through a half-broken UI into a folder of markdown + screenshots your coding agent can read. Hotkey, click the thing, talk — the note saves itself, with the CSS selector, the screenshots, and whatever the console threw at that exact moment.
no enter key. you stop talking, the bar drains, the note commits.
Your agent just built the feature. You’re clicking through it and a dozen things are subtly off — this button does nothing the second time, that column drifts, this list should be sorted. Typing all that into a chat window is slow and lossy, and you’ve forgotten the first one by the time you hit the third.
gripe turns it into a stream of consciousness →
01 · the output
a folder in your repo, not a chat scroll
Every session writes straight into the repo you connect — markdown built for a model to read, screenshots with the target spotlighted, and a close-up crop cut from the clean capture.
your-app/
└─ gripes/
└─ 2026-07-25-1432-checkout-flow/
├─ report.md ← hand this to your agent
├─ notes.json ← same thing, machine-readable
├─ 01-full.png ← viewport, target spotlighted
├─ 01-target.png ← close-up crop, upscaled
└─ 02-full.pngthe sleeper feature
A 90-line tap on the page’s own console.error, fetch and XHR rides along with every note. You point at a button; the report already contains the TypeError that broke it.
Then paste the line Gripe put on your clipboard:
Read gripes/2026-07-25-1432-checkout-flow/report.md — it’s a bug report I recorded while clicking through the running app, with screenshots. Look at every image, then fix what’s described.
## 1. Place order does nothing on the second click - **URL** `http://localhost:3000/checkout`- **Time** 14:32:11- **Element** `#submit`- **Element text** "Place order"- **Attributes** `data-testid="place-order"` `type="submit"`- **Box** 412,680 · 120×40- **Viewport** 1512×860 @2x · scrolled to 0,240  <button id="submit" class="btn btn-primary">Place order</button> <details><summary>Console / network at capture time (2)</summary> [error] TypeError: Cannot read properties of undefined (reading 'id') at Checkout.tsx:44[network] 500 Internal Server Error — /api/orders </details>
written for a model to read, not a human to skim
02 · video walkthroughs
your agent can’t watch video. record anyway.
Hit record and just use the app, narrating as you go. Twice a second Gripe fingerprints the screen and throws away every frame where nothing changed — the screenshots take themselves, only at the moments that matter. Your words are stamped onto the timeline where you said them, console and network errors land where they fired, and when you stop, Whisper re-transcribes the audio on your machine and quietly fixes the rough draft. Watch it work:
an hour of poking around distills to ~150 screenshots, a stamped transcript, and one report.md
60 seconds · rendered with remotion
gripes/2026-07-26-1104-walkthrough/ ├─ report.md ← the timeline: what you said over what changed ├─ transcript.txt ← every word, timestamped ├─ recording.json ← machine-readable ├─ frames/ ← the deduped keyframes ├─ grids/ ← 3×3 contact sheets └─ walkthrough.webm ← the raw video, if anyone's nostalgic
03 · controls
you don’t reach for the keyboard
Dictation starts on its own and survives your pauses — Chrome kills recognition on silence; Gripe restarts it under you. When you stop talking, a bar drains across the composer and the note commits. Keep talking, or touch a key, and it calls it off.
Four ways to point: element hover-highlights DOM nodes and records the selector — clicking a button’s inner label gets you the button, not the throwaway span. Region drags a box. Draw scribbles arrows on the page. Page is just a note about what you’re looking at.
the panel shows the shortcut chrome actually bound on your machine — click it to rebind
04 · under the hood
nothing leaves your machine
No accounts, no servers, no telemetry. The File System Access API writes straight into the repo folder you pick, Whisper runs in a worker next to your tabs, and the only runtime dependency is React — the ZIP writer, the PNG icon generator, and the screenshot compositor are all hand-rolled.
content script ──┬─ shadow-DOM overlay: picker, marquee, ink canvas, composer
├─ dictation, restarted through silences
└─ composites the capture: spotlight + box + strokes + crop
│ chrome.runtime
▼
background SW ───┬─ tab capture (background-only API)
└─ IndexedDB: sessions, notes, image blobs
│
▼
side panel ──────┬─ React view over that state
└─ File System Access: writes straight into your repo05 · install
two minutes, no store
- 1clone and build — npm install && npm run build
- 2chrome://extensions → developer mode → load unpacked → pick dist/
- 3click the icon, hit Connect folder, choose your repo — Chrome remembers it across restarts
known edges
- won’t run on chrome:// pages, the web store, or other extensions — chrome forbids it
- dictation asks for mic permission per site; grant it once on your dev origin
- screenshots are the visible viewport — devtools aren’t in frame
- gripes/ is yours to gitignore or commit. nothing else in the folder you connect is ever touched