Redesign gt seance: ZFC-compliant literal seance with predecessors (gt-7qvd7)

Major redesign based on design review:

1. REMOVED: Claude Code internal parsing (ZFC violation)
   - Deleted internal/claude/sessions.go (parsed ~/.claude/projects/)
   - This coupled us to Claude Code's undocumented internal format

2. ADDED: Event-based session discovery
   - gt prime now emits session_start events to ~/gt/.events.jsonl
   - Events include role, session_id, topic, cwd
   - Discovery reads our own event stream (ZFC-compliant)

3. ADDED: --talk flag for actual seances
   - gt seance --talk <session-id> spawns: claude --fork-session --resume <id>
   - --fork-session creates a new session (read-only, no grave disturbance)
   - You literally talk to your predecessor: "Where did you put X?"

4. ADDED: One-shot prompt mode
   - gt seance --talk <id> -p "Where is the config?"
   - Uses claude --print for quick questions

The name "seance" is now literal - you commune with the dead (past sessions).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gastown/crew/joe
2025-12-31 00:27:59 -08:00
committed by Steve Yegge
parent 35586b57e5
commit 189db8a80e
5 changed files with 261 additions and 470 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/beads"
"github.com/steveyegge/gastown/internal/events"
"github.com/steveyegge/gastown/internal/lock"
"github.com/steveyegge/gastown/internal/style"
"github.com/steveyegge/gastown/internal/templates"
@@ -111,6 +112,9 @@ func runPrime(cmd *cobra.Command, args []string) error {
// Report agent state as running (ZFC: agents self-report state)
reportAgentState(ctx, "running")
// Emit session_start event for seance discovery
emitSessionEvent(ctx)
// Output context
if err := outputPrimeContext(ctx); err != nil {
return err
@@ -1392,3 +1396,35 @@ func checkPendingEscalations(ctx RoleContext) {
fmt.Println("Close resolved ones with `bd close <id> --reason \"resolution\"`")
fmt.Println()
}
// emitSessionEvent emits a session_start event for seance discovery.
// The event is written to ~/gt/.events.jsonl and can be queried via gt seance.
// Session ID comes from CLAUDE_SESSION_ID env var if available.
func emitSessionEvent(ctx RoleContext) {
if ctx.Role == RoleUnknown {
return
}
// Get agent identity for the actor field
actor := getAgentIdentity(ctx)
if actor == "" {
return
}
// Get session ID from environment (set by Claude Code hooks)
sessionID := os.Getenv("CLAUDE_SESSION_ID")
if sessionID == "" {
// Fall back to a generated identifier
sessionID = fmt.Sprintf("%s-%d", actor, os.Getpid())
}
// Determine topic from hook state or default
topic := ""
if ctx.Role == RoleWitness || ctx.Role == RoleRefinery || ctx.Role == RoleDeacon {
topic = "patrol"
}
// Emit the event
payload := events.SessionPayload(sessionID, actor, topic, ctx.WorkDir)
events.LogFeed(events.TypeSessionStart, actor, payload)
}