Add --on flag to gt sling for formula scaffolding (gt-8tmz.9)

When --on is specified, the first argument is a formula name:
  gt sling shiny --on gt-abc123

This applies the formula to existing work, creating wisp scaffolding
that shapes execution of the target bead.

Changes:
- Add Formula field to SlungWork wisp type
- Add --on flag to gt sling command
- Verify both bead and formula exist before slinging
- Update dry-run output to show formula info

🤖 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-25 02:00:25 -08:00
parent a3cee4ad89
commit 2f8bc581a6
2 changed files with 67 additions and 5 deletions

View File

@@ -35,6 +35,13 @@ Examples:
gt sling gt-abc crew # Sling to crew worker
gt sling gt-abc gastown/crew/max # Sling to specific agent
Formula scaffolding (--on flag):
gt sling shiny --on gt-abc # Apply shiny formula to existing work
gt sling mol-review --on gt-abc crew # Apply review formula, sling to crew
When --on is specified, the first argument is a formula name (not a bead).
The formula shapes execution of the target bead, creating wisp scaffolding.
Compare:
gt hook <bead> # Just attach (no action)
gt sling <bead> # Attach + start now (keep context)
@@ -46,20 +53,33 @@ The propulsion principle: if it's on your hook, YOU RUN IT.`,
}
var (
slingSubject string
slingMessage string
slingDryRun bool
slingSubject string
slingMessage string
slingDryRun bool
slingOnTarget string // --on flag: target bead when slinging a formula
)
func init() {
slingCmd.Flags().StringVarP(&slingSubject, "subject", "s", "", "Context subject for the work")
slingCmd.Flags().StringVarP(&slingMessage, "message", "m", "", "Context message for the work")
slingCmd.Flags().BoolVarP(&slingDryRun, "dry-run", "n", false, "Show what would be done")
slingCmd.Flags().StringVar(&slingOnTarget, "on", "", "Apply formula to existing bead (implies wisp scaffolding)")
rootCmd.AddCommand(slingCmd)
}
func runSling(cmd *cobra.Command, args []string) error {
beadID := args[0]
// Determine if we're in formula mode (--on flag)
var beadID string
var formulaName string
if slingOnTarget != "" {
// Formula mode: gt sling <formula> --on <bead>
formulaName = args[0]
beadID = slingOnTarget
} else {
// Normal mode: gt sling <bead>
beadID = args[0]
}
// Polecats cannot sling - check early before writing anything
if polecatName := os.Getenv("GT_POLECAT"); polecatName != "" {
@@ -71,6 +91,13 @@ func runSling(cmd *cobra.Command, args []string) error {
return err
}
// If formula specified, verify it exists
if formulaName != "" {
if err := verifyFormulaExists(formulaName); err != nil {
return err
}
}
// Determine target agent (self or specified)
var targetAgent string
var targetPane string
@@ -128,12 +155,21 @@ func runSling(cmd *cobra.Command, args []string) error {
sw := wisp.NewSlungWork(beadID, targetAgent)
sw.Subject = slingSubject
sw.Context = slingMessage
sw.Formula = formulaName
fmt.Printf("%s Slinging %s to %s...\n", style.Bold.Render("🎯"), beadID, targetAgent)
// Display what we're doing
if formulaName != "" {
fmt.Printf("%s Slinging formula %s on %s to %s...\n", style.Bold.Render("🎯"), formulaName, beadID, targetAgent)
} else {
fmt.Printf("%s Slinging %s to %s...\n", style.Bold.Render("🎯"), beadID, targetAgent)
}
if slingDryRun {
fmt.Printf("Would create wisp: %s\n", wisp.HookPath(hookRoot, targetAgent))
fmt.Printf(" bead_id: %s\n", beadID)
if formulaName != "" {
fmt.Printf(" formula: %s\n", formulaName)
}
fmt.Printf(" agent: %s\n", targetAgent)
fmt.Printf(" hook_root: %s\n", hookRoot)
if slingSubject != "" {
@@ -294,3 +330,24 @@ func detectCloneRoot() (string, error) {
}
return strings.TrimSpace(string(out)), nil
}
// verifyFormulaExists checks that the formula exists using bd formula show.
// Formulas can be proto beads (mol-*) or formula files (.formula.json).
func verifyFormulaExists(formulaName string) error {
// Try as a proto bead first (mol-* prefix is common)
cmd := exec.Command("bd", "show", formulaName, "--json")
if err := cmd.Run(); err == nil {
return nil // Found as a proto
}
// Try with mol- prefix
cmd = exec.Command("bd", "show", "mol-"+formulaName, "--json")
if err := cmd.Run(); err == nil {
return nil // Found as mol-<name>
}
// TODO: Check for .formula.json file in search paths
// For now, we require the formula to exist as a proto
return fmt.Errorf("formula '%s' not found (try 'bd cook' to create it from a .formula.json file)", formulaName)
}

View File

@@ -53,6 +53,11 @@ type SlungWork struct {
// BeadID is the issue/bead to work on (e.g., "gt-xxx").
BeadID string `json:"bead_id"`
// Formula is the optional formula/form to apply to the work.
// When set, this creates scaffolding around the target bead.
// Used by `gt sling <formula> --on <bead>`.
Formula string `json:"formula,omitempty"`
// Context is optional additional context from the slinger.
Context string `json:"context,omitempty"`