Skip to content

tokenmaxxer: the meeting room that ships while you talk#1

Merged
rogeriochaves merged 37 commits into
mainfrom
room-that-ships
Jun 13, 2026
Merged

tokenmaxxer: the meeting room that ships while you talk#1
rogeriochaves merged 37 commits into
mainfrom
room-that-ships

Conversation

@rogeriochaves

@rogeriochaves rogeriochaves commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What this is

Hackathon build for the theme "what if compute and tokens were no longer a limitation".

A meeting room with an always-on microphone and a realtime voice agent (Max, on Inworld gemma-4). You talk; Max turns it into a swarm. A spoken mission becomes N Claude Code agents that all land in one shared Kanban Code channel and self-organize there: one claims the CSS foundations, another takes the pages, a third reviews. You assigned no roles. The channel is the agent loop, a natural ralph-loop where the agents hold each other to the mission while you keep talking.

It drives the real desktop, not a tab: real Warp terminals fly open with Claude Code working, the KanbanCode board comes forward on the room's channel so you watch them coordinate live, and open_url puts the running site or a GitHub issue on the screen. A floating HUD shows the room is listening, on top of everything.

This PR pivots the project from the earlier page-codegen prototype (a fast model painting pages) to the agent-swarm model above. The jimmy proxy, page tools, model switching, and the LLM routing brain are removed.

Why the swarm wins

  • Agentic leverage — N independent Claude sessions on one mission, plus a voice agent steering them live. Not one agent with hidden sub-tasks: N real sessions you can see and talk to.
  • Measurable impact — 1 agent is one context window on one thread; N agents is N context windows working in parallel. Separate sessions give full control of all of them.
  • The agent loop — the shared channel is a natural ralph-loop: agents message each other, find issues, push forward; one can step up as supervisor.
  • Cost / quality — visible, controllable agents don't burn tokens on hidden, random work.
  • Collaboration — the team guides the swarm by voice, live, together.
  • Technical ambition — the desktop layer sits behind a platform-agnostic adapter so it runs on Windows too, not just macOS.

Architecture

  • server/ — voice gateway (OpenAI Realtime-compatible WS proxying Inworld, server-owned session config + tool execution), the room engine (orchestrator/room.ts: spawn a swarm into a kanban channel, the coordinate-first agent brief, a deterministic project registry that resolves a spoken hint to a real checkout + URL with no LLM in the hot path), and the desktop control layer (platform-agnostic DesktopController; macOS adapter via osascript + Warp + chromeless Chrome; Windows stub).
  • Tools (Inworld): spawn_room (mission, topic, agents?, project?), message_room (steer a running room), add_agents (grow it), open_url (show a site / issue), check_progress (status from the channel).
  • hud/ — Electron frameless always-on-top overlay wrapping the console in HUD mode.
  • console/ — room console (transcript, tool feed, live fleet) + the compact HUD view.
  • specs/ — BDD feature specs (room-orchestration.feature covers the swarm).

The agents talk over Kanban Code channels: each agent has a tmux session kanban tracks, and kanban channel send broadcasts into every other agent's pane. Max joins as @max to drop the mission in and pass along voice corrections.

