feat(rig): Add gt rig start command for multi-rig startup (gt-11z8l)

Add new 'gt rig start <rig>...' command that starts witness and refinery
on patrol for one or more rigs. Similar to 'gt rig boot' but supports
multiple rigs in a single invocation.

- Iterates over all provided rig names
- Skips already-running agents with clear output
- Reports success/failure per-rig with summary

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
furiosa
2026-01-02 12:43:55 -08:00
committed by Steve Yegge
parent 52a610b01b
commit 2c1e8e2220

View File

@@ -114,6 +114,27 @@ Examples:
RunE: runRigBoot,
}
var rigStartCmd = &cobra.Command{
Use: "start <rig>...",
Short: "Start witness and refinery on patrol for one or more rigs",
Long: `Start the witness and refinery agents on patrol for one or more rigs.
This is similar to 'gt rig boot' but supports multiple rigs at once.
For each rig, it starts:
- The witness (if not already running)
- The refinery (if not already running)
Polecats are NOT started by this command - they are spawned
on demand when work is assigned.
Examples:
gt rig start gastown
gt rig start gastown beads
gt rig start gastown beads myproject`,
Args: cobra.MinimumNArgs(1),
RunE: runRigStart,
}
var rigRebootCmd = &cobra.Command{
Use: "reboot <rig>",
Short: "Restart witness and refinery for a rig",
@@ -195,6 +216,7 @@ func init() {
rigCmd.AddCommand(rigRemoveCmd)
rigCmd.AddCommand(rigResetCmd)
rigCmd.AddCommand(rigShutdownCmd)
rigCmd.AddCommand(rigStartCmd)
rigCmd.AddCommand(rigStatusCmd)
rigAddCmd.Flags().StringVar(&rigAddPrefix, "prefix", "", "Beads issue prefix (default: derived from name)")
@@ -666,6 +688,103 @@ func runRigBoot(cmd *cobra.Command, args []string) error {
return nil
}
func runRigStart(cmd *cobra.Command, args []string) error {
// Find workspace once
townRoot, err := workspace.FindFromCwdOrError()
if err != nil {
return fmt.Errorf("not in a Gas Town workspace: %w", err)
}
// Load rigs config
rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
rigsConfig, err := config.LoadRigsConfig(rigsPath)
if err != nil {
rigsConfig = &config.RigsConfig{Rigs: make(map[string]config.RigEntry)}
}
g := git.NewGit(townRoot)
rigMgr := rig.NewManager(townRoot, rigsConfig, g)
t := tmux.NewTmux()
var successRigs []string
var failedRigs []string
for _, rigName := range args {
r, err := rigMgr.GetRig(rigName)
if err != nil {
fmt.Printf("%s Rig '%s' not found\n", style.Warning.Render("⚠"), rigName)
failedRigs = append(failedRigs, rigName)
continue
}
fmt.Printf("Starting rig %s...\n", style.Bold.Render(rigName))
var started []string
var skipped []string
hasError := false
// 1. Start the witness
witnessSession := fmt.Sprintf("gt-%s-witness", rigName)
witnessRunning, _ := t.HasSession(witnessSession)
if witnessRunning {
skipped = append(skipped, "witness")
} else {
fmt.Printf(" Starting witness...\n")
created, err := ensureWitnessSession(rigName, r)
if err != nil {
fmt.Printf(" %s Failed to start witness: %v\n", style.Warning.Render("⚠"), err)
hasError = true
} else if created {
witMgr := witness.NewManager(r)
_ = witMgr.Start()
started = append(started, "witness")
}
}
// 2. Start the refinery
refinerySession := fmt.Sprintf("gt-%s-refinery", rigName)
refineryRunning, _ := t.HasSession(refinerySession)
if refineryRunning {
skipped = append(skipped, "refinery")
} else {
fmt.Printf(" Starting refinery...\n")
refMgr := refinery.NewManager(r)
if err := refMgr.Start(false); err != nil {
fmt.Printf(" %s Failed to start refinery: %v\n", style.Warning.Render("⚠"), err)
hasError = true
} else {
started = append(started, "refinery")
}
}
// Report results for this rig
if len(started) > 0 {
fmt.Printf(" %s Started: %s\n", style.Success.Render("✓"), strings.Join(started, ", "))
}
if len(skipped) > 0 {
fmt.Printf(" %s Skipped: %s (already running)\n", style.Dim.Render("•"), strings.Join(skipped, ", "))
}
if hasError {
failedRigs = append(failedRigs, rigName)
} else {
successRigs = append(successRigs, rigName)
}
fmt.Println()
}
// Summary
if len(successRigs) > 0 {
fmt.Printf("%s Started rigs: %s\n", style.Success.Render("✓"), strings.Join(successRigs, ", "))
}
if len(failedRigs) > 0 {
fmt.Printf("%s Failed rigs: %s\n", style.Warning.Render("⚠"), strings.Join(failedRigs, ", "))
return fmt.Errorf("some rigs failed to start")
}
return nil
}
func runRigShutdown(cmd *cobra.Command, args []string) error {
rigName := args[0]