diff --git a/docs/property-layers.md b/docs/property-layers.md new file mode 100644 index 00000000..88cf797d --- /dev/null +++ b/docs/property-layers.md @@ -0,0 +1,300 @@ +# Property Layers: Multi-Level Configuration + +> Implementation guide for Gas Town's configuration system. +> Created: 2025-01-06 + +## Overview + +Gas Town uses a layered property system for configuration. Properties are +looked up through multiple layers, with earlier layers overriding later ones. +This enables both local control and global coordination. + +## The Four Layers + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 1. WISP LAYER (transient, town-local) │ +│ Location: /.beads-wisp/config/ │ +│ Synced: Never │ +│ Use: Temporary local overrides │ +└─────────────────────────────┬───────────────────────────────┘ + │ if missing + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 2. RIG BEAD LAYER (persistent, synced globally) │ +│ Location: /.beads/ (rig identity bead labels) │ +│ Synced: Via git (all clones see it) │ +│ Use: Project-wide operational state │ +└─────────────────────────────┬───────────────────────────────┘ + │ if missing + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 3. TOWN DEFAULTS │ +│ Location: ~/gt/config.json or ~/gt/.beads/ │ +│ Synced: N/A (per-town) │ +│ Use: Town-wide policies │ +└─────────────────────────────┬───────────────────────────────┘ + │ if missing + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 4. SYSTEM DEFAULTS (compiled in) │ +│ Use: Fallback when nothing else specified │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Lookup Behavior + +### Override Semantics (Default) + +For most properties, the first non-nil value wins: + +```go +func GetConfig(key string) interface{} { + if val := wisp.Get(key); val != nil { + if val == Blocked { return nil } + return val + } + if val := rigBead.GetLabel(key); val != nil { + return val + } + if val := townDefaults.Get(key); val != nil { + return val + } + return systemDefaults[key] +} +``` + +### Stacking Semantics (Integers) + +For integer properties, values from wisp and bead layers **add** to the base: + +```go +func GetIntConfig(key string) int { + base := getBaseDefault(key) // Town or system default + beadAdj := rigBead.GetInt(key) // 0 if missing + wispAdj := wisp.GetInt(key) // 0 if missing + return base + beadAdj + wispAdj +} +``` + +This enables temporary adjustments without changing the base value. + +### Blocking Inheritance + +You can explicitly block a property from being inherited: + +```bash +gt rig config set gastown auto_restart --block +``` + +This creates a "blocked" marker in the wisp layer. Even if the rig bead +or defaults say `auto_restart: true`, the lookup returns nil. + +## Rig Identity Beads + +Each rig has an identity bead for operational state: + +```yaml +id: gt-rig-gastown +type: rig +name: gastown +repo: git@github.com:steveyegge/gastown.git +prefix: gt + +labels: + - status:operational + - priority:normal +``` + +These beads sync via git, so all clones of the rig see the same state. + +## Two-Level Rig Control + +### Level 1: Park (Local, Ephemeral) + +```bash +gt rig park gastown # Stop services, daemon won't restart +gt rig unpark gastown # Allow services to run +``` + +- Stored in wisp layer (`.beads-wisp/config/`) +- Only affects this town +- Disappears on cleanup +- Use: Local maintenance, debugging + +### Level 2: Dock (Global, Persistent) + +```bash +gt rig dock gastown # Set status:docked label on rig bead +gt rig undock gastown # Remove label +``` + +- Stored on rig identity bead +- Syncs to all clones via git +- Permanent until explicitly changed +- Use: Project-wide maintenance, coordinated downtime + +### Daemon Behavior + +The daemon checks both levels before auto-restarting: + +```go +func shouldAutoRestart(rig *Rig) bool { + status := rig.GetConfig("status") + if status == "parked" || status == "docked" { + return false + } + return true +} +``` + +## Configuration Keys + +| Key | Type | Behavior | Description | +|-----|------|----------|-------------| +| `status` | string | Override | operational/parked/docked | +| `auto_restart` | bool | Override | Daemon auto-restart behavior | +| `max_polecats` | int | Override | Maximum concurrent polecats | +| `priority_adjustment` | int | **Stack** | Scheduling priority modifier | +| `maintenance_window` | string | Override | When maintenance allowed | +| `dnd` | bool | Override | Do not disturb mode | + +## Commands + +### View Configuration + +```bash +gt rig config show gastown # Show effective config (all layers) +gt rig config show gastown --layer # Show which layer each value comes from +``` + +### Set Configuration + +```bash +# Set in wisp layer (local, ephemeral) +gt rig config set gastown key value + +# Set in bead layer (global, permanent) +gt rig config set gastown key value --global + +# Block inheritance +gt rig config set gastown key --block + +# Clear from wisp layer +gt rig config unset gastown key +``` + +### Rig Lifecycle + +```bash +gt rig park gastown # Local: stop + prevent restart +gt rig unpark gastown # Local: allow restart + +gt rig dock gastown # Global: mark as offline +gt rig undock gastown # Global: mark as operational + +gt rig status gastown # Show current state +``` + +## Examples + +### Temporary Priority Boost + +```bash +# Base priority: 0 (from defaults) +# Give this rig temporary priority boost for urgent work + +gt rig config set gastown priority_adjustment 10 + +# Effective priority: 0 + 10 = 10 +# When done, clear it: + +gt rig config unset gastown priority_adjustment +``` + +### Local Maintenance + +```bash +# I'm upgrading the local clone, don't restart services +gt rig park gastown + +# ... do maintenance ... + +gt rig unpark gastown +``` + +### Project-Wide Maintenance + +```bash +# Major refactor in progress, all clones should pause +gt rig dock gastown + +# Syncs via git - other towns see the rig as docked +bd sync + +# When done: +gt rig undock gastown +bd sync +``` + +### Block Auto-Restart Locally + +```bash +# Rig bead says auto_restart: true +# But I'm debugging and don't want that here + +gt rig config set gastown auto_restart --block + +# Now auto_restart returns nil for this town only +``` + +## Implementation Notes + +### Wisp Storage + +Wisp config stored in `.beads-wisp/config/.json`: + +```json +{ + "rig": "gastown", + "values": { + "status": "parked", + "priority_adjustment": 10 + }, + "blocked": ["auto_restart"] +} +``` + +### Rig Bead Labels + +Rig operational state stored as labels on the rig identity bead: + +```bash +bd label add gt-rig-gastown status:docked +bd label remove gt-rig-gastown status:docked +``` + +### Daemon Integration + +The daemon's lifecycle manager checks config before starting services: + +```go +func (d *Daemon) maybeStartRigServices(rig string) { + r := d.getRig(rig) + + status := r.GetConfig("status") + if status == "parked" || status == "docked" { + log.Info("Rig %s is offline, skipping auto-start", rig) + return + } + + d.ensureWitness(rig) + d.ensureRefinery(rig) +} +``` + +## Related Documents + +- `~/gt/docs/hop/PROPERTY-LAYERS.md` - Strategic architecture +- `wisp-architecture.md` - Wisp system design +- `agent-as-bead.md` - Agent identity beads (similar pattern)