bd sync: 2025-12-25 12:41:08
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
"id": "trigger-pending-spawns",
|
||||
"title": "Nudge newly spawned polecats",
|
||||
"needs": ["inbox-check"],
|
||||
"description": "Nudge newly spawned polecats that are ready for input.\n\nWhen polecats are spawned, their Claude session takes 10-20 seconds to initialize. The spawn command returns immediately without waiting. This step finds spawned polecats that are now ready and sends them a trigger to start working.\n\n```bash\n# For each rig with polecats\nfor rig in gastown beads; do\n gt polecats $rig\n # For each working polecat, check if Claude is ready\n # Use tmux capture-pane to look for \"> \" prompt\ndone\n```\n\nFor each ready polecat that hasn't been triggered yet:\n1. Send \"Begin.\" to trigger UserPromptSubmit hook\n2. The hook injects mail, polecat sees its assignment\n3. Mark polecat as triggered in state\n\nUse WaitForClaudeReady from tmux package (polls for \"> \" prompt). Timeout: 60 seconds per polecat. If not ready, try again next cycle."
|
||||
"description": "Nudge newly spawned polecats that are ready for input.\n\nWhen polecats are spawned, their Claude session takes 10-20 seconds to initialize. The spawn command returns immediately without waiting. This step finds spawned polecats that are now ready and sends them a trigger to start working.\n\n**ZFC-Compliant Observation** (AI observes AI):\n\n```bash\n# View pending spawns with captured terminal output\ngt deacon pending\n```\n\nFor each pending session, analyze the captured output:\n- Look for Claude's prompt indicator \"> \" at the start of a line\n- If prompt is visible, Claude is ready for input\n- Make the judgment call yourself - you're the AI observer\n\nFor each ready polecat:\n```bash\n# 1. Trigger the polecat\ngt nudge <session> \"Begin.\"\n\n# 2. Clear from pending list\ngt deacon pending <session>\n```\n\nThis triggers the UserPromptSubmit hook, which injects mail so the polecat sees its assignment.\n\n**Bootstrap mode** (daemon-only, no AI available):\nThe daemon uses `gt deacon trigger-pending` with regex detection. This ZFC violation is acceptable during cold startup when no AI agent is running yet."
|
||||
},
|
||||
{
|
||||
"id": "health-scan",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
{"id":"gt-0m6tl","title":"Digest: mol-deacon-patrol","description":"Patrol 17: All healthy","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-25T10:50:41.588767-08:00","updated_at":"2025-12-25T10:50:41.588767-08:00","closed_at":"2025-12-25T10:50:41.588725-08:00","close_reason":"Squashed from 8 wisps"}
|
||||
{"id":"gt-0mchz","title":"Digest: mol-deacon-patrol","description":"Patrol 8: All clear","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-25T00:02:09.286607-08:00","updated_at":"2025-12-25T00:02:09.286607-08:00","closed_at":"2025-12-25T00:02:09.28657-08:00","close_reason":"Squashed from 8 wisps"}
|
||||
{"id":"gt-0nh8","title":"gt prime should detect mayor role from any rig's mayor/ folder","description":"Currently gt prime only detects the Mayor role when run from town root (~/gt). It should also detect Mayor when run from:\n- ~/gt/gastown/mayor/rig (rig's internal mayor dir)\n- Any path containing /mayor/ under a rig\n\nThis would allow the mayor session to work correctly regardless of which rig directory it's attached to.","status":"open","priority":2,"issue_type":"bug","created_at":"2025-12-20T21:56:10.281534-08:00","updated_at":"2025-12-20T21:56:10.281534-08:00"}
|
||||
{"id":"gt-0odbt","title":"Replace WaitForClaudeReady with gt peek for steady-state agent observation","description":"## Problem\n\nWaitForClaudeReady uses regex to detect Claude's prompt, which is a ZFC violation.\n\n## Architectural Fix\n\n**Bootstrap (ZFC violation acceptable):**\nDuring cold town startup, no AI is available. Regex to get Deacon online is acceptable.\n\n**Steady State (proper ZFC):**\nOnce any agent is running, AI should observe AI:\n- Deacon starting polecats → Deacon uses gt peek\n- Deacon restarting → Mayor watches via gt peek\n- Mayor restarting → Deacon watches via gt peek\n\n## Implementation\n\n1. Keep WaitForClaudeReady for daemon bootstrap only\n2. Update gt deacon trigger-pending to use gt peek\n3. Document bootstrap vs steady-state distinction\n","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2025-12-25T12:34:32.712726-08:00","updated_at":"2025-12-25T12:36:04.186941-08:00"}
|
||||
{"id":"gt-0odbt","title":"Replace WaitForClaudeReady with gt peek for steady-state agent observation","description":"## Problem\n\nWaitForClaudeReady uses regex to detect Claude's prompt, which is a ZFC violation.\n\n## Architectural Fix\n\n**Bootstrap (ZFC violation acceptable):**\nDuring cold town startup, no AI is available. Regex to get Deacon online is acceptable.\n\n**Steady State (proper ZFC):**\nOnce any agent is running, AI should observe AI:\n- Deacon starting polecats → Deacon uses gt peek\n- Deacon restarting → Mayor watches via gt peek\n- Mayor restarting → Deacon watches via gt peek\n\n## Implementation\n\n1. Keep WaitForClaudeReady for daemon bootstrap only\n2. Update gt deacon trigger-pending to use gt peek\n3. Document bootstrap vs steady-state distinction\n","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-25T12:34:32.712726-08:00","updated_at":"2025-12-25T12:40:48.082699-08:00","closed_at":"2025-12-25T12:40:48.082699-08:00","close_reason":"Implemented gt deacon pending for ZFC-compliant AI observation. Added bootstrap vs steady-state documentation."}
|
||||
{"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"}]}
|
||||
{"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":"tombstone","priority":1,"issue_type":"task","created_at":"2025-12-15T23:18:03.177633-08:00","updated_at":"2025-12-25T01:30:41.67682-08:00","deleted_at":"2025-12-25T01:30:41.67682-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"task"}
|
||||
{"id":"gt-0pl","title":"Polecat CLAUDE.md: configure auto-approve for bd and gt commands","description":"Polecats get stuck waiting for bash command approval when running\nbd and gt commands. Need to configure Claude Code to auto-approve these.\n\nOptions:\n1. Add allowedTools to polecat CLAUDE.md\n2. Configure .claude/settings.json in polecat directory\n3. Use --dangerously-skip-permissions flag (not recommended)\n\nShould auto-approve:\n- bd (beads commands)\n- gt (gastown commands)\n- go build/test\n- git status/add/commit/push\n\nShould still require approval:\n- rm -rf\n- Arbitrary commands outside project\n\nRelated to polecat prompting (gt-e1y, gt-sd6).","status":"tombstone","priority":1,"issue_type":"task","created_at":"2025-12-17T14:10:27.611612-08:00","updated_at":"2025-12-25T01:30:41.67682-08:00","deleted_at":"2025-12-25T01:30:41.67682-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"task"}
|
||||
|
||||
+143
-4
@@ -93,17 +93,46 @@ Examples:
|
||||
|
||||
var deaconTriggerPendingCmd = &cobra.Command{
|
||||
Use: "trigger-pending",
|
||||
Short: "Trigger pending polecat spawns",
|
||||
Short: "Trigger pending polecat spawns (bootstrap mode)",
|
||||
Long: `Check inbox for POLECAT_STARTED messages and trigger ready polecats.
|
||||
|
||||
When gt spawn creates a new polecat, Claude takes 10-20 seconds to initialize.
|
||||
This command polls pending spawns and sends "Begin." when Claude is ready.
|
||||
⚠️ BOOTSTRAP MODE ONLY - Uses regex detection (ZFC violation acceptable).
|
||||
|
||||
This is typically called during the Deacon's patrol loop.`,
|
||||
This command uses WaitForClaudeReady (regex) to detect when Claude is ready.
|
||||
This is appropriate for daemon bootstrap when no AI is available.
|
||||
|
||||
In steady-state, the Deacon should use AI-based observation instead:
|
||||
gt deacon pending # View pending spawns with captured output
|
||||
gt peek <session> # Observe session output (AI analyzes)
|
||||
gt nudge <session> # Trigger when AI determines ready
|
||||
|
||||
This command is typically called by the daemon during cold startup.`,
|
||||
RunE: runDeaconTriggerPending,
|
||||
}
|
||||
|
||||
var deaconPendingCmd = &cobra.Command{
|
||||
Use: "pending [session-to-clear]",
|
||||
Short: "List pending spawns with captured output (for AI observation)",
|
||||
Long: `List pending polecat spawns with their terminal output for AI analysis.
|
||||
|
||||
This is the ZFC-compliant way for the Deacon (AI) to observe polecats:
|
||||
1. Run 'gt deacon pending' to see pending spawns and their output
|
||||
2. Analyze the output to determine if Claude is ready (look for "> " prompt)
|
||||
3. Run 'gt nudge <session> "Begin."' to trigger ready polecats
|
||||
4. Run 'gt deacon pending <session>' to clear from pending list
|
||||
|
||||
This replaces the regex-based trigger-pending for steady-state operation.
|
||||
The AI makes the readiness judgment, not hardcoded regex.
|
||||
|
||||
Examples:
|
||||
gt deacon pending # List all pending with output
|
||||
gt deacon pending gastown/p-abc123 # Clear specific session from pending`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: runDeaconPending,
|
||||
}
|
||||
|
||||
var triggerTimeout time.Duration
|
||||
var pendingLines int
|
||||
|
||||
func init() {
|
||||
deaconCmd.AddCommand(deaconStartCmd)
|
||||
@@ -113,11 +142,16 @@ func init() {
|
||||
deaconCmd.AddCommand(deaconRestartCmd)
|
||||
deaconCmd.AddCommand(deaconHeartbeatCmd)
|
||||
deaconCmd.AddCommand(deaconTriggerPendingCmd)
|
||||
deaconCmd.AddCommand(deaconPendingCmd)
|
||||
|
||||
// Flags for trigger-pending
|
||||
deaconTriggerPendingCmd.Flags().DurationVar(&triggerTimeout, "timeout", 2*time.Second,
|
||||
"Timeout for checking if Claude is ready")
|
||||
|
||||
// Flags for pending
|
||||
deaconPendingCmd.Flags().IntVarP(&pendingLines, "lines", "n", 15,
|
||||
"Number of terminal lines to capture per session")
|
||||
|
||||
rootCmd.AddCommand(deaconCmd)
|
||||
}
|
||||
|
||||
@@ -377,3 +411,108 @@ func runDeaconTriggerPending(cmd *cobra.Command, args []string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// runDeaconPending shows pending spawns with captured output for AI observation.
|
||||
// This is the ZFC-compliant way for Deacon to observe polecats.
|
||||
func runDeaconPending(cmd *cobra.Command, args []string) error {
|
||||
townRoot, err := workspace.FindFromCwdOrError()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// If session argument provided, clear it from pending
|
||||
if len(args) == 1 {
|
||||
return clearPendingSession(townRoot, args[0])
|
||||
}
|
||||
|
||||
// Step 1: Check inbox for new POLECAT_STARTED messages
|
||||
pending, err := deacon.CheckInboxForSpawns(townRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking inbox: %w", err)
|
||||
}
|
||||
|
||||
if len(pending) == 0 {
|
||||
fmt.Printf("%s No pending spawns\n", style.Dim.Render("○"))
|
||||
return nil
|
||||
}
|
||||
|
||||
t := tmux.NewTmux()
|
||||
|
||||
fmt.Printf("%s Pending spawns (%d):\n\n", style.Bold.Render("●"), len(pending))
|
||||
|
||||
for i, ps := range pending {
|
||||
// Check if session still exists
|
||||
running, err := t.HasSession(ps.Session)
|
||||
if err != nil {
|
||||
fmt.Printf("Session: %s\n", ps.Session)
|
||||
fmt.Printf(" Status: error checking session: %v\n\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !running {
|
||||
fmt.Printf("Session: %s\n", ps.Session)
|
||||
fmt.Printf(" Status: session no longer exists\n\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Capture terminal output for AI analysis
|
||||
output, err := t.CapturePane(ps.Session, pendingLines)
|
||||
if err != nil {
|
||||
fmt.Printf("Session: %s\n", ps.Session)
|
||||
fmt.Printf(" Status: error capturing output: %v\n\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Print session info
|
||||
fmt.Printf("Session: %s\n", ps.Session)
|
||||
fmt.Printf(" Rig: %s\n", ps.Rig)
|
||||
fmt.Printf(" Polecat: %s\n", ps.Polecat)
|
||||
if ps.Issue != "" {
|
||||
fmt.Printf(" Issue: %s\n", ps.Issue)
|
||||
}
|
||||
fmt.Printf(" Spawned: %s ago\n", time.Since(ps.SpawnedAt).Round(time.Second))
|
||||
fmt.Printf(" Terminal output (last %d lines):\n", pendingLines)
|
||||
fmt.Println(strings.Repeat("─", 50))
|
||||
fmt.Println(output)
|
||||
fmt.Println(strings.Repeat("─", 50))
|
||||
|
||||
if i < len(pending)-1 {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("%s To trigger a ready polecat:\n", style.Dim.Render("→"))
|
||||
fmt.Printf(" gt nudge <session> \"Begin.\"\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// clearPendingSession removes a session from the pending list.
|
||||
func clearPendingSession(townRoot, session string) error {
|
||||
pending, err := deacon.LoadPending(townRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading pending: %w", err)
|
||||
}
|
||||
|
||||
var remaining []*deacon.PendingSpawn
|
||||
found := false
|
||||
for _, ps := range pending {
|
||||
if ps.Session == session {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
remaining = append(remaining, ps)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return fmt.Errorf("session %s not found in pending list", session)
|
||||
}
|
||||
|
||||
if err := deacon.SavePending(townRoot, remaining); err != nil {
|
||||
return fmt.Errorf("saving pending: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s Cleared %s from pending list\n", style.Bold.Render("✓"), session)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -409,6 +409,24 @@ func (t *Tmux) WaitForShellReady(session string, timeout time.Duration) error {
|
||||
// WaitForClaudeReady polls until Claude's prompt indicator appears in the pane.
|
||||
// Claude is ready when we see "> " at the start of a line (the input prompt).
|
||||
// This is more reliable than just checking if node is running.
|
||||
//
|
||||
// IMPORTANT: Bootstrap vs Steady-State Observation
|
||||
//
|
||||
// This function uses regex to detect Claude's prompt - a ZFC violation.
|
||||
// ZFC (Zero False Commands) principle: AI should observe AI, not regex.
|
||||
//
|
||||
// Bootstrap (acceptable):
|
||||
// During cold startup when no AI agent is running, the daemon uses this
|
||||
// function to get the Deacon online. Regex is acceptable here.
|
||||
//
|
||||
// Steady-State (use AI observation instead):
|
||||
// Once any AI agent is running, observation should be AI-to-AI:
|
||||
// - Deacon starting polecats → use 'gt deacon pending' + AI analysis
|
||||
// - Deacon restarting → Mayor watches via 'gt peek'
|
||||
// - Mayor restarting → Deacon watches via 'gt peek'
|
||||
//
|
||||
// See: gt deacon pending (ZFC-compliant AI observation)
|
||||
// See: gt deacon trigger-pending (bootstrap mode, regex-based)
|
||||
func (t *Tmux) WaitForClaudeReady(session string, timeout time.Duration) error {
|
||||
deadline := time.Now().Add(timeout)
|
||||
for time.Now().Before(deadline) {
|
||||
|
||||
Reference in New Issue
Block a user