From dd0fb7ce905a16c8b771977e77e95f99801b7b66 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Thu, 25 Dec 2025 01:05:01 -0800 Subject: [PATCH] Remove bd mol run - orchestration belongs in gt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bd mol run was a convenience combo (pour + assign + pin + start) that felt like orchestration but lived in the data layer. This blurred the architectural boundary between bd (data) and gt (orchestration). - Delete cmd/bd/mol_run.go entirely - Update mol.go help text to remove run reference - Update mol_current.go to suggest bd pour instead gt spawn will implement the orchestration combo by calling the atomic bd commands (pour, update, pin) directly. Closes bd-00u3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cmd/bd/mol.go | 1 - cmd/bd/mol_current.go | 2 +- cmd/bd/mol_run.go | 177 ------------------------------------------ 3 files changed, 1 insertion(+), 179 deletions(-) delete mode 100644 cmd/bd/mol_run.go diff --git a/cmd/bd/mol.go b/cmd/bd/mol.go index 315f8b89..01c9cf65 100644 --- a/cmd/bd/mol.go +++ b/cmd/bd/mol.go @@ -51,7 +51,6 @@ Commands: catalog List available protos show Show proto/molecule structure and variables bond Polymorphic combine: proto+proto, proto+mol, mol+mol - run Pour + assign + pin for durable execution distill Extract proto from ad-hoc epic See also: diff --git a/cmd/bd/mol_current.go b/cmd/bd/mol_current.go index 6860f040..95a6651f 100644 --- a/cmd/bd/mol_current.go +++ b/cmd/bd/mol_current.go @@ -100,7 +100,7 @@ The output shows all steps with status indicators: } fmt.Println(".") fmt.Println("\nTo start work on a molecule:") - fmt.Println(" bd mol run # Spawn and start a new molecule") + fmt.Println(" bd pour # Instantiate a molecule from template") fmt.Println(" bd update --status in_progress # Claim a step") return } diff --git a/cmd/bd/mol_run.go b/cmd/bd/mol_run.go deleted file mode 100644 index 8d2b1c4d..00000000 --- a/cmd/bd/mol_run.go +++ /dev/null @@ -1,177 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" - - "github.com/spf13/cobra" - "github.com/steveyegge/beads/internal/beads" - "github.com/steveyegge/beads/internal/storage/sqlite" - "github.com/steveyegge/beads/internal/types" - "github.com/steveyegge/beads/internal/ui" -) - -var molRunCmd = &cobra.Command{ - Use: "run ", - Short: "Spawn proto and start execution (spawn + assign + pin)", - Long: `Run a molecule by spawning a proto and setting up for durable execution. - -This command: - 1. Spawns the molecule (creates issues from proto template) - 2. Assigns the root issue to the caller - 3. Sets root status to in_progress - 4. Pins the root issue for session recovery - -The proto can be specified by ID or title. Title matching is case-insensitive -and supports partial matches (e.g., "polecat" matches "mol-polecat-work"). - -After a crash or session reset, the pinned root issue ensures the agent -can resume from where it left off by checking 'bd ready'. - -The --template-db flag enables cross-database spawning: read templates from -one database (e.g., main) while writing spawned instances to another (e.g., wisp). -This is essential for wisp molecule spawning where templates exist in the main -database but instances should be ephemeral. - -Example: - bd mol run mol-polecat-work --var issue=gt-xxx # By title - bd mol run gt-lwuu --var issue=gt-xxx # By ID - bd mol run polecat --var issue=gt-xxx # By partial title - bd --db .beads-wisp/beads.db mol run mol-patrol --template-db .beads/beads.db`, - Args: cobra.ExactArgs(1), - Run: runMolRun, -} - -func runMolRun(cmd *cobra.Command, args []string) { - CheckReadonly("mol run") - - ctx := rootCtx - - // mol run requires direct store access - if store == nil { - if daemonClient != nil { - fmt.Fprintf(os.Stderr, "Error: mol run requires direct database access\n") - fmt.Fprintf(os.Stderr, "Hint: use --no-daemon flag: bd --no-daemon mol run %s ...\n", args[0]) - } else { - fmt.Fprintf(os.Stderr, "Error: no database connection\n") - } - os.Exit(1) - } - - varFlags, _ := cmd.Flags().GetStringSlice("var") - templateDB, _ := cmd.Flags().GetString("template-db") - - // Parse variables - vars := make(map[string]string) - for _, v := range varFlags { - parts := strings.SplitN(v, "=", 2) - if len(parts) != 2 { - fmt.Fprintf(os.Stderr, "Error: invalid variable format '%s', expected 'key=value'\n", v) - os.Exit(1) - } - vars[parts[0]] = parts[1] - } - - // Determine which store to use for reading the template - // If --template-db is set, open a separate connection for reading the template - // This enables cross-database spawning (read from main, write to wisp) - // - // Auto-discovery: if --db contains ".beads-wisp" (wisp storage) but --template-db - // is not set, automatically use the main database for templates. This handles the - // common case of spawning patrol molecules from main DB into wisp storage. - templateStore := store - if templateDB == "" && strings.Contains(dbPath, ".beads-wisp") { - // Auto-discover main database for templates - templateDB = beads.FindDatabasePath() - if templateDB == "" { - fmt.Fprintf(os.Stderr, "Error: cannot find main database for templates\n") - fmt.Fprintf(os.Stderr, "Hint: specify --template-db explicitly\n") - os.Exit(1) - } - } - if templateDB != "" { - var err error - templateStore, err = sqlite.NewWithTimeout(ctx, templateDB, lockTimeout) - if err != nil { - fmt.Fprintf(os.Stderr, "Error opening template database %s: %v\n", templateDB, err) - os.Exit(1) - } - defer func() { _ = templateStore.Close() }() - } - - // Resolve molecule ID from template store (supports both ID and title - bd-drcx) - moleculeID, err := resolveProtoIDOrTitle(ctx, templateStore, args[0]) - if err != nil { - fmt.Fprintf(os.Stderr, "Error resolving molecule %s: %v\n", args[0], err) - os.Exit(1) - } - - // Load the molecule subgraph from template store - subgraph, err := loadTemplateSubgraph(ctx, templateStore, moleculeID) - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading molecule: %v\n", err) - os.Exit(1) - } - - // Check for missing variables - requiredVars := extractAllVariables(subgraph) - var missingVars []string - for _, v := range requiredVars { - if _, ok := vars[v]; !ok { - missingVars = append(missingVars, v) - } - } - if len(missingVars) > 0 { - fmt.Fprintf(os.Stderr, "Error: missing required variables: %s\n", strings.Join(missingVars, ", ")) - fmt.Fprintf(os.Stderr, "Provide them with: --var %s=\n", missingVars[0]) - os.Exit(1) - } - - // Spawn the molecule with actor as assignee (wisp for cleanup - bd-2vh3) - result, err := spawnMolecule(ctx, store, subgraph, vars, actor, actor, true) - if err != nil { - fmt.Fprintf(os.Stderr, "Error spawning molecule: %v\n", err) - os.Exit(1) - } - - // Update root issue: set status=in_progress and pinned=true - rootID := result.NewEpicID - updates := map[string]interface{}{ - "status": string(types.StatusInProgress), - "pinned": true, - } - if err := store.UpdateIssue(ctx, rootID, updates, actor); err != nil { - fmt.Fprintf(os.Stderr, "Error updating root issue: %v\n", err) - os.Exit(1) - } - - // Schedule auto-flush - markDirtyAndScheduleFlush() - - if jsonOutput { - outputJSON(map[string]interface{}{ - "root_id": rootID, - "created": result.Created, - "id_mapping": result.IDMapping, - "pinned": true, - "status": "in_progress", - "assignee": actor, - }) - return - } - - fmt.Printf("%s Molecule running: created %d issues\n", ui.RenderPass("✓"), result.Created) - fmt.Printf(" Root issue: %s (pinned, in_progress)\n", rootID) - fmt.Printf(" Assignee: %s\n", actor) - fmt.Println("\nNext steps:") - fmt.Printf(" bd ready # Find unblocked work in this molecule\n") - fmt.Printf(" bd show %s # View molecule status\n", rootID) -} - -func init() { - molRunCmd.Flags().StringSlice("var", []string{}, "Variable substitution (key=value)") - molRunCmd.Flags().String("template-db", "", "Database to read templates from (enables cross-database spawning)") - - molCmd.AddCommand(molRunCmd) -}