When starting Mayor via 'gt may at', the session now: 1. Works from townRoot (~/gt) instead of mayorDir (~/gt/mayor) 2. Includes startup beacon with explicit instructions in initial prompt 3. Removes redundant post-start nudges (beacon has instructions) This matches the 'gt handoff' behavior where the agent immediately knows to check hook and mail on startup. Fixes: hq-h3449 (P0 escalation - horrendous starting UX) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
94 lines
3.4 KiB
Go
94 lines
3.4 KiB
Go
// Package session provides polecat session lifecycle management.
|
|
package session
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/steveyegge/gastown/internal/tmux"
|
|
)
|
|
|
|
// StartupNudgeConfig configures a startup nudge message.
|
|
type StartupNudgeConfig struct {
|
|
// Recipient is the address of the agent being nudged.
|
|
// Examples: "gastown/crew/gus", "deacon", "gastown/witness"
|
|
Recipient string
|
|
|
|
// Sender is the agent initiating the nudge.
|
|
// Examples: "mayor", "deacon", "self" (for handoff)
|
|
Sender string
|
|
|
|
// Topic describes why the session was started.
|
|
// Examples: "cold-start", "handoff", "assigned", or a mol-id
|
|
Topic string
|
|
|
|
// MolID is an optional molecule ID being worked.
|
|
// If provided, appended to topic as "topic:mol-id"
|
|
MolID string
|
|
}
|
|
|
|
// StartupNudge sends a formatted startup message to a Claude Code session.
|
|
// The message becomes the session title in Claude Code's /resume picker,
|
|
// enabling workers to find predecessor sessions.
|
|
//
|
|
// Format: [GAS TOWN] <recipient> <- <sender> • <timestamp> • <topic[:mol-id]>
|
|
//
|
|
// Examples:
|
|
// - [GAS TOWN] gastown/crew/gus <- deacon • 2025-12-30T15:42 • assigned:gt-abc12
|
|
// - [GAS TOWN] deacon <- mayor • 2025-12-30T08:00 • cold-start
|
|
// - [GAS TOWN] gastown/witness <- self • 2025-12-30T14:00 • handoff
|
|
//
|
|
// The message content doesn't trigger GUPP - CLAUDE.md and hooks handle that.
|
|
// The metadata makes sessions identifiable in /resume.
|
|
func StartupNudge(t *tmux.Tmux, session string, cfg StartupNudgeConfig) error {
|
|
message := FormatStartupNudge(cfg)
|
|
return t.NudgeSession(session, message)
|
|
}
|
|
|
|
// FormatStartupNudge builds the formatted startup nudge message.
|
|
// Separated from StartupNudge for testing and reuse.
|
|
func FormatStartupNudge(cfg StartupNudgeConfig) string {
|
|
// Use local time in compact format
|
|
timestamp := time.Now().Format("2006-01-02T15:04")
|
|
|
|
// Build topic string - append mol-id if provided
|
|
topic := cfg.Topic
|
|
if cfg.MolID != "" && cfg.Topic != "" {
|
|
topic = fmt.Sprintf("%s:%s", cfg.Topic, cfg.MolID)
|
|
} else if cfg.MolID != "" {
|
|
topic = cfg.MolID
|
|
} else if topic == "" {
|
|
topic = "ready"
|
|
}
|
|
|
|
// Build the beacon: [GAS TOWN] recipient <- sender • timestamp • topic
|
|
beacon := fmt.Sprintf("[GAS TOWN] %s <- %s • %s • %s",
|
|
cfg.Recipient, cfg.Sender, timestamp, topic)
|
|
|
|
// For handoff and cold-start, add explicit instructions so the agent knows what to do
|
|
// even if hooks haven't loaded CLAUDE.md yet
|
|
if cfg.Topic == "handoff" || cfg.Topic == "cold-start" {
|
|
beacon += "\n\nCheck your hook and mail, then act on the hook if present:\n" +
|
|
"1. `gt hook` - shows hooked work (if any)\n" +
|
|
"2. `gt mail inbox` - check for messages\n" +
|
|
"3. If work is hooked → execute it immediately\n" +
|
|
"4. If nothing hooked → wait for instructions"
|
|
}
|
|
|
|
// For assigned, work is already on the hook - just tell them to run it
|
|
// This prevents the "helpful assistant" exploration pattern (see PRIMING.md)
|
|
if cfg.Topic == "assigned" {
|
|
beacon += "\n\nWork is on your hook. Run `gt hook` now and begin immediately."
|
|
}
|
|
|
|
// For start/restart, add fallback instructions in case SessionStart hook fails
|
|
// to inject context via gt prime. This prevents the "No recent activity" state
|
|
// where agents sit idle because they received only metadata, no instructions.
|
|
// See: gt-uoc64 (crew workers starting without proper context injection)
|
|
if cfg.Topic == "start" || cfg.Topic == "restart" {
|
|
beacon += "\n\nRun `gt prime` now for full context, then check your hook and mail."
|
|
}
|
|
|
|
return beacon
|
|
}
|