Merge remote-tracking branch 'origin/polecat/Scabrous'

# Conflicts:
#	docs/architecture.md
#	docs/harness.md
#	internal/beads/builtin_molecules.go
#	internal/cmd/mail.go
#	internal/cmd/molecule.go
#	internal/cmd/mq.go
#	internal/git/git.go
#	internal/mail/router.go
This commit is contained in:
Steve Yegge
2025-12-19 17:59:36 -08:00
6 changed files with 32 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
{"id":"gt-01u","title":"Design: Collapse mail into beads","description":"## Proposal\n\nReplace the separate mail system (JSONL inboxes) with beads issues using a naming convention.\n\n## Rationale\n\nIf all state should be in beads (work items, swarm state, dependencies), why have a separate system for messages? Mail is just:\n- Handoffs (agent → self)\n- Commands (Mayor → Refinery)\n- Escalations (Witness → Mayor)\n\nThese can all be beads issues with a special prefix.\n\n## Design\n\n### Convention\n- Messages use `@-` prefix: `@-witness-1734012345`\n- Assignee = recipient\n- Status: open = unread, closed = read/acknowledged\n- Priority 0 = urgent\n\n### Commands (thin wrappers)\n```bash\ngt mail send witness -s \"Subject\" -m \"Body\"\n → bd create --prefix=@ --title=\"Subject\" --assignee=witness --description=\"Body\"\n\ngt mail inbox\n → bd list --prefix=@ --assignee=$(gt whoami) --status=open\n\ngt mail read @-abc\n → bd show @-abc \u0026\u0026 bd close @-abc\n```\n\n### Notification\nDaemon watches for new `@-` issues and pokes relevant sessions.\nOr: agents poll on heartbeat (simpler).\n\n## What We Remove\n- `mail/inbox.jsonl` files\n- Mail JSONL read/write code\n- Separate delivery mechanism\n\n## What We Keep\n- `gt mail` CLI (as wrapper)\n- Handoff semantics\n- Notification (via daemon or polling)\n\n## Benefits\n- One system, one sync, one query interface\n- All communication in git history\n- Simpler architecture\n\n## Risks\n- Beads prefix filtering must be efficient\n- Namespace collision with user prefixes\n- Performance for high-frequency messages (probably fine for handoffs)\n\n## Decision Point\nDo we need first-class mail support in beads (`bd mail` commands) or is convention sufficient?","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-16T02:10:18.32879-08:00","updated_at":"2025-12-16T13:12:16.46526-08:00","closed_at":"2025-12-16T13:12:16.46526-08:00","close_reason":"Design complete - filed as bd-kwro in Beads repo. Tracking via gt-r01."}
{"id":"gt-082","title":"Worker cleanup: Beads sync on shutdown","description":"Add beads sync verification to worker cleanup checklist and Witness verification.\n\n## Update to Decommission Checklist (gt-sd6)\n\nAdd to pre-done verification:\n- bd sync --status must show 'Up to date'\n- git status .beads/ must show no changes\n\n## Beads Edge Cases\n\nUncommitted beads changes:\n bd sync\n git add .beads/\n git commit -m 'beads: final sync'\n\nBeads sync conflict (rare):\n git fetch origin main\n git checkout main -- .beads/\n bd sync --force\n git add .beads/\n git commit -m 'beads: resolve sync conflict'\n\n## Update to Witness Verification (gt-f8v)\n\nWhen capturing worker state:\n town capture \u003cpolecat\u003e \"bd sync --status \u0026\u0026 git status .beads/\"\n\nCheck for:\n- bd sync --status shows 'Up to date'\n- git status .beads/ shows no changes\n\nIf beads not synced, nudge:\n WITNESS CHECK: Beads not synced. Run 'bd sync' then commit .beads/. Signal done when complete.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-15T19:47:21.757756-08:00","updated_at":"2025-12-15T20:48:37.663168-08:00","dependencies":[{"issue_id":"gt-082","depends_on_id":"gt-l3c","type":"blocks","created_at":"2025-12-15T19:47:35.977804-08:00","created_by":"daemon","metadata":"{}"}]}
{"id":"gt-0asj","title":"Merge: gt-5af.5","description":"branch: polecat/Scabrous\ntarget: main\nsource_issue: gt-5af.5\nrig: gastown","status":"closed","priority":1,"issue_type":"merge-request","created_at":"2025-12-19T17:50:25.227909-08:00","updated_at":"2025-12-19T17:52:57.683445-08:00","closed_at":"2025-12-19T17:52:57.683445-08:00","close_reason":"Superseded - source issue gt-5af.5 already closed, branch has extensive conflicts with main"}
{"id":"gt-0asj","title":"Merge: gt-5af.5","description":"branch: polecat/Scabrous\ntarget: main\nsource_issue: gt-5af.5\nrig: gastown","status":"open","priority":1,"issue_type":"merge-request","created_at":"2025-12-19T17:50:25.227909-08:00","updated_at":"2025-12-19T17:54:17.07007-08:00"}
{"id":"gt-0iy3","title":"Merge: gt-3x1.3","description":"branch: polecat/Doof\ntarget: main\nsource_issue: gt-3x1.3\nrig: gastown","status":"closed","priority":1,"issue_type":"merge-request","created_at":"2025-12-19T14:53:52.741123-08:00","updated_at":"2025-12-19T17:47:03.618858-08:00","closed_at":"2025-12-19T17:47:03.618858-08:00","close_reason":"Already merged to main (polecat/Doof)"}
{"id":"gt-0ol","title":"Update prompts.md: Engineer role and templates","description":"Update docs/prompts.md with Engineer role:\n\n1. Role Prompts table: Change Refinery to Engineer\n2. Add Engineer-specific prompts:\n - Session restart request template\n - Subtask filing template\n - Handoff mail template\n3. Update refinery.md template name to engineer.md\n4. Ensure consistency with architecture.md","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-16T23:12:05.279233-08:00","updated_at":"2025-12-16T23:12:05.279233-08:00","dependencies":[{"issue_id":"gt-0ol","depends_on_id":"gt-h5n","type":"blocks","created_at":"2025-12-16T23:12:15.013747-08:00","created_by":"daemon","metadata":"{}"}]}
{"id":"gt-0pc","title":"Document Overseer role (human operator)","description":"Document the Overseer role in Gas Town architecture.\n\n## The Overseer\n\nThe **Overseer** is the human operator of Gas Town. Not an agent - a person.\n\n## Responsibilities\n\n| Area | Overseer Does | Mayor/Agents Do |\n|------|---------------|-----------------|\n| Strategy | Define project goals | Execute toward goals |\n| Priorities | Set priority order | Work in priority order |\n| Escalations | Final decision on stuck work | Escalate to Overseer |\n| Resources | Provision machines | Use allocated resources |\n| Quality | Review \u0026 approve swarm output | Produce output |\n| Operations | Run gt commands, monitor dashboards | Do the work |\n\n## Key Interactions\n\n### Overseer → Mayor\n- Start/stop Mayor sessions\n- Direct Mayor via conversation\n- Review Mayor recommendations\n- Approve cross-rig decisions\n\n### Mayor → Overseer (Escalations)\n- Stuck workers after retries\n- Resource decisions (add machines, polecats)\n- Ambiguous requirements\n- Architecture decisions\n\n## Operating Cadence\n\nTypical Overseer workflow:\n1. Morning: Check status, review overnight work\n2. During day: Monitor, respond to escalations, adjust priorities\n3. End of day: Review progress, plan next batch\n\n## Commands for Overseers\n\n```bash\ngt status # Quick health check\ngt doctor # Detailed diagnostics \ngt doctor --fix # Auto-repair issues\ngt inbox # Messages from agents\ngt stop --all # Emergency halt\n```\n\n## Documentation Updates\n\nAdd to docs/architecture.md:\n- Overseer section under Agent Roles\n- Clarify Mayor reports to Overseer\n- Add Overseer to workflow diagrams","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-15T23:18:03.177633-08:00","updated_at":"2025-12-15T23:22:51.477786-08:00","closed_at":"2025-12-15T23:22:51.477786-08:00","close_reason":"Overseer role documented in docs/architecture.md"}

