Skip to content

Architecture

Qwack uses a host model — one collaborator runs the AI agent, everyone else participates through a relay.

There are three components in a Qwack session:

Host — One collaborator runs the OpenCode agent on their machine. They have full filesystem access and execute all code locally. API keys and credentials never leave the host’s machine. Conversation content (prompts, responses, tool output) is relayed so collaborators can follow along.

Collaborators — Everyone else runs Qwack in relay mode. Their TUI looks identical to the host’s — same streaming output, tool calls, and file diffs — but prompts are routed through the Qwack server to the host’s agent instead of running locally.

Qwack Server — A lightweight WebSocket relay that forwards messages between participants. It never runs an AI agent, executes code, accesses filesystems, or stores API keys.

AspectHost TUINon-Host TUI (relay mode)
Agent executionLocal OpenCode agent runsNo local agent
Prompt handlingSent to local agentIntercepted → sent to server
Agent outputRendered from local SSE eventsRendered from server WebSocket relay
Tool executionLocal filesystem accessNone — view only
SidebarPresence + todosPresence + todos (same)
Code editingAgent edits files directlyMust git pull / sync separately

The non-host TUI still starts OpenCode (for the file browser, settings, etc.) but the prompt input is intercepted before reaching the agent.


1. Host types prompt in Qwack TUI
2. Prompt goes to local OpenCode agent (normal flow)
3. Plugin captures prompt text, mirrors to server for broadcast
4. All collaborators see the prompt in their TUI
5. Agent processes prompt, output relayed to all
1. Non-host types prompt in Qwack TUI
2. TUI intercepts — does NOT send to local agent
3. TUI sends to server: { type: "prompt:request", content: "...", authorName: "sarah" }
4. Server relays to host's plugin: { type: "prompt:execute", content: "...", requestedBy: "sarah" }
5. Host's plugin injects prompt into local OpenCode agent
6. Agent processes prompt in its EXISTING conversation context
7. Output flows back: agent → plugin → server → all TUIs + web clients

What the server sees vs. what stays on host

Section titled “What the server sees vs. what stays on host”
DataWhere it staysWhat the server sees
API keysHost’s machine onlyNever
Source code filesHost’s machine onlyNever
Environment variablesHost’s machine onlyNever
Tool execution (shell, file I/O)Host’s machine onlyNever
.env, credentials, secretsHost’s machine onlyNever
Prompt textHost + server (relay)Yes (for relay, TLS-protected)
Agent output textHost + server (relay)Yes (for relay, TLS-protected)
Collaborator names + presenceServerYes (routing metadata)
Session metadataServerYes

The host role can be transferred deliberately or automatically:

Deliberate transfer via /qwack host <user>:

1. Current host runs: /qwack host bob
2. Server broadcasts session:host_change to all clients
3. Old host: switches to relay mode (conversation preserved)
4. New host: creates local OpenCode session, receives context snapshot
5. New host's agent gets full history injected into system prompt

Auto-failover on host disconnect:

1. Host disconnects (crash, network, close terminal)
2. Server broadcasts presence:leave, starts 5-second grace period
3. Non-host prompts are buffered (up to 20 messages)
4. If host reconnects within grace period: buffered prompts delivered
5. If not: server auto-promotes next connected collaborator
6. New host receives event history + snapshot

When the host disconnects from the Qwack session but continues working locally:

  1. The plugin queues events (prompts, output, messages) to ~/.config/qwack/offline-queue.json
  2. The TUI shows ⏳ N queued while offline
  3. On reconnect, events are flushed to the server with replayed: true flag
  4. Collaborators see historical events merge into the timeline by timestamp

Queue limit is 10MB — oldest events are dropped if exceeded.


LayerTechnology
RuntimeBun
TUISolidJS (Ink-like terminal rendering)
APIHono
DatabaseDynamoDB (production) / SQLite (local dev)
AuthOpenAuth (GitHub OAuth)
Real-timeWebSockets + Yjs CRDT
InfrastructureAWS Fargate + ALB, deployed via SST
BuildBun workspaces + Turbo
ValidationZod