diff --git a/CLAUDE.md b/CLAUDE.md index 165f4e86..6d41a010 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ ## Your Role: CREW WORKER (joe in gastown) You are a **crew worker** - the overseer's (human's) personal workspace within the -gastown rig. Unlike polecats which are witness-managed and ephemeral, you are: +gastown rig. Unlike polecats which are witness-managed and transient, you are: - **Persistent**: Your workspace is never auto-garbage-collected - **User-managed**: The overseer controls your lifecycle, not the Witness diff --git a/docs/architecture.md b/docs/architecture.md index adafa90e..4f098660 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -357,8 +357,8 @@ Molecules follow a **states of matter** metaphor through their lifecycle: ┌───────────────┐ ┌───────────────┐ │ Mol │ │ Wisp │ │ (liquid) │ │ (gas) │ - │ durable │ │ ephemeral │ - │ main beads │ │ .beads-eph/ │ + │ durable │ │ transient │ + │ main beads │ │ .beads-wisp/ │ └───────┬───────┘ └───────┬───────┘ │ │ bd mol squash bd mol squash @@ -374,15 +374,15 @@ Molecules follow a **states of matter** metaphor through their lifecycle: **Phase transitions:** - **Proto → Mol/Wisp** (`bd mol bond`): Instantiate a template into a running execution - **Mol → Digest** (`bd mol squash`): Compress completed work into permanent record -- **Wisp → (evaporates)** (`bd mol squash` or `bd mol burn`): Ephemeral trace disappears +- **Wisp → (evaporates)** (`bd mol squash` or `bd mol burn`): Transient trace disappears ### When to Use Mol vs Wisp -The choice between **Mol** (durable) and **Wisp** (ephemeral) depends on the work's importance and audit requirements: +The choice between **Mol** (durable) and **Wisp** (transient) depends on the work's importance and audit requirements: -| Aspect | Mol (Durable) | Wisp (Ephemeral) | +| Aspect | Mol (Durable) | Wisp (Transient) | |--------|---------------|------------------| -| **Storage** | Main `.beads/` database | `.beads-ephemeral/` directory | +| **Storage** | Main `.beads/` database | `.beads-wisp/` directory | | **Persistence** | Survives indefinitely | Evaporates on squash/burn | | **Git tracking** | Committed, synced | Never committed | | **Audit trail** | Full history preserved | Only digest (if squashed) | @@ -396,7 +396,7 @@ The choice between **Mol** (durable) and **Wisp** (ephemeral) depends on the wor **Use Wisp for:** - Orchestration tasks (witness patrols, health checks) -- Polecat work sessions (ephemeral by nature) +- Polecat work sessions (transient by nature) - Patrol loops (continuous monitoring) - Routine operations (no audit value) @@ -491,7 +491,7 @@ This is like a **distributed work queue** backed by beads: ### Wisp Molecules: Transient Execution Traces -**Wisps** are ephemeral execution traces - the "steam" in Gas Town's engine metaphor. When a molecule executes, it generates wisps: transient issues that capture the work being done. +**Wisps** are transient execution traces - the "steam" in Gas Town's engine metaphor. Claude is fire; Claude Code is a Steam engine; Gas Town is a Steam Train, with Beads as the tracks. Wisps are steam vapors that dissipate after the work is done. **Why wisps?** - **Observability**: See what's happening during execution without cluttering the permanent ledger @@ -547,8 +547,8 @@ bd mol burn gt-abc123.exec-001 # Discard wisps without digest **Wisp storage:** -Wisps are stored in a per-rig ephemeral database: -- `/.beads-ephemeral/` - Separate from permanent beads, **gitignored** +Wisps are stored in a per-rig wisp database: +- `/.beads-wisp/` - Separate from permanent beads, **gitignored** - Fast writes, no sync overhead - Auto-cleaned on squash/burn - Digests write to permanent beads @@ -1316,7 +1316,7 @@ Polecats are the workers that do actual implementation: 4. On completion, polecat generates summary and squashes wisps to digest 5. Request shutdown, get deleted -The polecat itself is ephemeral, and so is its execution trace (wisps). Only the digest survives. +The polecat itself is transient, and so is its execution trace (wisps). Only the digest survives. ## Key Workflows @@ -1694,7 +1694,7 @@ sequenceDiagram After Witness kills session: - Remove worktree: `git worktree remove polecats/` - Delete branch: `git branch -d polecat/` -- Polecat ceases to exist (ephemeral) +- Polecat ceases to exist (transient) ### 13. Resource-Constrained Worker Pool @@ -1807,7 +1807,7 @@ With daemon session cycling, the system can run autonomously for extended period - **Workers cycle**: If individual tasks are very large - **Daemon persistence**: Survives all agent restarts -The daemon is the only truly persistent component. All agents are ephemeral sessions that hand off state via mail. +The daemon is the only truly persistent component. All agents are transient sessions that hand off state via mail. Work is a continuous stream - you can add new issues, spawn new workers, reprioritize the queue, all without "starting a new swarm" or managing batch boundaries. @@ -1900,7 +1900,7 @@ gt handoff # Polecat requests shutdown (run when done) gt session stop