View File

@@ -1001,7 +1001,7 @@ Workers process issues independently. Work flows through the merge queue. No "sw
Gas Town Daemon (gt daemon)
├── Pokes Mayor periodically
├── Pokes all Witnesses periodically
├── Processes lifecycle requests from daemon/ inbox
├── Processes lifecycle requests from deacon/ inbox
└── Restarts sessions when cycle requested
Lifecycle Hierarchy:
@@ -1027,8 +1027,8 @@ gt handoff --restart # Fresh restart, no handoff
|-------|---------|------------------|
| Polecat | --shutdown | rig/witness |
| Refinery | --cycle | rig/witness |
| Witness | --cycle | daemon/ |
| Mayor | --cycle | daemon/ |
| Witness | --cycle | deacon/ |
| Mayor | --cycle | deacon/ |
**Lifecycle request protocol**:
1. Agent runs `gt handoff` (verifies git clean, sends handoff mail)
@@ -1044,7 +1044,7 @@ gt handoff --restart # Fresh restart, no handoff
- Poke Mayor: "HEARTBEAT: check your rigs"
- Poke each Witness: "HEARTBEAT: check your workers"
- Agents ignore poke if already working
- Process any lifecycle requests in daemon/ inbox
- Process any lifecycle requests in deacon/ inbox
- Restart dead sessions if cycle was requested
```mermaid

View File

@@ -225,7 +225,7 @@ func preFlightChecks() error {
func getManager(role Role) string {
switch role {
case RoleMayor, RoleWitness:
return "daemon/"
return "deacon/"
case RolePolecat, RoleRefinery:
// Would need rig context to determine witness address
// For now, use a placeholder pattern
@@ -233,7 +233,7 @@ func getManager(role Role) string {
case RoleCrew:
return "human" // Crew is human-managed
default:
return "daemon/"
return "deacon/"
}
}

View File

@@ -23,10 +23,10 @@ type BeadsMessage struct {
Status string `json:"status"`
}
// ProcessLifecycleRequests checks for and processes lifecycle requests from the daemon inbox.
// ProcessLifecycleRequests checks for and processes lifecycle requests from the deacon inbox.
func (d *Daemon) ProcessLifecycleRequests() {
// Get mail for daemon identity
cmd := exec.Command("bd", "mail", "inbox", "--identity", "daemon/", "--json")
// Get mail for deacon identity
cmd := exec.Command("bd", "mail", "inbox", "--identity", "deacon/", "--json")
cmd.Dir = d.config.TownRoot
output, err := cmd.Output()

View File

@@ -41,6 +41,19 @@ const (
TypeReply MessageType = "reply"
)
// Delivery specifies how a message is delivered to the recipient.
type Delivery string
const (
// DeliveryQueue creates the message in the mailbox for periodic checking.
// This is the default delivery mode. Agent checks with `gt mail check`.
DeliveryQueue Delivery = "queue"
// DeliveryInterrupt injects a system-reminder directly into the agent's session.
// Use for lifecycle events, URGENT priority, or stuck detection.
DeliveryInterrupt Delivery = "interrupt"
)
// Message represents a mail message between agents.
// This is the GGT-side representation; it gets translated to/from beads messages.
type Message struct {
@@ -71,6 +84,10 @@ type Message struct {
// Type indicates the message type (task, scavenge, notification, reply).
Type MessageType `json:"type"`
// Delivery specifies how the message is delivered (queue or interrupt).
// Queue: agent checks periodically. Interrupt: inject into session.
Delivery Delivery `json:"delivery,omitempty"`
// ThreadID groups related messages into a conversation thread.
ThreadID string `json:"thread_id,omitempty"`

View File

@@ -4,7 +4,7 @@
#
# Usage: mayor-respawn-daemon.sh [start|stop|status]
#
# The daemon monitors for mail to "daemon/" with subject containing "RESTART".
# The daemon monitors for mail to "deacon/" with subject containing "RESTART".
# When found, it:
# 1. Acknowledges the mail
# 2. Waits 5 seconds (for handoff mail to be sent)
@@ -23,10 +23,10 @@ log() {
check_for_restart() {
cd "$TOWN_ROOT" || return 1
# Check inbox for daemon identity - look for RESTART subject
# Set BD_IDENTITY=daemon so bd mail knows which inbox to check
# Check inbox for deacon identity - look for RESTART subject
# Set BD_IDENTITY=deacon so bd mail knows which inbox to check
local inbox
inbox=$(BD_IDENTITY=daemon bd mail inbox --json 2>/dev/null)
inbox=$(BD_IDENTITY=deacon bd mail inbox --json 2>/dev/null)
if [ -z "$inbox" ] || [ "$inbox" = "null" ] || [ "$inbox" = "[]" ]; then
return 1
@@ -41,7 +41,7 @@ check_for_restart() {
log "Found restart request: $msg_id"
# Acknowledge the message
BD_IDENTITY=daemon bd mail ack "$msg_id" 2>/dev/null
BD_IDENTITY=deacon bd mail ack "$msg_id" 2>/dev/null
log "Acknowledged restart request"
# Wait for handoff to complete