Hard problems solved on the way

  • 100% deterministic delegation (17/17 serial). A 17-case delegation eval (scripts/experiment-delegation.ts) showed gemma-4-26b mis-routing the room-op commands ("throw two more agents", "how's it going", "tell the room…") — it keys on salient words and ignores both the tool descriptions and the persona, and at its default warmth the same sentence routed differently across runs. A full description rewrite moved it 0%. The fix is two-part: session temperature: 0 (stable), plus a deterministic intent safety net (tools/intent.ts) that reads the user's actual utterance and overrides the model's pick when the verb is unambiguous, deferring to the model otherwise. Serial routing (one turn at a time, as in the live demo) went from 9/17 to 17/17; intent.unit.test.ts asserts the corrector on the exact eval dataset.
  • Agents reliably join the channel. The swarm is only visible if every agent runs kanban channel join. A fixed delay before sending the mission raced claude's cold boot (lost keystrokes → no join), and parallel launches raced the kanban CLI. Fixed by waiting for the REPL to be drawn, launching sessions sequentially then delivering missions as each boots, and confirming the handle appears in the channel (re-sending once if not).
  • open_url guessed dev ports. gemma-4 loves to invent localhost:3000. The resolver trusts a real remote URL (a GitHub issue) but maps localhost guesses and bare phrases ("the website") to the project's real URL.
  • Config-free unit tests. The engine imports config.ts, which requires live API keys at import; pure helpers (channel naming, the coordinate-first brief, the URL resolver, the intent corrector) moved into config-free modules so CI runs them with no .env.
  • Inworld emits nameless function calls with empty-properties schemas (every tool keeps a required param), and doesn't transcribe committed audio under turn_detection: null (a gateway whisper STT shim injects the turn as text). Transient capacity errors retry then switch to a fallback model mid-session.

Proof

  • Network-free unit tests (CI): project resolution, topic → channel naming, and the coordinate-first brief (it must tell each agent to JOIN the channel and coordinate BEFORE building, the whole delegation contract), plus the desktop tiler.
  • Delegation eval (scripts/experiment-delegation.ts) → LangWatch, scoring which tool each spoken request routes to.
  • Live dogfood: "get 3 agents on dark mode" spun up the room and an agent self-organized unprompted in the channel:

bolt: here, surveying the project. It's a Tailwind v4 site with a paper-white design system, no dark mode yet. Plan: I'll own the CSS foundations + global components (Nav, Footer, Hero...). Aria can take the pages + remaining sections. Starting now.

That unprompted teammate delegation, with no role assigned, is the whole thesis.

Screenshots

Captured during live QA runs (the desktop is the demo). Hero shots: the swarm of terminals fanning out with the KanbanCode board forward on the room channel; the channel showing agents claim slices and review each other; a browser window opened by open_url.

rogeriochaves and others added 30 commits June 12, 2026 21:41
- Gateway bridges OpenAI Realtime-compatible clients to Inworld upstream
- Server owns session config; clients only choose turn detection
- Tool calls executed server-side, dual wire-shape, deduped by call_id
- Malformed (nameless) tool calls dropped + dead-air recovery nudge
- check_progress schema requires a param: empty-properties schemas make
  gemma-4 emit nameless function calls
- jimmy speed chain outputs JSX body only, file skeleton applied in code;
  gemini thinking disabled; overall codegen deadline
- Playground file-per-page routing with crash boundary; console with mic,
  playback worklets, transcript, tool feed, fleet panel, preview
- STT shim: Inworld doesn't transcribe committed audio under manual turn
  detection (turn_detection null), so the gateway whispers the buffered
  turn and injects it upstream as text — scenario voice tests now hear
  real words end to end
- Capacity resilience: transient 'model at capacity' upstream errors are
  retried, repeated ones switch the session to a fallback model
  (google-ai-studio/gemini-2.5-flash) mid-session
- open_page teaches the model when a page doesn't exist; write_page
  protects the /home index; Max confirms page success as fact
- Voice scenario tests: dispatch-on-idea, progress check, spoken page
  request — all real audio, real tools, real fleet
- Voice tests persist full.wav + per-turn segments + manifest; agent
  audio independently verified by whisper transcription
- dispatch() registers a provisional fleet entry instantly so the room
  screen reacts the moment words are spoken, brain confirms or renames
- Brain default switched to claude-haiku-4-5: routing decisions 2-4s
  (was 5-10s), quality verified by the brain tests
- Upstream sendRaw queues until session ready (the console greet raced
  the Inworld connection and was silently dropped); the handshake
  session.update bypasses the queue (deadlock otherwise)
- Console greets only after session.created
- Persona: one request, one tool call
- Console grid: arbitrary fr tracks need minmax(0,...) — a long
  unbreakable tool-arg string blew the layout to 2382px
- qa-console script drives the real console with a synthesized wav as
  the microphone: greeting, VAD turns, tool feed, page on room screen
- experiment-codegen.ts: 8 page briefs x 4 models logged to LangWatch;
  jimmy p50 525ms vs 9-21s for the rest at 0.66 vs 0.92 quality —
  chain order is now data, not vibes (numbers in the speedChain comment)
- Tracing: brain routing, speed-chain codegen and tool execution spans
  via langwatch setupObservability; verified arriving with trace search
- Gateway auto-starts the jimmy proxy when it's down
- DEMO.md: demo arc, pre-flight checks, failure playbook, reset steps
- Full suite re-run: 19/19
- findByTopic and the brain's reuse candidates exclude status=gone
  agents (QA caught a dispatch routed as follow-up to a killed tmux)
- semantic VAD eagerness low: medium split one spoken request into 2-3
  turns, each re-triggering tools and polluting the model context
- write_page output steers the model away from repeat page tools
- Multi-turn edit voice scenario (write then edit the same page)
- QA script now drives the full demo arc: greet, page, dispatch, fleet
  panel, progress answer
The Iron Man delta. tokenmaxxer now drives the real desktop, not an iframe:

- DesktopController interface wraps all OS specifics; MacDesktopController
  (osascript) implemented, NoopDesktopController for tests/CI, Windows stub
  documented for the incoming teammate. Factory picks by platform + the
  TOKENMAXXER_DESKTOP flag; pure tiler (regionForSlot) is cross-platform.
- write_page/edit_page/open_page pop a chromeless Chrome app-window tiled
  top-right showing the live page (positions itself on the current Space via
  geometry flags; Vite HMR makes edits appear with no reload).
- dispatch_work opens a Warp window running tmux attached to the agent, so
  the room watches Claude work live; terminals fan out across quadrants.
- Proactive: on STATUS.md DONE the fleet fires a macOS notification and pops
  the PR window, even in silence.
- Tests: tiler + noop unit tests (headless), gated macOS integration test
  that really opens/tracks/closes a window. Existing suites stay headless.
- Page-codegen refactored into a model registry (jimmy, gemini-flash,
  haiku, inworld-gemma, gpt-4.1-mini) behind a uniform generate(); haiku
  via Anthropic, inworld-gemma via realtime text session
- settings.pageModel is runtime-mutable; set_page_model voice tool switches
  it, broadcast as tokenmaxxer.settings so the console reflects it; chain =
  selected primary + smart fallbacks
- Benchmark now spans all five models. Fresh numbers: jimmy 0.8s/0.65,
  inworld-gemma 8s/0.92, gemini-flash 8.6s/0.92, haiku 13s/0.93 (sharpest),
  gpt-4.1-mini 16s/0.90
- Tests: switching + every available model writes valid TSX (jimmy 4.5s,
  gemini 6.4s, haiku 9.8s, inworld-gemma 6.5s)
- The tool Max picks is the route: pages → write_page/edit_page (fast
  model), real work → dispatch_work (Claude agent in a terminal). Persona
  and the dispatch_work schema now draw the line explicitly (look-at vs
  runs/reads).
- routing.test.ts drives the real gateway with 6 labeled requests; pages
  route to a page tool, login/research/Stripe route to dispatch_work, all
  under ~1.3s.
- fleetDryRun flag lets routing tests assert tool choice without spawning
  real tmux agents.
The OpenAI Realtime adapter parked the agent transcript on
lastAgentTranscript but returned an audio-only message, so the LangWatch
Simulations UI showed blank audio players for Max's turns (the user
simulator already attached its transcript, which is why only Max looked
empty). maxAgent subclasses the adapter to attach the transcript as a
leading text part. A regression assertion proves the agent audio message
now carries text. (Same fix belongs upstream in the scenario framework.)
The listening layer split from the prototyping layer. The prototyping is
now real desktop windows; the HUD is a frameless, transparent,
always-on-top Electron overlay that floats above everything (incl.
full-screen apps, all Spaces) showing listening state, the last turn, the
last action and the fleet size.

