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:
Steve Yegge
2025-12-24 14:02:09 -08:00
parent 0acad8af25
commit c10709dc3f
17 changed files with 95 additions and 531 deletions

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)