terminology: spawn → pour/wisp for molecules (gt-9uy0)
Molecules use chemistry verbs, not spawn: - pour = create persistent mol (liquid) - wisp = create ephemeral wisp (vapor) - spawn = polecats only (workers) Changes: - Delete chemistry-design-changes.md (migration doc) - Remove migration tables from sling-design.md - Update bond tables: Spawn → Pour/Wisp - Rename spawnMoleculeFromProto → pourMoleculeFromProto - Rename spawnMoleculeOnIssue → runMoleculeOnIssue - Update templates: bd mol spawn → bd wisp - Update prime.go: commands and messages - Clean all docs and comments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -680,7 +680,7 @@ func showMoleculeProgress(b *beads.Beads, rootID string) {
|
||||
|
||||
// outputDeaconPatrolContext shows patrol molecule status for the Deacon.
|
||||
// Deacon uses wisps (Wisp:true issues in main .beads/) for patrol cycles.
|
||||
// Spawn creates wisp-marked issues that are auto-deleted on squash.
|
||||
// bd wisp creates wisp-marked issues that are auto-deleted on squash.
|
||||
func outputDeaconPatrolContext(ctx RoleContext) {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s\n\n", style.Bold.Render("## 🔄 Patrol Status (Wisp-based)"))
|
||||
@@ -732,8 +732,8 @@ func outputDeaconPatrolContext(ctx RoleContext) {
|
||||
}
|
||||
|
||||
if !hasPatrol {
|
||||
// No active patrol - AUTO-CREATE one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-deacon-patrol wisp...")
|
||||
// No active patrol - AUTO-SPAWN one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-deacon-patrol...")
|
||||
fmt.Println()
|
||||
|
||||
// Find the proto ID for mol-deacon-patrol
|
||||
@@ -767,7 +767,7 @@ func outputDeaconPatrolContext(ctx RoleContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the wisp
|
||||
// Create the patrol wisp
|
||||
cmdSpawn := exec.Command("bd", "--no-daemon", "wisp", protoID, "--assignee", "deacon")
|
||||
cmdSpawn.Dir = rigBeadsDir
|
||||
var stdoutSpawn, stderrSpawn bytes.Buffer
|
||||
@@ -776,7 +776,7 @@ func outputDeaconPatrolContext(ctx RoleContext) {
|
||||
|
||||
if err := cmdSpawn.Run(); err != nil {
|
||||
fmt.Printf("Failed to create patrol wisp: %s\n", stderrSpawn.String())
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp " + protoID))
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp" + protoID))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -816,7 +816,7 @@ func outputDeaconPatrolContext(ctx RoleContext) {
|
||||
fmt.Println("5. At cycle end (loop-or-exit step):")
|
||||
fmt.Println(" - Generate summary of patrol cycle")
|
||||
fmt.Println(" - Squash: `bd --no-daemon mol squash <mol-id> --summary \"<summary>\"`")
|
||||
fmt.Println(" - Loop back to spawn new wisp, or exit if context high")
|
||||
fmt.Println(" - Loop back to create new wisp, or exit if context high")
|
||||
if patrolID != "" {
|
||||
fmt.Println()
|
||||
fmt.Printf("Current patrol ID: %s\n", patrolID)
|
||||
@@ -898,8 +898,8 @@ func outputWitnessPatrolContext(ctx RoleContext) {
|
||||
}
|
||||
|
||||
if !hasPatrol {
|
||||
// No active patrol - AUTO-CREATE one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-witness-patrol wisp...")
|
||||
// No active patrol - AUTO-SPAWN one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-witness-patrol...")
|
||||
fmt.Println()
|
||||
|
||||
// Find the proto ID for mol-witness-patrol
|
||||
@@ -933,7 +933,7 @@ func outputWitnessPatrolContext(ctx RoleContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the wisp
|
||||
// Create the patrol wisp
|
||||
cmdSpawn := exec.Command("bd", "--no-daemon", "wisp", protoID, "--assignee", ctx.Rig+"/witness")
|
||||
cmdSpawn.Dir = witnessBeadsDir
|
||||
var stdoutSpawn, stderrSpawn bytes.Buffer
|
||||
@@ -942,7 +942,7 @@ func outputWitnessPatrolContext(ctx RoleContext) {
|
||||
|
||||
if err := cmdSpawn.Run(); err != nil {
|
||||
fmt.Printf("Failed to create patrol wisp: %s\n", stderrSpawn.String())
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp " + protoID))
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp" + protoID))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -982,7 +982,7 @@ func outputWitnessPatrolContext(ctx RoleContext) {
|
||||
fmt.Println("6. At cycle end (burn-or-loop step):")
|
||||
fmt.Println(" - Generate summary of patrol cycle")
|
||||
fmt.Println(" - Squash: `bd --no-daemon mol squash <mol-id> --summary \"<summary>\"`")
|
||||
fmt.Println(" - Loop back to spawn new wisp, or exit if context high")
|
||||
fmt.Println(" - Loop back to create new wisp, or exit if context high")
|
||||
if patrolID != "" {
|
||||
fmt.Println()
|
||||
fmt.Printf("Current patrol ID: %s\n", patrolID)
|
||||
@@ -1064,8 +1064,8 @@ func outputRefineryPatrolContext(ctx RoleContext) {
|
||||
}
|
||||
|
||||
if !hasPatrol {
|
||||
// No active patrol - AUTO-CREATE one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-refinery-patrol wisp...")
|
||||
// No active patrol - AUTO-SPAWN one
|
||||
fmt.Println("Status: **No active patrol** - creating mol-refinery-patrol...")
|
||||
fmt.Println()
|
||||
|
||||
// Find the proto ID for mol-refinery-patrol
|
||||
@@ -1099,7 +1099,7 @@ func outputRefineryPatrolContext(ctx RoleContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the wisp
|
||||
// Create the patrol wisp
|
||||
cmdSpawn := exec.Command("bd", "--no-daemon", "wisp", protoID, "--assignee", ctx.Rig+"/refinery")
|
||||
cmdSpawn.Dir = refineryBeadsDir
|
||||
var stdoutSpawn, stderrSpawn bytes.Buffer
|
||||
@@ -1108,7 +1108,7 @@ func outputRefineryPatrolContext(ctx RoleContext) {
|
||||
|
||||
if err := cmdSpawn.Run(); err != nil {
|
||||
fmt.Printf("Failed to create patrol wisp: %s\n", stderrSpawn.String())
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp " + protoID))
|
||||
fmt.Println(style.Dim.Render("Run manually: bd --no-daemon wisp" + protoID))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1148,7 +1148,7 @@ func outputRefineryPatrolContext(ctx RoleContext) {
|
||||
fmt.Println("6. At cycle end (burn-or-loop step):")
|
||||
fmt.Println(" - Generate summary of patrol cycle")
|
||||
fmt.Println(" - Squash: `bd --no-daemon mol squash <mol-id> --summary \"<summary>\"`")
|
||||
fmt.Println(" - Loop back to spawn new wisp, or exit if context high")
|
||||
fmt.Println(" - Loop back to create new wisp, or exit if context high")
|
||||
if patrolID != "" {
|
||||
fmt.Println()
|
||||
fmt.Printf("Current patrol ID: %s\n", patrolID)
|
||||
|
||||
@@ -50,7 +50,7 @@ SLING MECHANICS:
|
||||
┌─────────┐ ┌───────────────────────────────────────────┐
|
||||
│ THING │─────▶│ SLING PIPELINE │
|
||||
└─────────┘ │ │
|
||||
proto │ 1. SPAWN Proto → Molecule instance │
|
||||
proto │ 1. POUR Proto → Molecule instance │
|
||||
issue │ 2. ASSIGN Molecule → Target agent │
|
||||
epic │ 3. PIN Work → Agent's hook │
|
||||
│ 4. IGNITE Session starts automatically │
|
||||
@@ -525,8 +525,8 @@ func slingToPolecat(townRoot string, target *SlingTarget, thing *SlingThing) err
|
||||
|
||||
switch thing.Kind {
|
||||
case "proto":
|
||||
// Spawn molecule from proto
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, polecatAddress)
|
||||
// Pour molecule from proto
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, polecatAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -535,7 +535,7 @@ func slingToPolecat(townRoot string, target *SlingTarget, thing *SlingThing) err
|
||||
issueID = thing.ID
|
||||
if thing.Proto != "" {
|
||||
// Sling issue with molecule workflow
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, polecatAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, polecatAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -679,7 +679,7 @@ func slingToDeacon(townRoot string, target *SlingTarget, thing *SlingThing) erro
|
||||
ID: patrolIssueID, // Use the resolved beads issue ID
|
||||
IsWisp: true, // Patrol cycles are ephemeral (gt-jsup)
|
||||
}
|
||||
patrolID, _, err = spawnMoleculeFromProto(beadsPath, patrolThing, deaconAddress)
|
||||
patrolID, _, err = pourMoleculeFromProto(beadsPath, patrolThing, deaconAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting patrol: %w", err)
|
||||
}
|
||||
@@ -699,17 +699,17 @@ func slingToDeacon(townRoot string, target *SlingTarget, thing *SlingThing) erro
|
||||
var beadsIssue *BeadsIssue
|
||||
issueID := thing.ID
|
||||
|
||||
// For protos, we need to spawn the molecule but NOT pin it
|
||||
// For protos, we need to pour the molecule but NOT pin it
|
||||
var moleculeCtx *MoleculeContext
|
||||
var err error
|
||||
if thing.Kind == "proto" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, deaconAddress)
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, deaconAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if thing.Kind == "issue" {
|
||||
if thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, deaconAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, deaconAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -788,14 +788,14 @@ func slingToCrew(townRoot string, target *SlingTarget, thing *SlingThing) error
|
||||
|
||||
switch thing.Kind {
|
||||
case "proto":
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, crewAddress)
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, crewAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "issue":
|
||||
issueID = thing.ID
|
||||
if thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, crewAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, crewAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -882,7 +882,7 @@ func slingToWitness(townRoot string, target *SlingTarget, thing *SlingThing) err
|
||||
ID: patrolIssueID, // Use the resolved beads issue ID
|
||||
IsWisp: true, // Patrol cycles are ephemeral (gt-jsup)
|
||||
}
|
||||
patrolID, _, err = spawnMoleculeFromProto(beadsPath, patrolThing, witnessAddress)
|
||||
patrolID, _, err = pourMoleculeFromProto(beadsPath, patrolThing, witnessAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting patrol: %w", err)
|
||||
}
|
||||
@@ -902,17 +902,17 @@ func slingToWitness(townRoot string, target *SlingTarget, thing *SlingThing) err
|
||||
var beadsIssue *BeadsIssue
|
||||
issueID := thing.ID
|
||||
|
||||
// For protos, we need to spawn the molecule but NOT pin it
|
||||
// For protos, we need to pour the molecule but NOT pin it
|
||||
var moleculeCtx *MoleculeContext
|
||||
var err error
|
||||
if thing.Kind == "proto" {
|
||||
// Spawn molecule without pinning
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, witnessAddress)
|
||||
// Pour molecule without pinning
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, witnessAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if thing.Kind == "issue" && thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, witnessAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, witnessAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -980,14 +980,14 @@ func slingToPatrolWithReplace(townRoot, beadsPath, agentAddress string, thing *S
|
||||
|
||||
switch thing.Kind {
|
||||
case "proto":
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, agentAddress)
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, agentAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "issue":
|
||||
issueID = thing.ID
|
||||
if thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, agentAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, agentAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ func slingToRefinery(townRoot string, target *SlingTarget, thing *SlingThing) er
|
||||
ID: patrolIssueID, // Use the resolved beads issue ID
|
||||
IsWisp: true, // Patrol cycles are ephemeral (gt-jsup)
|
||||
}
|
||||
patrolID, _, err = spawnMoleculeFromProto(beadsPath, patrolThing, refineryAddress)
|
||||
patrolID, _, err = pourMoleculeFromProto(beadsPath, patrolThing, refineryAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting patrol: %w", err)
|
||||
}
|
||||
@@ -1069,16 +1069,16 @@ func slingToRefinery(townRoot string, target *SlingTarget, thing *SlingThing) er
|
||||
var beadsIssue *BeadsIssue
|
||||
issueID := thing.ID
|
||||
|
||||
// For protos, we need to spawn the molecule but NOT pin it
|
||||
// For protos, we need to pour the molecule but NOT pin it
|
||||
var moleculeCtx *MoleculeContext
|
||||
var err error
|
||||
if thing.Kind == "proto" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, refineryAddress)
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, refineryAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if thing.Kind == "issue" && thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, refineryAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, refineryAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1151,14 +1151,14 @@ func slingToMayor(townRoot string, target *SlingTarget, thing *SlingThing) error
|
||||
|
||||
switch thing.Kind {
|
||||
case "proto":
|
||||
issueID, moleculeCtx, err = spawnMoleculeFromProto(beadsPath, thing, mayorAddress)
|
||||
issueID, moleculeCtx, err = pourMoleculeFromProto(beadsPath, thing, mayorAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "issue":
|
||||
issueID = thing.ID
|
||||
if thing.Proto != "" {
|
||||
issueID, moleculeCtx, err = spawnMoleculeOnIssue(beadsPath, thing, mayorAddress)
|
||||
issueID, moleculeCtx, err = runMoleculeOnIssue(beadsPath, thing, mayorAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1209,15 +1209,15 @@ func slingToMayor(townRoot string, target *SlingTarget, thing *SlingThing) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// spawnMoleculeFromProto spawns a molecule from a proto template.
|
||||
func spawnMoleculeFromProto(beadsPath string, thing *SlingThing, assignee string) (string, *MoleculeContext, error) {
|
||||
// pourMoleculeFromProto creates a molecule from a proto template.
|
||||
func pourMoleculeFromProto(beadsPath string, thing *SlingThing, assignee string) (string, *MoleculeContext, error) {
|
||||
moleculeType := "molecule"
|
||||
if thing.IsWisp {
|
||||
moleculeType = "wisp"
|
||||
}
|
||||
fmt.Printf("Spawning %s from proto %s...\n", moleculeType, thing.ID)
|
||||
fmt.Printf("Creating %s from proto %s...\n", moleculeType, thing.ID)
|
||||
|
||||
// Use bd mol run to spawn the molecule
|
||||
// Use bd mol run to create the molecule
|
||||
args := []string{"--no-daemon", "mol", "run", thing.ID, "--json"}
|
||||
if assignee != "" {
|
||||
args = append(args, "--var", "assignee="+assignee)
|
||||
@@ -1266,7 +1266,7 @@ func spawnMoleculeFromProto(beadsPath string, thing *SlingThing, assignee string
|
||||
return "", nil, fmt.Errorf("parsing molecule result: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s spawned: %s (%d steps)\n",
|
||||
fmt.Printf("%s %s created: %s (%d steps)\n",
|
||||
style.Bold.Render("✓"), moleculeType, molResult.RootID, molResult.Created-1)
|
||||
|
||||
moleculeCtx := &MoleculeContext{
|
||||
@@ -1280,8 +1280,8 @@ func spawnMoleculeFromProto(beadsPath string, thing *SlingThing, assignee string
|
||||
return molResult.RootID, moleculeCtx, nil
|
||||
}
|
||||
|
||||
// spawnMoleculeOnIssue spawns a molecule workflow on an existing issue.
|
||||
func spawnMoleculeOnIssue(beadsPath string, thing *SlingThing, assignee string) (string, *MoleculeContext, error) {
|
||||
// runMoleculeOnIssue runs a molecule workflow on an existing issue.
|
||||
func runMoleculeOnIssue(beadsPath string, thing *SlingThing, assignee string) (string, *MoleculeContext, error) {
|
||||
fmt.Printf("Running molecule %s on issue %s...\n", thing.Proto, thing.ID)
|
||||
|
||||
args := []string{"--no-daemon", "mol", "run", thing.Proto,
|
||||
|
||||
@@ -250,7 +250,7 @@ func runSpawn(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// Handle molecule instantiation if specified
|
||||
if spawnMolecule != "" {
|
||||
// Use bd mol run to spawn the molecule - this handles everything:
|
||||
// Use bd mol run to create the molecule - this handles everything:
|
||||
// - Creates child issues from proto template
|
||||
// - Assigns root to polecat
|
||||
// - Sets root status to in_progress
|
||||
@@ -285,7 +285,7 @@ func runSpawn(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("parsing molecule result: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s Molecule spawned: %s (%d steps)\n",
|
||||
fmt.Printf("%s Molecule created: %s (%d steps)\n",
|
||||
style.Bold.Render("✓"), molResult.RootID, molResult.Created-1) // -1 for root
|
||||
|
||||
// Build molecule context for work assignment
|
||||
@@ -616,7 +616,7 @@ func buildSpawnContext(issue *BeadsIssue, message string) string {
|
||||
// MoleculeContext contains information about a molecule workflow assignment.
|
||||
type MoleculeContext struct {
|
||||
MoleculeID string // The molecule template ID (proto)
|
||||
RootIssueID string // The spawned molecule root issue
|
||||
RootIssueID string // The created molecule root issue
|
||||
TotalSteps int // Total number of steps in the molecule
|
||||
StepNumber int // Which step this is (1-indexed)
|
||||
IsWisp bool // True if this is a wisp (not durable mol)
|
||||
|
||||
Reference in New Issue
Block a user