@cleverops/toolbar
v0.2.5
Published
CleverOps review toolbar — drop-in React widget + Babel plugin + Turbopack loader for client-markup review sessions. Annotations land in Supabase and auto-create Linear issues for Claude Code to pick up.
Maintainers
Readme
@cleverops/toolbar
The CleverOps review toolbar. One npm package covers:
- Runtime widget —
<CleverOpsToolbar />React component. Activates only when a reviewer link contains?cleverops=<token>. Otherwise it rendersnulland does no work. - CDN script — lightweight loader at
https://markup.cleverops.dev/toolbar.jsfor non-React sites (Webflow, WordPress, static HTML). It loads the widget bundle only when a review token/config exists. - Source-location transform — adds
data-cleverops-loc="path:line:col"to JSX DOM elements at build time so element picks capture exact source locations for Claude Code. Available as@cleverops/toolbar/next(Turbopack-friendly Next plugin),@cleverops/toolbar/source-loc-loader(raw Turbopack/webpack loader), or@cleverops/toolbar/source-loc(Babel plugin for Vite/CRA).
Dashboard + API live at markup.cleverops.dev.
Quick start for Claude Code users
Paste a CLEVEROPS_API_KEY into your repo's .env.local (grab one from
markup.cleverops.dev → Settings → API keys), then tell Claude Code:
Set up CleverOps review. API key is in
.env.local.
Claude Code reads node_modules/@cleverops/toolbar/CLAUDE.md and takes care of
installing the package, wiring the Babel plugin, calling the bootstrap API, and
printing the reviewer link. Everything below is for manual setups.
Install (React / Next.js)
npm install @cleverops/toolbarRender once in your root layout:
// app/layout.tsx
import { CleverOpsToolbar } from '@cleverops/toolbar';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<CleverOpsToolbar />
</body>
</html>
);
}If your host framework strips package-level "use client" directives, add a
local client wrapper and import that from the layout:
// app/CleverOpsToolbarClient.tsx
'use client';
export { CleverOpsToolbar as default } from '@cleverops/toolbar';Custom API host (staging / self-hosted)
<CleverOpsToolbar apiHost="https://staging.markup.cleverops.dev" />Defaults to https://markup.cleverops.dev.
Install (script tag — any site)
Add to <head> or before </body>:
<script src="https://markup.cleverops.dev/toolbar.js" defer></script>With a custom API host:
<script
src="https://markup.cleverops.dev/toolbar.js"
data-api-host="https://staging.markup.cleverops.dev"
defer
></script>Source-location transform
Lets the element picker report exact path:line:col from the source repo — Claude Code picks up Linear issues and knows which file to edit. Pick the install path that matches your bundler.
Next.js (Turbopack or webpack)
Wrap the Next config:
// next.config.ts
import { withCleverOps } from '@cleverops/toolbar/next';
const nextConfig = { /* existing config */ };
export default withCleverOps(nextConfig);withCleverOps injects a Turbopack rule that runs the source-loc transform on .tsx/.jsx before SWC. Turbopack stays on; next/font/google, HMR, and SWC perf are unaffected. Webpack-mode Next builds use the Babel-plugin fallback below.
Vite
// vite.config.ts
import react from '@vitejs/plugin-react';
export default {
plugins: [
react({
babel: { plugins: ['@cleverops/toolbar/source-loc'] },
}),
],
};Babel plugin (fallback / non-Next bundlers)
// babel.config.js
module.exports = {
plugins: ['@cleverops/toolbar/source-loc'],
};Adding babel.config.js to a Next project switches the build off SWC entirely — only use this path on webpack-mode Next or other bundlers.
Raw Turbopack / webpack loader
If you don't want the withCleverOps wrapper, declare the loader rule yourself:
// next.config.ts
const nextConfig = {
turbopack: {
rules: {
'*.{tsx,jsx}': {
loaders: ['@cleverops/toolbar/source-loc-loader'],
as: '*.{tsx,jsx}',
},
},
},
};Plugin options
The Babel plugin (and, transitively, the loader and withCleverOps) accept these options:
| option | default | effect |
|---|---|---|
| include | everything under cwd | glob patterns or RegExp — only instrument matching files |
| exclude | ['node_modules/**'] | skip matches |
| attrName | 'data-cleverops-loc' | override attribute name |
| includeColumn | true | when false, emit path:line instead of path:line:col |
Example via the Babel plugin:
module.exports = {
plugins: [
['@cleverops/toolbar/source-loc', {
exclude: ['node_modules/**', '**/*.stories.tsx', '**/*.test.tsx'],
}],
],
};How it works
- Component (or CDN loader) mounts silently on page load.
- If the URL does not contain
?cleverops=<token>and there is no tab-scoped cached config, nothing else happens. - If it does, the toolbar:
POSTs the token to<apiHost>/api/widget/validate- Caches the resolved config in
sessionStorage(tab-scoped) - Strips the token from the address bar via
history.replaceState - Mounts a shadow-DOM toolbar
- Reviewer picks elements, sketches via Excalidraw, drops replacement images, writes comments.
- Submissions go to
<apiHost>/api/annotations+/api/screenshots. Each annotation auto-creates a Linear issue with selector, screenshot, source-loc, and the replacement file attached. - On SPA navigation within the same origin, the toolbar stays mounted. On cross-origin navigation it unmounts.
Gotchas
- Load the CDN loader in
<head>or withdeferin the body. - Strict CSP:
script-srcneedsmarkup.cleverops.devfor the script-tag build;connect-srcneeds your chosenapiHost. - The widget mounts in a shadow DOM to isolate styles. It won't be affected by your site's CSS.
Bundle sizes
dist/index.js/.cjs— self-contained npm entry with React/ReactDOM as peers.dist/cdn/toolbar.global.js— tiny CDN loader copied to/toolbar.js.dist/cdn/toolbar-app.js+ chunks — widget bundle copied to/toolbar-app.jsand lazy chunks.dist/source-loc.js/.cjs— ~3 KB. Babel plugin, Node-only.dist/source-loc-loader.js/.cjs— Turbopack/webpack loader wrapping the Babel plugin.dist/next/index.js/.cjs—withCleverOps()Next plugin wrapper.
Development
npm install
npm run -w @cleverops/toolbar build
npm run -w @cleverops/toolbar dev # watch mode
npm run -w @cleverops/toolbar typecheck