Add session beacon for predecessor discovery via /resume

Inject an identity beacon as the first message when Gas Town starts Claude
sessions. This beacon becomes the session title in Claude Code '/resume
picker, enabling workers to find their predecessor sessions for debugging.

Beacon format: [GAS TOWN] <address> • <mol-id or "ready"> • <timestamp>

Examples:
- [GAS TOWN] gastown/crew/max • gt-abc12 • 2025-12-30T14:32
- [GAS TOWN] gastown/polecats/Toast • ready • 2025-12-30T09:15
- [GAS TOWN] deacon • patrol • 2025-12-30T08:00

Workers can now press / in /resume picker and search for their address
(e.g., "gastown/crew/max") to see all predecessor sessions.

Note: Respawn-loop agents (deacon/refinery via up.go) skip beacon injection
since Claude restarts multiple times - would need post-restart injection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-30 18:01:47 -08:00
parent 5c61c8c334
commit 66042da18b
8 changed files with 166 additions and 1 deletions

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/steveyegge/gastown/internal/claude"
"github.com/steveyegge/gastown/internal/constants"
"github.com/steveyegge/gastown/internal/rig"
"github.com/steveyegge/gastown/internal/tmux"
)
@@ -185,6 +186,21 @@ func (m *Manager) Start(polecat string, opts StartOptions) error {
return fmt.Errorf("sending command: %w", err)
}
// Wait for Claude to start (non-fatal: session continues even if this times out)
if err := m.tmux.WaitForCommand(sessionID, constants.SupportedShells, constants.ClaudeStartTimeout); err != nil {
// Non-fatal warning - Claude might still start
}
time.Sleep(constants.ShutdownNotifyDelay)
// Inject session beacon for predecessor discovery via /resume
// This becomes the session title in Claude Code's session picker
address := fmt.Sprintf("%s/polecats/%s", m.rig.Name, polecat)
molID := opts.Issue // Use issue ID if provided
beacon := SessionBeacon(address, molID)
if err := m.tmux.NudgeSession(sessionID, beacon); err != nil {
// Non-fatal: session works without beacon
}
return nil
}

View File

@@ -1,7 +1,10 @@
// Package session provides polecat session lifecycle management.
package session
import "fmt"
import (
"fmt"
"time"
)
// Prefix is the common prefix for all Gas Town tmux session names.
const Prefix = "gt-"
@@ -35,3 +38,22 @@ func CrewSessionName(rig, name string) string {
func PolecatSessionName(rig, name string) string {
return fmt.Sprintf("%s%s-%s", Prefix, rig, name)
}
// SessionBeacon generates an identity beacon message for Claude Code sessions.
// This beacon becomes the session title in /resume picker, enabling workers to
// find their predecessor sessions.
//
// Format: [GAS TOWN] <address> • <mol-id or "ready"> • <timestamp>
//
// Examples:
// - [GAS TOWN] gastown/crew/max • gt-abc12 • 2025-12-30T14:32
// - [GAS TOWN] gastown/polecats/Toast • ready • 2025-12-30T09:15
// - [GAS TOWN] deacon • patrol • 2025-12-30T08:00
func SessionBeacon(address, molID string) string {
if molID == "" {
molID = "ready"
}
// Use local time in a compact format
timestamp := time.Now().Format("2006-01-02T15:04")
return fmt.Sprintf("[GAS TOWN] %s • %s • %s", address, molID, timestamp)
}