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: <rig>/.beads-wisp/config/ ││ Synced: Never ││ Use: Temporary local overrides │└─────────────────────────────┬───────────────────────────────┘ │ if missing ▼┌─────────────────────────────────────────────────────────────┐│ 2. RIG BEAD LAYER (persistent, synced globally) ││ Location: <rig>/.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:
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:
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:
gt rig config set gastown auto_restart --blockThis 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:
id: gt-rig-gastowntype: rigname: gastownprefix: gt
labels: - status:operational - priority:normalThese beads sync via git, so all clones of the rig see the same state.
Two-Level Rig Control
Level 1: Park (Local, Ephemeral)
gt rig park gastown # Stop services, daemon won't restartgt 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)
gt rig dock gastown # Set status:docked label on rig beadgt 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:
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
gt rig config show gastown # Show effective config (all layers)gt rig config show gastown --layer # Show which layer each value comes fromSet Configuration
# 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 inheritancegt rig config set gastown key --block
# Clear from wisp layergt rig config unset gastown keyRig Lifecycle
gt rig park gastown # Local: stop + prevent restartgt rig unpark gastown # Local: allow restart
gt rig dock gastown # Global: mark as offlinegt rig undock gastown # Global: mark as operational
gt rig status gastown # Show current stateExamples
Temporary Priority Boost
# 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_adjustmentLocal Maintenance
# I'm upgrading the local clone, don't restart servicesgt rig park gastown
# ... do maintenance ...
gt rig unpark gastownProject-Wide Maintenance
# Major refactor in progress, all clones should pausegt rig dock gastown
# Syncs via git - other towns see the rig as dockedbd sync
# When done:gt rig undock gastownbd syncBlock Auto-Restart Locally
# 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 onlyImplementation Notes
Wisp Storage
Wisp config stored in .beads-wisp/config/<rig>.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:
bd label add gt-rig-gastown status:dockedbd label remove gt-rig-gastown status:dockedDaemon Integration
The daemon’s lifecycle manager checks config before starting services:
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 architecturewisp-architecture.md- Wisp system designagent-as-bead.md- Agent identity beads (similar pattern)