- console gains a compact Hud view (?hud=1) reusing the same room client
  (mic/playback/WS) as the full dashboard — verified floating over other
  apps with the listen control and live wiring.
- hud/ Electron shell wraps it; auto-grants the mic; cross-platform shell
  (same overlay runs on Windows once the desktop adapter lands there).
- pnpm hud launches it; README reframed around desktop control.
- DEMO.md: pnpm hud, accessibility/mic grants, the desktop arc (page
  window, Warp agent terminal, proactive PR, model switch), new failure
  modes and a fuller reset
- README architecture reframed around desktop control (done in prior
  commit), HUD run instructions
- preflight checks Chrome + a terminal are installed
- root: pnpm hud script
The frameless HUD had no way to close it and no guard against stacking, so
running pnpm hud twice left multiple invisible-chrome windows on top of each
other with no affordance to dismiss them.

- ✕ button on the bar (window.close), styled subtle, no-drag so it clicks
- Cmd/Ctrl+Q and Cmd/Ctrl+W quit, since a frameless overlay has no menu bar
- window-all-closed now quits on every platform: the overlay is the whole app
- requestSingleInstanceLock: a second launch focuses the existing window
  instead of opening another one
The product pivoted: drop chatjimmy/page generation entirely; the core is now
the voice agent spinning swarms of Claude Code agents into one shared kanban
channel where they self-organize (the channel is the agent loop).

- room-orchestration.feature: canonical room behavior (spawn/grow/message a
  room, the channel-as-ralph-loop, ten-agent tokenmaxxing, open a URL, fix a
  github issue with a fresh room)
- meeting-agent.feature: Max now delegates to rooms + open_url, no page tools
- orchestrator.feature: the room engine (one channel + N agents, deterministic
  naming, no LLM router, project->workspace, reuse by topic)
- desktop-control.feature: open_url browser window, KanbanCode app pinned
  top-left on the room channel, terminals fan out, HUD on top
- remove obsolete jimmy-era specs (playground, model-selection, task-routing)
The room no longer renders pages with a fast model; it turns talk into a
SWARM. A spoken mission becomes N Claude Code agents that all land in one
shared kanban channel and self-organize there. The channel is the agent
loop: agents claim slices, review each other, and push the mission forward
without Max micromanaging. One can step up as supervisor.

Engine (server/src/orchestrator/room.ts):
- spawn_room(mission, topic, agents?, project?): creates a channel, launches
  agents (names from a pool, no tokens spent generating them), gives each a
  coordinate-first brief (join the channel, read history, claim a slice, then
  build), pops a terminal per agent, and brings the KanbanCode board forward
  on the channel.
- message_room / add_agents: steer or grow a running room by topic.
- check_progress: status drawn from channel history, never invented.
- Deterministic project registry resolves a spoken hint (the website,
  langwatch) to a real checkout + URL, so dispatch is instant with no LLM in
  the hot path.

Tools (Inworld): spawn_room, message_room, add_agents, open_url,
check_progress. open_url trusts a real remote URL (a GitHub issue) but maps
localhost guesses and bare phrases (the website) to the running site.

Desktop: DesktopController gains focusChannel() — deep-links the board to a
channel and pins it top-left; terminals fan out, the browser sits top-right.

Removed entirely: the jimmy proxy, page codegen, model switching, the LLM
routing brain, and their tests. Network-free room.unit tests cover project
resolution, channel naming, and the coordinate-first brief; CI runs them.

Co-authored-by: tokenmaxxer-alexander <agent@tokenmaxxer>
The unit test imported the engine through room.ts/handlers.ts, which pull in
config.ts — and config requires live API keys at import, so CI (no .env)
threw 'INWORLD_API_KEY missing' before a single assertion ran. Move the pure
helpers the test needs into config-free modules: channelName + buildAgentBrief
into orchestrator/brief.ts, and the open_url resolver into tools/url.ts. The
test now imports only those + the project registry, and passes with no .env.

