Files
beads/cmd/bd/mol.go
Steve Yegge ee04b1ea96 feat: add dynamic molecule bonding with --ref flag (bd-xo1o.1)
Implements the Christmas Ornament pattern for patrol molecules:
- Add CloneOptions struct with ParentID and ChildRef for dynamic bonding
- Add generateBondedID() to create custom IDs like "patrol-x7k.arm-ace"
- Add --ref flag to `bd mol bond` for custom child references
- Variable substitution in childRef (e.g., "arm-{{polecat_name}}")

This enables:
  bd mol bond mol-polecat-arm bd-patrol --ref arm-{{name}} --var name=ace
  # Creates: bd-patrol.arm-ace, bd-patrol.arm-ace.capture, etc.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 03:38:38 -08:00

90 lines
3.5 KiB
Go

package main
import (
"context"
"github.com/spf13/cobra"
"github.com/steveyegge/beads/internal/storage"
)
// Molecule commands - work templates for agent workflows
//
// Terminology:
// - Proto: Uninstantiated template (easter egg: 'protomolecule' alias)
// - Molecule: A spawned instance of a proto
// - Spawn: Instantiate a proto, creating real issues from the template
// - Bond: Polymorphic combine operation (proto+proto, proto+mol, mol+mol)
// - Distill: Extract ad-hoc epic → reusable proto
// - Compound: Result of bonding
//
// Usage:
// bd mol catalog # List available protos
// bd mol show <id> # Show proto/molecule structure
// bd mol spawn <id> --var key=value # Instantiate proto → molecule
// MoleculeLabel is the label used to identify molecules (templates)
// Molecules use the same label as templates - they ARE templates with workflow semantics
const MoleculeLabel = BeadsTemplateLabel
// MoleculeSubgraph is an alias for TemplateSubgraph
// Molecules and templates share the same subgraph structure
type MoleculeSubgraph = TemplateSubgraph
var molCmd = &cobra.Command{
Use: "mol",
Aliases: []string{"protomolecule"}, // Easter egg for The Expanse fans
Short: "Molecule commands (work templates)",
Long: `Manage molecules - work templates for agent workflows.
Protos are template epics with the "template" label. They define a DAG of work
that can be spawned to create real issues (molecules).
The molecule metaphor:
- A proto is an uninstantiated template (reusable work pattern)
- Spawning creates a molecule (real issues) from the proto
- Variables ({{key}}) are substituted during spawning
- Bonding combines protos or molecules into compounds
- Distilling extracts a proto from an ad-hoc epic
Commands:
catalog List available protos
show Show proto/molecule structure and variables
spawn Instantiate a proto → molecule
bond Polymorphic combine: proto+proto, proto+mol, mol+mol
run Spawn + assign + pin for durable execution
distill Extract proto from ad-hoc epic (reverse of spawn)`,
}
// =============================================================================
// Molecule Helper Functions
// =============================================================================
// spawnMolecule creates new issues from the proto with variable substitution.
// This instantiates a proto (template) into a molecule (real issues).
// Wraps cloneSubgraph from template.go and returns InstantiateResult.
// If ephemeral is true, spawned issues are marked for bulk deletion when closed.
func spawnMolecule(ctx context.Context, s storage.Storage, subgraph *MoleculeSubgraph, vars map[string]string, assignee string, actorName string, ephemeral bool) (*InstantiateResult, error) {
opts := CloneOptions{
Vars: vars,
Assignee: assignee,
Actor: actorName,
Wisp: ephemeral,
}
return cloneSubgraph(ctx, s, subgraph, opts)
}
// spawnMoleculeWithOptions creates new issues from the proto using CloneOptions.
// This allows full control over dynamic bonding, variable substitution, and wisp phase.
func spawnMoleculeWithOptions(ctx context.Context, s storage.Storage, subgraph *MoleculeSubgraph, opts CloneOptions) (*InstantiateResult, error) {
return cloneSubgraph(ctx, s, subgraph, opts)
}
// printMoleculeTree prints the molecule structure as a tree
func printMoleculeTree(subgraph *MoleculeSubgraph, parentID string, depth int, isRoot bool) {
printTemplateTree(subgraph, parentID, depth, isRoot)
}
func init() {
rootCmd.AddCommand(molCmd)
}