From 2343e6b0ef72853f8371119a2a18a27663261f71 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Wed, 7 Jan 2026 13:08:40 -0800 Subject: [PATCH 01/14] feat: add RoleEnvVars and improve gt role CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces config.RoleEnvVars() as the single source of truth for role identity environment variables (GT_ROLE, GT_RIG, BD_ACTOR, etc.). CLI improvements: - Fix getRoleHome paths (witness has no /rig suffix, polecat/crew do) - Make gt role env read-only (displays current role from env/cwd) - Add EnvIncomplete handling: fill missing env vars from cwd with warning - Add cwd mismatch warnings when not in role home directory - gt role home now validates --polecat requires --rig Includes comprehensive e2e tests for all role detection scenarios. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/role.go | 168 ++++-- internal/cmd/role_e2e_test.go | 1056 +++++++++++++++++++++++++++++++++ internal/config/loader.go | 40 ++ 3 files changed, 1205 insertions(+), 59 deletions(-) create mode 100644 internal/cmd/role_e2e_test.go diff --git a/internal/cmd/role.go b/internal/cmd/role.go index b744095e..70871a0f 100644 --- a/internal/cmd/role.go +++ b/internal/cmd/role.go @@ -4,9 +4,11 @@ import ( "fmt" "os" "path/filepath" + "sort" "strings" "github.com/spf13/cobra" + "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/style" "github.com/steveyegge/gastown/internal/workspace" ) @@ -21,16 +23,17 @@ const ( // This is the canonical struct for role detection - used by both GetRole() // and detectRole() functions. type RoleInfo struct { - Role Role `json:"role"` - Source string `json:"source"` // "env", "cwd", or "explicit" - Home string `json:"home"` - Rig string `json:"rig,omitempty"` - Polecat string `json:"polecat,omitempty"` - EnvRole string `json:"env_role,omitempty"` // Value of GT_ROLE if set - CwdRole Role `json:"cwd_role,omitempty"` // Role detected from cwd - Mismatch bool `json:"mismatch,omitempty"` // True if env != cwd detection - TownRoot string `json:"town_root,omitempty"` - WorkDir string `json:"work_dir,omitempty"` // Current working directory + Role Role `json:"role"` + Source string `json:"source"` // "env", "cwd", or "explicit" + Home string `json:"home"` + Rig string `json:"rig,omitempty"` + Polecat string `json:"polecat,omitempty"` + EnvRole string `json:"env_role,omitempty"` // Value of GT_ROLE if set + CwdRole Role `json:"cwd_role,omitempty"` // Role detected from cwd + Mismatch bool `json:"mismatch,omitempty"` // True if env != cwd detection + EnvIncomplete bool `json:"env_incomplete,omitempty"` // True if env was set but missing rig/polecat, filled from cwd + TownRoot string `json:"town_root,omitempty"` + WorkDir string `json:"work_dir,omitempty"` // Current working directory } var roleCmd = &cobra.Command{ @@ -86,14 +89,18 @@ var roleListCmd = &cobra.Command{ var roleEnvCmd = &cobra.Command{ Use: "env", Short: "Print export statements for current role", - Long: `Print shell export statements to set GT_ROLE and GT_ROLE_HOME. + Long: `Print shell export statements for the current role. -Usage: - eval $(gt role env) # Set role env vars in current shell`, +Role is determined from GT_ROLE environment variable or current working directory. +This is a read-only command that displays the current role's env vars. + +Examples: + eval $(gt role env) # Export current role's env vars + gt role env # View what would be exported`, RunE: runRoleEnv, } -// Flags +// Flags for role home command var ( roleRig string rolePolecat string @@ -107,7 +114,7 @@ func init() { roleCmd.AddCommand(roleListCmd) roleCmd.AddCommand(roleEnvCmd) - // Add --rig flag to home command for witness/refinery/polecat + // Add --rig and --polecat flags to home command for overrides roleHomeCmd.Flags().StringVar(&roleRig, "rig", "", "Rig name (required for rig-specific roles)") roleHomeCmd.Flags().StringVar(&rolePolecat, "polecat", "", "Polecat/crew member name") } @@ -170,6 +177,20 @@ func GetRoleWithContext(cwd, townRoot string) (RoleInfo, error) { } } + // If env is incomplete (missing rig/polecat for roles that need them), + // fill gaps from cwd detection and mark as incomplete + needsRig := parsedRole == RoleWitness || parsedRole == RoleRefinery || parsedRole == RolePolecat || parsedRole == RoleCrew + needsPolecat := parsedRole == RolePolecat || parsedRole == RoleCrew + + if needsRig && info.Rig == "" && cwdCtx.Rig != "" { + info.Rig = cwdCtx.Rig + info.EnvIncomplete = true + } + if needsPolecat && info.Polecat == "" && cwdCtx.Polecat != "" { + info.Polecat = cwdCtx.Polecat + info.EnvIncomplete = true + } + // Check for mismatch with cwd detection if cwdCtx.Role != RoleUnknown && cwdCtx.Role != parsedRole { info.Mismatch = true @@ -277,7 +298,7 @@ func getRoleHome(role Role, rig, polecat, townRoot string) string { if rig == "" { return "" } - return filepath.Join(townRoot, rig, "witness", "rig") + return filepath.Join(townRoot, rig, "witness") case RoleRefinery: if rig == "" { return "" @@ -287,12 +308,12 @@ func getRoleHome(role Role, rig, polecat, townRoot string) string { if rig == "" || polecat == "" { return "" } - return filepath.Join(townRoot, rig, "polecats", polecat) + return filepath.Join(townRoot, rig, "polecats", polecat, "rig") case RoleCrew: if rig == "" || polecat == "" { return "" } - return filepath.Join(townRoot, rig, "crew", polecat) + return filepath.Join(townRoot, rig, "crew", polecat, "rig") default: return "" } @@ -335,6 +356,11 @@ func runRoleShow(cmd *cobra.Command, args []string) error { } func runRoleHome(cmd *cobra.Command, args []string) error { + cwd, err := os.Getwd() + if err != nil { + return fmt.Errorf("getting current directory: %w", err) + } + townRoot, err := workspace.FindFromCwd() if err != nil { return fmt.Errorf("finding workspace: %w", err) @@ -343,29 +369,29 @@ func runRoleHome(cmd *cobra.Command, args []string) error { return fmt.Errorf("not in a Gas Town workspace") } - var role Role - var rig, polecat string + // Validate flag combinations: --polecat requires --rig to prevent strange merges + if rolePolecat != "" && roleRig == "" { + return fmt.Errorf("--polecat requires --rig to be specified") + } + // Start with current role detection (from env vars or cwd) + info, err := GetRole() + if err != nil { + return err + } + role := info.Role + rig := info.Rig + polecat := info.Polecat + + // Apply overrides from arguments/flags if len(args) > 0 { - // Explicit role provided - role, rig, polecat = parseRoleString(args[0]) - - // Override with flags if provided - if roleRig != "" { - rig = roleRig - } - if rolePolecat != "" { - polecat = rolePolecat - } - } else { - // Use current role - info, err := GetRole() - if err != nil { - return err - } - role = info.Role - rig = info.Rig - polecat = info.Polecat + role, _, _ = parseRoleString(args[0]) + } + if roleRig != "" { + rig = roleRig + } + if rolePolecat != "" { + polecat = rolePolecat } home := getRoleHome(role, rig, polecat, townRoot) @@ -373,6 +399,11 @@ func runRoleHome(cmd *cobra.Command, args []string) error { return fmt.Errorf("cannot determine home for role %s (rig=%q, polecat=%q)", role, rig, polecat) } + // Warn if computed home doesn't match cwd + if home != cwd && !strings.HasPrefix(cwd, home) { + fmt.Fprintf(os.Stderr, "⚠️ Warning: cwd (%s) is not within role home (%s)\n", cwd, home) + } + fmt.Println(home) return nil } @@ -440,33 +471,52 @@ func runRoleList(cmd *cobra.Command, args []string) error { } func runRoleEnv(cmd *cobra.Command, args []string) error { + cwd, err := os.Getwd() + if err != nil { + return fmt.Errorf("getting current directory: %w", err) + } + + townRoot, err := workspace.FindFromCwd() + if err != nil { + return fmt.Errorf("finding workspace: %w", err) + } + if townRoot == "" { + return fmt.Errorf("not in a Gas Town workspace") + } + + // Get current role (read-only - from env vars or cwd) info, err := GetRole() if err != nil { return err } - // Build the role string for GT_ROLE - var roleStr string - switch info.Role { - case RoleMayor: - roleStr = "mayor" - case RoleDeacon: - roleStr = "deacon" - case RoleWitness: - roleStr = fmt.Sprintf("%s/witness", info.Rig) - case RoleRefinery: - roleStr = fmt.Sprintf("%s/refinery", info.Rig) - case RolePolecat: - roleStr = fmt.Sprintf("%s/polecats/%s", info.Rig, info.Polecat) - case RoleCrew: - roleStr = fmt.Sprintf("%s/crew/%s", info.Rig, info.Polecat) - default: - roleStr = string(info.Role) + home := getRoleHome(info.Role, info.Rig, info.Polecat, townRoot) + if home == "" { + return fmt.Errorf("cannot determine home for role %s (rig=%q, polecat=%q)", info.Role, info.Rig, info.Polecat) } - fmt.Printf("export %s=%s\n", EnvGTRole, roleStr) - if info.Home != "" { - fmt.Printf("export %s=%s\n", EnvGTRoleHome, info.Home) + // Warn if env was incomplete and we filled from cwd + if info.EnvIncomplete { + fmt.Fprintf(os.Stderr, "⚠️ Warning: env vars incomplete, filled from cwd\n") + } + + // Warn if computed home doesn't match cwd + if home != cwd && !strings.HasPrefix(cwd, home) { + fmt.Fprintf(os.Stderr, "⚠️ Warning: cwd (%s) is not within role home (%s)\n", cwd, home) + } + + // Get canonical env vars from shared source of truth + envVars := config.RoleEnvVars(string(info.Role), info.Rig, info.Polecat) + envVars[EnvGTRoleHome] = home + + // Output in sorted order for consistent output + keys := make([]string, 0, len(envVars)) + for k := range envVars { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + fmt.Printf("export %s=%s\n", k, envVars[k]) } return nil diff --git a/internal/cmd/role_e2e_test.go b/internal/cmd/role_e2e_test.go new file mode 100644 index 00000000..d1e0a431 --- /dev/null +++ b/internal/cmd/role_e2e_test.go @@ -0,0 +1,1056 @@ +//go:build integration + +package cmd + +import ( + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +// cleanGTEnv returns os.Environ() with all GT_* variables removed. +// This ensures tests don't inherit stale role environment from CI or previous tests. +func cleanGTEnv() []string { + var clean []string + for _, env := range os.Environ() { + if !strings.HasPrefix(env, "GT_") { + clean = append(clean, env) + } + } + return clean +} + +// TestRoleHomeE2E validates that gt role home returns correct paths +// for all role types after a full gt install. +func TestRoleHomeE2E(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + tests := []struct { + name string + args []string + expected string + }{ + { + name: "mayor", + args: []string{"role", "home", "mayor"}, + expected: filepath.Join(hqPath, "mayor"), + }, + { + name: "deacon", + args: []string{"role", "home", "deacon"}, + expected: filepath.Join(hqPath, "deacon"), + }, + { + name: "witness", + args: []string{"role", "home", "witness", "--rig", rigName}, + expected: filepath.Join(hqPath, rigName, "witness"), + }, + { + name: "refinery", + args: []string{"role", "home", "refinery", "--rig", rigName}, + expected: filepath.Join(hqPath, rigName, "refinery", "rig"), + }, + { + name: "polecat", + args: []string{"role", "home", "polecat", "--rig", rigName, "--polecat", "Toast"}, + expected: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + }, + { + name: "crew", + args: []string{"role", "home", "crew", "--rig", rigName, "--polecat", "worker1"}, + expected: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, tt.args...) + cmd.Dir = hqPath + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + // Use Output() to only capture stdout (warnings go to stderr) + output, err := cmd.Output() + if err != nil { + t.Fatalf("gt %v failed: %v\nOutput: %s", tt.args, err, output) + } + + got := strings.TrimSpace(string(output)) + if got != tt.expected { + t.Errorf("gt %v = %q, want %q", tt.args, got, tt.expected) + } + }) + } +} + +// TestRoleHomeMissingFlags validates that gt role home fails when required flags are missing. +func TestRoleHomeMissingFlags(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + tests := []struct { + name string + args []string + }{ + { + name: "witness without --rig", + args: []string{"role", "home", "witness"}, + }, + { + name: "refinery without --rig", + args: []string{"role", "home", "refinery"}, + }, + { + name: "polecat without --rig", + args: []string{"role", "home", "polecat", "--polecat", "Toast"}, + }, + { + name: "polecat without --polecat", + args: []string{"role", "home", "polecat", "--rig", "testrig"}, + }, + { + name: "crew without --rig", + args: []string{"role", "home", "crew", "--polecat", "worker1"}, + }, + { + name: "crew without --polecat", + args: []string{"role", "home", "crew", "--rig", "testrig"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, tt.args...) + cmd.Dir = hqPath + // Use cleanGTEnv to ensure no stale GT_* vars affect the test + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err == nil { + t.Errorf("gt %v should have failed but succeeded with output: %s", tt.args, output) + } + }) + } +} + + +// TestRoleHomeCwdDetection validates gt role home without arguments detects role from cwd. +func TestRoleHomeCwdDetection(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create rig directory structure for cwd detection + dirs := []string{ + filepath.Join(hqPath, rigName, "witness"), + filepath.Join(hqPath, rigName, "refinery", "rig"), + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + expected string + }{ + { + name: "mayor from mayor dir", + cwd: filepath.Join(hqPath, "mayor"), + expected: filepath.Join(hqPath, "mayor"), + }, + { + name: "deacon from deacon dir", + cwd: filepath.Join(hqPath, "deacon"), + expected: filepath.Join(hqPath, "deacon"), + }, + { + name: "witness from witness dir", + cwd: filepath.Join(hqPath, rigName, "witness"), + expected: filepath.Join(hqPath, rigName, "witness"), + }, + { + name: "refinery from refinery/rig dir", + cwd: filepath.Join(hqPath, rigName, "refinery", "rig"), + expected: filepath.Join(hqPath, rigName, "refinery", "rig"), + }, + { + name: "polecat from polecats/Toast/rig dir", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + expected: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + }, + { + name: "crew from crew/worker1/rig dir", + cwd: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + expected: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "home") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role home failed: %v\nOutput: %s", err, output) + } + + got := strings.TrimSpace(string(output)) + if got != tt.expected { + t.Errorf("gt role home = %q, want %q", got, tt.expected) + } + }) + } +} + +// TestRoleEnvCwdDetection validates gt role env without arguments detects role from cwd. +func TestRoleEnvCwdDetection(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create rig directory structure for cwd detection + dirs := []string{ + filepath.Join(hqPath, rigName, "witness"), + filepath.Join(hqPath, rigName, "refinery", "rig"), + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + want []string + }{ + { + name: "mayor from mayor dir", + cwd: filepath.Join(hqPath, "mayor"), + want: []string{ + "export GT_ROLE=mayor", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, "mayor"), + }, + }, + { + name: "deacon from deacon dir", + cwd: filepath.Join(hqPath, "deacon"), + want: []string{ + "export GT_ROLE=deacon", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, "deacon"), + }, + }, + { + name: "witness from witness dir", + cwd: filepath.Join(hqPath, rigName, "witness"), + want: []string{ + "export GT_ROLE=witness", + "export GT_RIG=" + rigName, + "export BD_ACTOR=" + rigName + "/witness", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, rigName, "witness"), + }, + }, + { + name: "refinery from refinery/rig dir", + cwd: filepath.Join(hqPath, rigName, "refinery", "rig"), + want: []string{ + "export GT_ROLE=refinery", + "export GT_RIG=" + rigName, + "export BD_ACTOR=" + rigName + "/refinery", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, rigName, "refinery", "rig"), + }, + }, + { + name: "polecat from polecats/Toast/rig dir", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + want: []string{ + "export GT_ROLE=polecat", + "export GT_RIG=" + rigName, + "export GT_POLECAT=Toast", + "export BD_ACTOR=" + rigName + "/polecats/Toast", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + }, + }, + { + name: "crew from crew/worker1/rig dir", + cwd: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + want: []string{ + "export GT_ROLE=crew", + "export GT_RIG=" + rigName, + "export GT_CREW=worker1", + "export BD_ACTOR=" + rigName + "/crew/worker1", + "export GT_ROLE_HOME=" + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "env") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role env failed: %v\nOutput: %s", err, output) + } + + got := string(output) + for _, w := range tt.want { + if !strings.Contains(got, w) { + t.Errorf("output missing %q\ngot: %s", w, got) + } + } + }) + } +} + +// TestRoleListE2E validates gt role list shows all roles. +func TestRoleListE2E(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + cmd = exec.Command(gtBinary, "role", "list") + cmd.Dir = hqPath + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role list failed: %v\nOutput: %s", err, output) + } + + got := string(output) + + // Check header + if !strings.Contains(got, "Available roles:") { + t.Errorf("output missing 'Available roles:' header\ngot: %s", got) + } + + // Check all roles are listed + roles := []string{"mayor", "deacon", "witness", "refinery", "polecat", "crew"} + for _, role := range roles { + if !strings.Contains(got, role) { + t.Errorf("output missing role %q\ngot: %s", role, got) + } + } +} + +// TestRoleShowE2E validates gt role show displays correct role info. +func TestRoleShowE2E(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create rig directory structure for cwd detection + dirs := []string{ + filepath.Join(hqPath, rigName, "witness"), + filepath.Join(hqPath, rigName, "refinery", "rig"), + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + wantRole string + wantSource string + wantHome string + wantRig string + wantWorker string + }{ + { + name: "mayor from mayor dir", + cwd: filepath.Join(hqPath, "mayor"), + wantRole: "mayor", + wantSource: "cwd", + wantHome: filepath.Join(hqPath, "mayor"), + }, + { + name: "deacon from deacon dir", + cwd: filepath.Join(hqPath, "deacon"), + wantRole: "deacon", + wantSource: "cwd", + wantHome: filepath.Join(hqPath, "deacon"), + }, + { + name: "witness from witness dir", + cwd: filepath.Join(hqPath, rigName, "witness"), + wantRole: "witness", + wantSource: "cwd", + wantHome: filepath.Join(hqPath, rigName, "witness"), + wantRig: rigName, + }, + { + name: "polecat from polecats/Toast/rig dir", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + wantRole: "polecat", + wantSource: "cwd", + wantHome: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + wantRig: rigName, + wantWorker: "Toast", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "show") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role show failed: %v\nOutput: %s", err, output) + } + + got := string(output) + + if !strings.Contains(got, tt.wantRole) { + t.Errorf("output missing role %q\ngot: %s", tt.wantRole, got) + } + + if !strings.Contains(got, "Source: "+tt.wantSource) { + t.Errorf("output missing 'Source: %s'\ngot: %s", tt.wantSource, got) + } + + if !strings.Contains(got, "Home: "+tt.wantHome) { + t.Errorf("output missing 'Home: %s'\ngot: %s", tt.wantHome, got) + } + + if tt.wantRig != "" { + if !strings.Contains(got, "Rig: "+tt.wantRig) { + t.Errorf("output missing 'Rig: %s'\ngot: %s", tt.wantRig, got) + } + } + + if tt.wantWorker != "" { + if !strings.Contains(got, "Worker: "+tt.wantWorker) { + t.Errorf("output missing 'Worker: %s'\ngot: %s", tt.wantWorker, got) + } + } + }) + } +} + +// TestRoleShowMismatch validates gt role show displays mismatch warning. +func TestRoleShowMismatch(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + // Run from mayor dir but set GT_ROLE to deacon + cmd = exec.Command(gtBinary, "role", "show") + cmd.Dir = filepath.Join(hqPath, "mayor") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir, "GT_ROLE=deacon") + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role show failed: %v\nOutput: %s", err, output) + } + + got := string(output) + + // GT_ROLE takes precedence, so role should be deacon + if !strings.Contains(got, "deacon") { + t.Errorf("should show 'deacon' from GT_ROLE, got: %s", got) + } + + // Source should be env + if !strings.Contains(got, "Source: env") { + t.Errorf("source should be 'env', got: %s", got) + } + + // Should show mismatch warning + if !strings.Contains(got, "ROLE MISMATCH") { + t.Errorf("should show ROLE MISMATCH warning\ngot: %s", got) + } + + // Should show both the env value and cwd suggestion + if !strings.Contains(got, "GT_ROLE=deacon") { + t.Errorf("should show GT_ROLE value\ngot: %s", got) + } + + if !strings.Contains(got, "cwd suggests: mayor") { + t.Errorf("should show cwd suggestion\ngot: %s", got) + } +} + +// TestRoleDetectE2E validates gt role detect uses cwd and ignores GT_ROLE. +func TestRoleDetectE2E(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create rig directory structure for cwd detection + dirs := []string{ + filepath.Join(hqPath, rigName, "witness"), + filepath.Join(hqPath, rigName, "refinery", "rig"), + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + wantRole string + wantRig string + wantWorker string + }{ + { + name: "mayor from mayor dir", + cwd: filepath.Join(hqPath, "mayor"), + wantRole: "mayor", + }, + { + name: "deacon from deacon dir", + cwd: filepath.Join(hqPath, "deacon"), + wantRole: "deacon", + }, + { + name: "witness from witness dir", + cwd: filepath.Join(hqPath, rigName, "witness"), + wantRole: "witness", + wantRig: rigName, + }, + { + name: "refinery from refinery/rig dir", + cwd: filepath.Join(hqPath, rigName, "refinery", "rig"), + wantRole: "refinery", + wantRig: rigName, + }, + { + name: "polecat from polecats/Toast/rig dir", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + wantRole: "polecat", + wantRig: rigName, + wantWorker: "Toast", + }, + { + name: "crew from crew/worker1/rig dir", + cwd: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + wantRole: "crew", + wantRig: rigName, + wantWorker: "worker1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "detect") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role detect failed: %v\nOutput: %s", err, output) + } + + got := string(output) + + // Check role is detected + if !strings.Contains(got, tt.wantRole) { + t.Errorf("output missing role %q\ngot: %s", tt.wantRole, got) + } + + // Check "(from cwd)" marker + if !strings.Contains(got, "(from cwd)") { + t.Errorf("output missing '(from cwd)' marker\ngot: %s", got) + } + + // Check rig if expected + if tt.wantRig != "" { + if !strings.Contains(got, "Rig: "+tt.wantRig) { + t.Errorf("output missing 'Rig: %s'\ngot: %s", tt.wantRig, got) + } + } + + // Check worker if expected + if tt.wantWorker != "" { + if !strings.Contains(got, "Worker: "+tt.wantWorker) { + t.Errorf("output missing 'Worker: %s'\ngot: %s", tt.wantWorker, got) + } + } + }) + } +} + +// TestRoleDetectIgnoresGTRole validates gt role detect ignores GT_ROLE env var. +func TestRoleDetectIgnoresGTRole(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + // Run from mayor dir but set GT_ROLE to deacon + cmd = exec.Command(gtBinary, "role", "detect") + cmd.Dir = filepath.Join(hqPath, "mayor") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir, "GT_ROLE=deacon") + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role detect failed: %v\nOutput: %s", err, output) + } + + got := string(output) + + // Should detect mayor from cwd, not deacon from env + if !strings.Contains(got, "mayor") { + t.Errorf("should detect 'mayor' from cwd, got: %s", got) + } + + // Should show mismatch warning + if !strings.Contains(got, "Mismatch") { + t.Errorf("should show mismatch warning when GT_ROLE disagrees\ngot: %s", got) + } + + if !strings.Contains(got, "GT_ROLE=deacon") { + t.Errorf("should show conflicting GT_ROLE value\ngot: %s", got) + } +} + +// TestRoleDetectInvalidPaths validates detection behavior for incomplete/invalid paths. +func TestRoleDetectInvalidPaths(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create incomplete directory structures + dirs := []string{ + filepath.Join(hqPath, rigName), // rig root + filepath.Join(hqPath, rigName, "polecats"), // polecats without name + filepath.Join(hqPath, rigName, "crew"), // crew without name + filepath.Join(hqPath, rigName, "refinery"), // refinery without /rig + filepath.Join(hqPath, rigName, "witness"), // witness (valid - no /rig needed) + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + wantRole string + }{ + { + name: "rig root returns unknown", + cwd: filepath.Join(hqPath, rigName), + wantRole: "unknown", + }, + { + name: "polecats without name returns unknown", + cwd: filepath.Join(hqPath, rigName, "polecats"), + wantRole: "unknown", + }, + { + name: "crew without name returns unknown", + cwd: filepath.Join(hqPath, rigName, "crew"), + wantRole: "unknown", + }, + { + name: "refinery without /rig still detects refinery", + cwd: filepath.Join(hqPath, rigName, "refinery"), + wantRole: "refinery", + }, + { + name: "witness without /rig detects witness", + cwd: filepath.Join(hqPath, rigName, "witness"), + wantRole: "witness", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "detect") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role detect failed: %v\nOutput: %s", err, output) + } + + got := string(output) + if !strings.Contains(got, tt.wantRole) { + t.Errorf("expected role %q\ngot: %s", tt.wantRole, got) + } + }) + } +} + +// TestRoleEnvIncompleteEnvVars validates gt role env fills gaps from cwd with warning. +func TestRoleEnvIncompleteEnvVars(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create rig directory structure for cwd detection + dirs := []string{ + filepath.Join(hqPath, rigName, "witness"), + filepath.Join(hqPath, rigName, "refinery", "rig"), + filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + envVars []string + wantExport []string // Expected exports in stdout + wantStderr string // Expected warning in stderr + }{ + { + name: "GT_ROLE=witness without GT_RIG, filled from cwd", + cwd: filepath.Join(hqPath, rigName, "witness"), + envVars: []string{"GT_ROLE=witness"}, + wantExport: []string{ + "export GT_ROLE=witness", + "export GT_RIG=" + rigName, + "export BD_ACTOR=" + rigName + "/witness", + }, + wantStderr: "env vars incomplete", + }, + { + name: "GT_ROLE=refinery without GT_RIG, filled from cwd", + cwd: filepath.Join(hqPath, rigName, "refinery", "rig"), + envVars: []string{"GT_ROLE=refinery"}, + wantExport: []string{ + "export GT_ROLE=refinery", + "export GT_RIG=" + rigName, + "export BD_ACTOR=" + rigName + "/refinery", + }, + wantStderr: "env vars incomplete", + }, + { + name: "GT_ROLE=polecat without GT_RIG or GT_POLECAT, filled from cwd", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + envVars: []string{"GT_ROLE=polecat"}, + wantExport: []string{ + "export GT_ROLE=polecat", + "export GT_RIG=" + rigName, + "export GT_POLECAT=Toast", + "export BD_ACTOR=" + rigName + "/polecats/Toast", + }, + wantStderr: "env vars incomplete", + }, + { + name: "GT_ROLE=polecat with GT_RIG but no GT_POLECAT, filled from cwd", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast", "rig"), + envVars: []string{"GT_ROLE=polecat", "GT_RIG=" + rigName}, + wantExport: []string{ + "export GT_ROLE=polecat", + "export GT_RIG=" + rigName, + "export GT_POLECAT=Toast", + "export BD_ACTOR=" + rigName + "/polecats/Toast", + }, + wantStderr: "env vars incomplete", + }, + { + name: "GT_ROLE=crew without GT_RIG or GT_CREW, filled from cwd", + cwd: filepath.Join(hqPath, rigName, "crew", "worker1", "rig"), + envVars: []string{"GT_ROLE=crew"}, + wantExport: []string{ + "export GT_ROLE=crew", + "export GT_RIG=" + rigName, + "export GT_CREW=worker1", + "export BD_ACTOR=" + rigName + "/crew/worker1", + }, + wantStderr: "env vars incomplete", + }, + { + name: "Complete env vars - no warning", + cwd: filepath.Join(hqPath, rigName, "witness"), + envVars: []string{"GT_ROLE=witness", "GT_RIG=" + rigName}, + wantExport: []string{ + "export GT_ROLE=witness", + "export GT_RIG=" + rigName, + "export BD_ACTOR=" + rigName + "/witness", + }, + wantStderr: "", // No warning expected + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "env") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + cmd.Env = append(cmd.Env, tt.envVars...) + + // Use CombinedOutput to see stderr for debugging, but separate stdout/stderr + stdout, _ := cmd.Output() // Only stdout + // Re-run to get stderr + cmd2 := exec.Command(gtBinary, "role", "env") + cmd2.Dir = tt.cwd + cmd2.Env = append(cleanGTEnv(), "HOME="+tmpDir) + cmd2.Env = append(cmd2.Env, tt.envVars...) + combined, _ := cmd2.CombinedOutput() + stderr := strings.TrimPrefix(string(combined), string(stdout)) + + // Check expected exports in stdout + gotStdout := string(stdout) + for _, w := range tt.wantExport { + if !strings.Contains(gotStdout, w) { + t.Errorf("stdout missing %q\ngot: %s", w, gotStdout) + } + } + + // Check expected warning in stderr + if tt.wantStderr != "" { + if !strings.Contains(stderr, tt.wantStderr) { + t.Errorf("stderr should contain %q\ngot: %s\ncombined: %s", tt.wantStderr, stderr, combined) + } + } else { + if strings.Contains(stderr, "incomplete") { + t.Errorf("stderr should not contain 'incomplete' warning\ngot: %s", stderr) + } + } + }) + } +} + +// TestRoleEnvCwdMismatchFromIncompleteDir validates warnings when in incomplete directories. +func TestRoleEnvCwdMismatchFromIncompleteDir(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create incomplete directory structures (missing /rig) + dirs := []string{ + filepath.Join(hqPath, rigName, "refinery"), // refinery without /rig + filepath.Join(hqPath, rigName, "polecats", "Toast"), // polecat without /rig + filepath.Join(hqPath, rigName, "crew", "worker1"), // crew without /rig + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + envVars []string + wantStderr string // Expected warning about cwd mismatch + }{ + { + name: "refinery without /rig shows cwd mismatch", + cwd: filepath.Join(hqPath, rigName, "refinery"), + envVars: []string{"GT_ROLE=refinery", "GT_RIG=" + rigName}, + wantStderr: "cwd", + }, + { + name: "polecat without /rig shows cwd mismatch", + cwd: filepath.Join(hqPath, rigName, "polecats", "Toast"), + envVars: []string{"GT_ROLE=polecat", "GT_RIG=" + rigName, "GT_POLECAT=Toast"}, + wantStderr: "cwd", + }, + { + name: "crew without /rig shows cwd mismatch", + cwd: filepath.Join(hqPath, rigName, "crew", "worker1"), + envVars: []string{"GT_ROLE=crew", "GT_RIG=" + rigName, "GT_CREW=worker1"}, + wantStderr: "cwd", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "env") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + cmd.Env = append(cmd.Env, tt.envVars...) + + combined, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("gt role env failed: %v\nOutput: %s", err, combined) + } + + // Check for cwd mismatch warning + if !strings.Contains(string(combined), tt.wantStderr) { + t.Errorf("output should contain %q warning\ngot: %s", tt.wantStderr, combined) + } + }) + } +} + +// TestRoleHomeInvalidPaths validates that commands fail gracefully for incomplete paths. +func TestRoleHomeInvalidPaths(t *testing.T) { + tmpDir := t.TempDir() + hqPath := filepath.Join(tmpDir, "test-hq") + gtBinary := buildGT(t) + + cmd := exec.Command(gtBinary, "install", hqPath, "--no-beads") + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("gt install failed: %v\nOutput: %s", err, output) + } + + rigName := "testrig" + + // Create incomplete directory structures + dirs := []string{ + filepath.Join(hqPath, rigName), + filepath.Join(hqPath, rigName, "polecats"), + filepath.Join(hqPath, rigName, "crew"), + } + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatalf("mkdir %s: %v", dir, err) + } + } + + tests := []struct { + name string + cwd string + shouldErr bool + }{ + { + name: "rig root fails", + cwd: filepath.Join(hqPath, rigName), + shouldErr: true, + }, + { + name: "polecats without name fails", + cwd: filepath.Join(hqPath, rigName, "polecats"), + shouldErr: true, + }, + { + name: "crew without name fails", + cwd: filepath.Join(hqPath, rigName, "crew"), + shouldErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command(gtBinary, "role", "home") + cmd.Dir = tt.cwd + cmd.Env = append(cleanGTEnv(), "HOME="+tmpDir) + + _, err := cmd.CombinedOutput() + if tt.shouldErr && err == nil { + t.Errorf("expected error but command succeeded") + } + if !tt.shouldErr && err != nil { + t.Errorf("expected success but got error: %v", err) + } + }) + } +} + diff --git a/internal/config/loader.go b/internal/config/loader.go index 7c4e8cef..b0d93dae 100644 --- a/internal/config/loader.go +++ b/internal/config/loader.go @@ -1170,6 +1170,46 @@ func BuildStartupCommandWithAgentOverride(envVars map[string]string, rigPath, pr return cmd, nil } +// RoleEnvVars returns the canonical environment variables for a role. +// This is the single source of truth for role identity env vars. +// The role parameter should be one of: "mayor", "deacon", "witness", "refinery", "polecat", "crew". +// For rig-specific roles, rig must be provided. +// For polecat/crew, polecatOrCrew must be the polecat or crew member name. +func RoleEnvVars(role, rig, polecatOrCrew string) map[string]string { + envVars := map[string]string{ + "GT_ROLE": role, + } + + switch role { + case "mayor": + envVars["BD_ACTOR"] = "mayor" + envVars["GIT_AUTHOR_NAME"] = "mayor" + case "deacon": + envVars["BD_ACTOR"] = "deacon" + envVars["GIT_AUTHOR_NAME"] = "deacon" + case "witness": + envVars["GT_RIG"] = rig + envVars["BD_ACTOR"] = fmt.Sprintf("%s/witness", rig) + envVars["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/witness", rig) + case "refinery": + envVars["GT_RIG"] = rig + envVars["BD_ACTOR"] = fmt.Sprintf("%s/refinery", rig) + envVars["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/refinery", rig) + case "polecat": + envVars["GT_RIG"] = rig + envVars["GT_POLECAT"] = polecatOrCrew + envVars["BD_ACTOR"] = fmt.Sprintf("%s/polecats/%s", rig, polecatOrCrew) + envVars["GIT_AUTHOR_NAME"] = polecatOrCrew + case "crew": + envVars["GT_RIG"] = rig + envVars["GT_CREW"] = polecatOrCrew + envVars["BD_ACTOR"] = fmt.Sprintf("%s/crew/%s", rig, polecatOrCrew) + envVars["GIT_AUTHOR_NAME"] = polecatOrCrew + } + + return envVars +} + // BuildAgentStartupCommand is a convenience function for starting agent sessions. // It sets standard environment variables (GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME) // and builds the full startup command. From 7150ce2624bda48229a3385ae75e3858273134a6 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Wed, 7 Jan 2026 13:08:59 -0800 Subject: [PATCH 02/14] refactor: update managers to use RoleEnvVars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidates all role startup code to use the shared RoleEnvVars() function, ensuring consistent env vars across tmux SetEnvironment and Claude startup command exports. Updated: - Mayor manager - Deacon startup (daemon.go) - Witness manager - Refinery manager - Polecat startup (daemon.go) - BuildPolecatStartupCommand, BuildCrewStartupCommand helpers This ensures all agents receive the same identity env vars regardless of startup path. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/config/loader.go | 40 ++++-------------------------------- internal/daemon/daemon.go | 22 +++++++++++--------- internal/mayor/manager.go | 7 +++++-- internal/refinery/manager.go | 22 ++++++++++++-------- internal/witness/manager.go | 8 +++++--- 5 files changed, 40 insertions(+), 59 deletions(-) diff --git a/internal/config/loader.go b/internal/config/loader.go index b0d93dae..62a062e7 100644 --- a/internal/config/loader.go +++ b/internal/config/loader.go @@ -1235,55 +1235,23 @@ func BuildAgentStartupCommandWithAgentOverride(role, bdActor, rigPath, prompt, a // BuildPolecatStartupCommand builds the startup command for a polecat. // Sets GT_ROLE, GT_RIG, GT_POLECAT, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildPolecatStartupCommand(rigName, polecatName, rigPath, prompt string) string { - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - envVars := map[string]string{ - "GT_ROLE": "polecat", - "GT_RIG": rigName, - "GT_POLECAT": polecatName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": polecatName, - } - return BuildStartupCommand(envVars, rigPath, prompt) + return BuildStartupCommand(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt) } // BuildPolecatStartupCommandWithAgentOverride is like BuildPolecatStartupCommand, but uses agentOverride if non-empty. func BuildPolecatStartupCommandWithAgentOverride(rigName, polecatName, rigPath, prompt, agentOverride string) (string, error) { - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - envVars := map[string]string{ - "GT_ROLE": "polecat", - "GT_RIG": rigName, - "GT_POLECAT": polecatName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": polecatName, - } - return BuildStartupCommandWithAgentOverride(envVars, rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt, agentOverride) } // BuildCrewStartupCommand builds the startup command for a crew member. // Sets GT_ROLE, GT_RIG, GT_CREW, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildCrewStartupCommand(rigName, crewName, rigPath, prompt string) string { - bdActor := fmt.Sprintf("%s/crew/%s", rigName, crewName) - envVars := map[string]string{ - "GT_ROLE": "crew", - "GT_RIG": rigName, - "GT_CREW": crewName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": crewName, - } - return BuildStartupCommand(envVars, rigPath, prompt) + return BuildStartupCommand(RoleEnvVars("crew", rigName, crewName), rigPath, prompt) } // BuildCrewStartupCommandWithAgentOverride is like BuildCrewStartupCommand, but uses agentOverride if non-empty. func BuildCrewStartupCommandWithAgentOverride(rigName, crewName, rigPath, prompt, agentOverride string) (string, error) { - bdActor := fmt.Sprintf("%s/crew/%s", rigName, crewName) - envVars := map[string]string{ - "GT_ROLE": "crew", - "GT_RIG": rigName, - "GT_CREW": crewName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": crewName, - } - return BuildStartupCommandWithAgentOverride(envVars, rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(RoleEnvVars("crew", rigName, crewName), rigPath, prompt, agentOverride) } // ExpectedPaneCommands returns tmux pane command names that indicate the runtime is running. diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 0a9186a2..c4498241 100755 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -847,17 +847,19 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) } // Set environment variables - _ = d.tmux.SetEnvironment(sessionName, "GT_ROLE", "polecat") - _ = d.tmux.SetEnvironment(sessionName, "GT_RIG", rigName) - _ = d.tmux.SetEnvironment(sessionName, "GT_POLECAT", polecatName) - - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - _ = d.tmux.SetEnvironment(sessionName, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("polecat", rigName, polecatName) + // Add polecat-specific beads configuration beadsDir := filepath.Join(d.config.TownRoot, rigName, ".beads") - _ = d.tmux.SetEnvironment(sessionName, "BEADS_DIR", beadsDir) - _ = d.tmux.SetEnvironment(sessionName, "BEADS_NO_DAEMON", "1") - _ = d.tmux.SetEnvironment(sessionName, "BEADS_AGENT_NAME", fmt.Sprintf("%s/%s", rigName, polecatName)) + envVars["BEADS_DIR"] = beadsDir + envVars["BEADS_NO_DAEMON"] = "1" + envVars["BEADS_AGENT_NAME"] = fmt.Sprintf("%s/%s", rigName, polecatName) + + // Set all env vars in tmux session (for debugging) and they'll also be exported to Claude + for k, v := range envVars { + _ = d.tmux.SetEnvironment(sessionName, k, v) + } // Apply theme theme := tmux.AssignTheme(rigName) @@ -870,7 +872,7 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) // Launch Claude with environment exported inline // Pass rigPath so rig agent settings are honored (not town-level defaults) rigPath := filepath.Join(d.config.TownRoot, rigName) - startCmd := config.BuildPolecatStartupCommand(rigName, polecatName, rigPath, "") + startCmd := config.BuildStartupCommand(envVars, rigPath, "") if err := d.tmux.SendKeys(sessionName, startCmd); err != nil { return fmt.Errorf("sending startup command: %w", err) } diff --git a/internal/mayor/manager.go b/internal/mayor/manager.go index 6510a219..a2ec31fa 100644 --- a/internal/mayor/manager.go +++ b/internal/mayor/manager.go @@ -94,8 +94,11 @@ func (m *Manager) Start(agentOverride string) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "mayor") - _ = t.SetEnvironment(sessionID, "BD_ACTOR", "mayor") + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("mayor", "", "") + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply Mayor theming (non-fatal: theming failure doesn't affect operation) theme := tmux.MayorTheme() diff --git a/internal/refinery/manager.go b/internal/refinery/manager.go index 5eee6619..1fbe16b2 100644 --- a/internal/refinery/manager.go +++ b/internal/refinery/manager.go @@ -186,17 +186,23 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name) - _ = t.SetEnvironment(sessionID, "GT_REFINERY", "1") - _ = t.SetEnvironment(sessionID, "GT_ROLE", "refinery") - _ = t.SetEnvironment(sessionID, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("refinery", m.rig.Name, "") - // Set beads environment - refinery uses rig-level beads (non-fatal) + // Add refinery-specific flag + envVars["GT_REFINERY"] = "1" + + // Add beads environment - refinery uses rig-level beads // Use ResolveBeadsDir to handle both tracked (mayor/rig) and local beads beadsDir := beads.ResolveBeadsDir(m.rig.Path) - _ = t.SetEnvironment(sessionID, "BEADS_DIR", beadsDir) - _ = t.SetEnvironment(sessionID, "BEADS_NO_DAEMON", "1") - _ = t.SetEnvironment(sessionID, "BEADS_AGENT_NAME", fmt.Sprintf("%s/refinery", m.rig.Name)) + envVars["BEADS_DIR"] = beadsDir + envVars["BEADS_NO_DAEMON"] = "1" + envVars["BEADS_AGENT_NAME"] = envVars["BD_ACTOR"] + + // Set all env vars in tmux session (for debugging) and they'll also be exported to Claude + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply theme (non-fatal: theming failure doesn't affect operation) theme := tmux.AssignTheme(m.rig.Name) diff --git a/internal/witness/manager.go b/internal/witness/manager.go index 950fc782..c2181de9 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -164,9 +164,11 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "witness") - _ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name) - _ = t.SetEnvironment(sessionID, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("witness", m.rig.Name, "") + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply Gas Town theming (non-fatal: theming failure doesn't affect operation) theme := tmux.AssignTheme(m.rig.Name) From 1d88a73eaa81790306aedcbe35ef218aaf7afea0 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 03:28:46 -0800 Subject: [PATCH 03/14] fix: use ResolveBeadsDir for polecat BEADS_DIR Previously, polecat startup used hardcoded paths for BEADS_DIR that didn't follow redirects for repos with tracked beads. This meant polecats working in worktrees (where .beads/redirect points to the actual beads location) would use the wrong beads directory. Fixed locations: - daemon.go: polecat startup now uses ResolveBeadsDir - polecat/session_manager.go: session startup now uses ResolveBeadsDir Co-Authored-By: Claude Opus 4.5 --- internal/daemon/daemon.go | 5 +++-- internal/polecat/session_manager.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index c4498241..3b4c3489 100755 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -851,7 +851,9 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) envVars := config.RoleEnvVars("polecat", rigName, polecatName) // Add polecat-specific beads configuration - beadsDir := filepath.Join(d.config.TownRoot, rigName, ".beads") + // Use ResolveBeadsDir to follow redirects for repos with tracked beads + rigPath := filepath.Join(d.config.TownRoot, rigName) + beadsDir := beads.ResolveBeadsDir(rigPath) envVars["BEADS_DIR"] = beadsDir envVars["BEADS_NO_DAEMON"] = "1" envVars["BEADS_AGENT_NAME"] = fmt.Sprintf("%s/%s", rigName, polecatName) @@ -871,7 +873,6 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) // Launch Claude with environment exported inline // Pass rigPath so rig agent settings are honored (not town-level defaults) - rigPath := filepath.Join(d.config.TownRoot, rigName) startCmd := config.BuildStartupCommand(envVars, rigPath, "") if err := d.tmux.SendKeys(sessionName, startCmd); err != nil { return fmt.Errorf("sending startup command: %w", err) diff --git a/internal/polecat/session_manager.go b/internal/polecat/session_manager.go index 469b5d90..77d0cc99 100644 --- a/internal/polecat/session_manager.go +++ b/internal/polecat/session_manager.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" "github.com/steveyegge/gastown/internal/rig" @@ -194,8 +195,8 @@ func (m *SessionManager) Start(polecat string, opts SessionStartOptions) error { } // Set beads environment for worktree polecats (non-fatal) - townRoot := filepath.Dir(m.rig.Path) - beadsDir := filepath.Join(townRoot, ".beads") + // Use ResolveBeadsDir to follow redirects for repos with tracked beads + beadsDir := beads.ResolveBeadsDir(m.rig.Path) debugSession("SetEnvironment BEADS_DIR", m.tmux.SetEnvironment(sessionID, "BEADS_DIR", beadsDir)) debugSession("SetEnvironment BEADS_NO_DAEMON", m.tmux.SetEnvironment(sessionID, "BEADS_NO_DAEMON", "1")) debugSession("SetEnvironment BEADS_AGENT_NAME", m.tmux.SetEnvironment(sessionID, "BEADS_AGENT_NAME", fmt.Sprintf("%s/%s", m.rig.Name, polecat))) From 52b9a95f9895a0e9ea011efa03c510e433e4d434 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 03:28:47 -0800 Subject: [PATCH 04/14] feat(doctor): add env-vars check, remove redundant gtroot check Adds a new `gt doctor` check that verifies tmux session environment variables match expected values from `config.RoleEnvVars()`. - Checks all Gas Town sessions (gt-*, hq-*) - Compares actual tmux env vars against expected for each role - Reports mismatches with guidance to restart sessions - Treats no sessions as success (valid when Gas Town is down) - Skips deacon (doesn't use standard env vars) Also: - Adds `tmux.GetAllEnvironment()` to retrieve all session env vars - Removes redundant gtroot_check (env-vars check covers GT_ROOT) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/doctor.go | 2 +- internal/doctor/env_check.go | 147 +++++++++++++ internal/doctor/env_check_test.go | 313 +++++++++++++++++++++++++++ internal/doctor/gtroot_check.go | 119 ---------- internal/doctor/gtroot_check_test.go | 147 ------------- internal/tmux/tmux.go | 22 ++ 6 files changed, 483 insertions(+), 267 deletions(-) create mode 100644 internal/doctor/env_check.go create mode 100644 internal/doctor/env_check_test.go delete mode 100644 internal/doctor/gtroot_check.go delete mode 100644 internal/doctor/gtroot_check_test.go diff --git a/internal/cmd/doctor.go b/internal/cmd/doctor.go index eedeb4d6..52c99baf 100644 --- a/internal/cmd/doctor.go +++ b/internal/cmd/doctor.go @@ -133,7 +133,6 @@ func runDoctor(cmd *cobra.Command, args []string) error { d.Register(doctor.NewRoutesCheck()) d.Register(doctor.NewOrphanSessionCheck()) d.Register(doctor.NewOrphanProcessCheck()) - d.Register(doctor.NewGTRootCheck()) d.Register(doctor.NewWispGCCheck()) d.Register(doctor.NewBranchCheck()) d.Register(doctor.NewBeadsSyncOrphanCheck()) @@ -142,6 +141,7 @@ func runDoctor(cmd *cobra.Command, args []string) error { d.Register(doctor.NewLinkedPaneCheck()) d.Register(doctor.NewThemeCheck()) d.Register(doctor.NewCrashReportCheck()) + d.Register(doctor.NewEnvVarsCheck()) // Patrol system checks d.Register(doctor.NewPatrolMoleculesExistCheck()) diff --git a/internal/doctor/env_check.go b/internal/doctor/env_check.go new file mode 100644 index 00000000..dbf829b1 --- /dev/null +++ b/internal/doctor/env_check.go @@ -0,0 +1,147 @@ +package doctor + +import ( + "fmt" + "strings" + + "github.com/steveyegge/gastown/internal/config" + "github.com/steveyegge/gastown/internal/session" + "github.com/steveyegge/gastown/internal/tmux" +) + +// SessionEnvReader abstracts tmux session environment access for testing. +type SessionEnvReader interface { + ListSessions() ([]string, error) + GetAllEnvironment(session string) (map[string]string, error) +} + +// tmuxEnvReader wraps real tmux operations. +type tmuxEnvReader struct { + t *tmux.Tmux +} + +func (r *tmuxEnvReader) ListSessions() ([]string, error) { + return r.t.ListSessions() +} + +func (r *tmuxEnvReader) GetAllEnvironment(session string) (map[string]string, error) { + return r.t.GetAllEnvironment(session) +} + +// EnvVarsCheck verifies that tmux session environment variables match expected values. +type EnvVarsCheck struct { + BaseCheck + reader SessionEnvReader // nil means use real tmux +} + +// NewEnvVarsCheck creates a new env vars check. +func NewEnvVarsCheck() *EnvVarsCheck { + return &EnvVarsCheck{ + BaseCheck: BaseCheck{ + CheckName: "env-vars", + CheckDescription: "Verify tmux session environment variables match expected values", + }, + } +} + +// NewEnvVarsCheckWithReader creates a check with a custom reader (for testing). +func NewEnvVarsCheckWithReader(reader SessionEnvReader) *EnvVarsCheck { + c := NewEnvVarsCheck() + c.reader = reader + return c +} + +// Run checks environment variables for all Gas Town sessions. +func (c *EnvVarsCheck) Run(ctx *CheckContext) *CheckResult { + reader := c.reader + if reader == nil { + reader = &tmuxEnvReader{t: tmux.NewTmux()} + } + + sessions, err := reader.ListSessions() + if err != nil { + // No tmux server - treat as success (valid when Gas Town is down) + return &CheckResult{ + Name: c.Name(), + Status: StatusOK, + Message: "No tmux sessions running", + } + } + + // Filter to Gas Town sessions only (gt-* and hq-*) + var gtSessions []string + for _, sess := range sessions { + if strings.HasPrefix(sess, "gt-") || strings.HasPrefix(sess, "hq-") { + gtSessions = append(gtSessions, sess) + } + } + + if len(gtSessions) == 0 { + // No Gas Town sessions - treat as success (valid when Gas Town is down) + return &CheckResult{ + Name: c.Name(), + Status: StatusOK, + Message: "No Gas Town sessions running", + } + } + + var mismatches []string + checkedCount := 0 + + for _, sess := range gtSessions { + identity, err := session.ParseSessionName(sess) + if err != nil { + // Skip unparseable sessions + continue + } + + // Skip deacon - it doesn't use the standard env vars + if identity.Role == session.RoleDeacon { + continue + } + + // Get expected env vars based on role + expected := config.RoleEnvVars(string(identity.Role), identity.Rig, identity.Name) + + // Get actual tmux env vars + actual, err := reader.GetAllEnvironment(sess) + if err != nil { + mismatches = append(mismatches, fmt.Sprintf("%s: could not read env vars: %v", sess, err)) + continue + } + + checkedCount++ + + // Compare each expected var + for key, expectedVal := range expected { + actualVal, exists := actual[key] + if !exists { + mismatches = append(mismatches, fmt.Sprintf("%s: missing %s (expected %q)", sess, key, expectedVal)) + } else if actualVal != expectedVal { + mismatches = append(mismatches, fmt.Sprintf("%s: %s=%q (expected %q)", sess, key, actualVal, expectedVal)) + } + } + } + + if len(mismatches) == 0 { + return &CheckResult{ + Name: c.Name(), + Status: StatusOK, + Message: fmt.Sprintf("All %d session(s) have correct environment variables", checkedCount), + } + } + + // Add explanation about needing restart + details := append(mismatches, + "", + "Note: Mismatched session env vars won't affect running Claude until sessions restart.", + ) + + return &CheckResult{ + Name: c.Name(), + Status: StatusWarning, + Message: fmt.Sprintf("Found %d env var mismatch(es) across %d session(s)", len(mismatches), checkedCount), + Details: details, + FixHint: "Run 'gt shutdown && gt up' to restart sessions with correct env vars", + } +} diff --git a/internal/doctor/env_check_test.go b/internal/doctor/env_check_test.go new file mode 100644 index 00000000..df365c2b --- /dev/null +++ b/internal/doctor/env_check_test.go @@ -0,0 +1,313 @@ +package doctor + +import ( + "errors" + "testing" + + "github.com/steveyegge/gastown/internal/config" +) + +// mockEnvReader implements SessionEnvReader for testing. +type mockEnvReader struct { + sessions []string + sessionEnvs map[string]map[string]string + listErr error + envErrs map[string]error +} + +func (m *mockEnvReader) ListSessions() ([]string, error) { + if m.listErr != nil { + return nil, m.listErr + } + return m.sessions, nil +} + +func (m *mockEnvReader) GetAllEnvironment(session string) (map[string]string, error) { + if m.envErrs != nil { + if err, ok := m.envErrs[session]; ok { + return nil, err + } + } + if m.sessionEnvs != nil { + if env, ok := m.sessionEnvs[session]; ok { + return env, nil + } + } + return map[string]string{}, nil +} + +func TestEnvVarsCheck_NoSessions(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{}, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } + if result.Message != "No Gas Town sessions running" { + t.Errorf("Message = %q, want %q", result.Message, "No Gas Town sessions running") + } +} + +func TestEnvVarsCheck_ListSessionsError(t *testing.T) { + reader := &mockEnvReader{ + listErr: errors.New("tmux not running"), + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + // No tmux server is valid (Gas Town can be down) + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } + if result.Message != "No tmux sessions running" { + t.Errorf("Message = %q, want %q", result.Message, "No tmux sessions running") + } +} + +func TestEnvVarsCheck_NonGasTownSessions(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"other-session", "my-dev"}, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } + if result.Message != "No Gas Town sessions running" { + t.Errorf("Message = %q, want %q", result.Message, "No Gas Town sessions running") + } +} + +func TestEnvVarsCheck_MayorCorrect(t *testing.T) { + expected := config.RoleEnvVars("mayor", "", "") + reader := &mockEnvReader{ + sessions: []string{"hq-mayor"}, + sessionEnvs: map[string]map[string]string{ + "hq-mayor": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_MayorMissing(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"hq-mayor"}, + sessionEnvs: map[string]map[string]string{ + "hq-mayor": {}, // Missing all env vars + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + +func TestEnvVarsCheck_WitnessCorrect(t *testing.T) { + expected := config.RoleEnvVars("witness", "myrig", "") + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-witness"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-witness": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_WitnessMismatch(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-witness"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-witness": { + "GT_ROLE": "witness", + "GT_RIG": "wrongrig", // Wrong rig + }, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + +func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { + expected := config.RoleEnvVars("refinery", "myrig", "") + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-refinery"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-refinery": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_PolecatCorrect(t *testing.T) { + expected := config.RoleEnvVars("polecat", "myrig", "Toast") + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-Toast"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-Toast": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_PolecatMissing(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-Toast"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-Toast": { + "GT_ROLE": "polecat", + // Missing GT_RIG, GT_POLECAT, BD_ACTOR, GIT_AUTHOR_NAME + }, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + +func TestEnvVarsCheck_CrewCorrect(t *testing.T) { + expected := config.RoleEnvVars("crew", "myrig", "worker1") + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-crew-worker1"}, + sessionEnvs: map[string]map[string]string{ + "gt-myrig-crew-worker1": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_MultipleSessions(t *testing.T) { + mayorEnv := config.RoleEnvVars("mayor", "", "") + witnessEnv := config.RoleEnvVars("witness", "rig1", "") + polecatEnv := config.RoleEnvVars("polecat", "rig1", "Toast") + + reader := &mockEnvReader{ + sessions: []string{"hq-mayor", "gt-rig1-witness", "gt-rig1-Toast"}, + sessionEnvs: map[string]map[string]string{ + "hq-mayor": mayorEnv, + "gt-rig1-witness": witnessEnv, + "gt-rig1-Toast": polecatEnv, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } + if result.Message != "All 3 session(s) have correct environment variables" { + t.Errorf("Message = %q", result.Message) + } +} + +func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { + mayorEnv := config.RoleEnvVars("mayor", "", "") + + reader := &mockEnvReader{ + sessions: []string{"hq-mayor", "gt-rig1-witness"}, + sessionEnvs: map[string]map[string]string{ + "hq-mayor": mayorEnv, + "gt-rig1-witness": { + "GT_ROLE": "witness", + // Missing GT_RIG and other vars + }, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + +func TestEnvVarsCheck_DeaconSkipped(t *testing.T) { + // Deacon should be skipped - it doesn't use standard env vars + reader := &mockEnvReader{ + sessions: []string{"hq-deacon"}, + sessionEnvs: map[string]map[string]string{ + "hq-deacon": {}, // Empty - but should be skipped + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + // With only deacon (skipped), checkedCount=0, so should show "No Gas Town sessions" + // Actually no - the session exists but is skipped. Let me check the logic... + // The check filters to gt-* and hq-* first, then skips deacon. With deacon skipped, + // checkedCount stays 0, but gtSessions has 1 entry. + // Looking at the code, after skipping deacon, checkedCount=0 and mismatches is empty, + // so it returns OK with "All 0 session(s) have correct environment variables" + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} + +func TestEnvVarsCheck_GetEnvError(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"gt-myrig-witness"}, + envErrs: map[string]error{ + "gt-myrig-witness": errors.New("session not found"), + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + +func TestEnvVarsCheck_HyphenatedRig(t *testing.T) { + // Test rig name with hyphens: "foo-bar" + expected := config.RoleEnvVars("witness", "foo-bar", "") + reader := &mockEnvReader{ + sessions: []string{"gt-foo-bar-witness"}, + sessionEnvs: map[string]map[string]string{ + "gt-foo-bar-witness": expected, + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusOK { + t.Errorf("Status = %v, want StatusOK", result.Status) + } +} diff --git a/internal/doctor/gtroot_check.go b/internal/doctor/gtroot_check.go deleted file mode 100644 index d40859c9..00000000 --- a/internal/doctor/gtroot_check.go +++ /dev/null @@ -1,119 +0,0 @@ -package doctor - -import ( - "fmt" - "strings" - - "github.com/steveyegge/gastown/internal/tmux" -) - -// GTRootCheck verifies that tmux sessions have GT_ROOT set. -// Sessions without GT_ROOT cannot find town-level formulas. -type GTRootCheck struct { - BaseCheck - tmux TmuxEnvGetter // nil means use real tmux -} - -// TmuxEnvGetter abstracts tmux environment access for testing. -type TmuxEnvGetter interface { - ListSessions() ([]string, error) - GetEnvironment(session, key string) (string, error) -} - -// realTmux wraps real tmux operations. -type realTmux struct { - t *tmux.Tmux -} - -func (r *realTmux) ListSessions() ([]string, error) { - return r.t.ListSessions() -} - -func (r *realTmux) GetEnvironment(session, key string) (string, error) { - return r.t.GetEnvironment(session, key) -} - -// NewGTRootCheck creates a new GT_ROOT check. -func NewGTRootCheck() *GTRootCheck { - return >RootCheck{ - BaseCheck: BaseCheck{ - CheckName: "gt-root-env", - CheckDescription: "Verify sessions have GT_ROOT set for formula discovery", - }, - } -} - -// NewGTRootCheckWithTmux creates a check with a custom tmux interface (for testing). -func NewGTRootCheckWithTmux(t TmuxEnvGetter) *GTRootCheck { - c := NewGTRootCheck() - c.tmux = t - return c -} - -// Run checks GT_ROOT environment variable for all Gas Town sessions. -func (c *GTRootCheck) Run(ctx *CheckContext) *CheckResult { - t := c.tmux - if t == nil { - t = &realTmux{t: tmux.NewTmux()} - } - - sessions, err := t.ListSessions() - if err != nil { - // No tmux server - not an error, Gas Town might just be down - return &CheckResult{ - Name: c.Name(), - Status: StatusOK, - Message: "No tmux sessions running", - } - } - - // Filter to Gas Town sessions (gt-* and hq-*) - var gtSessions []string - for _, sess := range sessions { - if strings.HasPrefix(sess, "gt-") || strings.HasPrefix(sess, "hq-") { - gtSessions = append(gtSessions, sess) - } - } - - if len(gtSessions) == 0 { - return &CheckResult{ - Name: c.Name(), - Status: StatusOK, - Message: "No Gas Town sessions running", - } - } - - var missingSessions []string - var okCount int - - for _, sess := range gtSessions { - gtRoot, err := t.GetEnvironment(sess, "GT_ROOT") - if err != nil || gtRoot == "" { - missingSessions = append(missingSessions, sess) - } else { - okCount++ - } - } - - if len(missingSessions) == 0 { - return &CheckResult{ - Name: c.Name(), - Status: StatusOK, - Message: fmt.Sprintf("All %d session(s) have GT_ROOT set", okCount), - } - } - - details := make([]string, 0, len(missingSessions)+2) - for _, sess := range missingSessions { - details = append(details, fmt.Sprintf("Missing GT_ROOT: %s", sess)) - } - details = append(details, "", "Sessions without GT_ROOT cannot find town-level formulas.") - - return &CheckResult{ - Name: c.Name(), - Status: StatusWarning, - Message: fmt.Sprintf("%d session(s) missing GT_ROOT environment variable", len(missingSessions)), - Details: details, - FixHint: "Restart sessions to pick up GT_ROOT: gt shutdown && gt up", - } -} diff --git a/internal/doctor/gtroot_check_test.go b/internal/doctor/gtroot_check_test.go deleted file mode 100644 index 1bd0f867..00000000 --- a/internal/doctor/gtroot_check_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package doctor - -import ( - "testing" -) - -// mockTmuxEnv implements TmuxEnvGetter for testing. -type mockTmuxEnv struct { - sessions map[string]map[string]string // session -> env vars - listErr error - getErr error -} - -func (m *mockTmuxEnv) ListSessions() ([]string, error) { - if m.listErr != nil { - return nil, m.listErr - } - sessions := make([]string, 0, len(m.sessions)) - for s := range m.sessions { - sessions = append(sessions, s) - } - return sessions, nil -} - -func (m *mockTmuxEnv) GetEnvironment(session, key string) (string, error) { - if m.getErr != nil { - return "", m.getErr - } - if env, ok := m.sessions[session]; ok { - return env[key], nil - } - return "", nil -} - -func TestGTRootCheck_NoSessions(t *testing.T) { - mock := &mockTmuxEnv{sessions: map[string]map[string]string{}} - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusOK { - t.Errorf("expected StatusOK, got %v", result.Status) - } - if result.Message != "No Gas Town sessions running" { - t.Errorf("unexpected message: %s", result.Message) - } -} - -func TestGTRootCheck_NoGasTownSessions(t *testing.T) { - mock := &mockTmuxEnv{ - sessions: map[string]map[string]string{ - "other-session": {"SOME_VAR": "value"}, - }, - } - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusOK { - t.Errorf("expected StatusOK, got %v", result.Status) - } - if result.Message != "No Gas Town sessions running" { - t.Errorf("unexpected message: %s", result.Message) - } -} - -func TestGTRootCheck_AllSessionsHaveGTRoot(t *testing.T) { - mock := &mockTmuxEnv{ - sessions: map[string]map[string]string{ - "hq-mayor": {"GT_ROOT": "/home/user/gt", "GT_ROLE": "mayor"}, - "hq-deacon": {"GT_ROOT": "/home/user/gt", "GT_ROLE": "deacon"}, - "gt-myrig-witness": {"GT_ROOT": "/home/user/gt", "GT_ROLE": "witness"}, - "gt-myrig-refinery": {"GT_ROOT": "/home/user/gt", "GT_ROLE": "refinery"}, - }, - } - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusOK { - t.Errorf("expected StatusOK, got %v", result.Status) - } - if result.Message != "All 4 session(s) have GT_ROOT set" { - t.Errorf("unexpected message: %s", result.Message) - } -} - -func TestGTRootCheck_MissingGTRoot(t *testing.T) { - mock := &mockTmuxEnv{ - sessions: map[string]map[string]string{ - "hq-mayor": {"GT_ROOT": "/home/user/gt"}, - "gt-myrig-witness": {"GT_ROLE": "witness"}, // Missing GT_ROOT - "gt-myrig-refinery": {"GT_ROLE": "refinery"}, // Missing GT_ROOT - }, - } - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusWarning { - t.Errorf("expected StatusWarning, got %v", result.Status) - } - if result.Message != "2 session(s) missing GT_ROOT environment variable" { - t.Errorf("unexpected message: %s", result.Message) - } - if result.FixHint != "Restart sessions to pick up GT_ROOT: gt shutdown && gt up" { - t.Errorf("unexpected fix hint: %s", result.FixHint) - } -} - -func TestGTRootCheck_EmptyGTRoot(t *testing.T) { - mock := &mockTmuxEnv{ - sessions: map[string]map[string]string{ - "hq-mayor": {"GT_ROOT": ""}, // Empty GT_ROOT should be treated as missing - }, - } - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusWarning { - t.Errorf("expected StatusWarning, got %v", result.Status) - } -} - -func TestGTRootCheck_MixedPrefixes(t *testing.T) { - // Test that both gt-* and hq-* sessions are checked - mock := &mockTmuxEnv{ - sessions: map[string]map[string]string{ - "hq-mayor": {"GT_ROOT": "/home/user/gt"}, - "gt-rig-witness": {"GT_ROOT": "/home/user/gt"}, - "other-session": {}, // Should be ignored - "random": {}, // Should be ignored - }, - } - check := NewGTRootCheckWithTmux(mock) - - result := check.Run(&CheckContext{}) - - if result.Status != StatusOK { - t.Errorf("expected StatusOK, got %v", result.Status) - } - // Should only count the 2 Gas Town sessions - if result.Message != "All 2 session(s) have GT_ROOT set" { - t.Errorf("unexpected message: %s", result.Message) - } -} diff --git a/internal/tmux/tmux.go b/internal/tmux/tmux.go index 54afcdf3..f51a187f 100644 --- a/internal/tmux/tmux.go +++ b/internal/tmux/tmux.go @@ -497,6 +497,28 @@ func (t *Tmux) GetEnvironment(session, key string) (string, error) { return parts[1], nil } +// GetAllEnvironment returns all environment variables for a session. +func (t *Tmux) GetAllEnvironment(session string) (map[string]string, error) { + out, err := t.run("show-environment", "-t", session) + if err != nil { + return nil, err + } + + env := make(map[string]string) + for _, line := range strings.Split(out, "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "-") { + // Skip empty lines and unset markers (lines starting with -) + continue + } + parts := strings.SplitN(line, "=", 2) + if len(parts) == 2 { + env[parts[0]] = parts[1] + } + } + return env, nil +} + // RenameSession renames a session. func (t *Tmux) RenameSession(oldName, newName string) error { _, err := t.run("rename-session", "-t", oldName, newName) From e999ceb1c14a21ca5606e2f5a034be2fe5f7e650 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 09:20:33 -0800 Subject: [PATCH 05/14] refactor: consolidate agent env vars into config.AgentEnv Create centralized AgentEnv function as single source of truth for all agent environment variables. All agents now consistently receive: - GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME (role identity) - GT_ROOT, BEADS_DIR (workspace paths) - GT_RIG, GT_POLECAT/GT_CREW (rig-specific identity) - BEADS_AGENT_NAME, BEADS_NO_DAEMON (beads config) - CLAUDE_CONFIG_DIR (optional account selection) Remove RoleEnvVars in favor of AgentEnvSimple wrapper. Remove IncludeBeadsEnv flag - beads env vars always included. Update all manager and cmd call sites to use AgentEnv. Co-Authored-By: Claude Opus 4.5 --- internal/boot/boot.go | 13 +- internal/cmd/crew_at.go | 19 ++- internal/cmd/deacon.go | 11 +- internal/cmd/role.go | 2 +- internal/config/env.go | 204 ++++++++++++++++++++++++++++ internal/config/loader.go | 47 +------ internal/crew/manager.go | 19 ++- internal/daemon/daemon.go | 4 +- internal/daemon/lifecycle.go | 33 +++-- internal/deacon/manager.go | 12 +- internal/doctor/env_check.go | 2 +- internal/doctor/env_check_test.go | 20 +-- internal/mayor/manager.go | 9 +- internal/polecat/session_manager.go | 26 ++-- internal/refinery/manager.go | 18 +-- internal/witness/manager.go | 11 +- 16 files changed, 336 insertions(+), 114 deletions(-) create mode 100644 internal/config/env.go diff --git a/internal/boot/boot.go b/internal/boot/boot.go index 2b1a42f0..b2ce10f3 100644 --- a/internal/boot/boot.go +++ b/internal/boot/boot.go @@ -11,6 +11,7 @@ import ( "path/filepath" "time" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/tmux" ) @@ -190,9 +191,15 @@ func (b *Boot) spawnTmux() error { return fmt.Errorf("creating boot session: %w", err) } - // Set environment - _ = b.tmux.SetEnvironment(SessionName, "GT_ROLE", "boot") - _ = b.tmux.SetEnvironment(SessionName, "BD_ACTOR", "deacon-boot") + // Set environment using centralized AgentEnv for consistency + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "boot", + TownRoot: b.townRoot, + BeadsDir: beads.ResolveBeadsDir(b.townRoot), + }) + for k, v := range envVars { + _ = b.tmux.SetEnvironment(SessionName, k, v) + } // Launch Claude with environment exported inline and initial triage prompt // The "gt boot triage" prompt tells Boot to immediately start triage (GUPP principle) diff --git a/internal/cmd/crew_at.go b/internal/cmd/crew_at.go index 04d30773..f8e30f45 100644 --- a/internal/cmd/crew_at.go +++ b/internal/cmd/crew_at.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/spf13/cobra" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" "github.com/steveyegge/gastown/internal/crew" @@ -138,13 +139,17 @@ func runCrewAt(cmd *cobra.Command, args []string) error { } // Set environment (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "crew") - _ = t.SetEnvironment(sessionID, "GT_RIG", r.Name) - _ = t.SetEnvironment(sessionID, "GT_CREW", name) - - // Set runtime config dir for account selection (non-fatal) - if runtimeConfig.Session != nil && runtimeConfig.Session.ConfigDirEnv != "" && claudeConfigDir != "" { - _ = t.SetEnvironment(sessionID, runtimeConfig.Session.ConfigDirEnv, claudeConfigDir) + // Use centralized AgentEnv for consistency across all role startup paths + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "crew", + Rig: r.Name, + AgentName: name, + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(r.Path), + RuntimeConfigDir: claudeConfigDir, + }) + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) } // Apply rig-based theming (non-fatal: theming failure doesn't affect operation) diff --git a/internal/cmd/deacon.go b/internal/cmd/deacon.go index 00bfcc01..399d15a3 100644 --- a/internal/cmd/deacon.go +++ b/internal/cmd/deacon.go @@ -358,8 +358,15 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error { } // Set environment (non-fatal: session works without these) - _ = t.SetEnvironment(sessionName, "GT_ROLE", "deacon") - _ = t.SetEnvironment(sessionName, "BD_ACTOR", "deacon") + // Use centralized AgentEnv for consistency across all role startup paths + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "deacon", + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(townRoot), + }) + for k, v := range envVars { + _ = t.SetEnvironment(sessionName, k, v) + } // Apply Deacon theme (non-fatal: theming failure doesn't affect operation) // Note: ConfigureGasTownSession includes cycle bindings diff --git a/internal/cmd/role.go b/internal/cmd/role.go index 70871a0f..86249891 100644 --- a/internal/cmd/role.go +++ b/internal/cmd/role.go @@ -506,7 +506,7 @@ func runRoleEnv(cmd *cobra.Command, args []string) error { } // Get canonical env vars from shared source of truth - envVars := config.RoleEnvVars(string(info.Role), info.Rig, info.Polecat) + envVars := config.AgentEnvSimple(string(info.Role), info.Rig, info.Polecat) envVars[EnvGTRoleHome] = home // Output in sorted order for consistent output diff --git a/internal/config/env.go b/internal/config/env.go new file mode 100644 index 00000000..9fec04e8 --- /dev/null +++ b/internal/config/env.go @@ -0,0 +1,204 @@ +// Package config provides configuration loading and environment variable management. +package config + +import ( + "fmt" + "os" + "sort" + "strings" +) + +// AgentEnvConfig specifies the configuration for generating agent environment variables. +// This is the single source of truth for all agent environment configuration. +type AgentEnvConfig struct { + // Role is the agent role: mayor, deacon, witness, refinery, crew, polecat, boot + Role string + + // Rig is the rig name (empty for town-level agents like mayor/deacon) + Rig string + + // AgentName is the specific agent name (empty for singletons like witness/refinery) + // For polecats, this is the polecat name. For crew, this is the crew member name. + AgentName string + + // TownRoot is the root of the Gas Town workspace. + // Sets GT_ROOT environment variable. + TownRoot string + + // BeadsDir is the resolved BEADS_DIR path. + // Callers should use beads.ResolveBeadsDir() to compute this. + BeadsDir string + + // RuntimeConfigDir is the optional CLAUDE_CONFIG_DIR path + RuntimeConfigDir string + + // BeadsNoDaemon sets BEADS_NO_DAEMON=1 if true + // Used for polecats that should bypass the beads daemon + BeadsNoDaemon bool +} + +// AgentEnv returns all environment variables for an agent based on the config. +// This is the single source of truth for agent environment variables. +func AgentEnv(cfg AgentEnvConfig) map[string]string { + env := make(map[string]string) + + env["GT_ROLE"] = cfg.Role + + // Set role-specific variables + switch cfg.Role { + case "mayor": + env["BD_ACTOR"] = "mayor" + env["GIT_AUTHOR_NAME"] = "mayor" + + case "deacon": + env["BD_ACTOR"] = "deacon" + env["GIT_AUTHOR_NAME"] = "deacon" + + case "boot": + env["BD_ACTOR"] = "deacon-boot" + env["GIT_AUTHOR_NAME"] = "boot" + + case "witness": + env["GT_RIG"] = cfg.Rig + env["BD_ACTOR"] = fmt.Sprintf("%s/witness", cfg.Rig) + env["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/witness", cfg.Rig) + + case "refinery": + env["GT_RIG"] = cfg.Rig + env["BD_ACTOR"] = fmt.Sprintf("%s/refinery", cfg.Rig) + env["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/refinery", cfg.Rig) + + case "polecat": + env["GT_RIG"] = cfg.Rig + env["GT_POLECAT"] = cfg.AgentName + env["BD_ACTOR"] = fmt.Sprintf("%s/polecats/%s", cfg.Rig, cfg.AgentName) + env["GIT_AUTHOR_NAME"] = cfg.AgentName + + case "crew": + env["GT_RIG"] = cfg.Rig + env["GT_CREW"] = cfg.AgentName + env["BD_ACTOR"] = fmt.Sprintf("%s/crew/%s", cfg.Rig, cfg.AgentName) + env["GIT_AUTHOR_NAME"] = cfg.AgentName + } + + env["GT_ROOT"] = cfg.TownRoot + env["BEADS_DIR"] = cfg.BeadsDir + + // Set BEADS_AGENT_NAME for polecat/crew (uses same format as BD_ACTOR) + if cfg.Role == "polecat" || cfg.Role == "crew" { + env["BEADS_AGENT_NAME"] = fmt.Sprintf("%s/%s", cfg.Rig, cfg.AgentName) + } + + if cfg.BeadsNoDaemon { + env["BEADS_NO_DAEMON"] = "1" + } + + // Add optional runtime config directory + if cfg.RuntimeConfigDir != "" { + env["CLAUDE_CONFIG_DIR"] = cfg.RuntimeConfigDir + } + + return env +} + +// AgentEnvSimple is a convenience function for simple role-based env var lookup. +// Use this when you only need role, rig, and agentName without advanced options. +func AgentEnvSimple(role, rig, agentName string) map[string]string { + return AgentEnv(AgentEnvConfig{ + Role: role, + Rig: rig, + AgentName: agentName, + }) +} + +// ExportPrefix builds an export statement prefix for shell commands. +// Returns a string like "export GT_ROLE=mayor BD_ACTOR=mayor && " +// The keys are sorted for deterministic output. +func ExportPrefix(env map[string]string) string { + if len(env) == 0 { + return "" + } + + // Sort keys for deterministic output + keys := make([]string, 0, len(env)) + for k := range env { + keys = append(keys, k) + } + sort.Strings(keys) + + var parts []string + for _, k := range keys { + parts = append(parts, fmt.Sprintf("%s=%s", k, env[k])) + } + + return "export " + strings.Join(parts, " ") + " && " +} + +// BuildStartupCommandWithEnv builds a startup command with the given environment variables. +// This combines the export prefix with the agent command and optional prompt. +func BuildStartupCommandWithEnv(env map[string]string, agentCmd, prompt string) string { + prefix := ExportPrefix(env) + + if prompt != "" { + // Include prompt as argument to agent command + return fmt.Sprintf("%s%s %q", prefix, agentCmd, prompt) + } + return prefix + agentCmd +} + +// MergeEnv merges multiple environment maps, with later maps taking precedence. +func MergeEnv(maps ...map[string]string) map[string]string { + result := make(map[string]string) + for _, m := range maps { + for k, v := range m { + result[k] = v + } + } + return result +} + +// FilterEnv returns a new map with only the specified keys. +func FilterEnv(env map[string]string, keys ...string) map[string]string { + result := make(map[string]string) + for _, k := range keys { + if v, ok := env[k]; ok { + result[k] = v + } + } + return result +} + +// WithoutEnv returns a new map without the specified keys. +func WithoutEnv(env map[string]string, keys ...string) map[string]string { + result := make(map[string]string) + exclude := make(map[string]bool) + for _, k := range keys { + exclude[k] = true + } + for k, v := range env { + if !exclude[k] { + result[k] = v + } + } + return result +} + +// EnvForExecCommand returns os.Environ() with the given env vars appended. +// This is useful for setting cmd.Env on exec.Command. +func EnvForExecCommand(env map[string]string) []string { + result := os.Environ() + for k, v := range env { + result = append(result, k+"="+v) + } + return result +} + +// EnvToSlice converts an env map to a slice of "K=V" strings. +// Useful for appending to os.Environ() manually. +func EnvToSlice(env map[string]string) []string { + result := make([]string, 0, len(env)) + for k, v := range env { + result = append(result, k+"="+v) + } + return result +} diff --git a/internal/config/loader.go b/internal/config/loader.go index 62a062e7..f9fe0147 100644 --- a/internal/config/loader.go +++ b/internal/config/loader.go @@ -1170,45 +1170,6 @@ func BuildStartupCommandWithAgentOverride(envVars map[string]string, rigPath, pr return cmd, nil } -// RoleEnvVars returns the canonical environment variables for a role. -// This is the single source of truth for role identity env vars. -// The role parameter should be one of: "mayor", "deacon", "witness", "refinery", "polecat", "crew". -// For rig-specific roles, rig must be provided. -// For polecat/crew, polecatOrCrew must be the polecat or crew member name. -func RoleEnvVars(role, rig, polecatOrCrew string) map[string]string { - envVars := map[string]string{ - "GT_ROLE": role, - } - - switch role { - case "mayor": - envVars["BD_ACTOR"] = "mayor" - envVars["GIT_AUTHOR_NAME"] = "mayor" - case "deacon": - envVars["BD_ACTOR"] = "deacon" - envVars["GIT_AUTHOR_NAME"] = "deacon" - case "witness": - envVars["GT_RIG"] = rig - envVars["BD_ACTOR"] = fmt.Sprintf("%s/witness", rig) - envVars["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/witness", rig) - case "refinery": - envVars["GT_RIG"] = rig - envVars["BD_ACTOR"] = fmt.Sprintf("%s/refinery", rig) - envVars["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/refinery", rig) - case "polecat": - envVars["GT_RIG"] = rig - envVars["GT_POLECAT"] = polecatOrCrew - envVars["BD_ACTOR"] = fmt.Sprintf("%s/polecats/%s", rig, polecatOrCrew) - envVars["GIT_AUTHOR_NAME"] = polecatOrCrew - case "crew": - envVars["GT_RIG"] = rig - envVars["GT_CREW"] = polecatOrCrew - envVars["BD_ACTOR"] = fmt.Sprintf("%s/crew/%s", rig, polecatOrCrew) - envVars["GIT_AUTHOR_NAME"] = polecatOrCrew - } - - return envVars -} // BuildAgentStartupCommand is a convenience function for starting agent sessions. // It sets standard environment variables (GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME) @@ -1235,23 +1196,23 @@ func BuildAgentStartupCommandWithAgentOverride(role, bdActor, rigPath, prompt, a // BuildPolecatStartupCommand builds the startup command for a polecat. // Sets GT_ROLE, GT_RIG, GT_POLECAT, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildPolecatStartupCommand(rigName, polecatName, rigPath, prompt string) string { - return BuildStartupCommand(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt) + return BuildStartupCommand(AgentEnvSimple("polecat", rigName, polecatName), rigPath, prompt) } // BuildPolecatStartupCommandWithAgentOverride is like BuildPolecatStartupCommand, but uses agentOverride if non-empty. func BuildPolecatStartupCommandWithAgentOverride(rigName, polecatName, rigPath, prompt, agentOverride string) (string, error) { - return BuildStartupCommandWithAgentOverride(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(AgentEnvSimple("polecat", rigName, polecatName), rigPath, prompt, agentOverride) } // BuildCrewStartupCommand builds the startup command for a crew member. // Sets GT_ROLE, GT_RIG, GT_CREW, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildCrewStartupCommand(rigName, crewName, rigPath, prompt string) string { - return BuildStartupCommand(RoleEnvVars("crew", rigName, crewName), rigPath, prompt) + return BuildStartupCommand(AgentEnvSimple("crew", rigName, crewName), rigPath, prompt) } // BuildCrewStartupCommandWithAgentOverride is like BuildCrewStartupCommand, but uses agentOverride if non-empty. func BuildCrewStartupCommandWithAgentOverride(rigName, crewName, rigPath, prompt, agentOverride string) (string, error) { - return BuildStartupCommandWithAgentOverride(RoleEnvVars("crew", rigName, crewName), rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(AgentEnvSimple("crew", rigName, crewName), rigPath, prompt, agentOverride) } // ExpectedPaneCommands returns tmux pane command names that indicate the runtime is running. diff --git a/internal/crew/manager.go b/internal/crew/manager.go index 8270ec35..de97bc3f 100644 --- a/internal/crew/manager.go +++ b/internal/crew/manager.go @@ -514,13 +514,18 @@ func (m *Manager) Start(name string, opts StartOptions) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name) - _ = t.SetEnvironment(sessionID, "GT_CREW", name) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "crew") - - // Set CLAUDE_CONFIG_DIR for account selection (non-fatal) - if opts.ClaudeConfigDir != "" { - _ = t.SetEnvironment(sessionID, "CLAUDE_CONFIG_DIR", opts.ClaudeConfigDir) + // Use centralized AgentEnv for consistency across all role startup paths + townRoot := filepath.Dir(m.rig.Path) + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "crew", + Rig: m.rig.Name, + AgentName: name, + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(m.rig.Path), + RuntimeConfigDir: opts.ClaudeConfigDir, + }) + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) } // Apply rig-based theming (non-fatal: theming failure doesn't affect operation) diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 3b4c3489..cf1107b4 100755 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -847,8 +847,8 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) } // Set environment variables - // Use shared RoleEnvVars for consistency across all role startup paths - envVars := config.RoleEnvVars("polecat", rigName, polecatName) + // Use centralized AgentEnvSimple for consistency across all role startup paths + envVars := config.AgentEnvSimple("polecat", rigName, polecatName) // Add polecat-specific beads configuration // Use ResolveBeadsDir to follow redirects for repos with tracked beads diff --git a/internal/daemon/lifecycle.go b/internal/daemon/lifecycle.go index 23cff651..9b0c317f 100644 --- a/internal/daemon/lifecycle.go +++ b/internal/daemon/lifecycle.go @@ -487,18 +487,31 @@ func (d *Daemon) getStartCommand(roleConfig *beads.RoleConfig, parsed *ParsedIde } // setSessionEnvironment sets environment variables for the tmux session. -// Uses role bead config if available, falls back to hardcoded defaults. -func (d *Daemon) setSessionEnvironment(sessionName, identity string, config *beads.RoleConfig, parsed *ParsedIdentity) { - // Always set GT_ROLE - _ = d.tmux.SetEnvironment(sessionName, "GT_ROLE", identity) +// Uses centralized AgentEnv for consistency, plus role bead custom env vars if available. +func (d *Daemon) setSessionEnvironment(sessionName, identity string, roleConfig *beads.RoleConfig, parsed *ParsedIdentity) { + // Determine beads dir based on role type + var beadsPath string + if parsed.RigName != "" { + beadsPath = filepath.Join(d.config.TownRoot, parsed.RigName) + } else { + beadsPath = d.config.TownRoot + } - // BD_ACTOR uses slashes instead of dashes for path-like identity - bdActor := identityToBDActor(identity) - _ = d.tmux.SetEnvironment(sessionName, "BD_ACTOR", bdActor) + // Use centralized AgentEnv for base environment variables + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: parsed.RoleType, + Rig: parsed.RigName, + AgentName: parsed.AgentName, + TownRoot: d.config.TownRoot, + BeadsDir: beads.ResolveBeadsDir(beadsPath), + }) + for k, v := range envVars { + _ = d.tmux.SetEnvironment(sessionName, k, v) + } - // Set any custom env vars from role config - if config != nil { - for k, v := range config.EnvVars { + // Set any custom env vars from role config (bead-defined overrides) + if roleConfig != nil { + for k, v := range roleConfig.EnvVars { expanded := beads.ExpandRolePattern(v, d.config.TownRoot, parsed.RigName, parsed.AgentName, parsed.RoleType) _ = d.tmux.SetEnvironment(sessionName, k, expanded) } diff --git a/internal/deacon/manager.go b/internal/deacon/manager.go index d1d77d81..3696bb11 100644 --- a/internal/deacon/manager.go +++ b/internal/deacon/manager.go @@ -7,6 +7,7 @@ import ( "path/filepath" "time" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/claude" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" @@ -93,8 +94,15 @@ func (m *Manager) Start(agentOverride string) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "deacon") - _ = t.SetEnvironment(sessionID, "BD_ACTOR", "deacon") + // Use centralized AgentEnv for consistency across all role startup paths + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "deacon", + TownRoot: m.townRoot, + BeadsDir: beads.ResolveBeadsDir(m.townRoot), + }) + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply Deacon theming (non-fatal: theming failure doesn't affect operation) theme := tmux.DeaconTheme() diff --git a/internal/doctor/env_check.go b/internal/doctor/env_check.go index dbf829b1..6cd5d145 100644 --- a/internal/doctor/env_check.go +++ b/internal/doctor/env_check.go @@ -101,7 +101,7 @@ func (c *EnvVarsCheck) Run(ctx *CheckContext) *CheckResult { } // Get expected env vars based on role - expected := config.RoleEnvVars(string(identity.Role), identity.Rig, identity.Name) + expected := config.AgentEnvSimple(string(identity.Role), identity.Rig, identity.Name) // Get actual tmux env vars actual, err := reader.GetAllEnvironment(sess) diff --git a/internal/doctor/env_check_test.go b/internal/doctor/env_check_test.go index df365c2b..e6eb6918 100644 --- a/internal/doctor/env_check_test.go +++ b/internal/doctor/env_check_test.go @@ -83,7 +83,7 @@ func TestEnvVarsCheck_NonGasTownSessions(t *testing.T) { } func TestEnvVarsCheck_MayorCorrect(t *testing.T) { - expected := config.RoleEnvVars("mayor", "", "") + expected := config.AgentEnvSimple("mayor", "", "") reader := &mockEnvReader{ sessions: []string{"hq-mayor"}, sessionEnvs: map[string]map[string]string{ @@ -114,7 +114,7 @@ func TestEnvVarsCheck_MayorMissing(t *testing.T) { } func TestEnvVarsCheck_WitnessCorrect(t *testing.T) { - expected := config.RoleEnvVars("witness", "myrig", "") + expected := config.AgentEnvSimple("witness", "myrig", "") reader := &mockEnvReader{ sessions: []string{"gt-myrig-witness"}, sessionEnvs: map[string]map[string]string{ @@ -148,7 +148,7 @@ func TestEnvVarsCheck_WitnessMismatch(t *testing.T) { } func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { - expected := config.RoleEnvVars("refinery", "myrig", "") + expected := config.AgentEnvSimple("refinery", "myrig", "") reader := &mockEnvReader{ sessions: []string{"gt-myrig-refinery"}, sessionEnvs: map[string]map[string]string{ @@ -164,7 +164,7 @@ func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { } func TestEnvVarsCheck_PolecatCorrect(t *testing.T) { - expected := config.RoleEnvVars("polecat", "myrig", "Toast") + expected := config.AgentEnvSimple("polecat", "myrig", "Toast") reader := &mockEnvReader{ sessions: []string{"gt-myrig-Toast"}, sessionEnvs: map[string]map[string]string{ @@ -198,7 +198,7 @@ func TestEnvVarsCheck_PolecatMissing(t *testing.T) { } func TestEnvVarsCheck_CrewCorrect(t *testing.T) { - expected := config.RoleEnvVars("crew", "myrig", "worker1") + expected := config.AgentEnvSimple("crew", "myrig", "worker1") reader := &mockEnvReader{ sessions: []string{"gt-myrig-crew-worker1"}, sessionEnvs: map[string]map[string]string{ @@ -214,9 +214,9 @@ func TestEnvVarsCheck_CrewCorrect(t *testing.T) { } func TestEnvVarsCheck_MultipleSessions(t *testing.T) { - mayorEnv := config.RoleEnvVars("mayor", "", "") - witnessEnv := config.RoleEnvVars("witness", "rig1", "") - polecatEnv := config.RoleEnvVars("polecat", "rig1", "Toast") + mayorEnv := config.AgentEnvSimple("mayor", "", "") + witnessEnv := config.AgentEnvSimple("witness", "rig1", "") + polecatEnv := config.AgentEnvSimple("polecat", "rig1", "Toast") reader := &mockEnvReader{ sessions: []string{"hq-mayor", "gt-rig1-witness", "gt-rig1-Toast"}, @@ -238,7 +238,7 @@ func TestEnvVarsCheck_MultipleSessions(t *testing.T) { } func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { - mayorEnv := config.RoleEnvVars("mayor", "", "") + mayorEnv := config.AgentEnvSimple("mayor", "", "") reader := &mockEnvReader{ sessions: []string{"hq-mayor", "gt-rig1-witness"}, @@ -297,7 +297,7 @@ func TestEnvVarsCheck_GetEnvError(t *testing.T) { func TestEnvVarsCheck_HyphenatedRig(t *testing.T) { // Test rig name with hyphens: "foo-bar" - expected := config.RoleEnvVars("witness", "foo-bar", "") + expected := config.AgentEnvSimple("witness", "foo-bar", "") reader := &mockEnvReader{ sessions: []string{"gt-foo-bar-witness"}, sessionEnvs: map[string]map[string]string{ diff --git a/internal/mayor/manager.go b/internal/mayor/manager.go index a2ec31fa..896ffcab 100644 --- a/internal/mayor/manager.go +++ b/internal/mayor/manager.go @@ -7,6 +7,7 @@ import ( "path/filepath" "time" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/claude" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" @@ -94,8 +95,12 @@ func (m *Manager) Start(agentOverride string) error { } // Set environment variables (non-fatal: session works without these) - // Use shared RoleEnvVars for consistency across all role startup paths - envVars := config.RoleEnvVars("mayor", "", "") + // Use centralized AgentEnv for consistency across all role startup paths + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "mayor", + TownRoot: m.townRoot, + BeadsDir: beads.ResolveBeadsDir(m.townRoot), + }) for k, v := range envVars { _ = t.SetEnvironment(sessionID, k, v) } diff --git a/internal/polecat/session_manager.go b/internal/polecat/session_manager.go index 77d0cc99..23acc3a7 100644 --- a/internal/polecat/session_manager.go +++ b/internal/polecat/session_manager.go @@ -186,21 +186,21 @@ func (m *SessionManager) Start(polecat string, opts SessionStartOptions) error { } // Set environment (non-fatal: session works without these) - debugSession("SetEnvironment GT_RIG", m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)) - debugSession("SetEnvironment GT_POLECAT", m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)) - - // Set runtime config dir for account selection (non-fatal) - if runtimeConfig.Session != nil && runtimeConfig.Session.ConfigDirEnv != "" && opts.RuntimeConfigDir != "" { - debugSession("SetEnvironment "+runtimeConfig.Session.ConfigDirEnv, m.tmux.SetEnvironment(sessionID, runtimeConfig.Session.ConfigDirEnv, opts.RuntimeConfigDir)) + // Use centralized AgentEnv for consistency across all role startup paths + townRoot := filepath.Dir(m.rig.Path) + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "polecat", + Rig: m.rig.Name, + AgentName: polecat, + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(m.rig.Path), + RuntimeConfigDir: opts.RuntimeConfigDir, + BeadsNoDaemon: true, + }) + for k, v := range envVars { + debugSession("SetEnvironment "+k, m.tmux.SetEnvironment(sessionID, k, v)) } - // Set beads environment for worktree polecats (non-fatal) - // Use ResolveBeadsDir to follow redirects for repos with tracked beads - beadsDir := beads.ResolveBeadsDir(m.rig.Path) - debugSession("SetEnvironment BEADS_DIR", m.tmux.SetEnvironment(sessionID, "BEADS_DIR", beadsDir)) - debugSession("SetEnvironment BEADS_NO_DAEMON", m.tmux.SetEnvironment(sessionID, "BEADS_NO_DAEMON", "1")) - debugSession("SetEnvironment BEADS_AGENT_NAME", m.tmux.SetEnvironment(sessionID, "BEADS_AGENT_NAME", fmt.Sprintf("%s/%s", m.rig.Name, polecat))) - // Hook the issue to the polecat if provided via --issue flag if opts.Issue != "" { agentID := fmt.Sprintf("%s/polecats/%s", m.rig.Name, polecat) diff --git a/internal/refinery/manager.go b/internal/refinery/manager.go index 1fbe16b2..e1e02d81 100644 --- a/internal/refinery/manager.go +++ b/internal/refinery/manager.go @@ -186,19 +186,19 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - // Use shared RoleEnvVars for consistency across all role startup paths - envVars := config.RoleEnvVars("refinery", m.rig.Name, "") + // Use centralized AgentEnv for consistency across all role startup paths + townRoot := filepath.Dir(m.rig.Path) + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "refinery", + Rig: m.rig.Name, + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(m.rig.Path), + BeadsNoDaemon: true, + }) // Add refinery-specific flag envVars["GT_REFINERY"] = "1" - // Add beads environment - refinery uses rig-level beads - // Use ResolveBeadsDir to handle both tracked (mayor/rig) and local beads - beadsDir := beads.ResolveBeadsDir(m.rig.Path) - envVars["BEADS_DIR"] = beadsDir - envVars["BEADS_NO_DAEMON"] = "1" - envVars["BEADS_AGENT_NAME"] = envVars["BD_ACTOR"] - // Set all env vars in tmux session (for debugging) and they'll also be exported to Claude for k, v := range envVars { _ = t.SetEnvironment(sessionID, k, v) diff --git a/internal/witness/manager.go b/internal/witness/manager.go index c2181de9..91acd055 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -8,6 +8,7 @@ import ( "time" "github.com/steveyegge/gastown/internal/agent" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/claude" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" @@ -164,8 +165,14 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - // Use shared RoleEnvVars for consistency across all role startup paths - envVars := config.RoleEnvVars("witness", m.rig.Name, "") + // Use centralized AgentEnv for consistency across all role startup paths + townRoot := filepath.Dir(m.rig.Path) + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "witness", + Rig: m.rig.Name, + TownRoot: townRoot, + BeadsDir: beads.ResolveBeadsDir(m.rig.Path), + }) for k, v := range envVars { _ = t.SetEnvironment(sessionID, k, v) } From e9a013c0d2c2d0b4b3ad7392880cb40030c639fb Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 09:44:51 -0800 Subject: [PATCH 06/14] fix: add BEADS_NO_DAEMON to crew for isolated clone context Crew workspaces use clones with redirected beads directories, like polecat and refinery. They should bypass the bd daemon for fresh data and isolation. Co-Authored-By: Claude Opus 4.5 --- internal/cmd/crew_at.go | 1 + internal/crew/manager.go | 1 + 2 files changed, 2 insertions(+) diff --git a/internal/cmd/crew_at.go b/internal/cmd/crew_at.go index f8e30f45..245e89c5 100644 --- a/internal/cmd/crew_at.go +++ b/internal/cmd/crew_at.go @@ -147,6 +147,7 @@ func runCrewAt(cmd *cobra.Command, args []string) error { TownRoot: townRoot, BeadsDir: beads.ResolveBeadsDir(r.Path), RuntimeConfigDir: claudeConfigDir, + BeadsNoDaemon: true, }) for k, v := range envVars { _ = t.SetEnvironment(sessionID, k, v) diff --git a/internal/crew/manager.go b/internal/crew/manager.go index de97bc3f..312764a3 100644 --- a/internal/crew/manager.go +++ b/internal/crew/manager.go @@ -523,6 +523,7 @@ func (m *Manager) Start(name string, opts StartOptions) error { TownRoot: townRoot, BeadsDir: beads.ResolveBeadsDir(m.rig.Path), RuntimeConfigDir: opts.ClaudeConfigDir, + BeadsNoDaemon: true, }) for k, v := range envVars { _ = t.SetEnvironment(sessionID, k, v) From 64e14489810ed92302274b237aa8ca0150be97a0 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 09:50:29 -0800 Subject: [PATCH 07/14] test: add unit tests for config/env.go Tests for AgentEnv(), ExportPrefix(), BuildStartupCommandWithEnv(), and helper functions (MergeEnv, FilterEnv, WithoutEnv, EnvToSlice). Co-Authored-By: Claude Opus 4.5 --- internal/config/env_test.go | 271 ++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 internal/config/env_test.go diff --git a/internal/config/env_test.go b/internal/config/env_test.go new file mode 100644 index 00000000..4347d6c4 --- /dev/null +++ b/internal/config/env_test.go @@ -0,0 +1,271 @@ +package config + +import ( + "testing" +) + +func TestAgentEnv_Mayor(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "mayor", + TownRoot: "/town", + BeadsDir: "/town/.beads", + }) + + assertEnv(t, env, "GT_ROLE", "mayor") + assertEnv(t, env, "BD_ACTOR", "mayor") + assertEnv(t, env, "GIT_AUTHOR_NAME", "mayor") + assertEnv(t, env, "GT_ROOT", "/town") + assertEnv(t, env, "BEADS_DIR", "/town/.beads") + assertNotSet(t, env, "GT_RIG") + assertNotSet(t, env, "BEADS_NO_DAEMON") +} + +func TestAgentEnv_Witness(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "witness", + Rig: "myrig", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + }) + + assertEnv(t, env, "GT_ROLE", "witness") + assertEnv(t, env, "GT_RIG", "myrig") + assertEnv(t, env, "BD_ACTOR", "myrig/witness") + assertEnv(t, env, "GIT_AUTHOR_NAME", "myrig/witness") + assertEnv(t, env, "GT_ROOT", "/town") + assertEnv(t, env, "BEADS_DIR", "/town/myrig/.beads") +} + +func TestAgentEnv_Polecat(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "polecat", + Rig: "myrig", + AgentName: "Toast", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + BeadsNoDaemon: true, + }) + + assertEnv(t, env, "GT_ROLE", "polecat") + assertEnv(t, env, "GT_RIG", "myrig") + assertEnv(t, env, "GT_POLECAT", "Toast") + assertEnv(t, env, "BD_ACTOR", "myrig/polecats/Toast") + assertEnv(t, env, "GIT_AUTHOR_NAME", "Toast") + assertEnv(t, env, "BEADS_AGENT_NAME", "myrig/Toast") + assertEnv(t, env, "BEADS_NO_DAEMON", "1") +} + +func TestAgentEnv_Crew(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "crew", + Rig: "myrig", + AgentName: "emma", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + BeadsNoDaemon: true, + }) + + assertEnv(t, env, "GT_ROLE", "crew") + assertEnv(t, env, "GT_RIG", "myrig") + assertEnv(t, env, "GT_CREW", "emma") + assertEnv(t, env, "BD_ACTOR", "myrig/crew/emma") + assertEnv(t, env, "GIT_AUTHOR_NAME", "emma") + assertEnv(t, env, "BEADS_AGENT_NAME", "myrig/emma") + assertEnv(t, env, "BEADS_NO_DAEMON", "1") +} + +func TestAgentEnv_Refinery(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "refinery", + Rig: "myrig", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + BeadsNoDaemon: true, + }) + + assertEnv(t, env, "GT_ROLE", "refinery") + assertEnv(t, env, "GT_RIG", "myrig") + assertEnv(t, env, "BD_ACTOR", "myrig/refinery") + assertEnv(t, env, "GIT_AUTHOR_NAME", "myrig/refinery") + assertEnv(t, env, "BEADS_NO_DAEMON", "1") +} + +func TestAgentEnv_WithRuntimeConfigDir(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "polecat", + Rig: "myrig", + AgentName: "Toast", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + RuntimeConfigDir: "/home/user/.config/claude", + }) + + assertEnv(t, env, "CLAUDE_CONFIG_DIR", "/home/user/.config/claude") +} + +func TestAgentEnv_WithoutRuntimeConfigDir(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "polecat", + Rig: "myrig", + AgentName: "Toast", + TownRoot: "/town", + BeadsDir: "/town/myrig/.beads", + }) + + assertNotSet(t, env, "CLAUDE_CONFIG_DIR") +} + +func TestAgentEnvSimple(t *testing.T) { + env := AgentEnvSimple("polecat", "myrig", "Toast") + + assertEnv(t, env, "GT_ROLE", "polecat") + assertEnv(t, env, "GT_RIG", "myrig") + assertEnv(t, env, "GT_POLECAT", "Toast") + // Simple doesn't set TownRoot/BeadsDir + assertEnv(t, env, "GT_ROOT", "") + assertEnv(t, env, "BEADS_DIR", "") +} + +func TestExportPrefix(t *testing.T) { + tests := []struct { + name string + env map[string]string + expected string + }{ + { + name: "empty", + env: map[string]string{}, + expected: "", + }, + { + name: "single var", + env: map[string]string{"FOO": "bar"}, + expected: "export FOO=bar && ", + }, + { + name: "multiple vars sorted", + env: map[string]string{ + "ZZZ": "last", + "AAA": "first", + "MMM": "middle", + }, + expected: "export AAA=first MMM=middle ZZZ=last && ", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ExportPrefix(tt.env) + if result != tt.expected { + t.Errorf("ExportPrefix() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestBuildStartupCommandWithEnv(t *testing.T) { + tests := []struct { + name string + env map[string]string + agentCmd string + prompt string + expected string + }{ + { + name: "no env no prompt", + env: map[string]string{}, + agentCmd: "claude", + prompt: "", + expected: "claude", + }, + { + name: "env no prompt", + env: map[string]string{"GT_ROLE": "polecat"}, + agentCmd: "claude", + prompt: "", + expected: "export GT_ROLE=polecat && claude", + }, + { + name: "env with prompt", + env: map[string]string{"GT_ROLE": "polecat"}, + agentCmd: "claude", + prompt: "gt prime", + expected: `export GT_ROLE=polecat && claude "gt prime"`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := BuildStartupCommandWithEnv(tt.env, tt.agentCmd, tt.prompt) + if result != tt.expected { + t.Errorf("BuildStartupCommandWithEnv() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestMergeEnv(t *testing.T) { + a := map[string]string{"A": "1", "B": "2"} + b := map[string]string{"B": "override", "C": "3"} + + result := MergeEnv(a, b) + + assertEnv(t, result, "A", "1") + assertEnv(t, result, "B", "override") + assertEnv(t, result, "C", "3") +} + +func TestFilterEnv(t *testing.T) { + env := map[string]string{"A": "1", "B": "2", "C": "3"} + + result := FilterEnv(env, "A", "C") + + assertEnv(t, result, "A", "1") + assertNotSet(t, result, "B") + assertEnv(t, result, "C", "3") +} + +func TestWithoutEnv(t *testing.T) { + env := map[string]string{"A": "1", "B": "2", "C": "3"} + + result := WithoutEnv(env, "B") + + assertEnv(t, result, "A", "1") + assertNotSet(t, result, "B") + assertEnv(t, result, "C", "3") +} + +func TestEnvToSlice(t *testing.T) { + env := map[string]string{"A": "1", "B": "2"} + + result := EnvToSlice(env) + + if len(result) != 2 { + t.Errorf("EnvToSlice() returned %d items, want 2", len(result)) + } + + // Check both entries exist (order not guaranteed) + found := make(map[string]bool) + for _, s := range result { + found[s] = true + } + if !found["A=1"] || !found["B=2"] { + t.Errorf("EnvToSlice() = %v, want [A=1, B=2]", result) + } +} + +// Helper functions + +func assertEnv(t *testing.T, env map[string]string, key, expected string) { + t.Helper() + if got := env[key]; got != expected { + t.Errorf("env[%q] = %q, want %q", key, got, expected) + } +} + +func assertNotSet(t *testing.T, env map[string]string, key string) { + t.Helper() + if _, ok := env[key]; ok { + t.Errorf("env[%q] should not be set, but is %q", key, env[key]) + } +} From 9b4c7ac28bf13a953be702cc63a0092f957bca02 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 11:47:22 -0800 Subject: [PATCH 08/14] fix(doctor): check deacon env vars after AgentEnv refactor The env-vars doctor check was skipping deacon with a stale comment "it doesn't use standard env vars". After the AgentEnv refactor, deacon/manager.go now uses config.AgentEnv() like all other roles. - Remove the skip condition for deacon in env_check.go - Update test from TestEnvVarsCheck_DeaconSkipped to test deacon is actually checked (TestEnvVarsCheck_DeaconCorrect/DeaconMissing) Co-Authored-By: Claude Opus 4.5 --- internal/doctor/env_check.go | 5 ----- internal/doctor/env_check_test.go | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/internal/doctor/env_check.go b/internal/doctor/env_check.go index 6cd5d145..447ca690 100644 --- a/internal/doctor/env_check.go +++ b/internal/doctor/env_check.go @@ -95,11 +95,6 @@ func (c *EnvVarsCheck) Run(ctx *CheckContext) *CheckResult { continue } - // Skip deacon - it doesn't use the standard env vars - if identity.Role == session.RoleDeacon { - continue - } - // Get expected env vars based on role expected := config.AgentEnvSimple(string(identity.Role), identity.Rig, identity.Name) diff --git a/internal/doctor/env_check_test.go b/internal/doctor/env_check_test.go index e6eb6918..fc488e9b 100644 --- a/internal/doctor/env_check_test.go +++ b/internal/doctor/env_check_test.go @@ -258,28 +258,37 @@ func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { } } -func TestEnvVarsCheck_DeaconSkipped(t *testing.T) { - // Deacon should be skipped - it doesn't use standard env vars +func TestEnvVarsCheck_DeaconCorrect(t *testing.T) { + expected := config.AgentEnvSimple("deacon", "", "") reader := &mockEnvReader{ sessions: []string{"hq-deacon"}, sessionEnvs: map[string]map[string]string{ - "hq-deacon": {}, // Empty - but should be skipped + "hq-deacon": expected, }, } check := NewEnvVarsCheckWithReader(reader) result := check.Run(&CheckContext{}) - // With only deacon (skipped), checkedCount=0, so should show "No Gas Town sessions" - // Actually no - the session exists but is skipped. Let me check the logic... - // The check filters to gt-* and hq-* first, then skips deacon. With deacon skipped, - // checkedCount stays 0, but gtSessions has 1 entry. - // Looking at the code, after skipping deacon, checkedCount=0 and mismatches is empty, - // so it returns OK with "All 0 session(s) have correct environment variables" if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) } } +func TestEnvVarsCheck_DeaconMissing(t *testing.T) { + reader := &mockEnvReader{ + sessions: []string{"hq-deacon"}, + sessionEnvs: map[string]map[string]string{ + "hq-deacon": {}, // Missing all env vars + }, + } + check := NewEnvVarsCheckWithReader(reader) + result := check.Run(&CheckContext{}) + + if result.Status != StatusWarning { + t.Errorf("Status = %v, want StatusWarning", result.Status) + } +} + func TestEnvVarsCheck_GetEnvError(t *testing.T) { reader := &mockEnvReader{ sessions: []string{"gt-myrig-witness"}, From cc87fdd03da0313a94043c961106271a64d93959 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 11:47:57 -0800 Subject: [PATCH 09/14] fix(boot): use centralized AgentEnv in degraded mode spawnDegraded was manually constructing env vars, missing GT_ROOT, BEADS_DIR, and GIT_AUTHOR_NAME that spawnTmux sets via config.AgentEnv(). Now both paths use the same centralized env var generation for consistency. Co-Authored-By: Claude Opus 4.5 --- internal/boot/boot.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/boot/boot.go b/internal/boot/boot.go index b2ce10f3..5754ed06 100644 --- a/internal/boot/boot.go +++ b/internal/boot/boot.go @@ -223,11 +223,15 @@ func (b *Boot) spawnDegraded() error { // This performs the triage logic without a full Claude session cmd := exec.Command("gt", "boot", "triage", "--degraded") cmd.Dir = b.deaconDir - cmd.Env = append(os.Environ(), - "GT_ROLE=boot", - "BD_ACTOR=deacon-boot", - "GT_DEGRADED=true", - ) + + // Use centralized AgentEnv for consistency with tmux mode + envVars := config.AgentEnv(config.AgentEnvConfig{ + Role: "boot", + TownRoot: b.townRoot, + BeadsDir: beads.ResolveBeadsDir(b.townRoot), + }) + cmd.Env = config.EnvForExecCommand(envVars) + cmd.Env = append(cmd.Env, "GT_DEGRADED=true") // Run async - don't wait for completion return cmd.Start() From f1a2c569004613ad10f9e2bb17d36bc77320c86d Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 11:48:09 -0800 Subject: [PATCH 10/14] test: add unit tests for deacon and boot roles in config/env.go Complete test coverage for all roles in the centralized AgentEnv function: - TestAgentEnv_Deacon: verifies deacon env vars (GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME) - TestAgentEnv_Boot: verifies boot env vars including BD_ACTOR=deacon-boot Co-Authored-By: Claude Opus 4.5 --- internal/config/env_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 4347d6c4..06cffe84 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -90,6 +90,38 @@ func TestAgentEnv_Refinery(t *testing.T) { assertEnv(t, env, "BEADS_NO_DAEMON", "1") } +func TestAgentEnv_Deacon(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "deacon", + TownRoot: "/town", + BeadsDir: "/town/.beads", + }) + + assertEnv(t, env, "GT_ROLE", "deacon") + assertEnv(t, env, "BD_ACTOR", "deacon") + assertEnv(t, env, "GIT_AUTHOR_NAME", "deacon") + assertEnv(t, env, "GT_ROOT", "/town") + assertEnv(t, env, "BEADS_DIR", "/town/.beads") + assertNotSet(t, env, "GT_RIG") + assertNotSet(t, env, "BEADS_NO_DAEMON") +} + +func TestAgentEnv_Boot(t *testing.T) { + env := AgentEnv(AgentEnvConfig{ + Role: "boot", + TownRoot: "/town", + BeadsDir: "/town/.beads", + }) + + assertEnv(t, env, "GT_ROLE", "boot") + assertEnv(t, env, "BD_ACTOR", "deacon-boot") + assertEnv(t, env, "GIT_AUTHOR_NAME", "boot") + assertEnv(t, env, "GT_ROOT", "/town") + assertEnv(t, env, "BEADS_DIR", "/town/.beads") + assertNotSet(t, env, "GT_RIG") + assertNotSet(t, env, "BEADS_NO_DAEMON") +} + func TestAgentEnv_WithRuntimeConfigDir(t *testing.T) { env := AgentEnv(AgentEnvConfig{ Role: "polecat", From ce231a31af21ba7d4bf17f1b70c93eedd4a2ad84 Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 11:51:31 -0800 Subject: [PATCH 11/14] fix(doctor): use full AgentEnv for env-vars check The env-vars check was using AgentEnvSimple which doesn't know the actual TownRoot and BeadsDir paths. This could cause false positive mismatches when comparing expected (empty paths) vs actual (real paths). - Use config.AgentEnv with proper TownRoot and BeadsDir from CheckContext - Rig-level roles resolve beads dir from rig path - Update tests to use expectedEnv helper that generates full env vars Co-Authored-By: Claude Opus 4.5 --- internal/doctor/env_check.go | 20 +++++++- internal/doctor/env_check_test.go | 84 ++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/internal/doctor/env_check.go b/internal/doctor/env_check.go index 447ca690..c0751ea1 100644 --- a/internal/doctor/env_check.go +++ b/internal/doctor/env_check.go @@ -2,8 +2,10 @@ package doctor import ( "fmt" + "path/filepath" "strings" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/session" "github.com/steveyegge/gastown/internal/tmux" @@ -95,8 +97,22 @@ func (c *EnvVarsCheck) Run(ctx *CheckContext) *CheckResult { continue } - // Get expected env vars based on role - expected := config.AgentEnvSimple(string(identity.Role), identity.Rig, identity.Name) + // Get expected env vars based on role, emulating real call sites + // Town-level roles use TownRoot for beads, rig-level roles use rig path + var beadsDir string + if identity.Rig != "" { + rigPath := filepath.Join(ctx.TownRoot, identity.Rig) + beadsDir = beads.ResolveBeadsDir(rigPath) + } else { + beadsDir = beads.ResolveBeadsDir(ctx.TownRoot) + } + expected := config.AgentEnv(config.AgentEnvConfig{ + Role: string(identity.Role), + Rig: identity.Rig, + AgentName: identity.Name, + TownRoot: ctx.TownRoot, + BeadsDir: beadsDir, + }) // Get actual tmux env vars actual, err := reader.GetAllEnvironment(sess) diff --git a/internal/doctor/env_check_test.go b/internal/doctor/env_check_test.go index fc488e9b..f6a87a14 100644 --- a/internal/doctor/env_check_test.go +++ b/internal/doctor/env_check_test.go @@ -36,12 +36,40 @@ func (m *mockEnvReader) GetAllEnvironment(session string) (map[string]string, er return map[string]string{}, nil } +// testTownRoot is the town root used in tests. +// Tests use this fixed path so expected values match what the check generates. +const testTownRoot = "/town" + +// expectedEnv generates expected env vars matching what the check generates. +// For town-level roles (mayor, deacon), beadsDir is /town/.beads +// For rig-level roles, beadsDir is /town/rigName/.beads +func expectedEnv(role, rig, agentName string) map[string]string { + var beadsDir string + if rig != "" { + beadsDir = testTownRoot + "/" + rig + "/.beads" + } else { + beadsDir = testTownRoot + "/.beads" + } + return config.AgentEnv(config.AgentEnvConfig{ + Role: role, + Rig: rig, + AgentName: agentName, + TownRoot: testTownRoot, + BeadsDir: beadsDir, + }) +} + +// testCtx returns a CheckContext with the test town root. +func testCtx() *CheckContext { + return &CheckContext{TownRoot: testTownRoot} +} + func TestEnvVarsCheck_NoSessions(t *testing.T) { reader := &mockEnvReader{ sessions: []string{}, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -56,7 +84,7 @@ func TestEnvVarsCheck_ListSessionsError(t *testing.T) { listErr: errors.New("tmux not running"), } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) // No tmux server is valid (Gas Town can be down) if result.Status != StatusOK { @@ -72,7 +100,7 @@ func TestEnvVarsCheck_NonGasTownSessions(t *testing.T) { sessions: []string{"other-session", "my-dev"}, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -83,7 +111,7 @@ func TestEnvVarsCheck_NonGasTownSessions(t *testing.T) { } func TestEnvVarsCheck_MayorCorrect(t *testing.T) { - expected := config.AgentEnvSimple("mayor", "", "") + expected := expectedEnv("mayor", "", "") reader := &mockEnvReader{ sessions: []string{"hq-mayor"}, sessionEnvs: map[string]map[string]string{ @@ -91,7 +119,7 @@ func TestEnvVarsCheck_MayorCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -106,7 +134,7 @@ func TestEnvVarsCheck_MayorMissing(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -114,7 +142,7 @@ func TestEnvVarsCheck_MayorMissing(t *testing.T) { } func TestEnvVarsCheck_WitnessCorrect(t *testing.T) { - expected := config.AgentEnvSimple("witness", "myrig", "") + expected := expectedEnv("witness", "myrig", "") reader := &mockEnvReader{ sessions: []string{"gt-myrig-witness"}, sessionEnvs: map[string]map[string]string{ @@ -122,7 +150,7 @@ func TestEnvVarsCheck_WitnessCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -140,7 +168,7 @@ func TestEnvVarsCheck_WitnessMismatch(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -148,7 +176,7 @@ func TestEnvVarsCheck_WitnessMismatch(t *testing.T) { } func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { - expected := config.AgentEnvSimple("refinery", "myrig", "") + expected := expectedEnv("refinery", "myrig", "") reader := &mockEnvReader{ sessions: []string{"gt-myrig-refinery"}, sessionEnvs: map[string]map[string]string{ @@ -156,7 +184,7 @@ func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -164,7 +192,7 @@ func TestEnvVarsCheck_RefineryCorrect(t *testing.T) { } func TestEnvVarsCheck_PolecatCorrect(t *testing.T) { - expected := config.AgentEnvSimple("polecat", "myrig", "Toast") + expected := expectedEnv("polecat", "myrig", "Toast") reader := &mockEnvReader{ sessions: []string{"gt-myrig-Toast"}, sessionEnvs: map[string]map[string]string{ @@ -172,7 +200,7 @@ func TestEnvVarsCheck_PolecatCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -190,7 +218,7 @@ func TestEnvVarsCheck_PolecatMissing(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -198,7 +226,7 @@ func TestEnvVarsCheck_PolecatMissing(t *testing.T) { } func TestEnvVarsCheck_CrewCorrect(t *testing.T) { - expected := config.AgentEnvSimple("crew", "myrig", "worker1") + expected := expectedEnv("crew", "myrig", "worker1") reader := &mockEnvReader{ sessions: []string{"gt-myrig-crew-worker1"}, sessionEnvs: map[string]map[string]string{ @@ -206,7 +234,7 @@ func TestEnvVarsCheck_CrewCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -214,9 +242,9 @@ func TestEnvVarsCheck_CrewCorrect(t *testing.T) { } func TestEnvVarsCheck_MultipleSessions(t *testing.T) { - mayorEnv := config.AgentEnvSimple("mayor", "", "") - witnessEnv := config.AgentEnvSimple("witness", "rig1", "") - polecatEnv := config.AgentEnvSimple("polecat", "rig1", "Toast") + mayorEnv := expectedEnv("mayor", "", "") + witnessEnv := expectedEnv("witness", "rig1", "") + polecatEnv := expectedEnv("polecat", "rig1", "Toast") reader := &mockEnvReader{ sessions: []string{"hq-mayor", "gt-rig1-witness", "gt-rig1-Toast"}, @@ -227,7 +255,7 @@ func TestEnvVarsCheck_MultipleSessions(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -238,7 +266,7 @@ func TestEnvVarsCheck_MultipleSessions(t *testing.T) { } func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { - mayorEnv := config.AgentEnvSimple("mayor", "", "") + mayorEnv := expectedEnv("mayor", "", "") reader := &mockEnvReader{ sessions: []string{"hq-mayor", "gt-rig1-witness"}, @@ -251,7 +279,7 @@ func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -259,7 +287,7 @@ func TestEnvVarsCheck_MixedCorrectAndMismatch(t *testing.T) { } func TestEnvVarsCheck_DeaconCorrect(t *testing.T) { - expected := config.AgentEnvSimple("deacon", "", "") + expected := expectedEnv("deacon", "", "") reader := &mockEnvReader{ sessions: []string{"hq-deacon"}, sessionEnvs: map[string]map[string]string{ @@ -267,7 +295,7 @@ func TestEnvVarsCheck_DeaconCorrect(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) @@ -282,7 +310,7 @@ func TestEnvVarsCheck_DeaconMissing(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -297,7 +325,7 @@ func TestEnvVarsCheck_GetEnvError(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusWarning { t.Errorf("Status = %v, want StatusWarning", result.Status) @@ -306,7 +334,7 @@ func TestEnvVarsCheck_GetEnvError(t *testing.T) { func TestEnvVarsCheck_HyphenatedRig(t *testing.T) { // Test rig name with hyphens: "foo-bar" - expected := config.AgentEnvSimple("witness", "foo-bar", "") + expected := expectedEnv("witness", "foo-bar", "") reader := &mockEnvReader{ sessions: []string{"gt-foo-bar-witness"}, sessionEnvs: map[string]map[string]string{ @@ -314,7 +342,7 @@ func TestEnvVarsCheck_HyphenatedRig(t *testing.T) { }, } check := NewEnvVarsCheckWithReader(reader) - result := check.Run(&CheckContext{}) + result := check.Run(testCtx()) if result.Status != StatusOK { t.Errorf("Status = %v, want StatusOK", result.Status) From 65334320c7fef624f6b3454057defd100ae5f17c Mon Sep 17 00:00:00 2001 From: julianknutsen Date: Fri, 9 Jan 2026 12:30:41 -0800 Subject: [PATCH 12/14] docs: update environment variable documentation Update docs to reflect the centralized config.AgentEnv() function and complete environment variable coverage: reference.md: - Restructured env vars section with tables by category - Added GT_ROOT, GT_CREW, BEADS_AGENT_NAME documentation - Added "Environment by Role" quick reference table - Added doctor check documentation for env-vars validation identity.md: - Updated Environment Setup section with complete examples - Added crew environment example showing BEADS_NO_DAEMON - Mentioned centralized config.AgentEnv() function - Cross-referenced to reference.md for full details Co-Authored-By: Claude Opus 4.5 --- docs/identity.md | 33 +++++++++++++++++++++---- docs/reference.md | 61 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/docs/identity.md b/docs/identity.md index 40d6459b..455dcc03 100644 --- a/docs/identity.md +++ b/docs/identity.md @@ -88,15 +88,37 @@ All events include actor attribution: ## Environment Setup -The daemon sets these automatically when spawning agents: +Gas Town uses a centralized `config.AgentEnv()` function to set environment +variables consistently across all agent spawn paths (managers, daemon, boot). + +### Example: Polecat Environment ```bash -# Set by daemon for polecat 'toast' in rig 'gastown' -export BD_ACTOR="gastown/polecats/toast" -export GIT_AUTHOR_NAME="gastown/polecats/toast" +# Set automatically for polecat 'toast' in rig 'gastown' export GT_ROLE="polecat" export GT_RIG="gastown" export GT_POLECAT="toast" +export BD_ACTOR="gastown/polecats/toast" +export GIT_AUTHOR_NAME="gastown/polecats/toast" +export GT_ROOT="/home/user/gt" +export BEADS_DIR="/home/user/gt/gastown/.beads" +export BEADS_AGENT_NAME="gastown/toast" +export BEADS_NO_DAEMON="1" # Polecats use isolated beads context +``` + +### Example: Crew Environment + +```bash +# Set automatically for crew member 'joe' in rig 'gastown' +export GT_ROLE="crew" +export GT_RIG="gastown" +export GT_CREW="joe" +export BD_ACTOR="gastown/crew/joe" +export GIT_AUTHOR_NAME="gastown/crew/joe" +export GT_ROOT="/home/user/gt" +export BEADS_DIR="/home/user/gt/gastown/.beads" +export BEADS_AGENT_NAME="gastown/joe" +export BEADS_NO_DAEMON="1" # Crew uses isolated beads context ``` ### Manual Override @@ -108,6 +130,9 @@ export BD_ACTOR="gastown/crew/debug" bd create --title="Test issue" # Will show created_by: gastown/crew/debug ``` +See [reference.md](reference.md#environment-variables) for the complete +environment variable reference. + ## Identity Parsing The format supports programmatic parsing: diff --git a/docs/reference.md b/docs/reference.md index 6341ad9a..3c027d94 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -206,17 +206,60 @@ gt mol step done # Complete a molecule step ## Environment Variables +Gas Town sets environment variables for each agent session via `config.AgentEnv()`. +These are set in tmux session environment when agents are spawned. + +### Core Variables (All Agents) + +| Variable | Purpose | Example | +|----------|---------|---------| +| `GT_ROLE` | Agent role type | `mayor`, `witness`, `polecat`, `crew` | +| `GT_ROOT` | Town root directory | `/home/user/gt` | +| `BD_ACTOR` | Agent identity for attribution | `gastown/polecats/toast` | +| `GIT_AUTHOR_NAME` | Commit attribution (same as BD_ACTOR) | `gastown/polecats/toast` | +| `BEADS_DIR` | Beads database location | `/home/user/gt/gastown/.beads` | + +### Rig-Level Variables + +| Variable | Purpose | Roles | +|----------|---------|-------| +| `GT_RIG` | Rig name | witness, refinery, polecat, crew | +| `GT_POLECAT` | Polecat worker name | polecat only | +| `GT_CREW` | Crew worker name | crew only | +| `BEADS_AGENT_NAME` | Agent name for beads operations | polecat, crew | +| `BEADS_NO_DAEMON` | Disable beads daemon (isolated context) | polecat, crew | + +### Other Variables + | Variable | Purpose | |----------|---------| -| `BD_ACTOR` | Agent identity for attribution (see [identity.md](identity.md)) | -| `BEADS_DIR` | Point to shared beads database | -| `BEADS_NO_DAEMON` | Required for worktree polecats | -| `GIT_AUTHOR_NAME` | Set to BD_ACTOR for commit attribution | -| `GIT_AUTHOR_EMAIL` | Workspace owner email | -| `GT_TOWN_ROOT` | Override town root detection | -| `GT_ROLE` | Agent role type (mayor, polecat, etc.) | -| `GT_RIG` | Rig name for rig-level agents | -| `GT_POLECAT` | Polecat name (for polecats only) | +| `GIT_AUTHOR_EMAIL` | Workspace owner email (from git config) | +| `GT_TOWN_ROOT` | Override town root detection (manual use) | +| `CLAUDE_RUNTIME_CONFIG_DIR` | Custom Claude settings directory | + +### Environment by Role + +| Role | Key Variables | +|------|---------------| +| **Mayor** | `GT_ROLE=mayor`, `BD_ACTOR=mayor` | +| **Deacon** | `GT_ROLE=deacon`, `BD_ACTOR=deacon` | +| **Boot** | `GT_ROLE=boot`, `BD_ACTOR=deacon-boot` | +| **Witness** | `GT_ROLE=witness`, `GT_RIG=`, `BD_ACTOR=/witness` | +| **Refinery** | `GT_ROLE=refinery`, `GT_RIG=`, `BD_ACTOR=/refinery` | +| **Polecat** | `GT_ROLE=polecat`, `GT_RIG=`, `GT_POLECAT=`, `BD_ACTOR=/polecats/` | +| **Crew** | `GT_ROLE=crew`, `GT_RIG=`, `GT_CREW=`, `BD_ACTOR=/crew/` | + +### Doctor Check + +The `gt doctor` command verifies that running tmux sessions have correct +environment variables. Mismatches are reported as warnings: + +``` +⚠ env-vars: Found 3 env var mismatch(es) across 1 session(s) + hq-mayor: missing GT_ROOT (expected "/home/user/gt") +``` + +Fix by restarting sessions: `gt shutdown && gt up` ## Agent Working Directories and Settings From e6bdc639ab239d6470bfae3db810a0b9589e6775 Mon Sep 17 00:00:00 2001 From: gastown/crew/gus Date: Fri, 9 Jan 2026 21:53:05 -0800 Subject: [PATCH 13/14] chore: sync embedded formulas with source --- .../formulas/mol-deacon-patrol.formula.toml | 44 +- .../formulas/towers-of-hanoi-10.formula.toml | 6188 +++++++++++++++++ .../formulas/towers-of-hanoi-7.formula.toml | 812 +++ .../formulas/towers-of-hanoi-9.formula.toml | 3116 +++++++++ .../formulas/towers-of-hanoi.formula.toml | 105 + 5 files changed, 10222 insertions(+), 43 deletions(-) create mode 100644 internal/formula/formulas/towers-of-hanoi-10.formula.toml create mode 100644 internal/formula/formulas/towers-of-hanoi-7.formula.toml create mode 100644 internal/formula/formulas/towers-of-hanoi-9.formula.toml create mode 100644 internal/formula/formulas/towers-of-hanoi.formula.toml diff --git a/internal/formula/formulas/mol-deacon-patrol.formula.toml b/internal/formula/formulas/mol-deacon-patrol.formula.toml index b02a87ae..aca940d5 100644 --- a/internal/formula/formulas/mol-deacon-patrol.formula.toml +++ b/internal/formula/formulas/mol-deacon-patrol.formula.toml @@ -148,52 +148,10 @@ bd gate list --json After closing a gate, the Waiters field contains mail addresses to notify. Send a brief notification to each waiter that the gate has cleared.""" -[[steps]] -id = "github-gate-check" -title = "Check GitHub CI gates" -needs = ["inbox-check"] -description = """ -Discover and evaluate GitHub CI gates. - -GitHub gates (await_type: gh:run, gh:pr) require checking external CI status. -This step discovers new gates from GitHub activity and evaluates pending ones. - -**Step 1: Discover new GitHub gates** -```bash -bd gate discover -``` - -This scans for GitHub CI gates that should be created based on: -- Active PRs with required CI checks -- Workflow runs that molecules are waiting on - -**Step 2: Evaluate pending GitHub gates** -```bash -bd gate check --type=gh -``` - -For each GitHub gate, this checks: -- gh:run gates: Has the workflow run completed? Did it succeed? -- gh:pr gates: Has the PR been merged/closed? - -Gates that pass their condition are automatically closed. - -**Step 3: Report closures** -For any gates that were just closed, log the result: -```bash -# Gate closed: GitHub CI passed -# Gate closed: PR merged -``` - -**If no GitHub gates exist:** -Skip - nothing to check. - -**Exit criteria:** All GitHub gates evaluated, passing gates closed.""" - [[steps]] id = "dispatch-gated-molecules" title = "Dispatch molecules with resolved gates" -needs = ["gate-evaluation", "github-gate-check"] +needs = ["gate-evaluation"] description = """ Find molecules blocked on gates that have now closed and dispatch them. diff --git a/internal/formula/formulas/towers-of-hanoi-10.formula.toml b/internal/formula/formulas/towers-of-hanoi-10.formula.toml new file mode 100644 index 00000000..056e1070 --- /dev/null +++ b/internal/formula/formulas/towers-of-hanoi-10.formula.toml @@ -0,0 +1,6188 @@ +description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi (10 disks, 1023 moves) + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi-10" +version = 1 + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All 10 disks stacked on peg A. Largest on bottom." + + +[[steps]] +id = "move-1" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 1/1023)" +needs = ["setup"] + +[[steps]] +id = "move-2" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 2/1023)" +needs = ["move-1"] + +[[steps]] +id = "move-3" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 3/1023)" +needs = ["move-2"] + +[[steps]] +id = "move-4" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 4/1023)" +needs = ["move-3"] + +[[steps]] +id = "move-5" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 5/1023)" +needs = ["move-4"] + +[[steps]] +id = "move-6" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 6/1023)" +needs = ["move-5"] + +[[steps]] +id = "move-7" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 7/1023)" +needs = ["move-6"] + +[[steps]] +id = "move-8" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 8/1023)" +needs = ["move-7"] + +[[steps]] +id = "move-9" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 9/1023)" +needs = ["move-8"] + +[[steps]] +id = "move-10" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 10/1023)" +needs = ["move-9"] + +[[steps]] +id = "move-11" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 11/1023)" +needs = ["move-10"] + +[[steps]] +id = "move-12" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 12/1023)" +needs = ["move-11"] + +[[steps]] +id = "move-13" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 13/1023)" +needs = ["move-12"] + +[[steps]] +id = "move-14" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 14/1023)" +needs = ["move-13"] + +[[steps]] +id = "move-15" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 15/1023)" +needs = ["move-14"] + +[[steps]] +id = "move-16" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 16/1023)" +needs = ["move-15"] + +[[steps]] +id = "move-17" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 17/1023)" +needs = ["move-16"] + +[[steps]] +id = "move-18" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 18/1023)" +needs = ["move-17"] + +[[steps]] +id = "move-19" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 19/1023)" +needs = ["move-18"] + +[[steps]] +id = "move-20" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 20/1023)" +needs = ["move-19"] + +[[steps]] +id = "move-21" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 21/1023)" +needs = ["move-20"] + +[[steps]] +id = "move-22" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 22/1023)" +needs = ["move-21"] + +[[steps]] +id = "move-23" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 23/1023)" +needs = ["move-22"] + +[[steps]] +id = "move-24" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 24/1023)" +needs = ["move-23"] + +[[steps]] +id = "move-25" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 25/1023)" +needs = ["move-24"] + +[[steps]] +id = "move-26" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 26/1023)" +needs = ["move-25"] + +[[steps]] +id = "move-27" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 27/1023)" +needs = ["move-26"] + +[[steps]] +id = "move-28" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 28/1023)" +needs = ["move-27"] + +[[steps]] +id = "move-29" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 29/1023)" +needs = ["move-28"] + +[[steps]] +id = "move-30" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 30/1023)" +needs = ["move-29"] + +[[steps]] +id = "move-31" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 31/1023)" +needs = ["move-30"] + +[[steps]] +id = "move-32" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 32/1023)" +needs = ["move-31"] + +[[steps]] +id = "move-33" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 33/1023)" +needs = ["move-32"] + +[[steps]] +id = "move-34" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 34/1023)" +needs = ["move-33"] + +[[steps]] +id = "move-35" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 35/1023)" +needs = ["move-34"] + +[[steps]] +id = "move-36" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 36/1023)" +needs = ["move-35"] + +[[steps]] +id = "move-37" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 37/1023)" +needs = ["move-36"] + +[[steps]] +id = "move-38" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 38/1023)" +needs = ["move-37"] + +[[steps]] +id = "move-39" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 39/1023)" +needs = ["move-38"] + +[[steps]] +id = "move-40" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 40/1023)" +needs = ["move-39"] + +[[steps]] +id = "move-41" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 41/1023)" +needs = ["move-40"] + +[[steps]] +id = "move-42" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 42/1023)" +needs = ["move-41"] + +[[steps]] +id = "move-43" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 43/1023)" +needs = ["move-42"] + +[[steps]] +id = "move-44" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 44/1023)" +needs = ["move-43"] + +[[steps]] +id = "move-45" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 45/1023)" +needs = ["move-44"] + +[[steps]] +id = "move-46" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 46/1023)" +needs = ["move-45"] + +[[steps]] +id = "move-47" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 47/1023)" +needs = ["move-46"] + +[[steps]] +id = "move-48" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 48/1023)" +needs = ["move-47"] + +[[steps]] +id = "move-49" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 49/1023)" +needs = ["move-48"] + +[[steps]] +id = "move-50" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 50/1023)" +needs = ["move-49"] + +[[steps]] +id = "move-51" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 51/1023)" +needs = ["move-50"] + +[[steps]] +id = "move-52" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 52/1023)" +needs = ["move-51"] + +[[steps]] +id = "move-53" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 53/1023)" +needs = ["move-52"] + +[[steps]] +id = "move-54" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 54/1023)" +needs = ["move-53"] + +[[steps]] +id = "move-55" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 55/1023)" +needs = ["move-54"] + +[[steps]] +id = "move-56" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 56/1023)" +needs = ["move-55"] + +[[steps]] +id = "move-57" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 57/1023)" +needs = ["move-56"] + +[[steps]] +id = "move-58" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 58/1023)" +needs = ["move-57"] + +[[steps]] +id = "move-59" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 59/1023)" +needs = ["move-58"] + +[[steps]] +id = "move-60" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 60/1023)" +needs = ["move-59"] + +[[steps]] +id = "move-61" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 61/1023)" +needs = ["move-60"] + +[[steps]] +id = "move-62" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 62/1023)" +needs = ["move-61"] + +[[steps]] +id = "move-63" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 63/1023)" +needs = ["move-62"] + +[[steps]] +id = "move-64" +title = "Move disk 7: A → B" +description = "Move disk 7 from peg A to peg B. (Move 64/1023)" +needs = ["move-63"] + +[[steps]] +id = "move-65" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 65/1023)" +needs = ["move-64"] + +[[steps]] +id = "move-66" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 66/1023)" +needs = ["move-65"] + +[[steps]] +id = "move-67" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 67/1023)" +needs = ["move-66"] + +[[steps]] +id = "move-68" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 68/1023)" +needs = ["move-67"] + +[[steps]] +id = "move-69" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 69/1023)" +needs = ["move-68"] + +[[steps]] +id = "move-70" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 70/1023)" +needs = ["move-69"] + +[[steps]] +id = "move-71" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 71/1023)" +needs = ["move-70"] + +[[steps]] +id = "move-72" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 72/1023)" +needs = ["move-71"] + +[[steps]] +id = "move-73" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 73/1023)" +needs = ["move-72"] + +[[steps]] +id = "move-74" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 74/1023)" +needs = ["move-73"] + +[[steps]] +id = "move-75" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 75/1023)" +needs = ["move-74"] + +[[steps]] +id = "move-76" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 76/1023)" +needs = ["move-75"] + +[[steps]] +id = "move-77" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 77/1023)" +needs = ["move-76"] + +[[steps]] +id = "move-78" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 78/1023)" +needs = ["move-77"] + +[[steps]] +id = "move-79" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 79/1023)" +needs = ["move-78"] + +[[steps]] +id = "move-80" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 80/1023)" +needs = ["move-79"] + +[[steps]] +id = "move-81" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 81/1023)" +needs = ["move-80"] + +[[steps]] +id = "move-82" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 82/1023)" +needs = ["move-81"] + +[[steps]] +id = "move-83" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 83/1023)" +needs = ["move-82"] + +[[steps]] +id = "move-84" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 84/1023)" +needs = ["move-83"] + +[[steps]] +id = "move-85" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 85/1023)" +needs = ["move-84"] + +[[steps]] +id = "move-86" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 86/1023)" +needs = ["move-85"] + +[[steps]] +id = "move-87" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 87/1023)" +needs = ["move-86"] + +[[steps]] +id = "move-88" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 88/1023)" +needs = ["move-87"] + +[[steps]] +id = "move-89" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 89/1023)" +needs = ["move-88"] + +[[steps]] +id = "move-90" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 90/1023)" +needs = ["move-89"] + +[[steps]] +id = "move-91" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 91/1023)" +needs = ["move-90"] + +[[steps]] +id = "move-92" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 92/1023)" +needs = ["move-91"] + +[[steps]] +id = "move-93" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 93/1023)" +needs = ["move-92"] + +[[steps]] +id = "move-94" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 94/1023)" +needs = ["move-93"] + +[[steps]] +id = "move-95" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 95/1023)" +needs = ["move-94"] + +[[steps]] +id = "move-96" +title = "Move disk 6: C → B" +description = "Move disk 6 from peg C to peg B. (Move 96/1023)" +needs = ["move-95"] + +[[steps]] +id = "move-97" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 97/1023)" +needs = ["move-96"] + +[[steps]] +id = "move-98" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 98/1023)" +needs = ["move-97"] + +[[steps]] +id = "move-99" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 99/1023)" +needs = ["move-98"] + +[[steps]] +id = "move-100" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 100/1023)" +needs = ["move-99"] + +[[steps]] +id = "move-101" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 101/1023)" +needs = ["move-100"] + +[[steps]] +id = "move-102" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 102/1023)" +needs = ["move-101"] + +[[steps]] +id = "move-103" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 103/1023)" +needs = ["move-102"] + +[[steps]] +id = "move-104" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 104/1023)" +needs = ["move-103"] + +[[steps]] +id = "move-105" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 105/1023)" +needs = ["move-104"] + +[[steps]] +id = "move-106" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 106/1023)" +needs = ["move-105"] + +[[steps]] +id = "move-107" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 107/1023)" +needs = ["move-106"] + +[[steps]] +id = "move-108" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 108/1023)" +needs = ["move-107"] + +[[steps]] +id = "move-109" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 109/1023)" +needs = ["move-108"] + +[[steps]] +id = "move-110" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 110/1023)" +needs = ["move-109"] + +[[steps]] +id = "move-111" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 111/1023)" +needs = ["move-110"] + +[[steps]] +id = "move-112" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 112/1023)" +needs = ["move-111"] + +[[steps]] +id = "move-113" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 113/1023)" +needs = ["move-112"] + +[[steps]] +id = "move-114" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 114/1023)" +needs = ["move-113"] + +[[steps]] +id = "move-115" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 115/1023)" +needs = ["move-114"] + +[[steps]] +id = "move-116" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 116/1023)" +needs = ["move-115"] + +[[steps]] +id = "move-117" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 117/1023)" +needs = ["move-116"] + +[[steps]] +id = "move-118" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 118/1023)" +needs = ["move-117"] + +[[steps]] +id = "move-119" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 119/1023)" +needs = ["move-118"] + +[[steps]] +id = "move-120" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 120/1023)" +needs = ["move-119"] + +[[steps]] +id = "move-121" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 121/1023)" +needs = ["move-120"] + +[[steps]] +id = "move-122" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 122/1023)" +needs = ["move-121"] + +[[steps]] +id = "move-123" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 123/1023)" +needs = ["move-122"] + +[[steps]] +id = "move-124" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 124/1023)" +needs = ["move-123"] + +[[steps]] +id = "move-125" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 125/1023)" +needs = ["move-124"] + +[[steps]] +id = "move-126" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 126/1023)" +needs = ["move-125"] + +[[steps]] +id = "move-127" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 127/1023)" +needs = ["move-126"] + +[[steps]] +id = "move-128" +title = "Move disk 8: A → C" +description = "Move disk 8 from peg A to peg C. (Move 128/1023)" +needs = ["move-127"] + +[[steps]] +id = "move-129" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 129/1023)" +needs = ["move-128"] + +[[steps]] +id = "move-130" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 130/1023)" +needs = ["move-129"] + +[[steps]] +id = "move-131" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 131/1023)" +needs = ["move-130"] + +[[steps]] +id = "move-132" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 132/1023)" +needs = ["move-131"] + +[[steps]] +id = "move-133" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 133/1023)" +needs = ["move-132"] + +[[steps]] +id = "move-134" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 134/1023)" +needs = ["move-133"] + +[[steps]] +id = "move-135" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 135/1023)" +needs = ["move-134"] + +[[steps]] +id = "move-136" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 136/1023)" +needs = ["move-135"] + +[[steps]] +id = "move-137" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 137/1023)" +needs = ["move-136"] + +[[steps]] +id = "move-138" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 138/1023)" +needs = ["move-137"] + +[[steps]] +id = "move-139" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 139/1023)" +needs = ["move-138"] + +[[steps]] +id = "move-140" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 140/1023)" +needs = ["move-139"] + +[[steps]] +id = "move-141" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 141/1023)" +needs = ["move-140"] + +[[steps]] +id = "move-142" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 142/1023)" +needs = ["move-141"] + +[[steps]] +id = "move-143" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 143/1023)" +needs = ["move-142"] + +[[steps]] +id = "move-144" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 144/1023)" +needs = ["move-143"] + +[[steps]] +id = "move-145" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 145/1023)" +needs = ["move-144"] + +[[steps]] +id = "move-146" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 146/1023)" +needs = ["move-145"] + +[[steps]] +id = "move-147" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 147/1023)" +needs = ["move-146"] + +[[steps]] +id = "move-148" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 148/1023)" +needs = ["move-147"] + +[[steps]] +id = "move-149" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 149/1023)" +needs = ["move-148"] + +[[steps]] +id = "move-150" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 150/1023)" +needs = ["move-149"] + +[[steps]] +id = "move-151" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 151/1023)" +needs = ["move-150"] + +[[steps]] +id = "move-152" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 152/1023)" +needs = ["move-151"] + +[[steps]] +id = "move-153" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 153/1023)" +needs = ["move-152"] + +[[steps]] +id = "move-154" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 154/1023)" +needs = ["move-153"] + +[[steps]] +id = "move-155" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 155/1023)" +needs = ["move-154"] + +[[steps]] +id = "move-156" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 156/1023)" +needs = ["move-155"] + +[[steps]] +id = "move-157" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 157/1023)" +needs = ["move-156"] + +[[steps]] +id = "move-158" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 158/1023)" +needs = ["move-157"] + +[[steps]] +id = "move-159" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 159/1023)" +needs = ["move-158"] + +[[steps]] +id = "move-160" +title = "Move disk 6: B → A" +description = "Move disk 6 from peg B to peg A. (Move 160/1023)" +needs = ["move-159"] + +[[steps]] +id = "move-161" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 161/1023)" +needs = ["move-160"] + +[[steps]] +id = "move-162" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 162/1023)" +needs = ["move-161"] + +[[steps]] +id = "move-163" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 163/1023)" +needs = ["move-162"] + +[[steps]] +id = "move-164" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 164/1023)" +needs = ["move-163"] + +[[steps]] +id = "move-165" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 165/1023)" +needs = ["move-164"] + +[[steps]] +id = "move-166" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 166/1023)" +needs = ["move-165"] + +[[steps]] +id = "move-167" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 167/1023)" +needs = ["move-166"] + +[[steps]] +id = "move-168" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 168/1023)" +needs = ["move-167"] + +[[steps]] +id = "move-169" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 169/1023)" +needs = ["move-168"] + +[[steps]] +id = "move-170" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 170/1023)" +needs = ["move-169"] + +[[steps]] +id = "move-171" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 171/1023)" +needs = ["move-170"] + +[[steps]] +id = "move-172" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 172/1023)" +needs = ["move-171"] + +[[steps]] +id = "move-173" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 173/1023)" +needs = ["move-172"] + +[[steps]] +id = "move-174" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 174/1023)" +needs = ["move-173"] + +[[steps]] +id = "move-175" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 175/1023)" +needs = ["move-174"] + +[[steps]] +id = "move-176" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 176/1023)" +needs = ["move-175"] + +[[steps]] +id = "move-177" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 177/1023)" +needs = ["move-176"] + +[[steps]] +id = "move-178" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 178/1023)" +needs = ["move-177"] + +[[steps]] +id = "move-179" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 179/1023)" +needs = ["move-178"] + +[[steps]] +id = "move-180" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 180/1023)" +needs = ["move-179"] + +[[steps]] +id = "move-181" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 181/1023)" +needs = ["move-180"] + +[[steps]] +id = "move-182" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 182/1023)" +needs = ["move-181"] + +[[steps]] +id = "move-183" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 183/1023)" +needs = ["move-182"] + +[[steps]] +id = "move-184" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 184/1023)" +needs = ["move-183"] + +[[steps]] +id = "move-185" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 185/1023)" +needs = ["move-184"] + +[[steps]] +id = "move-186" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 186/1023)" +needs = ["move-185"] + +[[steps]] +id = "move-187" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 187/1023)" +needs = ["move-186"] + +[[steps]] +id = "move-188" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 188/1023)" +needs = ["move-187"] + +[[steps]] +id = "move-189" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 189/1023)" +needs = ["move-188"] + +[[steps]] +id = "move-190" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 190/1023)" +needs = ["move-189"] + +[[steps]] +id = "move-191" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 191/1023)" +needs = ["move-190"] + +[[steps]] +id = "move-192" +title = "Move disk 7: B → C" +description = "Move disk 7 from peg B to peg C. (Move 192/1023)" +needs = ["move-191"] + +[[steps]] +id = "move-193" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 193/1023)" +needs = ["move-192"] + +[[steps]] +id = "move-194" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 194/1023)" +needs = ["move-193"] + +[[steps]] +id = "move-195" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 195/1023)" +needs = ["move-194"] + +[[steps]] +id = "move-196" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 196/1023)" +needs = ["move-195"] + +[[steps]] +id = "move-197" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 197/1023)" +needs = ["move-196"] + +[[steps]] +id = "move-198" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 198/1023)" +needs = ["move-197"] + +[[steps]] +id = "move-199" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 199/1023)" +needs = ["move-198"] + +[[steps]] +id = "move-200" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 200/1023)" +needs = ["move-199"] + +[[steps]] +id = "move-201" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 201/1023)" +needs = ["move-200"] + +[[steps]] +id = "move-202" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 202/1023)" +needs = ["move-201"] + +[[steps]] +id = "move-203" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 203/1023)" +needs = ["move-202"] + +[[steps]] +id = "move-204" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 204/1023)" +needs = ["move-203"] + +[[steps]] +id = "move-205" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 205/1023)" +needs = ["move-204"] + +[[steps]] +id = "move-206" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 206/1023)" +needs = ["move-205"] + +[[steps]] +id = "move-207" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 207/1023)" +needs = ["move-206"] + +[[steps]] +id = "move-208" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 208/1023)" +needs = ["move-207"] + +[[steps]] +id = "move-209" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 209/1023)" +needs = ["move-208"] + +[[steps]] +id = "move-210" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 210/1023)" +needs = ["move-209"] + +[[steps]] +id = "move-211" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 211/1023)" +needs = ["move-210"] + +[[steps]] +id = "move-212" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 212/1023)" +needs = ["move-211"] + +[[steps]] +id = "move-213" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 213/1023)" +needs = ["move-212"] + +[[steps]] +id = "move-214" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 214/1023)" +needs = ["move-213"] + +[[steps]] +id = "move-215" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 215/1023)" +needs = ["move-214"] + +[[steps]] +id = "move-216" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 216/1023)" +needs = ["move-215"] + +[[steps]] +id = "move-217" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 217/1023)" +needs = ["move-216"] + +[[steps]] +id = "move-218" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 218/1023)" +needs = ["move-217"] + +[[steps]] +id = "move-219" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 219/1023)" +needs = ["move-218"] + +[[steps]] +id = "move-220" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 220/1023)" +needs = ["move-219"] + +[[steps]] +id = "move-221" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 221/1023)" +needs = ["move-220"] + +[[steps]] +id = "move-222" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 222/1023)" +needs = ["move-221"] + +[[steps]] +id = "move-223" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 223/1023)" +needs = ["move-222"] + +[[steps]] +id = "move-224" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 224/1023)" +needs = ["move-223"] + +[[steps]] +id = "move-225" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 225/1023)" +needs = ["move-224"] + +[[steps]] +id = "move-226" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 226/1023)" +needs = ["move-225"] + +[[steps]] +id = "move-227" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 227/1023)" +needs = ["move-226"] + +[[steps]] +id = "move-228" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 228/1023)" +needs = ["move-227"] + +[[steps]] +id = "move-229" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 229/1023)" +needs = ["move-228"] + +[[steps]] +id = "move-230" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 230/1023)" +needs = ["move-229"] + +[[steps]] +id = "move-231" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 231/1023)" +needs = ["move-230"] + +[[steps]] +id = "move-232" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 232/1023)" +needs = ["move-231"] + +[[steps]] +id = "move-233" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 233/1023)" +needs = ["move-232"] + +[[steps]] +id = "move-234" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 234/1023)" +needs = ["move-233"] + +[[steps]] +id = "move-235" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 235/1023)" +needs = ["move-234"] + +[[steps]] +id = "move-236" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 236/1023)" +needs = ["move-235"] + +[[steps]] +id = "move-237" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 237/1023)" +needs = ["move-236"] + +[[steps]] +id = "move-238" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 238/1023)" +needs = ["move-237"] + +[[steps]] +id = "move-239" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 239/1023)" +needs = ["move-238"] + +[[steps]] +id = "move-240" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 240/1023)" +needs = ["move-239"] + +[[steps]] +id = "move-241" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 241/1023)" +needs = ["move-240"] + +[[steps]] +id = "move-242" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 242/1023)" +needs = ["move-241"] + +[[steps]] +id = "move-243" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 243/1023)" +needs = ["move-242"] + +[[steps]] +id = "move-244" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 244/1023)" +needs = ["move-243"] + +[[steps]] +id = "move-245" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 245/1023)" +needs = ["move-244"] + +[[steps]] +id = "move-246" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 246/1023)" +needs = ["move-245"] + +[[steps]] +id = "move-247" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 247/1023)" +needs = ["move-246"] + +[[steps]] +id = "move-248" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 248/1023)" +needs = ["move-247"] + +[[steps]] +id = "move-249" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 249/1023)" +needs = ["move-248"] + +[[steps]] +id = "move-250" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 250/1023)" +needs = ["move-249"] + +[[steps]] +id = "move-251" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 251/1023)" +needs = ["move-250"] + +[[steps]] +id = "move-252" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 252/1023)" +needs = ["move-251"] + +[[steps]] +id = "move-253" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 253/1023)" +needs = ["move-252"] + +[[steps]] +id = "move-254" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 254/1023)" +needs = ["move-253"] + +[[steps]] +id = "move-255" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 255/1023)" +needs = ["move-254"] + +[[steps]] +id = "move-256" +title = "Move disk 9: A → B" +description = "Move disk 9 from peg A to peg B. (Move 256/1023)" +needs = ["move-255"] + +[[steps]] +id = "move-257" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 257/1023)" +needs = ["move-256"] + +[[steps]] +id = "move-258" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 258/1023)" +needs = ["move-257"] + +[[steps]] +id = "move-259" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 259/1023)" +needs = ["move-258"] + +[[steps]] +id = "move-260" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 260/1023)" +needs = ["move-259"] + +[[steps]] +id = "move-261" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 261/1023)" +needs = ["move-260"] + +[[steps]] +id = "move-262" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 262/1023)" +needs = ["move-261"] + +[[steps]] +id = "move-263" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 263/1023)" +needs = ["move-262"] + +[[steps]] +id = "move-264" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 264/1023)" +needs = ["move-263"] + +[[steps]] +id = "move-265" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 265/1023)" +needs = ["move-264"] + +[[steps]] +id = "move-266" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 266/1023)" +needs = ["move-265"] + +[[steps]] +id = "move-267" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 267/1023)" +needs = ["move-266"] + +[[steps]] +id = "move-268" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 268/1023)" +needs = ["move-267"] + +[[steps]] +id = "move-269" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 269/1023)" +needs = ["move-268"] + +[[steps]] +id = "move-270" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 270/1023)" +needs = ["move-269"] + +[[steps]] +id = "move-271" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 271/1023)" +needs = ["move-270"] + +[[steps]] +id = "move-272" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 272/1023)" +needs = ["move-271"] + +[[steps]] +id = "move-273" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 273/1023)" +needs = ["move-272"] + +[[steps]] +id = "move-274" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 274/1023)" +needs = ["move-273"] + +[[steps]] +id = "move-275" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 275/1023)" +needs = ["move-274"] + +[[steps]] +id = "move-276" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 276/1023)" +needs = ["move-275"] + +[[steps]] +id = "move-277" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 277/1023)" +needs = ["move-276"] + +[[steps]] +id = "move-278" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 278/1023)" +needs = ["move-277"] + +[[steps]] +id = "move-279" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 279/1023)" +needs = ["move-278"] + +[[steps]] +id = "move-280" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 280/1023)" +needs = ["move-279"] + +[[steps]] +id = "move-281" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 281/1023)" +needs = ["move-280"] + +[[steps]] +id = "move-282" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 282/1023)" +needs = ["move-281"] + +[[steps]] +id = "move-283" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 283/1023)" +needs = ["move-282"] + +[[steps]] +id = "move-284" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 284/1023)" +needs = ["move-283"] + +[[steps]] +id = "move-285" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 285/1023)" +needs = ["move-284"] + +[[steps]] +id = "move-286" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 286/1023)" +needs = ["move-285"] + +[[steps]] +id = "move-287" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 287/1023)" +needs = ["move-286"] + +[[steps]] +id = "move-288" +title = "Move disk 6: C → B" +description = "Move disk 6 from peg C to peg B. (Move 288/1023)" +needs = ["move-287"] + +[[steps]] +id = "move-289" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 289/1023)" +needs = ["move-288"] + +[[steps]] +id = "move-290" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 290/1023)" +needs = ["move-289"] + +[[steps]] +id = "move-291" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 291/1023)" +needs = ["move-290"] + +[[steps]] +id = "move-292" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 292/1023)" +needs = ["move-291"] + +[[steps]] +id = "move-293" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 293/1023)" +needs = ["move-292"] + +[[steps]] +id = "move-294" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 294/1023)" +needs = ["move-293"] + +[[steps]] +id = "move-295" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 295/1023)" +needs = ["move-294"] + +[[steps]] +id = "move-296" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 296/1023)" +needs = ["move-295"] + +[[steps]] +id = "move-297" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 297/1023)" +needs = ["move-296"] + +[[steps]] +id = "move-298" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 298/1023)" +needs = ["move-297"] + +[[steps]] +id = "move-299" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 299/1023)" +needs = ["move-298"] + +[[steps]] +id = "move-300" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 300/1023)" +needs = ["move-299"] + +[[steps]] +id = "move-301" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 301/1023)" +needs = ["move-300"] + +[[steps]] +id = "move-302" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 302/1023)" +needs = ["move-301"] + +[[steps]] +id = "move-303" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 303/1023)" +needs = ["move-302"] + +[[steps]] +id = "move-304" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 304/1023)" +needs = ["move-303"] + +[[steps]] +id = "move-305" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 305/1023)" +needs = ["move-304"] + +[[steps]] +id = "move-306" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 306/1023)" +needs = ["move-305"] + +[[steps]] +id = "move-307" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 307/1023)" +needs = ["move-306"] + +[[steps]] +id = "move-308" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 308/1023)" +needs = ["move-307"] + +[[steps]] +id = "move-309" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 309/1023)" +needs = ["move-308"] + +[[steps]] +id = "move-310" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 310/1023)" +needs = ["move-309"] + +[[steps]] +id = "move-311" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 311/1023)" +needs = ["move-310"] + +[[steps]] +id = "move-312" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 312/1023)" +needs = ["move-311"] + +[[steps]] +id = "move-313" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 313/1023)" +needs = ["move-312"] + +[[steps]] +id = "move-314" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 314/1023)" +needs = ["move-313"] + +[[steps]] +id = "move-315" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 315/1023)" +needs = ["move-314"] + +[[steps]] +id = "move-316" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 316/1023)" +needs = ["move-315"] + +[[steps]] +id = "move-317" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 317/1023)" +needs = ["move-316"] + +[[steps]] +id = "move-318" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 318/1023)" +needs = ["move-317"] + +[[steps]] +id = "move-319" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 319/1023)" +needs = ["move-318"] + +[[steps]] +id = "move-320" +title = "Move disk 7: C → A" +description = "Move disk 7 from peg C to peg A. (Move 320/1023)" +needs = ["move-319"] + +[[steps]] +id = "move-321" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 321/1023)" +needs = ["move-320"] + +[[steps]] +id = "move-322" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 322/1023)" +needs = ["move-321"] + +[[steps]] +id = "move-323" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 323/1023)" +needs = ["move-322"] + +[[steps]] +id = "move-324" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 324/1023)" +needs = ["move-323"] + +[[steps]] +id = "move-325" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 325/1023)" +needs = ["move-324"] + +[[steps]] +id = "move-326" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 326/1023)" +needs = ["move-325"] + +[[steps]] +id = "move-327" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 327/1023)" +needs = ["move-326"] + +[[steps]] +id = "move-328" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 328/1023)" +needs = ["move-327"] + +[[steps]] +id = "move-329" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 329/1023)" +needs = ["move-328"] + +[[steps]] +id = "move-330" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 330/1023)" +needs = ["move-329"] + +[[steps]] +id = "move-331" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 331/1023)" +needs = ["move-330"] + +[[steps]] +id = "move-332" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 332/1023)" +needs = ["move-331"] + +[[steps]] +id = "move-333" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 333/1023)" +needs = ["move-332"] + +[[steps]] +id = "move-334" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 334/1023)" +needs = ["move-333"] + +[[steps]] +id = "move-335" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 335/1023)" +needs = ["move-334"] + +[[steps]] +id = "move-336" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 336/1023)" +needs = ["move-335"] + +[[steps]] +id = "move-337" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 337/1023)" +needs = ["move-336"] + +[[steps]] +id = "move-338" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 338/1023)" +needs = ["move-337"] + +[[steps]] +id = "move-339" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 339/1023)" +needs = ["move-338"] + +[[steps]] +id = "move-340" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 340/1023)" +needs = ["move-339"] + +[[steps]] +id = "move-341" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 341/1023)" +needs = ["move-340"] + +[[steps]] +id = "move-342" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 342/1023)" +needs = ["move-341"] + +[[steps]] +id = "move-343" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 343/1023)" +needs = ["move-342"] + +[[steps]] +id = "move-344" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 344/1023)" +needs = ["move-343"] + +[[steps]] +id = "move-345" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 345/1023)" +needs = ["move-344"] + +[[steps]] +id = "move-346" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 346/1023)" +needs = ["move-345"] + +[[steps]] +id = "move-347" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 347/1023)" +needs = ["move-346"] + +[[steps]] +id = "move-348" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 348/1023)" +needs = ["move-347"] + +[[steps]] +id = "move-349" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 349/1023)" +needs = ["move-348"] + +[[steps]] +id = "move-350" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 350/1023)" +needs = ["move-349"] + +[[steps]] +id = "move-351" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 351/1023)" +needs = ["move-350"] + +[[steps]] +id = "move-352" +title = "Move disk 6: B → A" +description = "Move disk 6 from peg B to peg A. (Move 352/1023)" +needs = ["move-351"] + +[[steps]] +id = "move-353" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 353/1023)" +needs = ["move-352"] + +[[steps]] +id = "move-354" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 354/1023)" +needs = ["move-353"] + +[[steps]] +id = "move-355" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 355/1023)" +needs = ["move-354"] + +[[steps]] +id = "move-356" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 356/1023)" +needs = ["move-355"] + +[[steps]] +id = "move-357" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 357/1023)" +needs = ["move-356"] + +[[steps]] +id = "move-358" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 358/1023)" +needs = ["move-357"] + +[[steps]] +id = "move-359" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 359/1023)" +needs = ["move-358"] + +[[steps]] +id = "move-360" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 360/1023)" +needs = ["move-359"] + +[[steps]] +id = "move-361" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 361/1023)" +needs = ["move-360"] + +[[steps]] +id = "move-362" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 362/1023)" +needs = ["move-361"] + +[[steps]] +id = "move-363" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 363/1023)" +needs = ["move-362"] + +[[steps]] +id = "move-364" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 364/1023)" +needs = ["move-363"] + +[[steps]] +id = "move-365" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 365/1023)" +needs = ["move-364"] + +[[steps]] +id = "move-366" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 366/1023)" +needs = ["move-365"] + +[[steps]] +id = "move-367" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 367/1023)" +needs = ["move-366"] + +[[steps]] +id = "move-368" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 368/1023)" +needs = ["move-367"] + +[[steps]] +id = "move-369" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 369/1023)" +needs = ["move-368"] + +[[steps]] +id = "move-370" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 370/1023)" +needs = ["move-369"] + +[[steps]] +id = "move-371" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 371/1023)" +needs = ["move-370"] + +[[steps]] +id = "move-372" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 372/1023)" +needs = ["move-371"] + +[[steps]] +id = "move-373" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 373/1023)" +needs = ["move-372"] + +[[steps]] +id = "move-374" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 374/1023)" +needs = ["move-373"] + +[[steps]] +id = "move-375" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 375/1023)" +needs = ["move-374"] + +[[steps]] +id = "move-376" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 376/1023)" +needs = ["move-375"] + +[[steps]] +id = "move-377" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 377/1023)" +needs = ["move-376"] + +[[steps]] +id = "move-378" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 378/1023)" +needs = ["move-377"] + +[[steps]] +id = "move-379" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 379/1023)" +needs = ["move-378"] + +[[steps]] +id = "move-380" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 380/1023)" +needs = ["move-379"] + +[[steps]] +id = "move-381" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 381/1023)" +needs = ["move-380"] + +[[steps]] +id = "move-382" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 382/1023)" +needs = ["move-381"] + +[[steps]] +id = "move-383" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 383/1023)" +needs = ["move-382"] + +[[steps]] +id = "move-384" +title = "Move disk 8: C → B" +description = "Move disk 8 from peg C to peg B. (Move 384/1023)" +needs = ["move-383"] + +[[steps]] +id = "move-385" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 385/1023)" +needs = ["move-384"] + +[[steps]] +id = "move-386" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 386/1023)" +needs = ["move-385"] + +[[steps]] +id = "move-387" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 387/1023)" +needs = ["move-386"] + +[[steps]] +id = "move-388" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 388/1023)" +needs = ["move-387"] + +[[steps]] +id = "move-389" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 389/1023)" +needs = ["move-388"] + +[[steps]] +id = "move-390" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 390/1023)" +needs = ["move-389"] + +[[steps]] +id = "move-391" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 391/1023)" +needs = ["move-390"] + +[[steps]] +id = "move-392" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 392/1023)" +needs = ["move-391"] + +[[steps]] +id = "move-393" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 393/1023)" +needs = ["move-392"] + +[[steps]] +id = "move-394" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 394/1023)" +needs = ["move-393"] + +[[steps]] +id = "move-395" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 395/1023)" +needs = ["move-394"] + +[[steps]] +id = "move-396" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 396/1023)" +needs = ["move-395"] + +[[steps]] +id = "move-397" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 397/1023)" +needs = ["move-396"] + +[[steps]] +id = "move-398" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 398/1023)" +needs = ["move-397"] + +[[steps]] +id = "move-399" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 399/1023)" +needs = ["move-398"] + +[[steps]] +id = "move-400" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 400/1023)" +needs = ["move-399"] + +[[steps]] +id = "move-401" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 401/1023)" +needs = ["move-400"] + +[[steps]] +id = "move-402" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 402/1023)" +needs = ["move-401"] + +[[steps]] +id = "move-403" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 403/1023)" +needs = ["move-402"] + +[[steps]] +id = "move-404" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 404/1023)" +needs = ["move-403"] + +[[steps]] +id = "move-405" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 405/1023)" +needs = ["move-404"] + +[[steps]] +id = "move-406" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 406/1023)" +needs = ["move-405"] + +[[steps]] +id = "move-407" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 407/1023)" +needs = ["move-406"] + +[[steps]] +id = "move-408" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 408/1023)" +needs = ["move-407"] + +[[steps]] +id = "move-409" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 409/1023)" +needs = ["move-408"] + +[[steps]] +id = "move-410" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 410/1023)" +needs = ["move-409"] + +[[steps]] +id = "move-411" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 411/1023)" +needs = ["move-410"] + +[[steps]] +id = "move-412" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 412/1023)" +needs = ["move-411"] + +[[steps]] +id = "move-413" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 413/1023)" +needs = ["move-412"] + +[[steps]] +id = "move-414" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 414/1023)" +needs = ["move-413"] + +[[steps]] +id = "move-415" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 415/1023)" +needs = ["move-414"] + +[[steps]] +id = "move-416" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 416/1023)" +needs = ["move-415"] + +[[steps]] +id = "move-417" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 417/1023)" +needs = ["move-416"] + +[[steps]] +id = "move-418" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 418/1023)" +needs = ["move-417"] + +[[steps]] +id = "move-419" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 419/1023)" +needs = ["move-418"] + +[[steps]] +id = "move-420" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 420/1023)" +needs = ["move-419"] + +[[steps]] +id = "move-421" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 421/1023)" +needs = ["move-420"] + +[[steps]] +id = "move-422" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 422/1023)" +needs = ["move-421"] + +[[steps]] +id = "move-423" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 423/1023)" +needs = ["move-422"] + +[[steps]] +id = "move-424" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 424/1023)" +needs = ["move-423"] + +[[steps]] +id = "move-425" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 425/1023)" +needs = ["move-424"] + +[[steps]] +id = "move-426" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 426/1023)" +needs = ["move-425"] + +[[steps]] +id = "move-427" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 427/1023)" +needs = ["move-426"] + +[[steps]] +id = "move-428" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 428/1023)" +needs = ["move-427"] + +[[steps]] +id = "move-429" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 429/1023)" +needs = ["move-428"] + +[[steps]] +id = "move-430" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 430/1023)" +needs = ["move-429"] + +[[steps]] +id = "move-431" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 431/1023)" +needs = ["move-430"] + +[[steps]] +id = "move-432" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 432/1023)" +needs = ["move-431"] + +[[steps]] +id = "move-433" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 433/1023)" +needs = ["move-432"] + +[[steps]] +id = "move-434" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 434/1023)" +needs = ["move-433"] + +[[steps]] +id = "move-435" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 435/1023)" +needs = ["move-434"] + +[[steps]] +id = "move-436" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 436/1023)" +needs = ["move-435"] + +[[steps]] +id = "move-437" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 437/1023)" +needs = ["move-436"] + +[[steps]] +id = "move-438" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 438/1023)" +needs = ["move-437"] + +[[steps]] +id = "move-439" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 439/1023)" +needs = ["move-438"] + +[[steps]] +id = "move-440" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 440/1023)" +needs = ["move-439"] + +[[steps]] +id = "move-441" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 441/1023)" +needs = ["move-440"] + +[[steps]] +id = "move-442" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 442/1023)" +needs = ["move-441"] + +[[steps]] +id = "move-443" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 443/1023)" +needs = ["move-442"] + +[[steps]] +id = "move-444" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 444/1023)" +needs = ["move-443"] + +[[steps]] +id = "move-445" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 445/1023)" +needs = ["move-444"] + +[[steps]] +id = "move-446" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 446/1023)" +needs = ["move-445"] + +[[steps]] +id = "move-447" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 447/1023)" +needs = ["move-446"] + +[[steps]] +id = "move-448" +title = "Move disk 7: A → B" +description = "Move disk 7 from peg A to peg B. (Move 448/1023)" +needs = ["move-447"] + +[[steps]] +id = "move-449" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 449/1023)" +needs = ["move-448"] + +[[steps]] +id = "move-450" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 450/1023)" +needs = ["move-449"] + +[[steps]] +id = "move-451" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 451/1023)" +needs = ["move-450"] + +[[steps]] +id = "move-452" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 452/1023)" +needs = ["move-451"] + +[[steps]] +id = "move-453" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 453/1023)" +needs = ["move-452"] + +[[steps]] +id = "move-454" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 454/1023)" +needs = ["move-453"] + +[[steps]] +id = "move-455" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 455/1023)" +needs = ["move-454"] + +[[steps]] +id = "move-456" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 456/1023)" +needs = ["move-455"] + +[[steps]] +id = "move-457" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 457/1023)" +needs = ["move-456"] + +[[steps]] +id = "move-458" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 458/1023)" +needs = ["move-457"] + +[[steps]] +id = "move-459" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 459/1023)" +needs = ["move-458"] + +[[steps]] +id = "move-460" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 460/1023)" +needs = ["move-459"] + +[[steps]] +id = "move-461" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 461/1023)" +needs = ["move-460"] + +[[steps]] +id = "move-462" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 462/1023)" +needs = ["move-461"] + +[[steps]] +id = "move-463" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 463/1023)" +needs = ["move-462"] + +[[steps]] +id = "move-464" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 464/1023)" +needs = ["move-463"] + +[[steps]] +id = "move-465" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 465/1023)" +needs = ["move-464"] + +[[steps]] +id = "move-466" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 466/1023)" +needs = ["move-465"] + +[[steps]] +id = "move-467" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 467/1023)" +needs = ["move-466"] + +[[steps]] +id = "move-468" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 468/1023)" +needs = ["move-467"] + +[[steps]] +id = "move-469" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 469/1023)" +needs = ["move-468"] + +[[steps]] +id = "move-470" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 470/1023)" +needs = ["move-469"] + +[[steps]] +id = "move-471" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 471/1023)" +needs = ["move-470"] + +[[steps]] +id = "move-472" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 472/1023)" +needs = ["move-471"] + +[[steps]] +id = "move-473" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 473/1023)" +needs = ["move-472"] + +[[steps]] +id = "move-474" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 474/1023)" +needs = ["move-473"] + +[[steps]] +id = "move-475" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 475/1023)" +needs = ["move-474"] + +[[steps]] +id = "move-476" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 476/1023)" +needs = ["move-475"] + +[[steps]] +id = "move-477" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 477/1023)" +needs = ["move-476"] + +[[steps]] +id = "move-478" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 478/1023)" +needs = ["move-477"] + +[[steps]] +id = "move-479" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 479/1023)" +needs = ["move-478"] + +[[steps]] +id = "move-480" +title = "Move disk 6: C → B" +description = "Move disk 6 from peg C to peg B. (Move 480/1023)" +needs = ["move-479"] + +[[steps]] +id = "move-481" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 481/1023)" +needs = ["move-480"] + +[[steps]] +id = "move-482" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 482/1023)" +needs = ["move-481"] + +[[steps]] +id = "move-483" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 483/1023)" +needs = ["move-482"] + +[[steps]] +id = "move-484" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 484/1023)" +needs = ["move-483"] + +[[steps]] +id = "move-485" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 485/1023)" +needs = ["move-484"] + +[[steps]] +id = "move-486" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 486/1023)" +needs = ["move-485"] + +[[steps]] +id = "move-487" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 487/1023)" +needs = ["move-486"] + +[[steps]] +id = "move-488" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 488/1023)" +needs = ["move-487"] + +[[steps]] +id = "move-489" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 489/1023)" +needs = ["move-488"] + +[[steps]] +id = "move-490" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 490/1023)" +needs = ["move-489"] + +[[steps]] +id = "move-491" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 491/1023)" +needs = ["move-490"] + +[[steps]] +id = "move-492" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 492/1023)" +needs = ["move-491"] + +[[steps]] +id = "move-493" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 493/1023)" +needs = ["move-492"] + +[[steps]] +id = "move-494" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 494/1023)" +needs = ["move-493"] + +[[steps]] +id = "move-495" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 495/1023)" +needs = ["move-494"] + +[[steps]] +id = "move-496" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 496/1023)" +needs = ["move-495"] + +[[steps]] +id = "move-497" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 497/1023)" +needs = ["move-496"] + +[[steps]] +id = "move-498" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 498/1023)" +needs = ["move-497"] + +[[steps]] +id = "move-499" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 499/1023)" +needs = ["move-498"] + +[[steps]] +id = "move-500" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 500/1023)" +needs = ["move-499"] + +[[steps]] +id = "move-501" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 501/1023)" +needs = ["move-500"] + +[[steps]] +id = "move-502" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 502/1023)" +needs = ["move-501"] + +[[steps]] +id = "move-503" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 503/1023)" +needs = ["move-502"] + +[[steps]] +id = "move-504" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 504/1023)" +needs = ["move-503"] + +[[steps]] +id = "move-505" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 505/1023)" +needs = ["move-504"] + +[[steps]] +id = "move-506" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 506/1023)" +needs = ["move-505"] + +[[steps]] +id = "move-507" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 507/1023)" +needs = ["move-506"] + +[[steps]] +id = "move-508" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 508/1023)" +needs = ["move-507"] + +[[steps]] +id = "move-509" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 509/1023)" +needs = ["move-508"] + +[[steps]] +id = "move-510" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 510/1023)" +needs = ["move-509"] + +[[steps]] +id = "move-511" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 511/1023)" +needs = ["move-510"] + +[[steps]] +id = "move-512" +title = "Move disk 10: A → C" +description = "Move disk 10 from peg A to peg C. (Move 512/1023)" +needs = ["move-511"] + +[[steps]] +id = "move-513" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 513/1023)" +needs = ["move-512"] + +[[steps]] +id = "move-514" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 514/1023)" +needs = ["move-513"] + +[[steps]] +id = "move-515" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 515/1023)" +needs = ["move-514"] + +[[steps]] +id = "move-516" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 516/1023)" +needs = ["move-515"] + +[[steps]] +id = "move-517" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 517/1023)" +needs = ["move-516"] + +[[steps]] +id = "move-518" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 518/1023)" +needs = ["move-517"] + +[[steps]] +id = "move-519" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 519/1023)" +needs = ["move-518"] + +[[steps]] +id = "move-520" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 520/1023)" +needs = ["move-519"] + +[[steps]] +id = "move-521" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 521/1023)" +needs = ["move-520"] + +[[steps]] +id = "move-522" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 522/1023)" +needs = ["move-521"] + +[[steps]] +id = "move-523" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 523/1023)" +needs = ["move-522"] + +[[steps]] +id = "move-524" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 524/1023)" +needs = ["move-523"] + +[[steps]] +id = "move-525" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 525/1023)" +needs = ["move-524"] + +[[steps]] +id = "move-526" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 526/1023)" +needs = ["move-525"] + +[[steps]] +id = "move-527" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 527/1023)" +needs = ["move-526"] + +[[steps]] +id = "move-528" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 528/1023)" +needs = ["move-527"] + +[[steps]] +id = "move-529" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 529/1023)" +needs = ["move-528"] + +[[steps]] +id = "move-530" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 530/1023)" +needs = ["move-529"] + +[[steps]] +id = "move-531" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 531/1023)" +needs = ["move-530"] + +[[steps]] +id = "move-532" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 532/1023)" +needs = ["move-531"] + +[[steps]] +id = "move-533" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 533/1023)" +needs = ["move-532"] + +[[steps]] +id = "move-534" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 534/1023)" +needs = ["move-533"] + +[[steps]] +id = "move-535" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 535/1023)" +needs = ["move-534"] + +[[steps]] +id = "move-536" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 536/1023)" +needs = ["move-535"] + +[[steps]] +id = "move-537" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 537/1023)" +needs = ["move-536"] + +[[steps]] +id = "move-538" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 538/1023)" +needs = ["move-537"] + +[[steps]] +id = "move-539" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 539/1023)" +needs = ["move-538"] + +[[steps]] +id = "move-540" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 540/1023)" +needs = ["move-539"] + +[[steps]] +id = "move-541" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 541/1023)" +needs = ["move-540"] + +[[steps]] +id = "move-542" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 542/1023)" +needs = ["move-541"] + +[[steps]] +id = "move-543" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 543/1023)" +needs = ["move-542"] + +[[steps]] +id = "move-544" +title = "Move disk 6: B → A" +description = "Move disk 6 from peg B to peg A. (Move 544/1023)" +needs = ["move-543"] + +[[steps]] +id = "move-545" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 545/1023)" +needs = ["move-544"] + +[[steps]] +id = "move-546" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 546/1023)" +needs = ["move-545"] + +[[steps]] +id = "move-547" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 547/1023)" +needs = ["move-546"] + +[[steps]] +id = "move-548" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 548/1023)" +needs = ["move-547"] + +[[steps]] +id = "move-549" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 549/1023)" +needs = ["move-548"] + +[[steps]] +id = "move-550" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 550/1023)" +needs = ["move-549"] + +[[steps]] +id = "move-551" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 551/1023)" +needs = ["move-550"] + +[[steps]] +id = "move-552" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 552/1023)" +needs = ["move-551"] + +[[steps]] +id = "move-553" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 553/1023)" +needs = ["move-552"] + +[[steps]] +id = "move-554" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 554/1023)" +needs = ["move-553"] + +[[steps]] +id = "move-555" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 555/1023)" +needs = ["move-554"] + +[[steps]] +id = "move-556" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 556/1023)" +needs = ["move-555"] + +[[steps]] +id = "move-557" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 557/1023)" +needs = ["move-556"] + +[[steps]] +id = "move-558" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 558/1023)" +needs = ["move-557"] + +[[steps]] +id = "move-559" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 559/1023)" +needs = ["move-558"] + +[[steps]] +id = "move-560" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 560/1023)" +needs = ["move-559"] + +[[steps]] +id = "move-561" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 561/1023)" +needs = ["move-560"] + +[[steps]] +id = "move-562" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 562/1023)" +needs = ["move-561"] + +[[steps]] +id = "move-563" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 563/1023)" +needs = ["move-562"] + +[[steps]] +id = "move-564" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 564/1023)" +needs = ["move-563"] + +[[steps]] +id = "move-565" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 565/1023)" +needs = ["move-564"] + +[[steps]] +id = "move-566" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 566/1023)" +needs = ["move-565"] + +[[steps]] +id = "move-567" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 567/1023)" +needs = ["move-566"] + +[[steps]] +id = "move-568" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 568/1023)" +needs = ["move-567"] + +[[steps]] +id = "move-569" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 569/1023)" +needs = ["move-568"] + +[[steps]] +id = "move-570" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 570/1023)" +needs = ["move-569"] + +[[steps]] +id = "move-571" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 571/1023)" +needs = ["move-570"] + +[[steps]] +id = "move-572" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 572/1023)" +needs = ["move-571"] + +[[steps]] +id = "move-573" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 573/1023)" +needs = ["move-572"] + +[[steps]] +id = "move-574" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 574/1023)" +needs = ["move-573"] + +[[steps]] +id = "move-575" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 575/1023)" +needs = ["move-574"] + +[[steps]] +id = "move-576" +title = "Move disk 7: B → C" +description = "Move disk 7 from peg B to peg C. (Move 576/1023)" +needs = ["move-575"] + +[[steps]] +id = "move-577" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 577/1023)" +needs = ["move-576"] + +[[steps]] +id = "move-578" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 578/1023)" +needs = ["move-577"] + +[[steps]] +id = "move-579" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 579/1023)" +needs = ["move-578"] + +[[steps]] +id = "move-580" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 580/1023)" +needs = ["move-579"] + +[[steps]] +id = "move-581" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 581/1023)" +needs = ["move-580"] + +[[steps]] +id = "move-582" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 582/1023)" +needs = ["move-581"] + +[[steps]] +id = "move-583" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 583/1023)" +needs = ["move-582"] + +[[steps]] +id = "move-584" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 584/1023)" +needs = ["move-583"] + +[[steps]] +id = "move-585" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 585/1023)" +needs = ["move-584"] + +[[steps]] +id = "move-586" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 586/1023)" +needs = ["move-585"] + +[[steps]] +id = "move-587" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 587/1023)" +needs = ["move-586"] + +[[steps]] +id = "move-588" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 588/1023)" +needs = ["move-587"] + +[[steps]] +id = "move-589" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 589/1023)" +needs = ["move-588"] + +[[steps]] +id = "move-590" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 590/1023)" +needs = ["move-589"] + +[[steps]] +id = "move-591" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 591/1023)" +needs = ["move-590"] + +[[steps]] +id = "move-592" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 592/1023)" +needs = ["move-591"] + +[[steps]] +id = "move-593" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 593/1023)" +needs = ["move-592"] + +[[steps]] +id = "move-594" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 594/1023)" +needs = ["move-593"] + +[[steps]] +id = "move-595" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 595/1023)" +needs = ["move-594"] + +[[steps]] +id = "move-596" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 596/1023)" +needs = ["move-595"] + +[[steps]] +id = "move-597" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 597/1023)" +needs = ["move-596"] + +[[steps]] +id = "move-598" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 598/1023)" +needs = ["move-597"] + +[[steps]] +id = "move-599" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 599/1023)" +needs = ["move-598"] + +[[steps]] +id = "move-600" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 600/1023)" +needs = ["move-599"] + +[[steps]] +id = "move-601" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 601/1023)" +needs = ["move-600"] + +[[steps]] +id = "move-602" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 602/1023)" +needs = ["move-601"] + +[[steps]] +id = "move-603" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 603/1023)" +needs = ["move-602"] + +[[steps]] +id = "move-604" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 604/1023)" +needs = ["move-603"] + +[[steps]] +id = "move-605" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 605/1023)" +needs = ["move-604"] + +[[steps]] +id = "move-606" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 606/1023)" +needs = ["move-605"] + +[[steps]] +id = "move-607" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 607/1023)" +needs = ["move-606"] + +[[steps]] +id = "move-608" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 608/1023)" +needs = ["move-607"] + +[[steps]] +id = "move-609" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 609/1023)" +needs = ["move-608"] + +[[steps]] +id = "move-610" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 610/1023)" +needs = ["move-609"] + +[[steps]] +id = "move-611" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 611/1023)" +needs = ["move-610"] + +[[steps]] +id = "move-612" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 612/1023)" +needs = ["move-611"] + +[[steps]] +id = "move-613" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 613/1023)" +needs = ["move-612"] + +[[steps]] +id = "move-614" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 614/1023)" +needs = ["move-613"] + +[[steps]] +id = "move-615" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 615/1023)" +needs = ["move-614"] + +[[steps]] +id = "move-616" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 616/1023)" +needs = ["move-615"] + +[[steps]] +id = "move-617" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 617/1023)" +needs = ["move-616"] + +[[steps]] +id = "move-618" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 618/1023)" +needs = ["move-617"] + +[[steps]] +id = "move-619" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 619/1023)" +needs = ["move-618"] + +[[steps]] +id = "move-620" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 620/1023)" +needs = ["move-619"] + +[[steps]] +id = "move-621" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 621/1023)" +needs = ["move-620"] + +[[steps]] +id = "move-622" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 622/1023)" +needs = ["move-621"] + +[[steps]] +id = "move-623" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 623/1023)" +needs = ["move-622"] + +[[steps]] +id = "move-624" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 624/1023)" +needs = ["move-623"] + +[[steps]] +id = "move-625" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 625/1023)" +needs = ["move-624"] + +[[steps]] +id = "move-626" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 626/1023)" +needs = ["move-625"] + +[[steps]] +id = "move-627" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 627/1023)" +needs = ["move-626"] + +[[steps]] +id = "move-628" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 628/1023)" +needs = ["move-627"] + +[[steps]] +id = "move-629" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 629/1023)" +needs = ["move-628"] + +[[steps]] +id = "move-630" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 630/1023)" +needs = ["move-629"] + +[[steps]] +id = "move-631" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 631/1023)" +needs = ["move-630"] + +[[steps]] +id = "move-632" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 632/1023)" +needs = ["move-631"] + +[[steps]] +id = "move-633" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 633/1023)" +needs = ["move-632"] + +[[steps]] +id = "move-634" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 634/1023)" +needs = ["move-633"] + +[[steps]] +id = "move-635" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 635/1023)" +needs = ["move-634"] + +[[steps]] +id = "move-636" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 636/1023)" +needs = ["move-635"] + +[[steps]] +id = "move-637" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 637/1023)" +needs = ["move-636"] + +[[steps]] +id = "move-638" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 638/1023)" +needs = ["move-637"] + +[[steps]] +id = "move-639" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 639/1023)" +needs = ["move-638"] + +[[steps]] +id = "move-640" +title = "Move disk 8: B → A" +description = "Move disk 8 from peg B to peg A. (Move 640/1023)" +needs = ["move-639"] + +[[steps]] +id = "move-641" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 641/1023)" +needs = ["move-640"] + +[[steps]] +id = "move-642" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 642/1023)" +needs = ["move-641"] + +[[steps]] +id = "move-643" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 643/1023)" +needs = ["move-642"] + +[[steps]] +id = "move-644" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 644/1023)" +needs = ["move-643"] + +[[steps]] +id = "move-645" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 645/1023)" +needs = ["move-644"] + +[[steps]] +id = "move-646" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 646/1023)" +needs = ["move-645"] + +[[steps]] +id = "move-647" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 647/1023)" +needs = ["move-646"] + +[[steps]] +id = "move-648" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 648/1023)" +needs = ["move-647"] + +[[steps]] +id = "move-649" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 649/1023)" +needs = ["move-648"] + +[[steps]] +id = "move-650" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 650/1023)" +needs = ["move-649"] + +[[steps]] +id = "move-651" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 651/1023)" +needs = ["move-650"] + +[[steps]] +id = "move-652" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 652/1023)" +needs = ["move-651"] + +[[steps]] +id = "move-653" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 653/1023)" +needs = ["move-652"] + +[[steps]] +id = "move-654" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 654/1023)" +needs = ["move-653"] + +[[steps]] +id = "move-655" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 655/1023)" +needs = ["move-654"] + +[[steps]] +id = "move-656" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 656/1023)" +needs = ["move-655"] + +[[steps]] +id = "move-657" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 657/1023)" +needs = ["move-656"] + +[[steps]] +id = "move-658" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 658/1023)" +needs = ["move-657"] + +[[steps]] +id = "move-659" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 659/1023)" +needs = ["move-658"] + +[[steps]] +id = "move-660" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 660/1023)" +needs = ["move-659"] + +[[steps]] +id = "move-661" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 661/1023)" +needs = ["move-660"] + +[[steps]] +id = "move-662" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 662/1023)" +needs = ["move-661"] + +[[steps]] +id = "move-663" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 663/1023)" +needs = ["move-662"] + +[[steps]] +id = "move-664" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 664/1023)" +needs = ["move-663"] + +[[steps]] +id = "move-665" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 665/1023)" +needs = ["move-664"] + +[[steps]] +id = "move-666" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 666/1023)" +needs = ["move-665"] + +[[steps]] +id = "move-667" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 667/1023)" +needs = ["move-666"] + +[[steps]] +id = "move-668" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 668/1023)" +needs = ["move-667"] + +[[steps]] +id = "move-669" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 669/1023)" +needs = ["move-668"] + +[[steps]] +id = "move-670" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 670/1023)" +needs = ["move-669"] + +[[steps]] +id = "move-671" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 671/1023)" +needs = ["move-670"] + +[[steps]] +id = "move-672" +title = "Move disk 6: C → B" +description = "Move disk 6 from peg C to peg B. (Move 672/1023)" +needs = ["move-671"] + +[[steps]] +id = "move-673" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 673/1023)" +needs = ["move-672"] + +[[steps]] +id = "move-674" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 674/1023)" +needs = ["move-673"] + +[[steps]] +id = "move-675" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 675/1023)" +needs = ["move-674"] + +[[steps]] +id = "move-676" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 676/1023)" +needs = ["move-675"] + +[[steps]] +id = "move-677" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 677/1023)" +needs = ["move-676"] + +[[steps]] +id = "move-678" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 678/1023)" +needs = ["move-677"] + +[[steps]] +id = "move-679" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 679/1023)" +needs = ["move-678"] + +[[steps]] +id = "move-680" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 680/1023)" +needs = ["move-679"] + +[[steps]] +id = "move-681" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 681/1023)" +needs = ["move-680"] + +[[steps]] +id = "move-682" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 682/1023)" +needs = ["move-681"] + +[[steps]] +id = "move-683" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 683/1023)" +needs = ["move-682"] + +[[steps]] +id = "move-684" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 684/1023)" +needs = ["move-683"] + +[[steps]] +id = "move-685" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 685/1023)" +needs = ["move-684"] + +[[steps]] +id = "move-686" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 686/1023)" +needs = ["move-685"] + +[[steps]] +id = "move-687" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 687/1023)" +needs = ["move-686"] + +[[steps]] +id = "move-688" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 688/1023)" +needs = ["move-687"] + +[[steps]] +id = "move-689" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 689/1023)" +needs = ["move-688"] + +[[steps]] +id = "move-690" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 690/1023)" +needs = ["move-689"] + +[[steps]] +id = "move-691" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 691/1023)" +needs = ["move-690"] + +[[steps]] +id = "move-692" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 692/1023)" +needs = ["move-691"] + +[[steps]] +id = "move-693" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 693/1023)" +needs = ["move-692"] + +[[steps]] +id = "move-694" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 694/1023)" +needs = ["move-693"] + +[[steps]] +id = "move-695" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 695/1023)" +needs = ["move-694"] + +[[steps]] +id = "move-696" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 696/1023)" +needs = ["move-695"] + +[[steps]] +id = "move-697" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 697/1023)" +needs = ["move-696"] + +[[steps]] +id = "move-698" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 698/1023)" +needs = ["move-697"] + +[[steps]] +id = "move-699" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 699/1023)" +needs = ["move-698"] + +[[steps]] +id = "move-700" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 700/1023)" +needs = ["move-699"] + +[[steps]] +id = "move-701" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 701/1023)" +needs = ["move-700"] + +[[steps]] +id = "move-702" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 702/1023)" +needs = ["move-701"] + +[[steps]] +id = "move-703" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 703/1023)" +needs = ["move-702"] + +[[steps]] +id = "move-704" +title = "Move disk 7: C → A" +description = "Move disk 7 from peg C to peg A. (Move 704/1023)" +needs = ["move-703"] + +[[steps]] +id = "move-705" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 705/1023)" +needs = ["move-704"] + +[[steps]] +id = "move-706" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 706/1023)" +needs = ["move-705"] + +[[steps]] +id = "move-707" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 707/1023)" +needs = ["move-706"] + +[[steps]] +id = "move-708" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 708/1023)" +needs = ["move-707"] + +[[steps]] +id = "move-709" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 709/1023)" +needs = ["move-708"] + +[[steps]] +id = "move-710" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 710/1023)" +needs = ["move-709"] + +[[steps]] +id = "move-711" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 711/1023)" +needs = ["move-710"] + +[[steps]] +id = "move-712" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 712/1023)" +needs = ["move-711"] + +[[steps]] +id = "move-713" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 713/1023)" +needs = ["move-712"] + +[[steps]] +id = "move-714" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 714/1023)" +needs = ["move-713"] + +[[steps]] +id = "move-715" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 715/1023)" +needs = ["move-714"] + +[[steps]] +id = "move-716" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 716/1023)" +needs = ["move-715"] + +[[steps]] +id = "move-717" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 717/1023)" +needs = ["move-716"] + +[[steps]] +id = "move-718" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 718/1023)" +needs = ["move-717"] + +[[steps]] +id = "move-719" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 719/1023)" +needs = ["move-718"] + +[[steps]] +id = "move-720" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 720/1023)" +needs = ["move-719"] + +[[steps]] +id = "move-721" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 721/1023)" +needs = ["move-720"] + +[[steps]] +id = "move-722" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 722/1023)" +needs = ["move-721"] + +[[steps]] +id = "move-723" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 723/1023)" +needs = ["move-722"] + +[[steps]] +id = "move-724" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 724/1023)" +needs = ["move-723"] + +[[steps]] +id = "move-725" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 725/1023)" +needs = ["move-724"] + +[[steps]] +id = "move-726" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 726/1023)" +needs = ["move-725"] + +[[steps]] +id = "move-727" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 727/1023)" +needs = ["move-726"] + +[[steps]] +id = "move-728" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 728/1023)" +needs = ["move-727"] + +[[steps]] +id = "move-729" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 729/1023)" +needs = ["move-728"] + +[[steps]] +id = "move-730" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 730/1023)" +needs = ["move-729"] + +[[steps]] +id = "move-731" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 731/1023)" +needs = ["move-730"] + +[[steps]] +id = "move-732" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 732/1023)" +needs = ["move-731"] + +[[steps]] +id = "move-733" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 733/1023)" +needs = ["move-732"] + +[[steps]] +id = "move-734" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 734/1023)" +needs = ["move-733"] + +[[steps]] +id = "move-735" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 735/1023)" +needs = ["move-734"] + +[[steps]] +id = "move-736" +title = "Move disk 6: B → A" +description = "Move disk 6 from peg B to peg A. (Move 736/1023)" +needs = ["move-735"] + +[[steps]] +id = "move-737" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 737/1023)" +needs = ["move-736"] + +[[steps]] +id = "move-738" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 738/1023)" +needs = ["move-737"] + +[[steps]] +id = "move-739" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 739/1023)" +needs = ["move-738"] + +[[steps]] +id = "move-740" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 740/1023)" +needs = ["move-739"] + +[[steps]] +id = "move-741" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 741/1023)" +needs = ["move-740"] + +[[steps]] +id = "move-742" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 742/1023)" +needs = ["move-741"] + +[[steps]] +id = "move-743" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 743/1023)" +needs = ["move-742"] + +[[steps]] +id = "move-744" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 744/1023)" +needs = ["move-743"] + +[[steps]] +id = "move-745" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 745/1023)" +needs = ["move-744"] + +[[steps]] +id = "move-746" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 746/1023)" +needs = ["move-745"] + +[[steps]] +id = "move-747" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 747/1023)" +needs = ["move-746"] + +[[steps]] +id = "move-748" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 748/1023)" +needs = ["move-747"] + +[[steps]] +id = "move-749" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 749/1023)" +needs = ["move-748"] + +[[steps]] +id = "move-750" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 750/1023)" +needs = ["move-749"] + +[[steps]] +id = "move-751" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 751/1023)" +needs = ["move-750"] + +[[steps]] +id = "move-752" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 752/1023)" +needs = ["move-751"] + +[[steps]] +id = "move-753" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 753/1023)" +needs = ["move-752"] + +[[steps]] +id = "move-754" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 754/1023)" +needs = ["move-753"] + +[[steps]] +id = "move-755" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 755/1023)" +needs = ["move-754"] + +[[steps]] +id = "move-756" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 756/1023)" +needs = ["move-755"] + +[[steps]] +id = "move-757" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 757/1023)" +needs = ["move-756"] + +[[steps]] +id = "move-758" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 758/1023)" +needs = ["move-757"] + +[[steps]] +id = "move-759" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 759/1023)" +needs = ["move-758"] + +[[steps]] +id = "move-760" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 760/1023)" +needs = ["move-759"] + +[[steps]] +id = "move-761" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 761/1023)" +needs = ["move-760"] + +[[steps]] +id = "move-762" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 762/1023)" +needs = ["move-761"] + +[[steps]] +id = "move-763" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 763/1023)" +needs = ["move-762"] + +[[steps]] +id = "move-764" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 764/1023)" +needs = ["move-763"] + +[[steps]] +id = "move-765" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 765/1023)" +needs = ["move-764"] + +[[steps]] +id = "move-766" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 766/1023)" +needs = ["move-765"] + +[[steps]] +id = "move-767" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 767/1023)" +needs = ["move-766"] + +[[steps]] +id = "move-768" +title = "Move disk 9: B → C" +description = "Move disk 9 from peg B to peg C. (Move 768/1023)" +needs = ["move-767"] + +[[steps]] +id = "move-769" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 769/1023)" +needs = ["move-768"] + +[[steps]] +id = "move-770" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 770/1023)" +needs = ["move-769"] + +[[steps]] +id = "move-771" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 771/1023)" +needs = ["move-770"] + +[[steps]] +id = "move-772" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 772/1023)" +needs = ["move-771"] + +[[steps]] +id = "move-773" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 773/1023)" +needs = ["move-772"] + +[[steps]] +id = "move-774" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 774/1023)" +needs = ["move-773"] + +[[steps]] +id = "move-775" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 775/1023)" +needs = ["move-774"] + +[[steps]] +id = "move-776" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 776/1023)" +needs = ["move-775"] + +[[steps]] +id = "move-777" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 777/1023)" +needs = ["move-776"] + +[[steps]] +id = "move-778" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 778/1023)" +needs = ["move-777"] + +[[steps]] +id = "move-779" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 779/1023)" +needs = ["move-778"] + +[[steps]] +id = "move-780" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 780/1023)" +needs = ["move-779"] + +[[steps]] +id = "move-781" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 781/1023)" +needs = ["move-780"] + +[[steps]] +id = "move-782" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 782/1023)" +needs = ["move-781"] + +[[steps]] +id = "move-783" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 783/1023)" +needs = ["move-782"] + +[[steps]] +id = "move-784" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 784/1023)" +needs = ["move-783"] + +[[steps]] +id = "move-785" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 785/1023)" +needs = ["move-784"] + +[[steps]] +id = "move-786" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 786/1023)" +needs = ["move-785"] + +[[steps]] +id = "move-787" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 787/1023)" +needs = ["move-786"] + +[[steps]] +id = "move-788" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 788/1023)" +needs = ["move-787"] + +[[steps]] +id = "move-789" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 789/1023)" +needs = ["move-788"] + +[[steps]] +id = "move-790" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 790/1023)" +needs = ["move-789"] + +[[steps]] +id = "move-791" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 791/1023)" +needs = ["move-790"] + +[[steps]] +id = "move-792" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 792/1023)" +needs = ["move-791"] + +[[steps]] +id = "move-793" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 793/1023)" +needs = ["move-792"] + +[[steps]] +id = "move-794" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 794/1023)" +needs = ["move-793"] + +[[steps]] +id = "move-795" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 795/1023)" +needs = ["move-794"] + +[[steps]] +id = "move-796" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 796/1023)" +needs = ["move-795"] + +[[steps]] +id = "move-797" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 797/1023)" +needs = ["move-796"] + +[[steps]] +id = "move-798" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 798/1023)" +needs = ["move-797"] + +[[steps]] +id = "move-799" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 799/1023)" +needs = ["move-798"] + +[[steps]] +id = "move-800" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 800/1023)" +needs = ["move-799"] + +[[steps]] +id = "move-801" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 801/1023)" +needs = ["move-800"] + +[[steps]] +id = "move-802" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 802/1023)" +needs = ["move-801"] + +[[steps]] +id = "move-803" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 803/1023)" +needs = ["move-802"] + +[[steps]] +id = "move-804" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 804/1023)" +needs = ["move-803"] + +[[steps]] +id = "move-805" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 805/1023)" +needs = ["move-804"] + +[[steps]] +id = "move-806" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 806/1023)" +needs = ["move-805"] + +[[steps]] +id = "move-807" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 807/1023)" +needs = ["move-806"] + +[[steps]] +id = "move-808" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 808/1023)" +needs = ["move-807"] + +[[steps]] +id = "move-809" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 809/1023)" +needs = ["move-808"] + +[[steps]] +id = "move-810" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 810/1023)" +needs = ["move-809"] + +[[steps]] +id = "move-811" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 811/1023)" +needs = ["move-810"] + +[[steps]] +id = "move-812" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 812/1023)" +needs = ["move-811"] + +[[steps]] +id = "move-813" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 813/1023)" +needs = ["move-812"] + +[[steps]] +id = "move-814" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 814/1023)" +needs = ["move-813"] + +[[steps]] +id = "move-815" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 815/1023)" +needs = ["move-814"] + +[[steps]] +id = "move-816" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 816/1023)" +needs = ["move-815"] + +[[steps]] +id = "move-817" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 817/1023)" +needs = ["move-816"] + +[[steps]] +id = "move-818" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 818/1023)" +needs = ["move-817"] + +[[steps]] +id = "move-819" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 819/1023)" +needs = ["move-818"] + +[[steps]] +id = "move-820" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 820/1023)" +needs = ["move-819"] + +[[steps]] +id = "move-821" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 821/1023)" +needs = ["move-820"] + +[[steps]] +id = "move-822" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 822/1023)" +needs = ["move-821"] + +[[steps]] +id = "move-823" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 823/1023)" +needs = ["move-822"] + +[[steps]] +id = "move-824" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 824/1023)" +needs = ["move-823"] + +[[steps]] +id = "move-825" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 825/1023)" +needs = ["move-824"] + +[[steps]] +id = "move-826" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 826/1023)" +needs = ["move-825"] + +[[steps]] +id = "move-827" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 827/1023)" +needs = ["move-826"] + +[[steps]] +id = "move-828" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 828/1023)" +needs = ["move-827"] + +[[steps]] +id = "move-829" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 829/1023)" +needs = ["move-828"] + +[[steps]] +id = "move-830" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 830/1023)" +needs = ["move-829"] + +[[steps]] +id = "move-831" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 831/1023)" +needs = ["move-830"] + +[[steps]] +id = "move-832" +title = "Move disk 7: A → B" +description = "Move disk 7 from peg A to peg B. (Move 832/1023)" +needs = ["move-831"] + +[[steps]] +id = "move-833" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 833/1023)" +needs = ["move-832"] + +[[steps]] +id = "move-834" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 834/1023)" +needs = ["move-833"] + +[[steps]] +id = "move-835" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 835/1023)" +needs = ["move-834"] + +[[steps]] +id = "move-836" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 836/1023)" +needs = ["move-835"] + +[[steps]] +id = "move-837" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 837/1023)" +needs = ["move-836"] + +[[steps]] +id = "move-838" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 838/1023)" +needs = ["move-837"] + +[[steps]] +id = "move-839" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 839/1023)" +needs = ["move-838"] + +[[steps]] +id = "move-840" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 840/1023)" +needs = ["move-839"] + +[[steps]] +id = "move-841" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 841/1023)" +needs = ["move-840"] + +[[steps]] +id = "move-842" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 842/1023)" +needs = ["move-841"] + +[[steps]] +id = "move-843" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 843/1023)" +needs = ["move-842"] + +[[steps]] +id = "move-844" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 844/1023)" +needs = ["move-843"] + +[[steps]] +id = "move-845" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 845/1023)" +needs = ["move-844"] + +[[steps]] +id = "move-846" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 846/1023)" +needs = ["move-845"] + +[[steps]] +id = "move-847" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 847/1023)" +needs = ["move-846"] + +[[steps]] +id = "move-848" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 848/1023)" +needs = ["move-847"] + +[[steps]] +id = "move-849" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 849/1023)" +needs = ["move-848"] + +[[steps]] +id = "move-850" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 850/1023)" +needs = ["move-849"] + +[[steps]] +id = "move-851" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 851/1023)" +needs = ["move-850"] + +[[steps]] +id = "move-852" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 852/1023)" +needs = ["move-851"] + +[[steps]] +id = "move-853" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 853/1023)" +needs = ["move-852"] + +[[steps]] +id = "move-854" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 854/1023)" +needs = ["move-853"] + +[[steps]] +id = "move-855" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 855/1023)" +needs = ["move-854"] + +[[steps]] +id = "move-856" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 856/1023)" +needs = ["move-855"] + +[[steps]] +id = "move-857" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 857/1023)" +needs = ["move-856"] + +[[steps]] +id = "move-858" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 858/1023)" +needs = ["move-857"] + +[[steps]] +id = "move-859" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 859/1023)" +needs = ["move-858"] + +[[steps]] +id = "move-860" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 860/1023)" +needs = ["move-859"] + +[[steps]] +id = "move-861" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 861/1023)" +needs = ["move-860"] + +[[steps]] +id = "move-862" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 862/1023)" +needs = ["move-861"] + +[[steps]] +id = "move-863" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 863/1023)" +needs = ["move-862"] + +[[steps]] +id = "move-864" +title = "Move disk 6: C → B" +description = "Move disk 6 from peg C to peg B. (Move 864/1023)" +needs = ["move-863"] + +[[steps]] +id = "move-865" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 865/1023)" +needs = ["move-864"] + +[[steps]] +id = "move-866" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 866/1023)" +needs = ["move-865"] + +[[steps]] +id = "move-867" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 867/1023)" +needs = ["move-866"] + +[[steps]] +id = "move-868" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 868/1023)" +needs = ["move-867"] + +[[steps]] +id = "move-869" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 869/1023)" +needs = ["move-868"] + +[[steps]] +id = "move-870" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 870/1023)" +needs = ["move-869"] + +[[steps]] +id = "move-871" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 871/1023)" +needs = ["move-870"] + +[[steps]] +id = "move-872" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 872/1023)" +needs = ["move-871"] + +[[steps]] +id = "move-873" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 873/1023)" +needs = ["move-872"] + +[[steps]] +id = "move-874" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 874/1023)" +needs = ["move-873"] + +[[steps]] +id = "move-875" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 875/1023)" +needs = ["move-874"] + +[[steps]] +id = "move-876" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 876/1023)" +needs = ["move-875"] + +[[steps]] +id = "move-877" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 877/1023)" +needs = ["move-876"] + +[[steps]] +id = "move-878" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 878/1023)" +needs = ["move-877"] + +[[steps]] +id = "move-879" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 879/1023)" +needs = ["move-878"] + +[[steps]] +id = "move-880" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 880/1023)" +needs = ["move-879"] + +[[steps]] +id = "move-881" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 881/1023)" +needs = ["move-880"] + +[[steps]] +id = "move-882" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 882/1023)" +needs = ["move-881"] + +[[steps]] +id = "move-883" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 883/1023)" +needs = ["move-882"] + +[[steps]] +id = "move-884" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 884/1023)" +needs = ["move-883"] + +[[steps]] +id = "move-885" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 885/1023)" +needs = ["move-884"] + +[[steps]] +id = "move-886" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 886/1023)" +needs = ["move-885"] + +[[steps]] +id = "move-887" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 887/1023)" +needs = ["move-886"] + +[[steps]] +id = "move-888" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 888/1023)" +needs = ["move-887"] + +[[steps]] +id = "move-889" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 889/1023)" +needs = ["move-888"] + +[[steps]] +id = "move-890" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 890/1023)" +needs = ["move-889"] + +[[steps]] +id = "move-891" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 891/1023)" +needs = ["move-890"] + +[[steps]] +id = "move-892" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 892/1023)" +needs = ["move-891"] + +[[steps]] +id = "move-893" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 893/1023)" +needs = ["move-892"] + +[[steps]] +id = "move-894" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 894/1023)" +needs = ["move-893"] + +[[steps]] +id = "move-895" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 895/1023)" +needs = ["move-894"] + +[[steps]] +id = "move-896" +title = "Move disk 8: A → C" +description = "Move disk 8 from peg A to peg C. (Move 896/1023)" +needs = ["move-895"] + +[[steps]] +id = "move-897" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 897/1023)" +needs = ["move-896"] + +[[steps]] +id = "move-898" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 898/1023)" +needs = ["move-897"] + +[[steps]] +id = "move-899" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 899/1023)" +needs = ["move-898"] + +[[steps]] +id = "move-900" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 900/1023)" +needs = ["move-899"] + +[[steps]] +id = "move-901" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 901/1023)" +needs = ["move-900"] + +[[steps]] +id = "move-902" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 902/1023)" +needs = ["move-901"] + +[[steps]] +id = "move-903" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 903/1023)" +needs = ["move-902"] + +[[steps]] +id = "move-904" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 904/1023)" +needs = ["move-903"] + +[[steps]] +id = "move-905" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 905/1023)" +needs = ["move-904"] + +[[steps]] +id = "move-906" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 906/1023)" +needs = ["move-905"] + +[[steps]] +id = "move-907" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 907/1023)" +needs = ["move-906"] + +[[steps]] +id = "move-908" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 908/1023)" +needs = ["move-907"] + +[[steps]] +id = "move-909" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 909/1023)" +needs = ["move-908"] + +[[steps]] +id = "move-910" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 910/1023)" +needs = ["move-909"] + +[[steps]] +id = "move-911" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 911/1023)" +needs = ["move-910"] + +[[steps]] +id = "move-912" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 912/1023)" +needs = ["move-911"] + +[[steps]] +id = "move-913" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 913/1023)" +needs = ["move-912"] + +[[steps]] +id = "move-914" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 914/1023)" +needs = ["move-913"] + +[[steps]] +id = "move-915" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 915/1023)" +needs = ["move-914"] + +[[steps]] +id = "move-916" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 916/1023)" +needs = ["move-915"] + +[[steps]] +id = "move-917" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 917/1023)" +needs = ["move-916"] + +[[steps]] +id = "move-918" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 918/1023)" +needs = ["move-917"] + +[[steps]] +id = "move-919" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 919/1023)" +needs = ["move-918"] + +[[steps]] +id = "move-920" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 920/1023)" +needs = ["move-919"] + +[[steps]] +id = "move-921" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 921/1023)" +needs = ["move-920"] + +[[steps]] +id = "move-922" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 922/1023)" +needs = ["move-921"] + +[[steps]] +id = "move-923" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 923/1023)" +needs = ["move-922"] + +[[steps]] +id = "move-924" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 924/1023)" +needs = ["move-923"] + +[[steps]] +id = "move-925" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 925/1023)" +needs = ["move-924"] + +[[steps]] +id = "move-926" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 926/1023)" +needs = ["move-925"] + +[[steps]] +id = "move-927" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 927/1023)" +needs = ["move-926"] + +[[steps]] +id = "move-928" +title = "Move disk 6: B → A" +description = "Move disk 6 from peg B to peg A. (Move 928/1023)" +needs = ["move-927"] + +[[steps]] +id = "move-929" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 929/1023)" +needs = ["move-928"] + +[[steps]] +id = "move-930" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 930/1023)" +needs = ["move-929"] + +[[steps]] +id = "move-931" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 931/1023)" +needs = ["move-930"] + +[[steps]] +id = "move-932" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 932/1023)" +needs = ["move-931"] + +[[steps]] +id = "move-933" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 933/1023)" +needs = ["move-932"] + +[[steps]] +id = "move-934" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 934/1023)" +needs = ["move-933"] + +[[steps]] +id = "move-935" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 935/1023)" +needs = ["move-934"] + +[[steps]] +id = "move-936" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 936/1023)" +needs = ["move-935"] + +[[steps]] +id = "move-937" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 937/1023)" +needs = ["move-936"] + +[[steps]] +id = "move-938" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 938/1023)" +needs = ["move-937"] + +[[steps]] +id = "move-939" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 939/1023)" +needs = ["move-938"] + +[[steps]] +id = "move-940" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 940/1023)" +needs = ["move-939"] + +[[steps]] +id = "move-941" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 941/1023)" +needs = ["move-940"] + +[[steps]] +id = "move-942" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 942/1023)" +needs = ["move-941"] + +[[steps]] +id = "move-943" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 943/1023)" +needs = ["move-942"] + +[[steps]] +id = "move-944" +title = "Move disk 5: C → A" +description = "Move disk 5 from peg C to peg A. (Move 944/1023)" +needs = ["move-943"] + +[[steps]] +id = "move-945" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 945/1023)" +needs = ["move-944"] + +[[steps]] +id = "move-946" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 946/1023)" +needs = ["move-945"] + +[[steps]] +id = "move-947" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 947/1023)" +needs = ["move-946"] + +[[steps]] +id = "move-948" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 948/1023)" +needs = ["move-947"] + +[[steps]] +id = "move-949" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 949/1023)" +needs = ["move-948"] + +[[steps]] +id = "move-950" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 950/1023)" +needs = ["move-949"] + +[[steps]] +id = "move-951" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 951/1023)" +needs = ["move-950"] + +[[steps]] +id = "move-952" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 952/1023)" +needs = ["move-951"] + +[[steps]] +id = "move-953" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 953/1023)" +needs = ["move-952"] + +[[steps]] +id = "move-954" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 954/1023)" +needs = ["move-953"] + +[[steps]] +id = "move-955" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 955/1023)" +needs = ["move-954"] + +[[steps]] +id = "move-956" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 956/1023)" +needs = ["move-955"] + +[[steps]] +id = "move-957" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 957/1023)" +needs = ["move-956"] + +[[steps]] +id = "move-958" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 958/1023)" +needs = ["move-957"] + +[[steps]] +id = "move-959" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 959/1023)" +needs = ["move-958"] + +[[steps]] +id = "move-960" +title = "Move disk 7: B → C" +description = "Move disk 7 from peg B to peg C. (Move 960/1023)" +needs = ["move-959"] + +[[steps]] +id = "move-961" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 961/1023)" +needs = ["move-960"] + +[[steps]] +id = "move-962" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 962/1023)" +needs = ["move-961"] + +[[steps]] +id = "move-963" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 963/1023)" +needs = ["move-962"] + +[[steps]] +id = "move-964" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 964/1023)" +needs = ["move-963"] + +[[steps]] +id = "move-965" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 965/1023)" +needs = ["move-964"] + +[[steps]] +id = "move-966" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 966/1023)" +needs = ["move-965"] + +[[steps]] +id = "move-967" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 967/1023)" +needs = ["move-966"] + +[[steps]] +id = "move-968" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 968/1023)" +needs = ["move-967"] + +[[steps]] +id = "move-969" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 969/1023)" +needs = ["move-968"] + +[[steps]] +id = "move-970" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 970/1023)" +needs = ["move-969"] + +[[steps]] +id = "move-971" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 971/1023)" +needs = ["move-970"] + +[[steps]] +id = "move-972" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 972/1023)" +needs = ["move-971"] + +[[steps]] +id = "move-973" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 973/1023)" +needs = ["move-972"] + +[[steps]] +id = "move-974" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 974/1023)" +needs = ["move-973"] + +[[steps]] +id = "move-975" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 975/1023)" +needs = ["move-974"] + +[[steps]] +id = "move-976" +title = "Move disk 5: A → B" +description = "Move disk 5 from peg A to peg B. (Move 976/1023)" +needs = ["move-975"] + +[[steps]] +id = "move-977" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 977/1023)" +needs = ["move-976"] + +[[steps]] +id = "move-978" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 978/1023)" +needs = ["move-977"] + +[[steps]] +id = "move-979" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 979/1023)" +needs = ["move-978"] + +[[steps]] +id = "move-980" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 980/1023)" +needs = ["move-979"] + +[[steps]] +id = "move-981" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 981/1023)" +needs = ["move-980"] + +[[steps]] +id = "move-982" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 982/1023)" +needs = ["move-981"] + +[[steps]] +id = "move-983" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 983/1023)" +needs = ["move-982"] + +[[steps]] +id = "move-984" +title = "Move disk 4: C → B" +description = "Move disk 4 from peg C to peg B. (Move 984/1023)" +needs = ["move-983"] + +[[steps]] +id = "move-985" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 985/1023)" +needs = ["move-984"] + +[[steps]] +id = "move-986" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 986/1023)" +needs = ["move-985"] + +[[steps]] +id = "move-987" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 987/1023)" +needs = ["move-986"] + +[[steps]] +id = "move-988" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 988/1023)" +needs = ["move-987"] + +[[steps]] +id = "move-989" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 989/1023)" +needs = ["move-988"] + +[[steps]] +id = "move-990" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 990/1023)" +needs = ["move-989"] + +[[steps]] +id = "move-991" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 991/1023)" +needs = ["move-990"] + +[[steps]] +id = "move-992" +title = "Move disk 6: A → C" +description = "Move disk 6 from peg A to peg C. (Move 992/1023)" +needs = ["move-991"] + +[[steps]] +id = "move-993" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 993/1023)" +needs = ["move-992"] + +[[steps]] +id = "move-994" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 994/1023)" +needs = ["move-993"] + +[[steps]] +id = "move-995" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 995/1023)" +needs = ["move-994"] + +[[steps]] +id = "move-996" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 996/1023)" +needs = ["move-995"] + +[[steps]] +id = "move-997" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 997/1023)" +needs = ["move-996"] + +[[steps]] +id = "move-998" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 998/1023)" +needs = ["move-997"] + +[[steps]] +id = "move-999" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 999/1023)" +needs = ["move-998"] + +[[steps]] +id = "move-1000" +title = "Move disk 4: B → A" +description = "Move disk 4 from peg B to peg A. (Move 1000/1023)" +needs = ["move-999"] + +[[steps]] +id = "move-1001" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 1001/1023)" +needs = ["move-1000"] + +[[steps]] +id = "move-1002" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 1002/1023)" +needs = ["move-1001"] + +[[steps]] +id = "move-1003" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 1003/1023)" +needs = ["move-1002"] + +[[steps]] +id = "move-1004" +title = "Move disk 3: C → A" +description = "Move disk 3 from peg C to peg A. (Move 1004/1023)" +needs = ["move-1003"] + +[[steps]] +id = "move-1005" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 1005/1023)" +needs = ["move-1004"] + +[[steps]] +id = "move-1006" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 1006/1023)" +needs = ["move-1005"] + +[[steps]] +id = "move-1007" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 1007/1023)" +needs = ["move-1006"] + +[[steps]] +id = "move-1008" +title = "Move disk 5: B → C" +description = "Move disk 5 from peg B to peg C. (Move 1008/1023)" +needs = ["move-1007"] + +[[steps]] +id = "move-1009" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 1009/1023)" +needs = ["move-1008"] + +[[steps]] +id = "move-1010" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 1010/1023)" +needs = ["move-1009"] + +[[steps]] +id = "move-1011" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 1011/1023)" +needs = ["move-1010"] + +[[steps]] +id = "move-1012" +title = "Move disk 3: A → B" +description = "Move disk 3 from peg A to peg B. (Move 1012/1023)" +needs = ["move-1011"] + +[[steps]] +id = "move-1013" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 1013/1023)" +needs = ["move-1012"] + +[[steps]] +id = "move-1014" +title = "Move disk 2: C → B" +description = "Move disk 2 from peg C to peg B. (Move 1014/1023)" +needs = ["move-1013"] + +[[steps]] +id = "move-1015" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 1015/1023)" +needs = ["move-1014"] + +[[steps]] +id = "move-1016" +title = "Move disk 4: A → C" +description = "Move disk 4 from peg A to peg C. (Move 1016/1023)" +needs = ["move-1015"] + +[[steps]] +id = "move-1017" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 1017/1023)" +needs = ["move-1016"] + +[[steps]] +id = "move-1018" +title = "Move disk 2: B → A" +description = "Move disk 2 from peg B to peg A. (Move 1018/1023)" +needs = ["move-1017"] + +[[steps]] +id = "move-1019" +title = "Move disk 1: C → A" +description = "Move disk 1 from peg C to peg A. (Move 1019/1023)" +needs = ["move-1018"] + +[[steps]] +id = "move-1020" +title = "Move disk 3: B → C" +description = "Move disk 3 from peg B to peg C. (Move 1020/1023)" +needs = ["move-1019"] + +[[steps]] +id = "move-1021" +title = "Move disk 1: A → B" +description = "Move disk 1 from peg A to peg B. (Move 1021/1023)" +needs = ["move-1020"] + +[[steps]] +id = "move-1022" +title = "Move disk 2: A → C" +description = "Move disk 2 from peg A to peg C. (Move 1022/1023)" +needs = ["move-1021"] + +[[steps]] +id = "move-1023" +title = "Move disk 1: B → C" +description = "Move disk 1 from peg B to peg C. (Move 1023/1023)" +needs = ["move-1022"] + +[[steps]] +id = "verify" +title = "Verify final state" +description = "All 10 disks now on peg C. Tower intact, all moves were legal." +needs = ["move-1023"] diff --git a/internal/formula/formulas/towers-of-hanoi-7.formula.toml b/internal/formula/formulas/towers-of-hanoi-7.formula.toml new file mode 100644 index 00000000..4ae41674 --- /dev/null +++ b/internal/formula/formulas/towers-of-hanoi-7.formula.toml @@ -0,0 +1,812 @@ +description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi (7 disks, 127 moves) + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi-7" +version = 1 + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All 7 disks stacked on peg A. Largest on bottom." + + +[[steps]] +id = "move-1" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 1/127)" +needs = ["setup"] + +[[steps]] +id = "move-2" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 2/127)" +needs = ["move-1"] + +[[steps]] +id = "move-3" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 3/127)" +needs = ["move-2"] + +[[steps]] +id = "move-4" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 4/127)" +needs = ["move-3"] + +[[steps]] +id = "move-5" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 5/127)" +needs = ["move-4"] + +[[steps]] +id = "move-6" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 6/127)" +needs = ["move-5"] + +[[steps]] +id = "move-7" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 7/127)" +needs = ["move-6"] + +[[steps]] +id = "move-8" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 8/127)" +needs = ["move-7"] + +[[steps]] +id = "move-9" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 9/127)" +needs = ["move-8"] + +[[steps]] +id = "move-10" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 10/127)" +needs = ["move-9"] + +[[steps]] +id = "move-11" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 11/127)" +needs = ["move-10"] + +[[steps]] +id = "move-12" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 12/127)" +needs = ["move-11"] + +[[steps]] +id = "move-13" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 13/127)" +needs = ["move-12"] + +[[steps]] +id = "move-14" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 14/127)" +needs = ["move-13"] + +[[steps]] +id = "move-15" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 15/127)" +needs = ["move-14"] + +[[steps]] +id = "move-16" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 16/127)" +needs = ["move-15"] + +[[steps]] +id = "move-17" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 17/127)" +needs = ["move-16"] + +[[steps]] +id = "move-18" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 18/127)" +needs = ["move-17"] + +[[steps]] +id = "move-19" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 19/127)" +needs = ["move-18"] + +[[steps]] +id = "move-20" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 20/127)" +needs = ["move-19"] + +[[steps]] +id = "move-21" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 21/127)" +needs = ["move-20"] + +[[steps]] +id = "move-22" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 22/127)" +needs = ["move-21"] + +[[steps]] +id = "move-23" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 23/127)" +needs = ["move-22"] + +[[steps]] +id = "move-24" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 24/127)" +needs = ["move-23"] + +[[steps]] +id = "move-25" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 25/127)" +needs = ["move-24"] + +[[steps]] +id = "move-26" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 26/127)" +needs = ["move-25"] + +[[steps]] +id = "move-27" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 27/127)" +needs = ["move-26"] + +[[steps]] +id = "move-28" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 28/127)" +needs = ["move-27"] + +[[steps]] +id = "move-29" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 29/127)" +needs = ["move-28"] + +[[steps]] +id = "move-30" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 30/127)" +needs = ["move-29"] + +[[steps]] +id = "move-31" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 31/127)" +needs = ["move-30"] + +[[steps]] +id = "move-32" +title = "Move disk 6: A → B" +description = "Move disk 6 from peg A to peg B. (Move 32/127)" +needs = ["move-31"] + +[[steps]] +id = "move-33" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 33/127)" +needs = ["move-32"] + +[[steps]] +id = "move-34" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 34/127)" +needs = ["move-33"] + +[[steps]] +id = "move-35" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 35/127)" +needs = ["move-34"] + +[[steps]] +id = "move-36" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 36/127)" +needs = ["move-35"] + +[[steps]] +id = "move-37" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 37/127)" +needs = ["move-36"] + +[[steps]] +id = "move-38" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 38/127)" +needs = ["move-37"] + +[[steps]] +id = "move-39" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 39/127)" +needs = ["move-38"] + +[[steps]] +id = "move-40" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 40/127)" +needs = ["move-39"] + +[[steps]] +id = "move-41" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 41/127)" +needs = ["move-40"] + +[[steps]] +id = "move-42" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 42/127)" +needs = ["move-41"] + +[[steps]] +id = "move-43" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 43/127)" +needs = ["move-42"] + +[[steps]] +id = "move-44" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 44/127)" +needs = ["move-43"] + +[[steps]] +id = "move-45" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 45/127)" +needs = ["move-44"] + +[[steps]] +id = "move-46" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 46/127)" +needs = ["move-45"] + +[[steps]] +id = "move-47" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 47/127)" +needs = ["move-46"] + +[[steps]] +id = "move-48" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 48/127)" +needs = ["move-47"] + +[[steps]] +id = "move-49" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 49/127)" +needs = ["move-48"] + +[[steps]] +id = "move-50" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 50/127)" +needs = ["move-49"] + +[[steps]] +id = "move-51" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 51/127)" +needs = ["move-50"] + +[[steps]] +id = "move-52" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 52/127)" +needs = ["move-51"] + +[[steps]] +id = "move-53" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 53/127)" +needs = ["move-52"] + +[[steps]] +id = "move-54" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 54/127)" +needs = ["move-53"] + +[[steps]] +id = "move-55" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 55/127)" +needs = ["move-54"] + +[[steps]] +id = "move-56" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 56/127)" +needs = ["move-55"] + +[[steps]] +id = "move-57" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 57/127)" +needs = ["move-56"] + +[[steps]] +id = "move-58" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 58/127)" +needs = ["move-57"] + +[[steps]] +id = "move-59" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 59/127)" +needs = ["move-58"] + +[[steps]] +id = "move-60" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 60/127)" +needs = ["move-59"] + +[[steps]] +id = "move-61" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 61/127)" +needs = ["move-60"] + +[[steps]] +id = "move-62" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 62/127)" +needs = ["move-61"] + +[[steps]] +id = "move-63" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 63/127)" +needs = ["move-62"] + +[[steps]] +id = "move-64" +title = "Move disk 7: A → C" +description = "Move disk 7 from peg A to peg C. (Move 64/127)" +needs = ["move-63"] + +[[steps]] +id = "move-65" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 65/127)" +needs = ["move-64"] + +[[steps]] +id = "move-66" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 66/127)" +needs = ["move-65"] + +[[steps]] +id = "move-67" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 67/127)" +needs = ["move-66"] + +[[steps]] +id = "move-68" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 68/127)" +needs = ["move-67"] + +[[steps]] +id = "move-69" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 69/127)" +needs = ["move-68"] + +[[steps]] +id = "move-70" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 70/127)" +needs = ["move-69"] + +[[steps]] +id = "move-71" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 71/127)" +needs = ["move-70"] + +[[steps]] +id = "move-72" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 72/127)" +needs = ["move-71"] + +[[steps]] +id = "move-73" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 73/127)" +needs = ["move-72"] + +[[steps]] +id = "move-74" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 74/127)" +needs = ["move-73"] + +[[steps]] +id = "move-75" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 75/127)" +needs = ["move-74"] + +[[steps]] +id = "move-76" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 76/127)" +needs = ["move-75"] + +[[steps]] +id = "move-77" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 77/127)" +needs = ["move-76"] + +[[steps]] +id = "move-78" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 78/127)" +needs = ["move-77"] + +[[steps]] +id = "move-79" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 79/127)" +needs = ["move-78"] + +[[steps]] +id = "move-80" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 80/127)" +needs = ["move-79"] + +[[steps]] +id = "move-81" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 81/127)" +needs = ["move-80"] + +[[steps]] +id = "move-82" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 82/127)" +needs = ["move-81"] + +[[steps]] +id = "move-83" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 83/127)" +needs = ["move-82"] + +[[steps]] +id = "move-84" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 84/127)" +needs = ["move-83"] + +[[steps]] +id = "move-85" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 85/127)" +needs = ["move-84"] + +[[steps]] +id = "move-86" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 86/127)" +needs = ["move-85"] + +[[steps]] +id = "move-87" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 87/127)" +needs = ["move-86"] + +[[steps]] +id = "move-88" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 88/127)" +needs = ["move-87"] + +[[steps]] +id = "move-89" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 89/127)" +needs = ["move-88"] + +[[steps]] +id = "move-90" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 90/127)" +needs = ["move-89"] + +[[steps]] +id = "move-91" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 91/127)" +needs = ["move-90"] + +[[steps]] +id = "move-92" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 92/127)" +needs = ["move-91"] + +[[steps]] +id = "move-93" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 93/127)" +needs = ["move-92"] + +[[steps]] +id = "move-94" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 94/127)" +needs = ["move-93"] + +[[steps]] +id = "move-95" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 95/127)" +needs = ["move-94"] + +[[steps]] +id = "move-96" +title = "Move disk 6: B → C" +description = "Move disk 6 from peg B to peg C. (Move 96/127)" +needs = ["move-95"] + +[[steps]] +id = "move-97" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 97/127)" +needs = ["move-96"] + +[[steps]] +id = "move-98" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 98/127)" +needs = ["move-97"] + +[[steps]] +id = "move-99" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 99/127)" +needs = ["move-98"] + +[[steps]] +id = "move-100" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 100/127)" +needs = ["move-99"] + +[[steps]] +id = "move-101" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 101/127)" +needs = ["move-100"] + +[[steps]] +id = "move-102" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 102/127)" +needs = ["move-101"] + +[[steps]] +id = "move-103" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 103/127)" +needs = ["move-102"] + +[[steps]] +id = "move-104" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 104/127)" +needs = ["move-103"] + +[[steps]] +id = "move-105" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 105/127)" +needs = ["move-104"] + +[[steps]] +id = "move-106" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 106/127)" +needs = ["move-105"] + +[[steps]] +id = "move-107" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 107/127)" +needs = ["move-106"] + +[[steps]] +id = "move-108" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 108/127)" +needs = ["move-107"] + +[[steps]] +id = "move-109" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 109/127)" +needs = ["move-108"] + +[[steps]] +id = "move-110" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 110/127)" +needs = ["move-109"] + +[[steps]] +id = "move-111" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 111/127)" +needs = ["move-110"] + +[[steps]] +id = "move-112" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 112/127)" +needs = ["move-111"] + +[[steps]] +id = "move-113" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 113/127)" +needs = ["move-112"] + +[[steps]] +id = "move-114" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 114/127)" +needs = ["move-113"] + +[[steps]] +id = "move-115" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 115/127)" +needs = ["move-114"] + +[[steps]] +id = "move-116" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 116/127)" +needs = ["move-115"] + +[[steps]] +id = "move-117" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 117/127)" +needs = ["move-116"] + +[[steps]] +id = "move-118" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 118/127)" +needs = ["move-117"] + +[[steps]] +id = "move-119" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 119/127)" +needs = ["move-118"] + +[[steps]] +id = "move-120" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 120/127)" +needs = ["move-119"] + +[[steps]] +id = "move-121" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 121/127)" +needs = ["move-120"] + +[[steps]] +id = "move-122" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 122/127)" +needs = ["move-121"] + +[[steps]] +id = "move-123" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 123/127)" +needs = ["move-122"] + +[[steps]] +id = "move-124" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 124/127)" +needs = ["move-123"] + +[[steps]] +id = "move-125" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 125/127)" +needs = ["move-124"] + +[[steps]] +id = "move-126" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 126/127)" +needs = ["move-125"] + +[[steps]] +id = "move-127" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 127/127)" +needs = ["move-126"] + +[[steps]] +id = "verify" +title = "Verify final state" +description = "All 7 disks now on peg C. Tower intact, all moves were legal." +needs = ["move-127"] diff --git a/internal/formula/formulas/towers-of-hanoi-9.formula.toml b/internal/formula/formulas/towers-of-hanoi-9.formula.toml new file mode 100644 index 00000000..44174481 --- /dev/null +++ b/internal/formula/formulas/towers-of-hanoi-9.formula.toml @@ -0,0 +1,3116 @@ +description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi (9 disks, 511 moves) + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi-9" +version = 1 + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All 9 disks stacked on peg A. Largest on bottom." + + +[[steps]] +id = "move-1" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 1/511)" +needs = ["setup"] + +[[steps]] +id = "move-2" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 2/511)" +needs = ["move-1"] + +[[steps]] +id = "move-3" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 3/511)" +needs = ["move-2"] + +[[steps]] +id = "move-4" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 4/511)" +needs = ["move-3"] + +[[steps]] +id = "move-5" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 5/511)" +needs = ["move-4"] + +[[steps]] +id = "move-6" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 6/511)" +needs = ["move-5"] + +[[steps]] +id = "move-7" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 7/511)" +needs = ["move-6"] + +[[steps]] +id = "move-8" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 8/511)" +needs = ["move-7"] + +[[steps]] +id = "move-9" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 9/511)" +needs = ["move-8"] + +[[steps]] +id = "move-10" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 10/511)" +needs = ["move-9"] + +[[steps]] +id = "move-11" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 11/511)" +needs = ["move-10"] + +[[steps]] +id = "move-12" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 12/511)" +needs = ["move-11"] + +[[steps]] +id = "move-13" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 13/511)" +needs = ["move-12"] + +[[steps]] +id = "move-14" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 14/511)" +needs = ["move-13"] + +[[steps]] +id = "move-15" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 15/511)" +needs = ["move-14"] + +[[steps]] +id = "move-16" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 16/511)" +needs = ["move-15"] + +[[steps]] +id = "move-17" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 17/511)" +needs = ["move-16"] + +[[steps]] +id = "move-18" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 18/511)" +needs = ["move-17"] + +[[steps]] +id = "move-19" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 19/511)" +needs = ["move-18"] + +[[steps]] +id = "move-20" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 20/511)" +needs = ["move-19"] + +[[steps]] +id = "move-21" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 21/511)" +needs = ["move-20"] + +[[steps]] +id = "move-22" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 22/511)" +needs = ["move-21"] + +[[steps]] +id = "move-23" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 23/511)" +needs = ["move-22"] + +[[steps]] +id = "move-24" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 24/511)" +needs = ["move-23"] + +[[steps]] +id = "move-25" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 25/511)" +needs = ["move-24"] + +[[steps]] +id = "move-26" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 26/511)" +needs = ["move-25"] + +[[steps]] +id = "move-27" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 27/511)" +needs = ["move-26"] + +[[steps]] +id = "move-28" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 28/511)" +needs = ["move-27"] + +[[steps]] +id = "move-29" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 29/511)" +needs = ["move-28"] + +[[steps]] +id = "move-30" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 30/511)" +needs = ["move-29"] + +[[steps]] +id = "move-31" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 31/511)" +needs = ["move-30"] + +[[steps]] +id = "move-32" +title = "Move disk 6: A → B" +description = "Move disk 6 from peg A to peg B. (Move 32/511)" +needs = ["move-31"] + +[[steps]] +id = "move-33" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 33/511)" +needs = ["move-32"] + +[[steps]] +id = "move-34" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 34/511)" +needs = ["move-33"] + +[[steps]] +id = "move-35" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 35/511)" +needs = ["move-34"] + +[[steps]] +id = "move-36" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 36/511)" +needs = ["move-35"] + +[[steps]] +id = "move-37" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 37/511)" +needs = ["move-36"] + +[[steps]] +id = "move-38" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 38/511)" +needs = ["move-37"] + +[[steps]] +id = "move-39" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 39/511)" +needs = ["move-38"] + +[[steps]] +id = "move-40" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 40/511)" +needs = ["move-39"] + +[[steps]] +id = "move-41" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 41/511)" +needs = ["move-40"] + +[[steps]] +id = "move-42" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 42/511)" +needs = ["move-41"] + +[[steps]] +id = "move-43" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 43/511)" +needs = ["move-42"] + +[[steps]] +id = "move-44" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 44/511)" +needs = ["move-43"] + +[[steps]] +id = "move-45" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 45/511)" +needs = ["move-44"] + +[[steps]] +id = "move-46" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 46/511)" +needs = ["move-45"] + +[[steps]] +id = "move-47" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 47/511)" +needs = ["move-46"] + +[[steps]] +id = "move-48" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 48/511)" +needs = ["move-47"] + +[[steps]] +id = "move-49" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 49/511)" +needs = ["move-48"] + +[[steps]] +id = "move-50" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 50/511)" +needs = ["move-49"] + +[[steps]] +id = "move-51" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 51/511)" +needs = ["move-50"] + +[[steps]] +id = "move-52" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 52/511)" +needs = ["move-51"] + +[[steps]] +id = "move-53" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 53/511)" +needs = ["move-52"] + +[[steps]] +id = "move-54" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 54/511)" +needs = ["move-53"] + +[[steps]] +id = "move-55" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 55/511)" +needs = ["move-54"] + +[[steps]] +id = "move-56" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 56/511)" +needs = ["move-55"] + +[[steps]] +id = "move-57" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 57/511)" +needs = ["move-56"] + +[[steps]] +id = "move-58" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 58/511)" +needs = ["move-57"] + +[[steps]] +id = "move-59" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 59/511)" +needs = ["move-58"] + +[[steps]] +id = "move-60" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 60/511)" +needs = ["move-59"] + +[[steps]] +id = "move-61" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 61/511)" +needs = ["move-60"] + +[[steps]] +id = "move-62" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 62/511)" +needs = ["move-61"] + +[[steps]] +id = "move-63" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 63/511)" +needs = ["move-62"] + +[[steps]] +id = "move-64" +title = "Move disk 7: A → C" +description = "Move disk 7 from peg A to peg C. (Move 64/511)" +needs = ["move-63"] + +[[steps]] +id = "move-65" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 65/511)" +needs = ["move-64"] + +[[steps]] +id = "move-66" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 66/511)" +needs = ["move-65"] + +[[steps]] +id = "move-67" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 67/511)" +needs = ["move-66"] + +[[steps]] +id = "move-68" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 68/511)" +needs = ["move-67"] + +[[steps]] +id = "move-69" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 69/511)" +needs = ["move-68"] + +[[steps]] +id = "move-70" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 70/511)" +needs = ["move-69"] + +[[steps]] +id = "move-71" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 71/511)" +needs = ["move-70"] + +[[steps]] +id = "move-72" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 72/511)" +needs = ["move-71"] + +[[steps]] +id = "move-73" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 73/511)" +needs = ["move-72"] + +[[steps]] +id = "move-74" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 74/511)" +needs = ["move-73"] + +[[steps]] +id = "move-75" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 75/511)" +needs = ["move-74"] + +[[steps]] +id = "move-76" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 76/511)" +needs = ["move-75"] + +[[steps]] +id = "move-77" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 77/511)" +needs = ["move-76"] + +[[steps]] +id = "move-78" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 78/511)" +needs = ["move-77"] + +[[steps]] +id = "move-79" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 79/511)" +needs = ["move-78"] + +[[steps]] +id = "move-80" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 80/511)" +needs = ["move-79"] + +[[steps]] +id = "move-81" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 81/511)" +needs = ["move-80"] + +[[steps]] +id = "move-82" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 82/511)" +needs = ["move-81"] + +[[steps]] +id = "move-83" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 83/511)" +needs = ["move-82"] + +[[steps]] +id = "move-84" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 84/511)" +needs = ["move-83"] + +[[steps]] +id = "move-85" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 85/511)" +needs = ["move-84"] + +[[steps]] +id = "move-86" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 86/511)" +needs = ["move-85"] + +[[steps]] +id = "move-87" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 87/511)" +needs = ["move-86"] + +[[steps]] +id = "move-88" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 88/511)" +needs = ["move-87"] + +[[steps]] +id = "move-89" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 89/511)" +needs = ["move-88"] + +[[steps]] +id = "move-90" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 90/511)" +needs = ["move-89"] + +[[steps]] +id = "move-91" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 91/511)" +needs = ["move-90"] + +[[steps]] +id = "move-92" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 92/511)" +needs = ["move-91"] + +[[steps]] +id = "move-93" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 93/511)" +needs = ["move-92"] + +[[steps]] +id = "move-94" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 94/511)" +needs = ["move-93"] + +[[steps]] +id = "move-95" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 95/511)" +needs = ["move-94"] + +[[steps]] +id = "move-96" +title = "Move disk 6: B → C" +description = "Move disk 6 from peg B to peg C. (Move 96/511)" +needs = ["move-95"] + +[[steps]] +id = "move-97" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 97/511)" +needs = ["move-96"] + +[[steps]] +id = "move-98" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 98/511)" +needs = ["move-97"] + +[[steps]] +id = "move-99" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 99/511)" +needs = ["move-98"] + +[[steps]] +id = "move-100" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 100/511)" +needs = ["move-99"] + +[[steps]] +id = "move-101" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 101/511)" +needs = ["move-100"] + +[[steps]] +id = "move-102" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 102/511)" +needs = ["move-101"] + +[[steps]] +id = "move-103" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 103/511)" +needs = ["move-102"] + +[[steps]] +id = "move-104" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 104/511)" +needs = ["move-103"] + +[[steps]] +id = "move-105" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 105/511)" +needs = ["move-104"] + +[[steps]] +id = "move-106" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 106/511)" +needs = ["move-105"] + +[[steps]] +id = "move-107" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 107/511)" +needs = ["move-106"] + +[[steps]] +id = "move-108" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 108/511)" +needs = ["move-107"] + +[[steps]] +id = "move-109" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 109/511)" +needs = ["move-108"] + +[[steps]] +id = "move-110" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 110/511)" +needs = ["move-109"] + +[[steps]] +id = "move-111" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 111/511)" +needs = ["move-110"] + +[[steps]] +id = "move-112" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 112/511)" +needs = ["move-111"] + +[[steps]] +id = "move-113" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 113/511)" +needs = ["move-112"] + +[[steps]] +id = "move-114" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 114/511)" +needs = ["move-113"] + +[[steps]] +id = "move-115" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 115/511)" +needs = ["move-114"] + +[[steps]] +id = "move-116" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 116/511)" +needs = ["move-115"] + +[[steps]] +id = "move-117" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 117/511)" +needs = ["move-116"] + +[[steps]] +id = "move-118" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 118/511)" +needs = ["move-117"] + +[[steps]] +id = "move-119" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 119/511)" +needs = ["move-118"] + +[[steps]] +id = "move-120" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 120/511)" +needs = ["move-119"] + +[[steps]] +id = "move-121" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 121/511)" +needs = ["move-120"] + +[[steps]] +id = "move-122" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 122/511)" +needs = ["move-121"] + +[[steps]] +id = "move-123" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 123/511)" +needs = ["move-122"] + +[[steps]] +id = "move-124" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 124/511)" +needs = ["move-123"] + +[[steps]] +id = "move-125" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 125/511)" +needs = ["move-124"] + +[[steps]] +id = "move-126" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 126/511)" +needs = ["move-125"] + +[[steps]] +id = "move-127" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 127/511)" +needs = ["move-126"] + +[[steps]] +id = "move-128" +title = "Move disk 8: A → B" +description = "Move disk 8 from peg A to peg B. (Move 128/511)" +needs = ["move-127"] + +[[steps]] +id = "move-129" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 129/511)" +needs = ["move-128"] + +[[steps]] +id = "move-130" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 130/511)" +needs = ["move-129"] + +[[steps]] +id = "move-131" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 131/511)" +needs = ["move-130"] + +[[steps]] +id = "move-132" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 132/511)" +needs = ["move-131"] + +[[steps]] +id = "move-133" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 133/511)" +needs = ["move-132"] + +[[steps]] +id = "move-134" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 134/511)" +needs = ["move-133"] + +[[steps]] +id = "move-135" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 135/511)" +needs = ["move-134"] + +[[steps]] +id = "move-136" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 136/511)" +needs = ["move-135"] + +[[steps]] +id = "move-137" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 137/511)" +needs = ["move-136"] + +[[steps]] +id = "move-138" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 138/511)" +needs = ["move-137"] + +[[steps]] +id = "move-139" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 139/511)" +needs = ["move-138"] + +[[steps]] +id = "move-140" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 140/511)" +needs = ["move-139"] + +[[steps]] +id = "move-141" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 141/511)" +needs = ["move-140"] + +[[steps]] +id = "move-142" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 142/511)" +needs = ["move-141"] + +[[steps]] +id = "move-143" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 143/511)" +needs = ["move-142"] + +[[steps]] +id = "move-144" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 144/511)" +needs = ["move-143"] + +[[steps]] +id = "move-145" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 145/511)" +needs = ["move-144"] + +[[steps]] +id = "move-146" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 146/511)" +needs = ["move-145"] + +[[steps]] +id = "move-147" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 147/511)" +needs = ["move-146"] + +[[steps]] +id = "move-148" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 148/511)" +needs = ["move-147"] + +[[steps]] +id = "move-149" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 149/511)" +needs = ["move-148"] + +[[steps]] +id = "move-150" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 150/511)" +needs = ["move-149"] + +[[steps]] +id = "move-151" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 151/511)" +needs = ["move-150"] + +[[steps]] +id = "move-152" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 152/511)" +needs = ["move-151"] + +[[steps]] +id = "move-153" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 153/511)" +needs = ["move-152"] + +[[steps]] +id = "move-154" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 154/511)" +needs = ["move-153"] + +[[steps]] +id = "move-155" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 155/511)" +needs = ["move-154"] + +[[steps]] +id = "move-156" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 156/511)" +needs = ["move-155"] + +[[steps]] +id = "move-157" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 157/511)" +needs = ["move-156"] + +[[steps]] +id = "move-158" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 158/511)" +needs = ["move-157"] + +[[steps]] +id = "move-159" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 159/511)" +needs = ["move-158"] + +[[steps]] +id = "move-160" +title = "Move disk 6: C → A" +description = "Move disk 6 from peg C to peg A. (Move 160/511)" +needs = ["move-159"] + +[[steps]] +id = "move-161" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 161/511)" +needs = ["move-160"] + +[[steps]] +id = "move-162" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 162/511)" +needs = ["move-161"] + +[[steps]] +id = "move-163" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 163/511)" +needs = ["move-162"] + +[[steps]] +id = "move-164" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 164/511)" +needs = ["move-163"] + +[[steps]] +id = "move-165" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 165/511)" +needs = ["move-164"] + +[[steps]] +id = "move-166" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 166/511)" +needs = ["move-165"] + +[[steps]] +id = "move-167" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 167/511)" +needs = ["move-166"] + +[[steps]] +id = "move-168" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 168/511)" +needs = ["move-167"] + +[[steps]] +id = "move-169" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 169/511)" +needs = ["move-168"] + +[[steps]] +id = "move-170" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 170/511)" +needs = ["move-169"] + +[[steps]] +id = "move-171" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 171/511)" +needs = ["move-170"] + +[[steps]] +id = "move-172" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 172/511)" +needs = ["move-171"] + +[[steps]] +id = "move-173" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 173/511)" +needs = ["move-172"] + +[[steps]] +id = "move-174" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 174/511)" +needs = ["move-173"] + +[[steps]] +id = "move-175" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 175/511)" +needs = ["move-174"] + +[[steps]] +id = "move-176" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 176/511)" +needs = ["move-175"] + +[[steps]] +id = "move-177" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 177/511)" +needs = ["move-176"] + +[[steps]] +id = "move-178" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 178/511)" +needs = ["move-177"] + +[[steps]] +id = "move-179" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 179/511)" +needs = ["move-178"] + +[[steps]] +id = "move-180" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 180/511)" +needs = ["move-179"] + +[[steps]] +id = "move-181" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 181/511)" +needs = ["move-180"] + +[[steps]] +id = "move-182" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 182/511)" +needs = ["move-181"] + +[[steps]] +id = "move-183" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 183/511)" +needs = ["move-182"] + +[[steps]] +id = "move-184" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 184/511)" +needs = ["move-183"] + +[[steps]] +id = "move-185" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 185/511)" +needs = ["move-184"] + +[[steps]] +id = "move-186" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 186/511)" +needs = ["move-185"] + +[[steps]] +id = "move-187" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 187/511)" +needs = ["move-186"] + +[[steps]] +id = "move-188" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 188/511)" +needs = ["move-187"] + +[[steps]] +id = "move-189" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 189/511)" +needs = ["move-188"] + +[[steps]] +id = "move-190" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 190/511)" +needs = ["move-189"] + +[[steps]] +id = "move-191" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 191/511)" +needs = ["move-190"] + +[[steps]] +id = "move-192" +title = "Move disk 7: C → B" +description = "Move disk 7 from peg C to peg B. (Move 192/511)" +needs = ["move-191"] + +[[steps]] +id = "move-193" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 193/511)" +needs = ["move-192"] + +[[steps]] +id = "move-194" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 194/511)" +needs = ["move-193"] + +[[steps]] +id = "move-195" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 195/511)" +needs = ["move-194"] + +[[steps]] +id = "move-196" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 196/511)" +needs = ["move-195"] + +[[steps]] +id = "move-197" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 197/511)" +needs = ["move-196"] + +[[steps]] +id = "move-198" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 198/511)" +needs = ["move-197"] + +[[steps]] +id = "move-199" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 199/511)" +needs = ["move-198"] + +[[steps]] +id = "move-200" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 200/511)" +needs = ["move-199"] + +[[steps]] +id = "move-201" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 201/511)" +needs = ["move-200"] + +[[steps]] +id = "move-202" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 202/511)" +needs = ["move-201"] + +[[steps]] +id = "move-203" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 203/511)" +needs = ["move-202"] + +[[steps]] +id = "move-204" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 204/511)" +needs = ["move-203"] + +[[steps]] +id = "move-205" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 205/511)" +needs = ["move-204"] + +[[steps]] +id = "move-206" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 206/511)" +needs = ["move-205"] + +[[steps]] +id = "move-207" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 207/511)" +needs = ["move-206"] + +[[steps]] +id = "move-208" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 208/511)" +needs = ["move-207"] + +[[steps]] +id = "move-209" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 209/511)" +needs = ["move-208"] + +[[steps]] +id = "move-210" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 210/511)" +needs = ["move-209"] + +[[steps]] +id = "move-211" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 211/511)" +needs = ["move-210"] + +[[steps]] +id = "move-212" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 212/511)" +needs = ["move-211"] + +[[steps]] +id = "move-213" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 213/511)" +needs = ["move-212"] + +[[steps]] +id = "move-214" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 214/511)" +needs = ["move-213"] + +[[steps]] +id = "move-215" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 215/511)" +needs = ["move-214"] + +[[steps]] +id = "move-216" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 216/511)" +needs = ["move-215"] + +[[steps]] +id = "move-217" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 217/511)" +needs = ["move-216"] + +[[steps]] +id = "move-218" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 218/511)" +needs = ["move-217"] + +[[steps]] +id = "move-219" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 219/511)" +needs = ["move-218"] + +[[steps]] +id = "move-220" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 220/511)" +needs = ["move-219"] + +[[steps]] +id = "move-221" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 221/511)" +needs = ["move-220"] + +[[steps]] +id = "move-222" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 222/511)" +needs = ["move-221"] + +[[steps]] +id = "move-223" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 223/511)" +needs = ["move-222"] + +[[steps]] +id = "move-224" +title = "Move disk 6: A → B" +description = "Move disk 6 from peg A to peg B. (Move 224/511)" +needs = ["move-223"] + +[[steps]] +id = "move-225" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 225/511)" +needs = ["move-224"] + +[[steps]] +id = "move-226" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 226/511)" +needs = ["move-225"] + +[[steps]] +id = "move-227" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 227/511)" +needs = ["move-226"] + +[[steps]] +id = "move-228" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 228/511)" +needs = ["move-227"] + +[[steps]] +id = "move-229" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 229/511)" +needs = ["move-228"] + +[[steps]] +id = "move-230" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 230/511)" +needs = ["move-229"] + +[[steps]] +id = "move-231" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 231/511)" +needs = ["move-230"] + +[[steps]] +id = "move-232" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 232/511)" +needs = ["move-231"] + +[[steps]] +id = "move-233" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 233/511)" +needs = ["move-232"] + +[[steps]] +id = "move-234" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 234/511)" +needs = ["move-233"] + +[[steps]] +id = "move-235" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 235/511)" +needs = ["move-234"] + +[[steps]] +id = "move-236" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 236/511)" +needs = ["move-235"] + +[[steps]] +id = "move-237" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 237/511)" +needs = ["move-236"] + +[[steps]] +id = "move-238" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 238/511)" +needs = ["move-237"] + +[[steps]] +id = "move-239" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 239/511)" +needs = ["move-238"] + +[[steps]] +id = "move-240" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 240/511)" +needs = ["move-239"] + +[[steps]] +id = "move-241" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 241/511)" +needs = ["move-240"] + +[[steps]] +id = "move-242" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 242/511)" +needs = ["move-241"] + +[[steps]] +id = "move-243" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 243/511)" +needs = ["move-242"] + +[[steps]] +id = "move-244" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 244/511)" +needs = ["move-243"] + +[[steps]] +id = "move-245" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 245/511)" +needs = ["move-244"] + +[[steps]] +id = "move-246" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 246/511)" +needs = ["move-245"] + +[[steps]] +id = "move-247" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 247/511)" +needs = ["move-246"] + +[[steps]] +id = "move-248" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 248/511)" +needs = ["move-247"] + +[[steps]] +id = "move-249" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 249/511)" +needs = ["move-248"] + +[[steps]] +id = "move-250" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 250/511)" +needs = ["move-249"] + +[[steps]] +id = "move-251" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 251/511)" +needs = ["move-250"] + +[[steps]] +id = "move-252" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 252/511)" +needs = ["move-251"] + +[[steps]] +id = "move-253" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 253/511)" +needs = ["move-252"] + +[[steps]] +id = "move-254" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 254/511)" +needs = ["move-253"] + +[[steps]] +id = "move-255" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 255/511)" +needs = ["move-254"] + +[[steps]] +id = "move-256" +title = "Move disk 9: A → C" +description = "Move disk 9 from peg A to peg C. (Move 256/511)" +needs = ["move-255"] + +[[steps]] +id = "move-257" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 257/511)" +needs = ["move-256"] + +[[steps]] +id = "move-258" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 258/511)" +needs = ["move-257"] + +[[steps]] +id = "move-259" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 259/511)" +needs = ["move-258"] + +[[steps]] +id = "move-260" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 260/511)" +needs = ["move-259"] + +[[steps]] +id = "move-261" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 261/511)" +needs = ["move-260"] + +[[steps]] +id = "move-262" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 262/511)" +needs = ["move-261"] + +[[steps]] +id = "move-263" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 263/511)" +needs = ["move-262"] + +[[steps]] +id = "move-264" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 264/511)" +needs = ["move-263"] + +[[steps]] +id = "move-265" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 265/511)" +needs = ["move-264"] + +[[steps]] +id = "move-266" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 266/511)" +needs = ["move-265"] + +[[steps]] +id = "move-267" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 267/511)" +needs = ["move-266"] + +[[steps]] +id = "move-268" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 268/511)" +needs = ["move-267"] + +[[steps]] +id = "move-269" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 269/511)" +needs = ["move-268"] + +[[steps]] +id = "move-270" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 270/511)" +needs = ["move-269"] + +[[steps]] +id = "move-271" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 271/511)" +needs = ["move-270"] + +[[steps]] +id = "move-272" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 272/511)" +needs = ["move-271"] + +[[steps]] +id = "move-273" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 273/511)" +needs = ["move-272"] + +[[steps]] +id = "move-274" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 274/511)" +needs = ["move-273"] + +[[steps]] +id = "move-275" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 275/511)" +needs = ["move-274"] + +[[steps]] +id = "move-276" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 276/511)" +needs = ["move-275"] + +[[steps]] +id = "move-277" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 277/511)" +needs = ["move-276"] + +[[steps]] +id = "move-278" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 278/511)" +needs = ["move-277"] + +[[steps]] +id = "move-279" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 279/511)" +needs = ["move-278"] + +[[steps]] +id = "move-280" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 280/511)" +needs = ["move-279"] + +[[steps]] +id = "move-281" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 281/511)" +needs = ["move-280"] + +[[steps]] +id = "move-282" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 282/511)" +needs = ["move-281"] + +[[steps]] +id = "move-283" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 283/511)" +needs = ["move-282"] + +[[steps]] +id = "move-284" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 284/511)" +needs = ["move-283"] + +[[steps]] +id = "move-285" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 285/511)" +needs = ["move-284"] + +[[steps]] +id = "move-286" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 286/511)" +needs = ["move-285"] + +[[steps]] +id = "move-287" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 287/511)" +needs = ["move-286"] + +[[steps]] +id = "move-288" +title = "Move disk 6: B → C" +description = "Move disk 6 from peg B to peg C. (Move 288/511)" +needs = ["move-287"] + +[[steps]] +id = "move-289" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 289/511)" +needs = ["move-288"] + +[[steps]] +id = "move-290" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 290/511)" +needs = ["move-289"] + +[[steps]] +id = "move-291" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 291/511)" +needs = ["move-290"] + +[[steps]] +id = "move-292" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 292/511)" +needs = ["move-291"] + +[[steps]] +id = "move-293" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 293/511)" +needs = ["move-292"] + +[[steps]] +id = "move-294" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 294/511)" +needs = ["move-293"] + +[[steps]] +id = "move-295" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 295/511)" +needs = ["move-294"] + +[[steps]] +id = "move-296" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 296/511)" +needs = ["move-295"] + +[[steps]] +id = "move-297" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 297/511)" +needs = ["move-296"] + +[[steps]] +id = "move-298" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 298/511)" +needs = ["move-297"] + +[[steps]] +id = "move-299" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 299/511)" +needs = ["move-298"] + +[[steps]] +id = "move-300" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 300/511)" +needs = ["move-299"] + +[[steps]] +id = "move-301" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 301/511)" +needs = ["move-300"] + +[[steps]] +id = "move-302" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 302/511)" +needs = ["move-301"] + +[[steps]] +id = "move-303" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 303/511)" +needs = ["move-302"] + +[[steps]] +id = "move-304" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 304/511)" +needs = ["move-303"] + +[[steps]] +id = "move-305" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 305/511)" +needs = ["move-304"] + +[[steps]] +id = "move-306" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 306/511)" +needs = ["move-305"] + +[[steps]] +id = "move-307" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 307/511)" +needs = ["move-306"] + +[[steps]] +id = "move-308" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 308/511)" +needs = ["move-307"] + +[[steps]] +id = "move-309" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 309/511)" +needs = ["move-308"] + +[[steps]] +id = "move-310" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 310/511)" +needs = ["move-309"] + +[[steps]] +id = "move-311" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 311/511)" +needs = ["move-310"] + +[[steps]] +id = "move-312" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 312/511)" +needs = ["move-311"] + +[[steps]] +id = "move-313" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 313/511)" +needs = ["move-312"] + +[[steps]] +id = "move-314" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 314/511)" +needs = ["move-313"] + +[[steps]] +id = "move-315" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 315/511)" +needs = ["move-314"] + +[[steps]] +id = "move-316" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 316/511)" +needs = ["move-315"] + +[[steps]] +id = "move-317" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 317/511)" +needs = ["move-316"] + +[[steps]] +id = "move-318" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 318/511)" +needs = ["move-317"] + +[[steps]] +id = "move-319" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 319/511)" +needs = ["move-318"] + +[[steps]] +id = "move-320" +title = "Move disk 7: B → A" +description = "Move disk 7 from peg B to peg A. (Move 320/511)" +needs = ["move-319"] + +[[steps]] +id = "move-321" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 321/511)" +needs = ["move-320"] + +[[steps]] +id = "move-322" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 322/511)" +needs = ["move-321"] + +[[steps]] +id = "move-323" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 323/511)" +needs = ["move-322"] + +[[steps]] +id = "move-324" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 324/511)" +needs = ["move-323"] + +[[steps]] +id = "move-325" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 325/511)" +needs = ["move-324"] + +[[steps]] +id = "move-326" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 326/511)" +needs = ["move-325"] + +[[steps]] +id = "move-327" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 327/511)" +needs = ["move-326"] + +[[steps]] +id = "move-328" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 328/511)" +needs = ["move-327"] + +[[steps]] +id = "move-329" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 329/511)" +needs = ["move-328"] + +[[steps]] +id = "move-330" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 330/511)" +needs = ["move-329"] + +[[steps]] +id = "move-331" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 331/511)" +needs = ["move-330"] + +[[steps]] +id = "move-332" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 332/511)" +needs = ["move-331"] + +[[steps]] +id = "move-333" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 333/511)" +needs = ["move-332"] + +[[steps]] +id = "move-334" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 334/511)" +needs = ["move-333"] + +[[steps]] +id = "move-335" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 335/511)" +needs = ["move-334"] + +[[steps]] +id = "move-336" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 336/511)" +needs = ["move-335"] + +[[steps]] +id = "move-337" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 337/511)" +needs = ["move-336"] + +[[steps]] +id = "move-338" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 338/511)" +needs = ["move-337"] + +[[steps]] +id = "move-339" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 339/511)" +needs = ["move-338"] + +[[steps]] +id = "move-340" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 340/511)" +needs = ["move-339"] + +[[steps]] +id = "move-341" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 341/511)" +needs = ["move-340"] + +[[steps]] +id = "move-342" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 342/511)" +needs = ["move-341"] + +[[steps]] +id = "move-343" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 343/511)" +needs = ["move-342"] + +[[steps]] +id = "move-344" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 344/511)" +needs = ["move-343"] + +[[steps]] +id = "move-345" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 345/511)" +needs = ["move-344"] + +[[steps]] +id = "move-346" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 346/511)" +needs = ["move-345"] + +[[steps]] +id = "move-347" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 347/511)" +needs = ["move-346"] + +[[steps]] +id = "move-348" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 348/511)" +needs = ["move-347"] + +[[steps]] +id = "move-349" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 349/511)" +needs = ["move-348"] + +[[steps]] +id = "move-350" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 350/511)" +needs = ["move-349"] + +[[steps]] +id = "move-351" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 351/511)" +needs = ["move-350"] + +[[steps]] +id = "move-352" +title = "Move disk 6: C → A" +description = "Move disk 6 from peg C to peg A. (Move 352/511)" +needs = ["move-351"] + +[[steps]] +id = "move-353" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 353/511)" +needs = ["move-352"] + +[[steps]] +id = "move-354" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 354/511)" +needs = ["move-353"] + +[[steps]] +id = "move-355" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 355/511)" +needs = ["move-354"] + +[[steps]] +id = "move-356" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 356/511)" +needs = ["move-355"] + +[[steps]] +id = "move-357" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 357/511)" +needs = ["move-356"] + +[[steps]] +id = "move-358" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 358/511)" +needs = ["move-357"] + +[[steps]] +id = "move-359" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 359/511)" +needs = ["move-358"] + +[[steps]] +id = "move-360" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 360/511)" +needs = ["move-359"] + +[[steps]] +id = "move-361" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 361/511)" +needs = ["move-360"] + +[[steps]] +id = "move-362" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 362/511)" +needs = ["move-361"] + +[[steps]] +id = "move-363" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 363/511)" +needs = ["move-362"] + +[[steps]] +id = "move-364" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 364/511)" +needs = ["move-363"] + +[[steps]] +id = "move-365" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 365/511)" +needs = ["move-364"] + +[[steps]] +id = "move-366" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 366/511)" +needs = ["move-365"] + +[[steps]] +id = "move-367" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 367/511)" +needs = ["move-366"] + +[[steps]] +id = "move-368" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 368/511)" +needs = ["move-367"] + +[[steps]] +id = "move-369" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 369/511)" +needs = ["move-368"] + +[[steps]] +id = "move-370" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 370/511)" +needs = ["move-369"] + +[[steps]] +id = "move-371" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 371/511)" +needs = ["move-370"] + +[[steps]] +id = "move-372" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 372/511)" +needs = ["move-371"] + +[[steps]] +id = "move-373" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 373/511)" +needs = ["move-372"] + +[[steps]] +id = "move-374" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 374/511)" +needs = ["move-373"] + +[[steps]] +id = "move-375" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 375/511)" +needs = ["move-374"] + +[[steps]] +id = "move-376" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 376/511)" +needs = ["move-375"] + +[[steps]] +id = "move-377" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 377/511)" +needs = ["move-376"] + +[[steps]] +id = "move-378" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 378/511)" +needs = ["move-377"] + +[[steps]] +id = "move-379" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 379/511)" +needs = ["move-378"] + +[[steps]] +id = "move-380" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 380/511)" +needs = ["move-379"] + +[[steps]] +id = "move-381" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 381/511)" +needs = ["move-380"] + +[[steps]] +id = "move-382" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 382/511)" +needs = ["move-381"] + +[[steps]] +id = "move-383" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 383/511)" +needs = ["move-382"] + +[[steps]] +id = "move-384" +title = "Move disk 8: B → C" +description = "Move disk 8 from peg B to peg C. (Move 384/511)" +needs = ["move-383"] + +[[steps]] +id = "move-385" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 385/511)" +needs = ["move-384"] + +[[steps]] +id = "move-386" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 386/511)" +needs = ["move-385"] + +[[steps]] +id = "move-387" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 387/511)" +needs = ["move-386"] + +[[steps]] +id = "move-388" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 388/511)" +needs = ["move-387"] + +[[steps]] +id = "move-389" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 389/511)" +needs = ["move-388"] + +[[steps]] +id = "move-390" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 390/511)" +needs = ["move-389"] + +[[steps]] +id = "move-391" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 391/511)" +needs = ["move-390"] + +[[steps]] +id = "move-392" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 392/511)" +needs = ["move-391"] + +[[steps]] +id = "move-393" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 393/511)" +needs = ["move-392"] + +[[steps]] +id = "move-394" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 394/511)" +needs = ["move-393"] + +[[steps]] +id = "move-395" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 395/511)" +needs = ["move-394"] + +[[steps]] +id = "move-396" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 396/511)" +needs = ["move-395"] + +[[steps]] +id = "move-397" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 397/511)" +needs = ["move-396"] + +[[steps]] +id = "move-398" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 398/511)" +needs = ["move-397"] + +[[steps]] +id = "move-399" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 399/511)" +needs = ["move-398"] + +[[steps]] +id = "move-400" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 400/511)" +needs = ["move-399"] + +[[steps]] +id = "move-401" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 401/511)" +needs = ["move-400"] + +[[steps]] +id = "move-402" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 402/511)" +needs = ["move-401"] + +[[steps]] +id = "move-403" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 403/511)" +needs = ["move-402"] + +[[steps]] +id = "move-404" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 404/511)" +needs = ["move-403"] + +[[steps]] +id = "move-405" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 405/511)" +needs = ["move-404"] + +[[steps]] +id = "move-406" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 406/511)" +needs = ["move-405"] + +[[steps]] +id = "move-407" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 407/511)" +needs = ["move-406"] + +[[steps]] +id = "move-408" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 408/511)" +needs = ["move-407"] + +[[steps]] +id = "move-409" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 409/511)" +needs = ["move-408"] + +[[steps]] +id = "move-410" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 410/511)" +needs = ["move-409"] + +[[steps]] +id = "move-411" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 411/511)" +needs = ["move-410"] + +[[steps]] +id = "move-412" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 412/511)" +needs = ["move-411"] + +[[steps]] +id = "move-413" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 413/511)" +needs = ["move-412"] + +[[steps]] +id = "move-414" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 414/511)" +needs = ["move-413"] + +[[steps]] +id = "move-415" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 415/511)" +needs = ["move-414"] + +[[steps]] +id = "move-416" +title = "Move disk 6: A → B" +description = "Move disk 6 from peg A to peg B. (Move 416/511)" +needs = ["move-415"] + +[[steps]] +id = "move-417" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 417/511)" +needs = ["move-416"] + +[[steps]] +id = "move-418" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 418/511)" +needs = ["move-417"] + +[[steps]] +id = "move-419" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 419/511)" +needs = ["move-418"] + +[[steps]] +id = "move-420" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 420/511)" +needs = ["move-419"] + +[[steps]] +id = "move-421" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 421/511)" +needs = ["move-420"] + +[[steps]] +id = "move-422" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 422/511)" +needs = ["move-421"] + +[[steps]] +id = "move-423" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 423/511)" +needs = ["move-422"] + +[[steps]] +id = "move-424" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 424/511)" +needs = ["move-423"] + +[[steps]] +id = "move-425" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 425/511)" +needs = ["move-424"] + +[[steps]] +id = "move-426" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 426/511)" +needs = ["move-425"] + +[[steps]] +id = "move-427" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 427/511)" +needs = ["move-426"] + +[[steps]] +id = "move-428" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 428/511)" +needs = ["move-427"] + +[[steps]] +id = "move-429" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 429/511)" +needs = ["move-428"] + +[[steps]] +id = "move-430" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 430/511)" +needs = ["move-429"] + +[[steps]] +id = "move-431" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 431/511)" +needs = ["move-430"] + +[[steps]] +id = "move-432" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 432/511)" +needs = ["move-431"] + +[[steps]] +id = "move-433" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 433/511)" +needs = ["move-432"] + +[[steps]] +id = "move-434" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 434/511)" +needs = ["move-433"] + +[[steps]] +id = "move-435" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 435/511)" +needs = ["move-434"] + +[[steps]] +id = "move-436" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 436/511)" +needs = ["move-435"] + +[[steps]] +id = "move-437" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 437/511)" +needs = ["move-436"] + +[[steps]] +id = "move-438" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 438/511)" +needs = ["move-437"] + +[[steps]] +id = "move-439" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 439/511)" +needs = ["move-438"] + +[[steps]] +id = "move-440" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 440/511)" +needs = ["move-439"] + +[[steps]] +id = "move-441" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 441/511)" +needs = ["move-440"] + +[[steps]] +id = "move-442" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 442/511)" +needs = ["move-441"] + +[[steps]] +id = "move-443" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 443/511)" +needs = ["move-442"] + +[[steps]] +id = "move-444" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 444/511)" +needs = ["move-443"] + +[[steps]] +id = "move-445" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 445/511)" +needs = ["move-444"] + +[[steps]] +id = "move-446" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 446/511)" +needs = ["move-445"] + +[[steps]] +id = "move-447" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 447/511)" +needs = ["move-446"] + +[[steps]] +id = "move-448" +title = "Move disk 7: A → C" +description = "Move disk 7 from peg A to peg C. (Move 448/511)" +needs = ["move-447"] + +[[steps]] +id = "move-449" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 449/511)" +needs = ["move-448"] + +[[steps]] +id = "move-450" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 450/511)" +needs = ["move-449"] + +[[steps]] +id = "move-451" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 451/511)" +needs = ["move-450"] + +[[steps]] +id = "move-452" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 452/511)" +needs = ["move-451"] + +[[steps]] +id = "move-453" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 453/511)" +needs = ["move-452"] + +[[steps]] +id = "move-454" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 454/511)" +needs = ["move-453"] + +[[steps]] +id = "move-455" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 455/511)" +needs = ["move-454"] + +[[steps]] +id = "move-456" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 456/511)" +needs = ["move-455"] + +[[steps]] +id = "move-457" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 457/511)" +needs = ["move-456"] + +[[steps]] +id = "move-458" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 458/511)" +needs = ["move-457"] + +[[steps]] +id = "move-459" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 459/511)" +needs = ["move-458"] + +[[steps]] +id = "move-460" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 460/511)" +needs = ["move-459"] + +[[steps]] +id = "move-461" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 461/511)" +needs = ["move-460"] + +[[steps]] +id = "move-462" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 462/511)" +needs = ["move-461"] + +[[steps]] +id = "move-463" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 463/511)" +needs = ["move-462"] + +[[steps]] +id = "move-464" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 464/511)" +needs = ["move-463"] + +[[steps]] +id = "move-465" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 465/511)" +needs = ["move-464"] + +[[steps]] +id = "move-466" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 466/511)" +needs = ["move-465"] + +[[steps]] +id = "move-467" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 467/511)" +needs = ["move-466"] + +[[steps]] +id = "move-468" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 468/511)" +needs = ["move-467"] + +[[steps]] +id = "move-469" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 469/511)" +needs = ["move-468"] + +[[steps]] +id = "move-470" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 470/511)" +needs = ["move-469"] + +[[steps]] +id = "move-471" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 471/511)" +needs = ["move-470"] + +[[steps]] +id = "move-472" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 472/511)" +needs = ["move-471"] + +[[steps]] +id = "move-473" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 473/511)" +needs = ["move-472"] + +[[steps]] +id = "move-474" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 474/511)" +needs = ["move-473"] + +[[steps]] +id = "move-475" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 475/511)" +needs = ["move-474"] + +[[steps]] +id = "move-476" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 476/511)" +needs = ["move-475"] + +[[steps]] +id = "move-477" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 477/511)" +needs = ["move-476"] + +[[steps]] +id = "move-478" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 478/511)" +needs = ["move-477"] + +[[steps]] +id = "move-479" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 479/511)" +needs = ["move-478"] + +[[steps]] +id = "move-480" +title = "Move disk 6: B → C" +description = "Move disk 6 from peg B to peg C. (Move 480/511)" +needs = ["move-479"] + +[[steps]] +id = "move-481" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 481/511)" +needs = ["move-480"] + +[[steps]] +id = "move-482" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 482/511)" +needs = ["move-481"] + +[[steps]] +id = "move-483" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 483/511)" +needs = ["move-482"] + +[[steps]] +id = "move-484" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 484/511)" +needs = ["move-483"] + +[[steps]] +id = "move-485" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 485/511)" +needs = ["move-484"] + +[[steps]] +id = "move-486" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 486/511)" +needs = ["move-485"] + +[[steps]] +id = "move-487" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 487/511)" +needs = ["move-486"] + +[[steps]] +id = "move-488" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 488/511)" +needs = ["move-487"] + +[[steps]] +id = "move-489" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 489/511)" +needs = ["move-488"] + +[[steps]] +id = "move-490" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 490/511)" +needs = ["move-489"] + +[[steps]] +id = "move-491" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 491/511)" +needs = ["move-490"] + +[[steps]] +id = "move-492" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 492/511)" +needs = ["move-491"] + +[[steps]] +id = "move-493" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 493/511)" +needs = ["move-492"] + +[[steps]] +id = "move-494" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 494/511)" +needs = ["move-493"] + +[[steps]] +id = "move-495" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 495/511)" +needs = ["move-494"] + +[[steps]] +id = "move-496" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 496/511)" +needs = ["move-495"] + +[[steps]] +id = "move-497" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 497/511)" +needs = ["move-496"] + +[[steps]] +id = "move-498" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 498/511)" +needs = ["move-497"] + +[[steps]] +id = "move-499" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 499/511)" +needs = ["move-498"] + +[[steps]] +id = "move-500" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 500/511)" +needs = ["move-499"] + +[[steps]] +id = "move-501" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 501/511)" +needs = ["move-500"] + +[[steps]] +id = "move-502" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 502/511)" +needs = ["move-501"] + +[[steps]] +id = "move-503" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 503/511)" +needs = ["move-502"] + +[[steps]] +id = "move-504" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 504/511)" +needs = ["move-503"] + +[[steps]] +id = "move-505" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 505/511)" +needs = ["move-504"] + +[[steps]] +id = "move-506" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 506/511)" +needs = ["move-505"] + +[[steps]] +id = "move-507" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 507/511)" +needs = ["move-506"] + +[[steps]] +id = "move-508" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 508/511)" +needs = ["move-507"] + +[[steps]] +id = "move-509" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 509/511)" +needs = ["move-508"] + +[[steps]] +id = "move-510" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 510/511)" +needs = ["move-509"] + +[[steps]] +id = "move-511" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 511/511)" +needs = ["move-510"] + +[[steps]] +id = "verify" +title = "Verify final state" +description = "All 9 disks now on peg C. Tower intact, all moves were legal." +needs = ["move-511"] diff --git a/internal/formula/formulas/towers-of-hanoi.formula.toml b/internal/formula/formulas/towers-of-hanoi.formula.toml new file mode 100644 index 00000000..cd698cf0 --- /dev/null +++ b/internal/formula/formulas/towers-of-hanoi.formula.toml @@ -0,0 +1,105 @@ +description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi" +version = 2 + +[vars] +[vars.source_peg] +default = "A" +description = "Starting peg" +[vars.target_peg] +default = "C" +description = "Target peg" +[vars.auxiliary_peg] +default = "B" +description = "Helper peg" + +# 3-disk solution: 7 moves (2^3 - 1) +# Each step is a simple acknowledgment - the agent just closes it. + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All 3 disks stacked on peg A. Largest on bottom." + +[[steps]] +id = "move-1" +title = "Move disk 1: A → C" +description = "Move the smallest disk from peg A to peg C." +needs = ["setup"] + +[[steps]] +id = "move-2" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B." +needs = ["move-1"] + +[[steps]] +id = "move-3" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B." +needs = ["move-2"] + +[[steps]] +id = "move-4" +title = "Move disk 3: A → C" +description = "Move the largest disk from peg A to peg C." +needs = ["move-3"] + +[[steps]] +id = "move-5" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A." +needs = ["move-4"] + +[[steps]] +id = "move-6" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C." +needs = ["move-5"] + +[[steps]] +id = "move-7" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C." +needs = ["move-6"] + +[[steps]] +id = "verify" +title = "Verify final state" +description = "All 3 disks now on peg C. Tower intact, all moves were legal." +needs = ["move-7"] From 7a1ed80068cca482f3f04734fc987c1c3b4cd6b8 Mon Sep 17 00:00:00 2001 From: gastown/crew/gus Date: Fri, 9 Jan 2026 21:54:54 -0800 Subject: [PATCH 14/14] fix: remove unused identity parameter from setSessionEnvironment --- internal/daemon/lifecycle.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/daemon/lifecycle.go b/internal/daemon/lifecycle.go index 9b0c317f..c46126f4 100644 --- a/internal/daemon/lifecycle.go +++ b/internal/daemon/lifecycle.go @@ -371,7 +371,7 @@ func (d *Daemon) restartSession(sessionName, identity string) error { } // Set environment variables - d.setSessionEnvironment(sessionName, identity, config, parsed) + d.setSessionEnvironment(sessionName, config, parsed) // Apply theme (non-fatal: theming failure doesn't affect operation) d.applySessionTheme(sessionName, parsed) @@ -488,7 +488,7 @@ func (d *Daemon) getStartCommand(roleConfig *beads.RoleConfig, parsed *ParsedIde // setSessionEnvironment sets environment variables for the tmux session. // Uses centralized AgentEnv for consistency, plus role bead custom env vars if available. -func (d *Daemon) setSessionEnvironment(sessionName, identity string, roleConfig *beads.RoleConfig, parsed *ParsedIdentity) { +func (d *Daemon) setSessionEnvironment(sessionName string, roleConfig *beads.RoleConfig, parsed *ParsedIdentity) { // Determine beads dir based on role type var beadsPath string if parsed.RigName != "" {