Rename ephemeral -> wisp terminology throughout Gas Town

- .beads-ephemeral/ -> .beads-wisp/
- Rename doctor checks: EphemeralCheck -> WispCheck
- Update all docs to use 'transient' for polecats, 'wisp' for molecules
- Preserve 'ephemeral' only as descriptive adjective for wisps
- Steam engine metaphor: wisps are steam vapors that dissipate

Part of Christmas launch wisp terminology unification.
This commit is contained in:
Steve Yegge
2025-12-22 00:55:31 -08:00
parent f74f4f85da
commit f21343911f
21 changed files with 186 additions and 185 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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