Also rewrites the README around the room-swarm model.
Preflight drops the jimmy proxy and playground checks, adds a KanbanCode
running check and a kanban-channel round-trip (create + send + history) that
proves the agent-loop mechanism, and swaps the playground for the live site.
DEMO.md rewrites the arc around spinning up rooms of self-organizing agents,
steering them by voice, and running two missions in parallel.
The delegation eval (scripts/experiment-delegation.ts) showed open_url
over-firing as gemma-4's catch-all whenever it was unsure: 'throw two more
agents at it', 'how's it going in there', and bare 'redesign the X' all
misrouted to open_url. Tighten the tool descriptions and the persona so each
move claims its own trigger words and explicitly disclaims open_url, and
spell the routing out: SHOW -> open_url, DO -> spawn_room, STEER ->
message_room/add_agents, STATUS -> check_progress.

Also short-circuit launchAgent under fleetDryRun so add_agents into a live
room is exercisable headlessly (it reaches launchAgent directly, bypassing
launchRoom's guard).
- routing.test.ts: delegation routing (spawn_room / open_url / message_room /
  add_agents / check_progress) replacing the old page-vs-work routing
- gateway.test.ts: open_url + 'No rooms running' in place of write_page and
  the Fleet-empty assertion
- voice/max.voice.test.ts: room scenarios (spin up a room, open a url, status,
  open-issue-then-spin-a-fix-room); resets state on start
- scripts/experiment-delegation.ts: LangWatch delegation eval — labeled
  utterances scored against the tool Max picks, context-aware for follow-ups
- tests/helpers/reset.ts + scripts/reset-rooms.ts: one-command clean slate
  (kill room agents, delete room channels, baseline the served site)
The earlier accuracy (47-59%) understated reality: spawning a room in the same
conversation right before a steer/status case biased gemma-4 to repeat
spawn_room. Warming the rooms up once up front and testing every case in a
fresh turn (the live demo condition) gives the honest number — 76%, with
spawn_room/add_agents/check_progress all solid.
kanban channel delete keeps the append-only log, so a room re-created with the
same name replayed stale missions/joins from prior runs. Remove the .jsonl on
reset for a true clean slate.
gemma-4-26b could not reliably route the five tools from descriptions or the
persona — it keys on salient words ('repo' -> spawn_room, 'room' -> add_agents)
and ignores the rest, and at its default warmth the same sentence routed
differently across runs. Two fixes:

- Session temperature 0, so a given utterance routes the same way every time.
- A deterministic intent safety net (tools/intent.ts): the room-operation and
  show verbs ('tell/remind the room', 'N more / double the team', "how's it
  going", 'show me / put on the screen') are distinctive enough to recognize
  in code. The gateway runs it over the user's actual utterance and, when it
  confidently reads a different tool than the model picked, overrides — else it
  defers to the model (which nails spawn_room work and plain opens). The
  utterance is captured from the turn transcript, the whisper shim, or a typed
  turn, so it is set before the tool call lands.

Serial routing (one turn at a time, as in the live demo) is 15/15 on the
delegation set, up from 9/17. intent.unit.test.ts asserts the corrector on the
exact eval dataset — every steer/status/show utterance maps to the right tool,
and the six real-work requests are left untouched (returns null). CI runs it.
evaluation.run fires every case in parallel, which races the per-session
utterance capture against the shared gateway and reported a concurrency
artifact (53-71%). Gate the gateway hits through a one-at-a-time mutex (the
live demo condition). With the intent corrector + temperature 0, serial = 17/17
= 100%.
The demo centerpiece is the swarm visibly self-organizing in the channel, so
every agent MUST join it. Three things were losing agents:

- A fixed 6s delay before sending the mission raced claude's cold boot; a slow
  agent got the keystrokes before its REPL was drawn and never ran
  'kanban channel join'. Replaced with waitForClaudeReady (polls the pane).
- Launching agents in parallel raced the kanban CLI and could collapse two
  agents onto one card. Split into two phases: create every session
  sequentially, then deliver missions as each claude becomes ready (the slow
  boots still overlap, so it stays fast).
- Under load even a ready-looking REPL can swallow the first keystrokes, so
  after sending we confirm the agent's handle appears in the channel and
  re-send once if it didn't. Max also pins the mission before anyone joins, so
  it's in the history each agent reads on arrival.

Engine unit tests unchanged and green.
focusChannel shelled 'kanban channel open' (a kanbancode:// deep link) to
bring the board forward. When the URL scheme is registered to a different
build than the one running (e.g. after a dev rebuild), the deep link
relaunches that build and trips KanbanCode's quit-protection dialog mid-demo.

Bring the already-running KanbanCode forward via System Events instead — it
never launches anything, so no relaunch and no dialog. The top-left pin is
unchanged. Channel auto-select rode on the deep link and is dropped here; a
non-relaunching select belongs on the KanbanCode side.
Diagnosis: all agents boot and receive the mission (tens of k tokens of work),
but claude dives into the mission and doesn't reliably run 'kanban channel
join' itself — so only one agent ever appeared in the channel. The previous
confirm-and-resend made it worse, piling queued prompts onto busy agents.

Fix: right after 'kanban launch', the gateway force-joins the agent into the
channel by its returned card id ('kanban channel join --as <slug-handle>
--as-card-id <cardId>'). Membership is then guaranteed and independent of what
claude does; the card link means the agent still receives the channel's
broadcasts in its pane, and when it later posts from its tmux the membership
converges on the same handle (keyed by card id). The agent brief drops the
join step (it's already a member) and leads with read-history + claim-a-slice.

Verified: a 3-agent spawn now lands all three as tmx_aria/tmx_bolt/tmx_cleo
within ~8s.
Two notes from the live run:

- No way to tear a room down by voice. Add a close_room tool (kill the dark
  mode room / shut down the room / stop the agents on X) that kills the agents'
  tmux sessions and deletes the channel, with a deterministic intent rule so
  gemma doesn't see 'room' and pick add_agents.

- The KanbanCode board ended up UNDER the team's other Warp windows. The
  focus-last raise existed but was fire-and-forget and raced the equally
  fire-and-forget terminal pops. Now phase 1 collects the terminal-open
  promises, and the board raise is awaited AFTER they all settle, so it wins
  the z-order. Mission delivery moves to a background phase 2 (no window ops),
  so the board stays on top while claude boots.
Two rooms drew agent names from the same pool starting at aria/bolt/cleo, and
the tmux slug seeds a deterministic sessionId, so a second room resumed the
first room's claude under a new mission and its coordination was clobbered.

Allocate names monotonically: take one only if it is neither already in use nor
backed by a live tmux session (covers survivors of a gateway restart), and
recycle the pool only once the whole fleet drains. close_room now really kills
each session by slug (matching the reset script) and closes the leftover
terminal window, so a freed name is safe to reuse and 'kill the room' actually
clears the dead panes off screen.
open_url fired and Max said 'on the screen', but no Chrome appeared. The
chromeless app instance quits when its last window closes, so its pid dies;
openBrowser still held that pid and, on the same-url path, raised it to the
front instead of respawning. Raising a dead pid is a silent no-op, so nothing
showed. Reuse a tracked window only when its process is still alive (signal-0
check); otherwise drop the stale entry and spawn a fresh window.
Adds the close_room scenario to specs/room-orchestration.feature, a voice
scenario test (kill the dark mode room -> close_room), and kill/close cases
in the delegation eval. Adds the 2-minute meeting skit to DEMO.md with the
exact spoken wording for the demo.
@rogeriochaves rogeriochaves merged commit d40462d into main Jun 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant