Point at what’s wrong. Your agent fixes it.
Passback puts a small button on your site in development and on staging. Click anything, say what should change, and the comment goes to your coding agent or your tracker with the exact place in the code attached.
Open source. Source on GitHub · passback on npm
Or try the real thing: press the football in the corner of this page, then click anything. It is a demo: nothing you write is sent.
See
Open your own site. The button waits in the corner.Comment
Click the thing, write a line, draw an arrow if it helps.Fix
Your agent gets the comment in your own session, with the file and line for React on Vite or Next.Reported
The agent says it fixed the comment.One button for every stage of the work
- While you build
Local development
You and your coding agent. Point at your dev server, and the comment lands in the session that is writing the code, with the file and line for React on Vite or Next, and the element and selector elsewhere.
Goes to Claude Code, Codex, Cursor - Before you merge
Factory PR review
Agents open pull requests faster than anyone can read diffs. Review the running preview instead: point at what is off, and the agent fixes it on the same branch.
Goes to the pull request - On staging
Users' feedback
Testers, clients and teammates who never open the code. They click, write a line, draw an arrow. You get a task that names the exact element.
Goes to Linear, Plane, GitHub, Azure DevOps, GitLab, Trello, Notion, Asana, Jira, ClickUp
Your own agent, in your own session
Run one command, install the plugin it names and restart your agent. The football appears on your dev server. Every comment lands in the coding agent you already have open, with the element and selector, plus the file and line for React on Vite or Next in development. Nothing leaves your machine, and it is free. Still wrong? Click the fixed pin, say what is left, and the same agent gets the next round.
$ npx passback init added the plugin to vite.config.ts wired Claude Code, Codex and Cursor install it: npm i -D @passback/vite-plugin > /passback 1 new comment on src/components/Price.tsx:14 "The price sits lower than the title."
See what your agent receives
The comment's own file in .passback/inbox, as it sits right before your agent picks it up.
---
id: "35353535-3535-4353-8353-353535353535"
schemaVersion: 1
batchId: "35353535-3535-4353-8353-353535353536"
category: "visual"
status: "new"
iteration: 1
route: "/products/:id"
selector: "[data-testid=\"price\"]"
file: "src/App.tsx:21:5"
buildId: "3f2a9c1"
createdAt: "2026-10-24T12:00:00.000Z"
---
Price sits 4px right of the title's left edge; should line up with it.
```json annotations
[
{
"type": "align",
"edge": "left",
"a": "[data-testid=\"price\"]",
"b": "[data-testid=\"product-title\"]",
"actual": {
"a": 312,
"b": 308
}
}
]
```
The tool’s JSON content that passback_wait returns for that comment, not the MCP transport envelope. Paths are relative to the example project root. marks is the same list as comments, under its current key.
{
"comments": [
{
"id": "35353535-3535-4353-8353-353535353535",
"comment": "Price sits 4px right of the title's left edge; should line up with it.",
"route": "/products/:id",
"selector": "[data-testid=\"price\"]",
"file": "src/App.tsx:21:5",
"buildId": "3f2a9c1",
"inboxFile": ".passback/inbox/35353535-3535-4353-8353-353535353535.md",
"timeline": [
{
"t": -21430,
"kind": "navigation",
"from": "/",
"to": "/products/42"
},
{
"t": -8120,
"kind": "action",
"type": "scroll",
"delta": [0, 360]
},
{
"t": -1650,
"kind": "action",
"type": "click",
"selector": "[data-testid=\"price\"]"
}
]
}
],
"marks": [
{
"id": "35353535-3535-4353-8353-353535353535",
"comment": "Price sits 4px right of the title's left edge; should line up with it.",
"route": "/products/:id",
"selector": "[data-testid=\"price\"]",
"file": "src/App.tsx:21:5",
"buildId": "3f2a9c1",
"inboxFile": ".passback/inbox/35353535-3535-4353-8353-353535353535.md",
"timeline": [
{
"t": -21430,
"kind": "navigation",
"from": "/",
"to": "/products/42"
},
{
"t": -8120,
"kind": "action",
"type": "scroll",
"delta": [0, 360]
},
{
"t": -1650,
"kind": "action",
"type": "click",
"selector": "[data-testid=\"price\"]"
}
]
}
]
}A plugin where there is one, a script tag everywhere else
In development, React .jsx and .tsx on Vite or Next give the agent the file and line. React Router is not included. Vue on Vite gives component names and the .vue file in development, without line numbers. SvelteKit, Astro, Nuxt, React Router and other sites give the element, selector and page or route, without framework component names, source files or line numbers. A Vite plugin alone does not mean source locations. Any other site takes one script tag.
Comments from staging become tasks where your team already works
Passback is not a tracker. Each comment is filed in yours, with the page, the element and the code location attached, and the pin follows the task until it is fixed.
Send it to the agent, or straight to the feature's pull request
Open the preview of a pull request. The page knows which pull request built it, so your comments go back to exactly that work, and the agent that wrote it picks them up.
- 1Open the previewThe preview build of the pull request carries its number.
- 2Point and commentEach comment becomes a review comment on that pull request.
- 3The agent fixesIt pushes to the same branch. The preview rebuilds.
- 4You checkThe pin turns into a tick.
Local
npx passback review-prInstall for freeBase
Premium
A site is one key with up to 10 allowed origins.
Ready to pass it back?
Free on your own machine.