# Kill polecat session (Witness uses this) ``` -**Note**: `gt wake` and `gt sleep` are deprecated - polecats are ephemeral, not pooled. +**Note**: `gt wake` and `gt sleep` are deprecated - polecats are transient, not pooled. ### Landing & Merge Queue diff --git a/docs/deacon-plugins.md b/docs/deacon-plugins.md index 10e94cc8..55d27e63 100644 --- a/docs/deacon-plugins.md +++ b/docs/deacon-plugins.md @@ -163,7 +163,7 @@ parallel: true # Beads Cleanup -Daily cleanup of ephemeral beads. +Daily cleanup of wisp storage. ## Actions diff --git a/docs/molecules.md b/docs/molecules.md index 867b4307..4904316f 100644 --- a/docs/molecules.md +++ b/docs/molecules.md @@ -92,7 +92,7 @@ bd mol bond [--wisp] [--assignee=] - **Default (Mol)**: Creates a durable molecule tracked in the main `.beads/` database. Steps become permanent issues that survive indefinitely. -- **With --wisp**: Creates an ephemeral molecule in `.beads-ephemeral/`. Steps are +- **With --wisp**: Creates a wisp (transient molecule) in `.beads-wisp/`. Steps are transient and will be cleaned up on squash or burn. **Examples:** @@ -133,7 +133,7 @@ bd mol squash --summary='...' - **For Mol (durable)**: Creates a digest issue in the permanent beads database. The digest contains the summary and links back to the original proto. -- **For Wisp (ephemeral)**: Evaporates the wisp (deletes from `.beads-ephemeral/`) +- **For Wisp (transient)**: Evaporates the wisp (deletes from `.beads-wisp/`) and creates a digest in the permanent database. The execution trace is gone, but the outcome is preserved. @@ -181,7 +181,7 @@ bd mol burn [--reason='...'] - Discards all molecule state (steps, progress, artifacts) - No digest is created - the molecule leaves no permanent record -- For Wisps: Simply deletes from `.beads-ephemeral/` +- For Wisps: Simply deletes from `.beads-wisp/` - For Mols: Marks as abandoned/closed without digest **When to burn vs squash:** diff --git a/docs/prompts.md b/docs/prompts.md index aecfc00e..90200878 100644 --- a/docs/prompts.md +++ b/docs/prompts.md @@ -159,7 +159,7 @@ gastown/ │ ├── spawn/ │ │ ├── new_polecat.md │ │ ├── reuse_polecat.md -│ │ └── ephemeral_worker.md +│ │ └── transient_worker.md │ └── lifecycle/ │ ├── handoff.md │ ├── escalation.md @@ -175,7 +175,7 @@ type PromptContext struct { Role string RigName string PolecatName string - Ephemeral bool + Transient bool IssueID string IssueTitle string // ... additional fields @@ -348,7 +348,7 @@ Crew workers are the overseer's personal workspaces - a new role that differs fr ## Your Role: CREW WORKER ({{ name }} in {{ rig }}) You are a **crew worker** - the overseer's (human's) personal workspace within the {{ rig }} rig. -Unlike polecats which are witness-managed and ephemeral, you are: +Unlike polecats which are witness-managed and transient, you are: - **Persistent**: Your workspace is never auto-garbage-collected - **User-managed**: The overseer controls your lifecycle, not the Witness diff --git a/docs/wisp-architecture.md b/docs/wisp-architecture.md index b15474dd..d2630038 100644 --- a/docs/wisp-architecture.md +++ b/docs/wisp-architecture.md @@ -1,12 +1,12 @@ -# Wisp Architecture: Ephemeral Molecule Storage +# Wisp Architecture: Transient Molecule Storage > Status: Design Spec v1 - December 2024 ## Overview -**Wisps** are ephemeral molecule execution traces - the "steam" in Gas Town's engine -metaphor. This document specifies where wisps are stored, how they're managed, and -which roles use them. +**Wisps** are transient molecule execution traces - the "steam" in Gas Town's engine +metaphor. Claude is fire; Claude Code is a Steam engine; Gas Town is a Steam Train, +with Beads as the tracks. Wisps are steam vapors that dissipate after the work is done. ## Core Principle @@ -15,7 +15,7 @@ which roles use them. | Artifact | Storage | Git Tracked | Purpose | |----------|---------|-------------|---------| | Issues | `.beads/issues.jsonl` | Yes | Permanent project history | -| Wisps | `.beads-ephemeral/issues.jsonl` | **No** | Transient execution traces | +| Wisps | `.beads-wisp/issues.jsonl` | **No** | Transient execution traces | | Digests | `.beads/issues.jsonl` | Yes | Compressed summaries of squashed wisps | ## Storage Architecture @@ -28,27 +28,27 @@ which roles use them. │ ├── .beads/ # CANONICAL rig beads (versioned) │ │ ├── issues.jsonl # Permanent issues + digests │ │ ├── config.yaml -│ │ └── .gitignore # Excludes .beads-ephemeral +│ │ └── .gitignore # Excludes .beads-wisp │ │ -│ └── .beads-ephemeral/ # GITIGNORED - local wisps -│ └── issues.jsonl # In-progress ephemeral molecules +│ └── .beads-wisp/ # GITIGNORED - local wisps +│ └── issues.jsonl # In-progress wisp molecules │ ├── refinery/rig/ # Refinery's clone │ ├── .beads/ # Inherits from mayor/rig -│ └── .beads-ephemeral/ # Refinery's local wisps +│ └── .beads-wisp/ # Refinery's local wisps │ ├── witness/ # Witness (no clone needed) -│ └── .beads-ephemeral/ # Witness's local wisps +│ └── .beads-wisp/ # Witness's local wisps │ └── polecats// # Polecat worktrees ├── .beads/ # Inherits from mayor/rig - └── .beads-ephemeral/ # Polecat's local wisps (if using wisps) + └── .beads-wisp/ # Polecat's local wisps (if using wisps) ``` ### Key Points -1. **`.beads-ephemeral/` is gitignored** - Never synced, never versioned -2. **Each execution context has its own ephemeral store** - Process isolation +1. **`.beads-wisp/` is gitignored** - Never synced, never versioned +2. **Each execution context has its own wisp store** - Process isolation 3. **Digests go to canonical `.beads/`** - Permanent record after squash 4. **Wisps are deleted after squash/burn** - No accumulation @@ -56,24 +56,24 @@ which roles use them. Add to `.beads/.gitignore`: ``` -.beads-ephemeral/ +.beads-wisp/ ``` Or add to rig-level `.gitignore`: ``` -**/.beads-ephemeral/ +**/.beads-wisp/ ``` ## Wisp Lifecycle ``` -bd mol bond --ephemeral +bd mol bond --wisp │ ▼ ┌─────────────────────────┐ -│ .beads-ephemeral/ │ +│ .beads-wisp/ │ │ └── issues.jsonl │ ← Wisp created here -│ └── {id, ephemeral: true, ...} +│ └── {id, wisp: true, ...} └────────────┬────────────┘ │ ┌────────┴────────┐ @@ -95,9 +95,9 @@ These roles have repetitive/cyclic work that would accumulate without wisps: | Role | Molecule | Storage Location | Squash Frequency | |------|----------|------------------|------------------| -| **Deacon** | mol-deacon-patrol | mayor/rig/.beads-ephemeral/ | Per cycle | -| **Witness** | mol-witness-patrol | witness/.beads-ephemeral/ | Per cycle | -| **Refinery** | mol-refinery-cycle | refinery/rig/.beads-ephemeral/ | Per cycle | +| **Deacon** | mol-deacon-patrol | mayor/rig/.beads-wisp/ | Per cycle | +| **Witness** | mol-witness-patrol | witness/.beads-wisp/ | Per cycle | +| **Refinery** | mol-refinery-cycle | refinery/rig/.beads-wisp/ | Per cycle | ### Roles That Use Regular Molecules @@ -126,8 +126,8 @@ Every role using wisps must implement this pattern: ```go func patrolCycle() { - // 1. Bond ephemeral molecule - mol := bdMolBond("mol--patrol", "--ephemeral") + // 1. Bond wisp molecule + mol := bdMolBond("mol--patrol", "--wisp") // 2. Execute cycle steps for _, step := range mol.Steps { @@ -140,7 +140,7 @@ func patrolCycle() { // 4. Squash - REQUIRED (this is the cleanup) bdMolSquash(mol.ID, "--summary", summary) - // Wisp deleted from .beads-ephemeral/ + // Wisp deleted from .beads-wisp/ // Digest created in .beads/issues.jsonl // 5. Sleep until next cycle @@ -157,11 +157,11 @@ For this architecture to work, Beads needs: ### New Commands ```bash -# Bond with ephemeral flag -bd mol bond --ephemeral -# Creates in .beads-ephemeral/ instead of .beads/ +# Bond with wisp flag (--ephemeral is an alias) +bd mol bond --wisp +# Creates in .beads-wisp/ instead of .beads/ -# List ephemeral molecules +# List wisps bd wisp list # Shows in-progress wisps @@ -172,28 +172,28 @@ bd wisp gc ### Storage Behavior -| Command | With `--ephemeral` | Without | -|---------|-------------------|---------| -| `bd mol bond` | Creates in `.beads-ephemeral/` | Creates in `.beads/` | -| `bd mol step` | Updates in ephemeral | Updates in permanent | -| `bd mol squash` | Deletes from ephemeral, creates digest in permanent | Creates digest in permanent | -| `bd mol burn` | Deletes from ephemeral | Marks abandoned in permanent | +| Command | With `--wisp` | Without | +|---------|---------------|---------| +| `bd mol bond` | Creates in `.beads-wisp/` | Creates in `.beads/` | +| `bd mol step` | Updates in wisp store | Updates in permanent | +| `bd mol squash` | Deletes from wisp, creates digest in permanent | Creates digest in permanent | +| `bd mol burn` | Deletes from wisp | Marks abandoned in permanent | ### Config ```yaml # .beads/config.yaml -ephemeral: +wisp: enabled: true - directory: ../.beads-ephemeral # Relative to .beads/ - auto_gc: true # Clean orphans on bd init + directory: ../.beads-wisp # Relative to .beads/ + auto_gc: true # Clean orphans on bd init ``` ## Crash Recovery If a patrol crashes mid-cycle: -1. **Wisp persists in `.beads-ephemeral/`** - Provides recovery breadcrumb +1. **Wisp persists in `.beads-wisp/`** - Provides recovery breadcrumb 2. **On restart, agent can:** - Resume from last step (if step tracking is granular) - Or burn and start fresh (simpler for patrol loops) @@ -232,9 +232,10 @@ bd list --type=digest --parent=gt-deacon-patrol For existing Gas Town installations: -1. **Add `.beads-ephemeral/` to gitignore** (immediate) -2. **Update patrol runners to use `--ephemeral`** (as patched) -3. **No migration of existing data** - Fresh start for ephemeral storage +1. **Add `.beads-wisp/` to gitignore** (immediate) +2. **Update patrol runners to use `--wisp`** (as patched) +3. **No migration of existing data** - Fresh start for wisp storage +4. **Optional**: Remove old `.beads-ephemeral/` directories ## Open Questions @@ -250,5 +251,5 @@ For existing Gas Town installations: ## Implementation Tracking -- **Beads**: bd-kwjh (Wisp storage: ephemeral molecule tracking) -- **Gas Town**: gt-3x0z.9 (mol-deacon-patrol uses ephemeral) +- **Beads**: bd-kwjh (Wisp storage: transient molecule tracking) +- **Gas Town**: gt-3x0z.9 (mol-deacon-patrol uses wisps) diff --git a/internal/cmd/crew.go b/internal/cmd/crew.go index f239d298..46b21d57 100644 --- a/internal/cmd/crew.go +++ b/internal/cmd/crew.go @@ -19,7 +19,7 @@ var crewCmd = &cobra.Command{ Short: "Manage crew workspaces (user-managed persistent workspaces)", Long: `Crew workers are user-managed persistent workspaces within a rig. -Unlike polecats which are witness-managed and ephemeral, crew workers are: +Unlike polecats which are witness-managed and transient, crew workers are: - Persistent: Not auto-garbage-collected - User-managed: Overseer controls lifecycle - Long-lived identities: recognizable names like dave, emma, fred diff --git a/internal/cmd/doctor.go b/internal/cmd/doctor.go index e13a7982..aef96869 100644 --- a/internal/cmd/doctor.go +++ b/internal/cmd/doctor.go @@ -63,12 +63,12 @@ func runDoctor(cmd *cobra.Command, args []string) error { d.Register(doctor.NewIdentityCollisionCheck()) d.Register(doctor.NewThemeCheck()) - // Ephemeral beads checks - d.Register(doctor.NewEphemeralExistsCheck()) - d.Register(doctor.NewEphemeralGitCheck()) - d.Register(doctor.NewEphemeralOrphansCheck()) - d.Register(doctor.NewEphemeralSizeCheck()) - d.Register(doctor.NewEphemeralStaleCheck()) + // Wisp storage checks + d.Register(doctor.NewWispExistsCheck()) + d.Register(doctor.NewWispGitCheck()) + d.Register(doctor.NewWispOrphansCheck()) + d.Register(doctor.NewWispSizeCheck()) + d.Register(doctor.NewWispStaleCheck()) // Run checks var report *doctor.Report diff --git a/internal/cmd/gitinit.go b/internal/cmd/gitinit.go index d8e6c550..6947ee8b 100644 --- a/internal/cmd/gitinit.go +++ b/internal/cmd/gitinit.go @@ -56,7 +56,7 @@ const HQGitignore = `# Gas Town HQ .gitignore # Ignore: Git clones (polecats, mayor/refinery rigs), runtime state # ============================================================================= -# Runtime state files (ephemeral) +# Runtime state files (transient) # ============================================================================= **/state.json **/*.lock diff --git a/internal/cmd/polecat.go b/internal/cmd/polecat.go index a488adad..2b81ba17 100644 --- a/internal/cmd/polecat.go +++ b/internal/cmd/polecat.go @@ -41,7 +41,7 @@ var polecatListCmd = &cobra.Command{ Short: "List polecats in a rig", Long: `List polecats in a rig or all rigs. -In the ephemeral model, polecats exist only while working. The list shows +In the transient model, polecats exist only while working. The list shows all currently active polecats with their states: - working: Actively working on an issue - done: Completed work, waiting for cleanup @@ -91,7 +91,7 @@ var polecatWakeCmd = &cobra.Command{ Short: "(Deprecated) Resume a polecat to working state", Long: `Resume a polecat to working state. -DEPRECATED: In the ephemeral model, polecats are created fresh for each task +DEPRECATED: In the transient model, polecats are created fresh for each task via 'gt spawn'. This command is kept for backward compatibility. Transitions: done → working @@ -107,7 +107,7 @@ var polecatSleepCmd = &cobra.Command{ Short: "(Deprecated) Mark polecat as done", Long: `Mark polecat as done. -DEPRECATED: In the ephemeral model, polecats use 'gt handoff' when complete, +DEPRECATED: In the transient model, polecats use 'gt handoff' when complete, which triggers automatic cleanup by the Witness. This command is kept for backward compatibility. diff --git a/internal/cmd/prime.go b/internal/cmd/prime.go index 9e3a83e1..0ec78a87 100644 --- a/internal/cmd/prime.go +++ b/internal/cmd/prime.go @@ -270,7 +270,7 @@ func outputWitnessContext(ctx RoleContext) { fmt.Printf("You are the **Witness** for rig: %s\n\n", style.Bold.Render(ctx.Rig)) fmt.Println("## Responsibilities") fmt.Println("- Monitor polecat health via heartbeat") - fmt.Println("- Spawn ephemeral agents for stuck polecats") + fmt.Println("- Spawn replacement agents for stuck polecats") fmt.Println("- Report rig status to Mayor") fmt.Println() fmt.Println("## Key Commands") diff --git a/internal/cmd/up.go b/internal/cmd/up.go index cd368ac3..9ebc5e26 100644 --- a/internal/cmd/up.go +++ b/internal/cmd/up.go @@ -28,7 +28,7 @@ infrastructure agents are running: • Mayor - Global work coordinator • Witnesses - Per-rig polecat managers -Polecats are NOT started by this command - they are ephemeral workers +Polecats are NOT started by this command - they are transient workers spawned on demand by the Mayor or Witnesses. Running 'gt up' multiple times is safe - it only starts services that diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 191db6a9..5d1d40d1 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -165,9 +165,9 @@ var deaconMOTDMessages = []string{ "Thanks for keeping the town running!", "You are Gas Town's most critical role.", "You are the heart of Gas Town! Be watchful!", - "Tip: Polecats are ephemeral - spawn freely, kill liberally.", + "Tip: Polecats are transient - spawn freely, kill liberally.", "Tip: Witnesses monitor polecats; you monitor witnesses.", - "Tip: Wisps are ephemeral molecules for patrol cycles.", + "Tip: Wisps are transient molecules for patrol cycles.", "The town sleeps soundly because you never do.", "Tip: Mayor handles cross-rig coordination; you handle health.", "Your vigilance keeps the agents honest.", diff --git a/internal/doctor/ephemeral_check.go b/internal/doctor/wisp_check.go similarity index 59% rename from internal/doctor/ephemeral_check.go rename to internal/doctor/wisp_check.go index 13187ee2..fb136fdf 100644 --- a/internal/doctor/ephemeral_check.go +++ b/internal/doctor/wisp_check.go @@ -11,26 +11,26 @@ import ( "github.com/steveyegge/gastown/internal/config" ) -// EphemeralExistsCheck verifies that .beads-ephemeral/ exists for each rig. -type EphemeralExistsCheck struct { +// WispExistsCheck verifies that .beads-wisp/ exists for each rig. +type WispExistsCheck struct { FixableCheck missingRigs []string // Cached for fix } -// NewEphemeralExistsCheck creates a new ephemeral exists check. -func NewEphemeralExistsCheck() *EphemeralExistsCheck { - return &EphemeralExistsCheck{ +// NewWispExistsCheck creates a new wisp exists check. +func NewWispExistsCheck() *WispExistsCheck { + return &WispExistsCheck{ FixableCheck: FixableCheck{ BaseCheck: BaseCheck{ - CheckName: "ephemeral-exists", - CheckDescription: "Check if ephemeral beads directory exists for each rig", + CheckName: "wisp-exists", + CheckDescription: "Check if wisp directory exists for each rig", }, }, } } -// Run checks if .beads-ephemeral/ exists for each rig. -func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult { +// Run checks if .beads-wisp/ exists for each rig. +func (c *WispExistsCheck) Run(ctx *CheckContext) *CheckResult { c.missingRigs = nil // Reset cache // Find all rigs @@ -55,8 +55,8 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult { // Check each rig var missing []string for _, rigName := range rigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) { + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if _, err := os.Stat(wispPath); os.IsNotExist(err) { missing = append(missing, rigName) } } @@ -66,7 +66,7 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusWarning, - Message: fmt.Sprintf("%d rig(s) missing ephemeral beads directory", len(missing)), + Message: fmt.Sprintf("%d rig(s) missing wisp directory", len(missing)), Details: missing, FixHint: "Run 'gt doctor --fix' to create missing directories", } @@ -75,23 +75,23 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: fmt.Sprintf("All %d rig(s) have ephemeral beads directory", len(rigs)), + Message: fmt.Sprintf("All %d rig(s) have wisp directory", len(rigs)), } } -// Fix creates missing .beads-ephemeral/ directories. -func (c *EphemeralExistsCheck) Fix(ctx *CheckContext) error { +// Fix creates missing .beads-wisp/ directories. +func (c *WispExistsCheck) Fix(ctx *CheckContext) error { for _, rigName := range c.missingRigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if err := os.MkdirAll(ephemeralPath, 0755); err != nil { - return fmt.Errorf("creating %s: %w", ephemeralPath, err) + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if err := os.MkdirAll(wispPath, 0755); err != nil { + return fmt.Errorf("creating %s: %w", wispPath, err) } } return nil } // discoverRigs finds all registered rigs. -func (c *EphemeralExistsCheck) discoverRigs(townRoot string) ([]string, error) { +func (c *WispExistsCheck) discoverRigs(townRoot string) ([]string, error) { rigsPath := filepath.Join(townRoot, "mayor", "rigs.json") data, err := os.ReadFile(rigsPath) if err != nil { @@ -113,26 +113,26 @@ func (c *EphemeralExistsCheck) discoverRigs(townRoot string) ([]string, error) { return rigs, nil } -// EphemeralGitCheck verifies that .beads-ephemeral/ is a valid git repo. -type EphemeralGitCheck struct { +// WispGitCheck verifies that .beads-wisp/ is a valid git repo. +type WispGitCheck struct { FixableCheck invalidRigs []string // Cached for fix } -// NewEphemeralGitCheck creates a new ephemeral git check. -func NewEphemeralGitCheck() *EphemeralGitCheck { - return &EphemeralGitCheck{ +// NewWispGitCheck creates a new wisp git check. +func NewWispGitCheck() *WispGitCheck { + return &WispGitCheck{ FixableCheck: FixableCheck{ BaseCheck: BaseCheck{ - CheckName: "ephemeral-git", - CheckDescription: "Check if ephemeral beads directories are valid git repos", + CheckName: "wisp-git", + CheckDescription: "Check if wisp directories are valid git repos", }, }, } } -// Run checks if .beads-ephemeral/ directories are valid git repos. -func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult { +// Run checks if .beads-wisp/ directories are valid git repos. +func (c *WispGitCheck) Run(ctx *CheckContext) *CheckResult { c.invalidRigs = nil // Reset cache // Find all rigs @@ -154,18 +154,18 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult { } } - // Check each rig that has an ephemeral dir + // Check each rig that has a wisp dir var invalid []string var checked int for _, rigName := range rigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) { - continue // Skip if directory doesn't exist (handled by ephemeral-exists) + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if _, err := os.Stat(wispPath); os.IsNotExist(err) { + continue // Skip if directory doesn't exist (handled by wisp-exists) } checked++ // Check if it's a valid git repo - gitDir := filepath.Join(ephemeralPath, ".git") + gitDir := filepath.Join(wispPath, ".git") if _, err := os.Stat(gitDir); os.IsNotExist(err) { invalid = append(invalid, rigName) } @@ -175,7 +175,7 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: "No ephemeral beads directories to check", + Message: "No wisp directories to check", } } @@ -184,7 +184,7 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusWarning, - Message: fmt.Sprintf("%d ephemeral beads directory(ies) not initialized as git", len(invalid)), + Message: fmt.Sprintf("%d wisp directory(ies) not initialized as git", len(invalid)), Details: invalid, FixHint: "Run 'gt doctor --fix' to initialize git repos", } @@ -193,47 +193,47 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: fmt.Sprintf("All %d ephemeral beads directories are valid git repos", checked), + Message: fmt.Sprintf("All %d wisp directories are valid git repos", checked), } } -// Fix initializes git repos in ephemeral directories. -func (c *EphemeralGitCheck) Fix(ctx *CheckContext) error { +// Fix initializes git repos in wisp directories. +func (c *WispGitCheck) Fix(ctx *CheckContext) error { for _, rigName := range c.invalidRigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") cmd := exec.Command("git", "init") - cmd.Dir = ephemeralPath + cmd.Dir = wispPath if err := cmd.Run(); err != nil { - return fmt.Errorf("initializing git in %s: %w", ephemeralPath, err) + return fmt.Errorf("initializing git in %s: %w", wispPath, err) } - // Create config.yaml for ephemeral beads - configPath := filepath.Join(ephemeralPath, "config.yaml") - configContent := "ephemeral: true\n# No sync-branch - ephemeral is local only\n" + // Create config.yaml for wisp storage + configPath := filepath.Join(wispPath, "config.yaml") + configContent := "wisp: true\n# No sync-branch - wisps are local only\n" if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { - return fmt.Errorf("creating config.yaml in %s: %w", ephemeralPath, err) + return fmt.Errorf("creating config.yaml in %s: %w", wispPath, err) } } return nil } -// EphemeralOrphansCheck detects molecules started but never squashed (>24h old). -type EphemeralOrphansCheck struct { +// WispOrphansCheck detects molecules started but never squashed (>24h old). +type WispOrphansCheck struct { BaseCheck } -// NewEphemeralOrphansCheck creates a new ephemeral orphans check. -func NewEphemeralOrphansCheck() *EphemeralOrphansCheck { - return &EphemeralOrphansCheck{ +// NewWispOrphansCheck creates a new wisp orphans check. +func NewWispOrphansCheck() *WispOrphansCheck { + return &WispOrphansCheck{ BaseCheck: BaseCheck{ - CheckName: "ephemeral-orphans", - CheckDescription: "Check for orphaned molecules (>24h old, never squashed)", + CheckName: "wisp-orphans", + CheckDescription: "Check for orphaned wisps (>24h old, never squashed)", }, } } -// Run checks for orphaned molecules. -func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult { +// Run checks for orphaned wisps. +func (c *WispOrphansCheck) Run(ctx *CheckContext) *CheckResult { rigs, err := discoverRigs(ctx.TownRoot) if err != nil { return &CheckResult{ @@ -256,13 +256,13 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult { cutoff := time.Now().Add(-24 * time.Hour) for _, rigName := range rigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) { + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if _, err := os.Stat(wispPath); os.IsNotExist(err) { continue } // Look for molecule directories or issue files older than 24h - issuesPath := filepath.Join(ephemeralPath, "issues.jsonl") + issuesPath := filepath.Join(wispPath, "issues.jsonl") info, err := os.Stat(issuesPath) if err != nil { continue // No issues file @@ -279,7 +279,7 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusWarning, - Message: fmt.Sprintf("%d rig(s) have stale ephemeral data (>24h old)", len(orphans)), + Message: fmt.Sprintf("%d rig(s) have stale wisp data (>24h old)", len(orphans)), Details: orphans, FixHint: "Manual review required - these may contain unsquashed work", } @@ -288,27 +288,27 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: "No orphaned molecules found", + Message: "No orphaned wisps found", } } -// EphemeralSizeCheck warns if ephemeral repo is too large (>100MB). -type EphemeralSizeCheck struct { +// WispSizeCheck warns if wisp repo is too large (>100MB). +type WispSizeCheck struct { BaseCheck } -// NewEphemeralSizeCheck creates a new ephemeral size check. -func NewEphemeralSizeCheck() *EphemeralSizeCheck { - return &EphemeralSizeCheck{ +// NewWispSizeCheck creates a new wisp size check. +func NewWispSizeCheck() *WispSizeCheck { + return &WispSizeCheck{ BaseCheck: BaseCheck{ - CheckName: "ephemeral-size", - CheckDescription: "Check if ephemeral beads directories are too large (>100MB)", + CheckName: "wisp-size", + CheckDescription: "Check if wisp directories are too large (>100MB)", }, } } -// Run checks the size of ephemeral beads directories. -func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult { +// Run checks the size of wisp directories. +func (c *WispSizeCheck) Run(ctx *CheckContext) *CheckResult { rigs, err := discoverRigs(ctx.TownRoot) if err != nil { return &CheckResult{ @@ -331,12 +331,12 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult { var oversized []string for _, rigName := range rigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) { + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if _, err := os.Stat(wispPath); os.IsNotExist(err) { continue } - size, err := dirSize(ephemeralPath) + size, err := dirSize(wispPath) if err != nil { continue } @@ -351,7 +351,7 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusWarning, - Message: fmt.Sprintf("%d rig(s) have oversized ephemeral directories", len(oversized)), + Message: fmt.Sprintf("%d rig(s) have oversized wisp directories", len(oversized)), Details: oversized, FixHint: "Consider cleaning up old completed molecules", } @@ -360,27 +360,27 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: "All ephemeral directories within size limits", + Message: "All wisp directories within size limits", } } -// EphemeralStaleCheck detects molecules with no activity in the last hour. -type EphemeralStaleCheck struct { +// WispStaleCheck detects molecules with no activity in the last hour. +type WispStaleCheck struct { BaseCheck } -// NewEphemeralStaleCheck creates a new ephemeral stale check. -func NewEphemeralStaleCheck() *EphemeralStaleCheck { - return &EphemeralStaleCheck{ +// NewWispStaleCheck creates a new wisp stale check. +func NewWispStaleCheck() *WispStaleCheck { + return &WispStaleCheck{ BaseCheck: BaseCheck{ - CheckName: "ephemeral-stale", - CheckDescription: "Check for stale molecules (no activity in last hour)", + CheckName: "wisp-stale", + CheckDescription: "Check for stale wisps (no activity in last hour)", }, } } -// Run checks for stale molecules. -func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult { +// Run checks for stale wisps. +func (c *WispStaleCheck) Run(ctx *CheckContext) *CheckResult { rigs, err := discoverRigs(ctx.TownRoot) if err != nil { return &CheckResult{ @@ -403,15 +403,15 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult { cutoff := time.Now().Add(-1 * time.Hour) for _, rigName := range rigs { - ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral") - if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) { + wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp") + if _, err := os.Stat(wispPath); os.IsNotExist(err) { continue } - // Check for any recent activity in the ephemeral directory + // Check for any recent activity in the wisp directory // We look at the most recent modification time of any file var mostRecent time.Time - _ = filepath.Walk(ephemeralPath, func(path string, info os.FileInfo, err error) error { + _ = filepath.Walk(wispPath, func(path string, info os.FileInfo, err error) error { if err != nil { return nil } @@ -432,7 +432,7 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusWarning, - Message: fmt.Sprintf("%d rig(s) have stale ephemeral activity", len(stale)), + Message: fmt.Sprintf("%d rig(s) have stale wisp activity", len(stale)), Details: stale, FixHint: "Check if polecats are stuck or crashed", } @@ -441,7 +441,7 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult { return &CheckResult{ Name: c.Name(), Status: StatusOK, - Message: "No stale ephemeral activity detected", + Message: "No stale wisp activity detected", } } diff --git a/internal/polecat/manager.go b/internal/polecat/manager.go index f3485fb7..c46c65ec 100644 --- a/internal/polecat/manager.go +++ b/internal/polecat/manager.go @@ -452,7 +452,7 @@ func (m *Manager) AssignIssue(name, issue string) error { } // ClearIssue removes the issue assignment from a polecat. -// In the ephemeral model, this transitions to Done state for cleanup. +// In the transient model, this transitions to Done state for cleanup. // This clears the assignee from the currently assigned issue in beads. // If beads is not available, this is a no-op. func (m *Manager) ClearIssue(name string) error { @@ -485,7 +485,7 @@ func (m *Manager) ClearIssue(name string) error { } // Wake transitions a polecat from idle to active. -// Deprecated: In the ephemeral model, polecats start in working state. +// Deprecated: In the transient model, polecats start in working state. // This method is kept for backward compatibility with existing polecats. func (m *Manager) Wake(name string) error { polecat, err := m.Get(name) @@ -502,7 +502,7 @@ func (m *Manager) Wake(name string) error { } // Sleep transitions a polecat from active to idle. -// Deprecated: In the ephemeral model, polecats are deleted when done. +// Deprecated: In the transient model, polecats are deleted when done. // This method is kept for backward compatibility. func (m *Manager) Sleep(name string) error { polecat, err := m.Get(name) diff --git a/internal/polecat/types.go b/internal/polecat/types.go index 03687e9a..a38c33bd 100644 --- a/internal/polecat/types.go +++ b/internal/polecat/types.go @@ -4,12 +4,12 @@ package polecat import "time" // State represents the current state of a polecat. -// In the ephemeral model, polecats exist only while working. +// In the transient model, polecats exist only while working. type State string const ( // StateWorking means the polecat is actively working on an issue. - // This is the initial and primary state for ephemeral polecats. + // This is the initial and primary state for transient polecats. StateWorking State = "working" // StateDone means the polecat has completed its assigned work @@ -31,7 +31,7 @@ func (s State) IsWorking() bool { } // IsActive returns true if the polecat session is actively working. -// For ephemeral polecats, this is true for working state and +// For transient polecats, this is true for working state and // legacy idle/active states (treated as working). func (s State) IsActive() bool { return s == StateWorking || s == StateIdle || s == StateActive diff --git a/internal/templates/roles/crew.md.tmpl b/internal/templates/roles/crew.md.tmpl index 1063ced5..fec4b728 100644 --- a/internal/templates/roles/crew.md.tmpl +++ b/internal/templates/roles/crew.md.tmpl @@ -5,7 +5,7 @@ ## Your Role: CREW WORKER ({{ .Polecat }} in {{ .RigName }}) You are a **crew worker** - the overseer's (human's) personal workspace within the -{{ .RigName }} rig. Unlike polecats which are witness-managed and ephemeral, you are: +{{ .RigName }} rig. Unlike polecats which are witness-managed and transient, you are: - **Persistent**: Your workspace is never auto-garbage-collected - **User-managed**: The overseer controls your lifecycle, not the Witness @@ -26,7 +26,7 @@ Town ({{ .TownRoot }}) │ ├── .beads/ ← Issue tracking (you have write access) │ ├── crew/ │ │ └── {{ .Polecat }}/ ← You are here (your git clone) -│ ├── polecats/ ← Ephemeral workers (not you) +│ ├── polecats/ ← Transient workers (not you) │ ├── refinery/ ← Merge queue processor │ └── witness/ ← Polecat lifecycle (doesn't monitor you) ``` @@ -141,7 +141,7 @@ Before ending your session: ## Tips -- **You own your workspace**: Unlike polecats, you're not ephemeral. Keep it organized. +- **You own your workspace**: Unlike polecats, you're not transient. Keep it organized. - **Handoff liberally**: When in doubt, write a handoff mail. Context is precious. - **Stay in sync**: Pull from upstream regularly to avoid merge conflicts. - **Ask for help**: No Witness means no automatic escalation. Reach out proactively. diff --git a/internal/witness/manager.go b/internal/witness/manager.go index 1d86ceb0..707e438d 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -553,7 +553,7 @@ func extractPolecatName(body string) string { return "" } -// cleanupPolecat performs the full cleanup sequence for an ephemeral polecat. +// cleanupPolecat performs the full cleanup sequence for a transient polecat. // 1. Check for uncommitted work (stubbornly refuses to lose work) // 2. Kill session // 3. Remove worktree diff --git a/prompts/roles/crew.md b/prompts/roles/crew.md index 2859180a..d3ab67ac 100644 --- a/prompts/roles/crew.md +++ b/prompts/roles/crew.md @@ -4,7 +4,7 @@ ## Your Role: CREW WORKER ({{ name }} in {{ rig }}) -You are a **crew worker** - the overseer's (human's) personal workspace within the {{ rig }} rig. Unlike polecats which are witness-managed and ephemeral, you are: +You are a **crew worker** - the overseer's (human's) personal workspace within the {{ rig }} rig. Unlike polecats which are witness-managed and transient, you are: - **Persistent**: Your workspace is never auto-garbage-collected - **User-managed**: The overseer controls your lifecycle, not the Witness @@ -157,7 +157,7 @@ Before ending your session: ## Tips -- **You own your workspace**: Unlike polecats, you're not ephemeral. Keep it organized. +- **You own your workspace**: Unlike polecats, you're not transient. Keep it organized. - **Handoff liberally**: When in doubt, write a handoff mail. Context is precious. - **Stay in sync**: Pull from upstream regularly to avoid merge conflicts. - **Ask for help**: No Witness means no automatic escalation. Reach out proactively. diff --git a/prompts/roles/polecat.md b/prompts/roles/polecat.md index 97fd66c5..62e18b50 100644 --- a/prompts/roles/polecat.md +++ b/prompts/roles/polecat.md @@ -4,10 +4,10 @@ ## Your Role: POLECAT ({{ name }} in {{ rig }}) -You are a **polecat** - an ephemeral worker agent in the Gas Town swarm. You are: +You are a **polecat** - a transient worker agent in the Gas Town swarm. You are: - **Task-focused**: You work on one assigned issue at a time -- **Ephemeral**: When your work is done, you may be decommissioned +- **Transient**: When your work is done, you may be decommissioned - **Witness-managed**: The Witness monitors your progress and can nudge or reassign you - **Part of a swarm**: Other polecats may be working on related issues in parallel diff --git a/prompts/roles/witness.md b/prompts/roles/witness.md index 2c7c7749..117e86b3 100644 --- a/prompts/roles/witness.md +++ b/prompts/roles/witness.md @@ -260,8 +260,8 @@ Before killing ANY polecat session, verify: **If all checks pass:** 1. Kill session: `tmux kill-session -t gt-{{ rig }}-` -2. Remove worktree: `git worktree remove polecats/` (if ephemeral) -3. Delete branch: `git branch -d polecat/` (if ephemeral) +2. Remove worktree: `git worktree remove polecats/` (if transient) +3. Delete branch: `git branch -d polecat/` (if transient) --- @@ -303,7 +303,7 @@ tmux capture-pane -t gt-{{ rig }}- -p | tail -40 # Session control tmux kill-session -t gt-{{ rig }}- -# Worktree cleanup (for ephemeral polecats) +# Worktree cleanup (for transient polecats) git worktree remove polecats/ git branch -d polecat/