Two ways to try it: a runnable harness (no browser needed — for quickly seeing apps connect and work), and the full browser walk (the real extension). Automated spikes already prove the daemon
- gate + MCP + consent round-trip (
packages/sidekick/spike/*.mjs).
npm run try-appsSpawns the real daemon with a demo MCP server and runs three example "apps" through a headless
stand-in for the extension (the examples/harness/ dev-extension — same WS + pairing token + origin
stamping the real extension uses):
- chat.example — pure completion on your Claude (connect + stream).
- notes.example — agentic: reads a note via an MCP tool (auto-approved read).
- outbox.example — agentic write: one send you approve at consent, one you deny (blocked).
You'll see real model output, the gate approving reads, and per-action write consent — the same
flow the browser gives you, minus loading the extension. (Requires claude signed in locally.)
npm run try-adgen # or: npm run try-adgen -- https://your-brand.comURL in → the model uses real WebFetch to read the site → extracts the brand → calls a
Higgsfield image-generation tool 3× (each a per-action write consent) → returns ad images. It
uses a mock Higgsfield MCP (examples/harness/mock-higgsfield.mjs) that returns real
placeholder image URLs; point ~/.relay/mcp.json at the real Higgsfield connector and the same app
makes real ads — nothing else changes. This is the whole thesis in one run: the site borrows your
Claude and your connector, and spends nothing itself.
The apps also exist as real pages under examples/apps/ — chat, assistant, and
ad generator — for the browser walk below (npm run apps, port 5174).
The last mile — the real extension in a real browser.
npm install
npm run build # ordered: protocol → sidekick → sdk → extension → demoTo test tool calls, give the sidekick at least one MCP server. Create ~/.relay/mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"]
}
}
}Without this, completions still work; there are just no tools to grant.
npm run sidekickIt prints a pairing token and the backends online, e.g.:
[relay] sidekick listening on ws://127.0.0.1:8787 (paired-only)
[relay] pairing token (paste into the extension): abc123…
[relay] backends online: claude-code
Copy the token. (Requires you to be signed into Claude Code locally — claude on your PATH.)
- Open
chrome://extensions. - Toggle Developer mode (top-right).
- Click Load unpacked and select
packages/extension/. - The Relay icon appears in the toolbar. Click it → the popup shows not paired.
- Paste the pairing token → Pair. Status flips to paired.
npm run demo # serves http://127.0.0.1:5173Open http://127.0.0.1:5173.
| Step | Do | Expect |
|---|---|---|
| Connect | Click Connect Relay | A consent window opens showing the origin, models, and any tools (with read/write badges) + budgets. Approve. |
| Grant visible | Open the Relay popup | The origin is listed with its models/tools/budget; a Revoke button. |
| Complete | Click Ask (streamed) | The answer streams into the page — running on your local Claude. No API key was sent. |
| Audit | Open the popup | The request + connect show in the audit log; Export downloads it. |
| Revoke / kill | Click Revoke on the origin, or the kill switch | The site can no longer call; kill also drops the pairing token. |
An agentic completion (stream({ prompt, agentic: true })) that proposes a write tool (e.g.
filesystem write) triggers a per-action consent window every time, showing the exact args.
Deny it and the model is told it was blocked — the action never runs. This is the core security
property; it's proven headlessly in e2e-daemon-spike.mjs and this is its visible form.
- Page → SDK → provider detection — verified headlessly (the demo shows the graceful "not installed" fallback when the extension is absent).
- Extension inject + bridge + origin stamping — this manual walk (a real page gets a working
window.claude, and the daemon sees the browser-verified origin). - Daemon gate + consent + MCP — proven by the spikes and re-exercised here via the UI.
- "sidekick not reachable" in the page → the daemon isn't running, or the token is stale. Re-pair with the current token from the sidekick's output.
- Consent window doesn't open → check the extension's service-worker console
(
chrome://extensions→ Relay → Inspect views: service worker). - No tools in the consent window →
~/.relay/mcp.jsonis empty or a server failed to start (see the sidekick log line[mcp] connected N/M servers). - Completion errors → confirm
clauderuns locally (claude -p "hi").