Repurposing Spotify's discontinued Car Thing into a physical human-in-the-loop control surface for autonomous coding agents.
AI coding agents like Claude Code can work autonomously for long stretches — but you still have to babysit the terminal to catch the moment they finish, fail, or need your permission to do something. Agent Sidecar moves that attention/approval loop onto a dedicated physical device on your desk.
You start a coding task. The Car Thing lights up showing the agent is working. When the agent hits something that needs a human — "run this database migration?" — the screen flips to an attention state. You approve or deny with a physical button. The answer travels back and the agent continues. No terminal-watching.
This is not a Stream Deck clone, a Spotify controller, or a tiny second monitor. The product is specifically a human-in-the-loop interface for autonomous agents.
┌─ NORMAL ──────────┐ ┌─ ATTENTION ───────┐ ┌─ DONE ────────────┐
│ CLAUDE CODE │ │ ⚠ ACTION REQUIRED │ │ ✓ TASK COMPLETE │
│ Market Edge │ │ Run DB migration │ │ +184 -37 │
│ ● Working 02:14 │ │ [1]APPROVE [2]DENY │ │ Tests 24/24 ✓ │
└────────────────────┘ └────────────────────┘ └────────────────────┘
🟡 Early / research validated. Feasibility and architecture are done (docs/ARCHITECTURE.md); Phase 0 (the riskiest unknown) is in progress. No V1 yet — this repo is being built in the open, phase by phase.
The whole project hinges on bidirectional approval being possible without hacks. It is, on both ends:
- Claude Code exposes an HTTP
PreToolUsehook that POSTs a tool request to a URL and waits for the response to decideallow/deny. That response channel is how a physical button press becomes Claude's answer — no terminal scraping, no synthetic keystrokes. (hooks reference) - The Car Thing, via DeskThing, gives a web (React) runtime on the device, a server↔device transport over USB with reconnect, and a configurable knob/button mapping — so we write an app, not firmware.
claude (your terminal)
│ PreToolUse hook (POST, waits for reply)
▼
Sidecar daemon ──WS──► DeskThing app on Car Thing
▲ holds the hook request open │ ⚠ shows the request
└──────────── button press ◄──────────────┘ you approve / deny
→ daemon answers the still-open hook → Claude proceeds
See docs/ARCHITECTURE.md for the full feasibility report, component design, event protocol, phases, risks, and V2 plans.
A human takes seconds-to-minutes to approve. Everything depends on how long a Claude
Code hook will hold its response open before giving up. spike/phase0-hook-timeout/
measures exactly that against the real CLI.
cd spike/phase0-hook-timeout
./run.sh 5000 # hold 5s, confirm the mechanism
./run.sh 120000 # push toward the ceilingThe daemon-side round trip (hook → server holds → returns permissionDecision) is
already verified. See the spike's README for
current results.
TypeScript monorepo (npm workspaces):
| Path | Role |
|---|---|
packages/protocol |
Shared event/action schema (the normalized agent protocol) |
packages/agent-core |
Framework-free state machine, approval registry, audit log |
apps/daemon |
Local HTTP (hooks) + WebSocket (device) server — the brain |
apps/device |
DeskThing app: the on-device React UI |
adapters/claude-code |
Hook config + payload→event normalization + risk rules |
tools/fake-agent |
Scripted event emitter — develop with no real agent |
tools/virtual-carthing |
Run the device UI in a desktop browser — develop with no hardware |
agent-core and protocol stay dependency-free so "add Codex" or "add a phone client"
is a new adapter, not a rewrite.
MIT © 2026 Aaron Barke