How the Mayor Agent Functions as a Global Coordinator in Gastown
The Mayor agent serves as Gastown's central orchestrator, managing work dispatch through slot-open notifications, controlling escalation pathways for stuck workers, and maintaining global state visibility while protecting critical sections during interactive debugging sessions.
The Mayor is the central nervous system of the gastownhall/gastown distributed execution framework. As the global coordinator, it maintains a high-level view of all active workers (polecats) and pending tasks (beads), making authoritative decisions about resource allocation and exceptional condition handling. Unlike individual worker agents that handle specific computational tasks, the Mayor operates as a singleton process running in its own isolated session, ensuring centralized control without interference.
Global Role and Session Architecture
The Mayor's authority starts with its explicit declaration as a distinct role constant. In internal/constants/constants.go, the system defines RoleMayor = "mayor", establishing a canonical identifier used throughout the codebase for routing decisions and role-based access control.
Session isolation ensures the Mayor operates independently from worker processes. The Mayor runs inside a dedicated tmux session named gt-mayor, obtained via session.MayorSessionName(). This isolation allows the Mayor to persist across worker lifecycles and maintain state even when individual polecats terminate.
Slot-Open Notification Protocol
When a polecat completes its assigned bead, the Witness agent signals the Mayor through the slot-open notification system. The notifyMayorSlotOpen function in internal/witness/handlers.go (lines 880-900) implements this handshake:
// Inside internal/witness/handlers.go
if result.Handled {
// Tell the Mayor a polecat slot is free.
notifyMayorSlotOpen(workDir, rigName, payload.PolecatName, payload.Exit)
}
This function first attempts to nudge the Mayor's tmux session directly. If the session is unreachable, it falls back to writing a SLOT_OPEN channel event that the Mayor picks up immediately upon recovery. This dual-channel approach ensures the global coordinator never misses worker availability updates, even during transient session disruptions.
Escalation Handling and Safety Guards
The Mayor functions as the ultimate authority for exceptional conditions that automated workers cannot resolve. When the Witness detects stuck or unhealthy workers, it escalates to the Mayor rather than taking unilateral action.
Worker Escalation Pathways
According to the CLAUDE templates in templates/witness-CLAUDE.md (lines 8, 25, and 62), the system explicitly requires human-level approval for forced cleanup operations. The templates instruct:
7. **Escalation**: Report stuck workers to Mayor
...
Only use `--force` after Mayor authorizes or confirms work is unrecoverable.
This design prevents data loss by ensuring destructive operations receive explicit coordinator approval.
ACP Protection During Interactive Sessions
To prevent automatic cleanup during active debugging, the Mayor implements Assistant Code Prompt (ACP) protection. When the Mayor's ACP session is active, cleanup operations are suppressed. The check in internal/witness/handlers.go (around line 1335) implements this guard:
if mayorSession := session.MayorSessionName(); mayorSessionIsActive {
// Suppress automatic cleanup to prevent data loss during interactive debugging
}
This mechanism ensures that when developers are interactively debugging through the Mayor session, background workers cannot accidentally terminate processes or delete intermediate states.
Observability and Control Interfaces
The Mayor exposes its coordination state through multiple interfaces, allowing both automated systems and human operators to monitor global health.
Dashboard Status Exposure
The web dashboard renders the Mayor's operational status through the MayorStatus struct defined in internal/web/templates.go (lines 107-114). The dashboard handler fetches this status via:
mayor, err := h.fetcher.FetchMayor()
if err != nil {
log.Printf("dashboard: FetchMayor failed: %v", err)
}
The status includes critical visibility fields: IsAttached, IsActive, and Runtime, displayed in the convoy UI to indicate whether the global coordinator is alive and responsive.
Mail Routing and CLI Integration
The mail routing system in internal/mail/router.go (lines 260-270) treats the Mayor as a first-class recipient, routing messages addressed to mayor/ directly to the Mayor's session. This enables other agents—Witness, Deacon, and Refinery—to nudge the coordinator without knowing its underlying session details.
CLI commands throughout internal/cmd/* (including role.go and unsling.go) accept mayor as a valid target parameter. For example:
gt nudge mayor
gt mail mayor/status
gt prime mayor
This integration ensures the Mayor remains reachable from any part of the system, whether through automated mail routing or explicit operator commands.
Summary
- The Mayor agent operates as a singleton global coordinator in a dedicated
gt-mayortmux session, isolated from worker processes. - Slot-open notifications via
notifyMayorSlotOpenensure the Mayor tracks worker availability in real-time, enabling intelligent bead dispatch. - Escalation pathways route exceptional conditions through the Mayor, preventing automated systems from taking destructive actions without authorization.
- ACP protection suppresses automatic cleanup during interactive debugging sessions, preventing data loss while the Mayor is actively managing the system.
- Dashboard exposure and mail routing provide visibility and control interfaces, making the Mayor's coordination state observable and manageable through both web UI and CLI.
Frequently Asked Questions
What triggers the Mayor to dispatch new work?
The Mayor dispatches new beads when it receives slot-open notifications from the Witness agent. After a polecat completes its current task, the Witness calls notifyMayorSlotOpen in internal/witness/handlers.go, signaling that a worker slot is available. The Mayor then evaluates the pending work queue and assigns the next bead to the available worker.
How does the Mayor prevent accidental cleanup during debugging?
The Mayor implements ACP (Assistant Code Prompt) protection. When mayorSessionIsActive evaluates to true in internal/witness/handlers.go (around line 1335), automatic cleanup operations are suppressed. This prevents background workers from terminating processes or deleting state while a developer is interactively debugging through the Mayor session.
What happens if the Mayor session is not running?
If the Mayor's tmux session is unreachable, the notifyMayorSlotOpen function falls back to a file-based channel event mechanism. It writes a SLOT_OPEN event to the channel event file, which the Mayor processes immediately upon restart. This ensures no worker state changes are lost during temporary coordinator outages.
How do other agents communicate with the Mayor?
Agents communicate through the mail routing system defined in internal/mail/router.go (lines 260-270), which routes messages addressed to mayor/ to the Mayor's session. Additionally, CLI commands like gt nudge mayor or gt mail mayor/status provide direct interaction capabilities from anywhere in the system.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →