From 920e9ac196f3419a3c7e740312ef3dc52837f144 Mon Sep 17 00:00:00 2001 From: riker Date: Wed, 21 Jan 2026 16:10:36 -0800 Subject: [PATCH] fix(dog): spawn session when dispatching work to dogs Dogs are just directories with state files - they don't have sessions to receive and execute mail. This means `gt dog dispatch --plugin X` would assign work and send mail, but nothing would ever execute. This fix spawns a tmux session for the dog after dispatch, with an initial prompt that tells Claude to check mail and execute the plugin instructions. This makes dog dispatch actually work as intended. The session is named `gt--deacon-` following the pattern from showDogStatus. If session creation fails, we log a warning but don't fail the dispatch (mail was sent, work was assigned, human can manually start the session). Related: mayor guidance to have deacon execute dog work directly. This is a stepping stone - dogs now execute their own work via sessions. Co-Authored-By: Claude Opus 4.5 --- internal/cmd/dog.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/internal/cmd/dog.go b/internal/cmd/dog.go index 71459d9c..9a8174c0 100644 --- a/internal/cmd/dog.go +++ b/internal/cmd/dog.go @@ -791,6 +791,44 @@ func runDogDispatch(cmd *cobra.Command, args []string) error { return fmt.Errorf("sending plugin mail to dog: %w", err) } + // Spawn a session for the dog to execute the work. + // Without a session, the dog's mail inbox is never checked. + // See: https://github.com/steveyegge/gastown/issues/XXX (dog dispatch doesn't execute) + t := tmux.NewTmux() + townName, err := workspace.GetTownName(townRoot) + if err != nil { + townName = "gt" // fallback + } + dogSessionName := fmt.Sprintf("gt-%s-deacon-%s", townName, targetDog.Name) + + // Kill any stale session first + if has, _ := t.HasSession(dogSessionName); has { + _ = t.KillSessionWithProcesses(dogSessionName) + } + + // Build startup command with initial prompt to check mail and execute plugin + initialPrompt := fmt.Sprintf("I am dog %s. Check my mail inbox with 'gt mail inbox' and execute the plugin instructions I received.", targetDog.Name) + startCmd := config.BuildAgentStartupCommand("dog", "", townRoot, targetDog.Path, initialPrompt) + + // Create session from dog's directory + if err := t.NewSessionWithCommand(dogSessionName, targetDog.Path, startCmd); err != nil { + if !dogDispatchJSON { + fmt.Printf(" Warning: could not spawn dog session: %v\n", err) + } + // Non-fatal: mail was sent, dog is marked as working, but no session to execute + // The deacon or human can manually start the session later + } else { + // Set environment for the dog session + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "dog", + AgentName: targetDog.Name, + TownRoot: townRoot, + }) + for k, v := range envVars { + _ = t.SetEnvironment(dogSessionName, k, v) + } + } + // Success - output result if dogDispatchJSON { return json.NewEncoder(os.Stdout).Encode(result)