Drop-in toolbar for any website. Annotate the UI and capture selectors, computed styles, React component trees, and screenshots as an agent-ready prompt.
bun add devbar.shMount <Devbar /> once, anywhere in your tree. It renders a fixed toolbar and
owns its own overlays.
import { Devbar } from "devbar.sh";
function App() {
return (
<>
<YourApp />
<Devbar />
</>
);
}The stylesheet ships as a separate file — import it once alongside the component:
import "devbar.sh/styles.css";The CDN build (devbar.sh/cdn) inlines its own styles, so it needs no separate
import.
The toolbar is safe to import from a server-rendered tree — a Next.js root layout, a Remix root, an Astro island. It renders nothing on the server and nothing on the first client render, then appears once mounted, because what it draws depends on the host page's theme, a stored bar position and stored settings; producing markup without them would only fail to hydrate.
In Next.js, mount it in the root layout from a 'use client' module:
"use client";
import { Devbar } from "devbar.sh";
import "devbar.sh/styles.css";
export function DevToolbar() {
if (process.env.NODE_ENV !== "development") return null;
return <Devbar />;
}That still ships the toolbar's stylesheet to production, where the guard means
it is never used. To keep it out, put the two imports in a module of their own
and pull that module in with next/dynamic — Turbopack will not resolve a CSS
import from inside a dynamic() factory, so the imports have to sit at the top
of the module being imported, not in the factory.
| Import | What it is |
|---|---|
devbar.sh |
<Devbar />, init(), the payload types, and the local-agent hooks |
devbar.sh/styles.css |
Toolbar stylesheet (required for the component build) |
devbar.sh/cdn |
Self-contained IIFE bundle with styles inlined, for a <script> tag |
devbar.sh/local |
createLocalServer() — the local dispatcher used by the CLI |
devbar.sh/config |
defineConfig() and the devbar.config.ts types |
Only react, react-dom (peers) and two small runtime dependencies —
html-to-image and jiti — are installed with the package. The MCP server the
CLI runs is implemented directly rather than pulling in the MCP SDK, so
devbar mcp works with nothing else installed. The hosted
dashboard's server (Better Auth, Stripe, reports, MCP) lives in this repo under
src/server but is not published; see docs/DEPLOYMENT.md.
The package installs a devbar binary. Run it in a project and the toolbar
finds it — no server, token, or project props:
cd my-app
bunx devbar.sh init # writes devbar.config.ts
bunx devbar.sh # serves on 127.0.0.1:3100 and registers this project<Devbar />From there, reports go two ways:
- Push — the report is handed to an agent CLI (
claude,codex, oropencode) running in the project directory. Screenshots are written next to the prompt as files, so the agent can actually read them. - Pull — an agent session you already have open picks reports off the queue over MCP, and can inspect, screenshot, and highlight the page you are looking at right now.
claude mcp add devbar -- devbar mcp| Command | Does |
|---|---|
devbar |
start the server, or register this project with one |
devbar mcp |
MCP server on stdio |
devbar doctor |
check everything needed to dispatch |
devbar tasks [--watch] |
dispatch tasks and their status |
devbar reports |
captured reports |
devbar dispatch [id] |
dispatch one report, or every pending one |
devbar init |
write a starter devbar.config.ts |
devbar link |
print the wiring snippet for this project |
Discovery only runs on localhost pages and only probes 127.0.0.1:3100 and
:3101. Pass local={false} to switch it off, local={{ ports: [4000] }} to
point it elsewhere, or live={false} to hide the live page tools entirely.
Live page tools stay off until you switch on Agent live in the toolbar's
settings, per origin. Dispatch runs an agent in your repository, so the defaults
are conservative: loopback only, permission: "plan", no auto-dispatch. See
docs/LOCAL-AGENT.md for the config reference, the
supported agent CLIs, the MCP tool list, and the security model.
extension/ is a Manifest V3 extension that toggles the toolbar on any tab —
no code changes to the site. The toolbar bundle ships inside it as
devbar.cdn.js (written by bun run build), injected into the page's MAIN
world: MV3 forbids remotely hosted code, and React fiber data is invisible from
an isolated world, so element capture would lose component context there.
To run it from a checkout:
bun run build # writes extension/devbar.cdn.jsThen in Chrome: chrome://extensions → enable Developer mode → Load
unpacked → pick the extension/ directory. Open any http(s) page and click
the Devbar icon; the badge reads ON while the toolbar is mounted, and
clicking again removes it. Restricted pages (chrome://, the Web Store) cannot
be injected and show an ERR badge.
extension/example.html is a plain page wired to the same bundle, useful for
checking the script-tag path on its own.
To build the archive the Chrome Web Store accepts:
bun run build # writes extension/devbar.cdn.js
bun run package:extension # writes dist/devbar-extension-<version>.zipThe archive holds only the six files the extension loads — the icon SVG
sources, the icon generator, and example.html stay out of it. See
docs/CHROME-EXTENSION.md for store submission,
the listing assets, and how updates reach installed browsers.
Pick a tool, mark up the page, then export everything as a single prompt.
| Tool | What it captures |
|---|---|
| Select | An element plus its selector, React component path, and diagnostics |
| Marker | A numbered pin at a point on the page |
| Draw | Freehand annotation over a screenshot |
| Capture | Full-page or region screenshot |
| Record | A screen or tab recording |
While the Select tool is active, a badge follows the cursor showing the
element's tag and pixel size. ↑ widens the selection to the parent element and
↓ narrows it to the first child, so you can land on the wrapper you actually
mean instead of whichever node happens to be under the pointer.
Everything you capture collects in the dedicated Annotations panel, alongside History for past exports. Settings and Shortcuts live in a separate preferences panel opened from the toolbar's gear button.
At the top of the Annotations tab is a task field: one line saying what you
actually want changed. Annotations are evidence; the task is the intent. When
set, it leads the exported prompt as a ## Task section and the closing
instruction changes from "analyse these issues" to "carry out this task, using
the annotations as evidence". It is cleared along with the annotations on export.
Export copies the report as a Markdown prompt (or submits it to your server when one is configured); the caret next to it holds the other formats. Removing an annotation offers an Undo for a few seconds. Each row also has a locate button that scrolls the annotated element back into view.
| Keys | Action |
|---|---|
Alt+S / M / D / C / R |
Select / Marker / Draw / Capture / Record |
↑ ↓ |
Widen / narrow the selection (Select tool) |
↵ |
Annotate the current element, or save the note |
Esc |
Discard the note, exit the tool, or close the open panel |
Alt+A |
Toggle the annotations panel |
Alt+/ |
Keyboard shortcuts |
⌘Z |
Undo the last annotation |
⌘↵ |
Copy the report to the clipboard |
An Alt+<tool> shortcut works while another tool is active, switching directly
between tools.
Please see CONTRIBUTING.md for contribution guidelines.
MIT