Parent: #204 | Phase 2: Multi-Agent Orchestration
Revised (Feb 2026): The Mayor is now handled by a dedicated MayorDO (#338), not the Town DO. The Town DO focuses on cross-rig coordination: convoy lifecycle, escalation routing, rig registry, and watchdog heartbeat.
Goal
The Town DO manages cross-rig coordination: convoy lifecycle, escalation routing, and the watchdog heartbeat.
Note: The mayor agent is NOT part of this DO. The mayor lives in MayorDO (keyed by townId, see #338). The Town DO provides data that the MayorDO reads (rig registry, convoy state, escalations), but does not own the mayor session.
Town DO SQLite Schema
CREATE TABLE rigs (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
rig_do_id TEXT NOT NULL -- Rig DO durable object ID
);
CREATE TABLE convoys (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
total_beads INTEGER NOT NULL DEFAULT 0,
closed_beads INTEGER NOT NULL DEFAULT 0,
created_by TEXT,
created_at TEXT NOT NULL,
landed_at TEXT
);
CREATE TABLE convoy_beads (
convoy_id TEXT NOT NULL REFERENCES convoys(id),
bead_id TEXT NOT NULL,
rig_id TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'open',
PRIMARY KEY (convoy_id, bead_id)
);
CREATE TABLE escalations (
id TEXT PRIMARY KEY,
source_rig_id TEXT NOT NULL,
source_agent_id TEXT,
severity TEXT NOT NULL,
category TEXT,
message TEXT NOT NULL,
acknowledged INTEGER NOT NULL DEFAULT 0,
re_escalation_count INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
acknowledged_at TEXT
);
Key Methods
createConvoy(title, beads[]) — create convoy, distribute beads to Rig DOs
onBeadClosed(convoyId, beadId) — increment closed count, check if convoy has landed
routeEscalation(input) — route by severity: low → log, medium → mail Mayor (via MayorDO), high → webhook/email
watchdogHeartbeat() — DO alarm (3 min): check each Rig DO health, verify Town Container is alive via container.fetch('/health')
Dependencies
Acceptance Criteria
Parent: #204 | Phase 2: Multi-Agent Orchestration
Goal
The Town DO manages cross-rig coordination: convoy lifecycle, escalation routing, and the watchdog heartbeat.
Note: The mayor agent is NOT part of this DO. The mayor lives in
MayorDO(keyed bytownId, see #338). The Town DO provides data that the MayorDO reads (rig registry, convoy state, escalations), but does not own the mayor session.Town DO SQLite Schema
Key Methods
createConvoy(title, beads[])— create convoy, distribute beads to Rig DOsonBeadClosed(convoyId, beadId)— increment closed count, check if convoy has landedrouteEscalation(input)— route by severity: low → log, medium → mail Mayor (via MayorDO), high → webhook/emailwatchdogHeartbeat()— DO alarm (3 min): check each Rig DO health, verify Town Container is alive viacontainer.fetch('/health')Dependencies
Acceptance Criteria