Overview
Major refactoring of the gastown architecture to simplify the DO topology, replace subprocess-based agent management with the SDK, and establish a clean WebSocket event pipeline from agent to browser.
Full plan: plans/gastown-town-centric-refactor.md
Motivation
- Data is fragmented across DOs. Agent state, beads, mail, and review queues live in the Rig DO. Convoys/escalations live in the Town DO. Mayor state lives in a separate Mayor DO. The Town DO has no complete picture.
- Too many indirection layers for streaming. Events flow through 6 hops with SSE parsing, ring buffers, and HTTP polling in the middle.
- Spawning
kilo serve as a subprocess is unnecessary. The @kilocode/sdk provides createOpencode() for in-process server lifecycle and event.subscribe() for typed event streams.
- Config goes stale. Container env vars are injected once at boot and never refreshed. Model/token changes require a container restart.
- Models threaded through 6 layers. Should be configured at the town level and resolved at dispatch time.
Target Architecture
Three DOs total:
- TownDO — All control-plane data (rigs, agents, beads, mail, review queues, convoys, escalations, config). Single alarm for scheduling, health, and review processing.
- AgentDO (one per agent) — Event storage only. Isolates high-volume event streams from the 10GB Town DO budget.
- TownContainerDO — Container lifecycle, WebSocket relay.
Rig DO and Mayor DO are eliminated. The mayor becomes a regular agent row. Rigs become rows in a Town DO table.
SDK replaces subprocess: createOpencode() replaces Bun.spawn('kilo serve'). client.event.subscribe() replaces SSE parsing + ring buffers.
WebSocket all the way: SDK events → container WS → TownContainerDO WS → browser. No SSE, no polling, no tickets.
Config-on-request: TownDO attaches current resolved config to every container fetch() via X-Town-Config header. Zero staleness.
Implementation Phases
Phase A: Data Consolidation
Phase B: SDK-Based Agent Management
Phase C: WebSocket Streaming
Phase D: Proactive Startup & Config Cleanup
Files Deleted
container/src/kilo-server.ts
container/src/kilo-client.ts
container/src/sse-consumer.ts
src/dos/Rig.do.ts
src/dos/Mayor.do.ts
Risk Mitigation
- Data migration: New towns start fresh. Existing towns get a migration alarm.
- WebSocket reliability: Browser reconnects with backfill from AgentDO.
- SDK compatibility: Verify
createOpencode() works in Bun container.
- DO storage: Agent events isolated in per-agent AgentDOs (10GB each). Town DO stores only bounded control-plane data.
Parent: #204
Overview
Major refactoring of the gastown architecture to simplify the DO topology, replace subprocess-based agent management with the SDK, and establish a clean WebSocket event pipeline from agent to browser.
Full plan:
plans/gastown-town-centric-refactor.mdMotivation
kilo serveas a subprocess is unnecessary. The@kilocode/sdkprovidescreateOpencode()for in-process server lifecycle andevent.subscribe()for typed event streams.Target Architecture
Three DOs total:
Rig DO and Mayor DO are eliminated. The mayor becomes a regular agent row. Rigs become rows in a Town DO table.
SDK replaces subprocess:
createOpencode()replacesBun.spawn('kilo serve').client.event.subscribe()replaces SSE parsing + ring buffers.WebSocket all the way: SDK events → container WS → TownContainerDO WS → browser. No SSE, no polling, no tickets.
Config-on-request: TownDO attaches current resolved config to every container
fetch()viaX-Town-Configheader. Zero staleness.Implementation Phases
Phase A: Data Consolidation
Phase B: SDK-Based Agent Management
kilo-server.tswith SDKcreateOpencode()event.subscribe()kilo-client.tswith SDK clientPhase C: WebSocket Streaming
/ws)Phase D: Proactive Startup & Config Cleanup
Files Deleted
container/src/kilo-server.tscontainer/src/kilo-client.tscontainer/src/sse-consumer.tssrc/dos/Rig.do.tssrc/dos/Mayor.do.tsRisk Mitigation
createOpencode()works in Bun container.Parent: #204