Add docs/harness.md covering: - What a harness (installation directory) is - Directory structure with mayor/ config files - Town-level vs rig-level mayor presence - Beads architecture and resolution via BEADS_DIR - Relationship between harness and rigs - Example configurations and setup workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.7 KiB
Harness Documentation
A harness is the installation directory for Gas Town - the top-level workspace where your multi-agent system lives. The terms "harness" and "town" are used interchangeably.
What is a Harness?
Think of a harness as:
- Physical: A directory on your filesystem (e.g.,
~/gt/) - Logical: The container for all your rigs, agents, and coordination infrastructure
- Operational: The root from which the Mayor coordinates work across projects
A harness is NOT a git repository itself. It's a pure container that holds:
- Town-level configuration in
mayor/ - Town-level beads database in
.beads/ - Multiple rigs (each managing a project repository)
Creating a Harness
gt install ~/gt # Install Gas Town at ~/gt
gt install # Install at current directory
This creates the harness structure and initializes town-level beads with the gm- prefix.
Directory Structure
~/gt/ # Harness root (town)
├── CLAUDE.md # Mayor role prompting
├── .beads/ # Town-level beads (prefix: gm-)
│ ├── beads.db # Mayor mail, coordination, handoffs
│ └── config.yaml
│
├── mayor/ # Mayor's home directory
│ ├── town.json # Town configuration
│ ├── rigs.json # Registry of managed rigs
│ └── state.json # Mayor agent state
│
├── gastown/ # A rig (project container)
├── wyvern/ # Another rig
└── rigs/ # Optional: managed rig clones
Configuration Files
mayor/town.json
The town configuration identifies this directory as a Gas Town harness:
{
"type": "town",
"version": 1,
"name": "stevey-gastown",
"created_at": "2024-01-15T10:30:00Z"
}
The type: "town" field is the primary marker that identifies the harness root during workspace detection.
mayor/rigs.json
Registry of all managed rigs:
{
"version": 1,
"rigs": {
"gastown": {
"git_url": "https://github.com/steveyegge/gastown",
"added_at": "2024-01-15T10:30:00Z"
},
"wyvern": {
"git_url": "https://github.com/steveyegge/wyvern",
"added_at": "2024-01-16T14:20:00Z"
}
}
}
mayor/state.json
Mayor's agent state:
{
"role": "mayor",
"last_active": "2025-12-19T10:00:00Z"
}
Harness Detection
Gas Town finds the harness by walking up the directory tree looking for markers:
- Primary marker:
mayor/town.json- Definitive proof of harness root - Secondary marker:
mayor/directory - Less definitive, continues searching upward
This two-tier search prevents false matches on rig-level mayor/ directories.
// Simplified detection logic
func FindHarness(startDir string) string {
current := startDir
for current != "/" {
if exists(current + "/mayor/town.json") {
return current // Primary match
}
current = parent(current)
}
return ""
}
Mayor: Town-Level vs Rig-Level
Gas Town has two levels of "mayor" presence:
Town-Level Mayor (<harness>/mayor/)
- Location: At the harness root
- Purpose: Global coordination across all rigs
- Configuration: Contains
town.json,rigs.json,state.json - Mailbox: Uses town-level beads (
.beads/withgm-*prefix) - Responsibility: Work dispatch, cross-rig coordination, escalation handling
Per-Rig Mayor (<harness>/<rig>/mayor/rig/)
- Location: Within each rig's directory
- Purpose: Provides the canonical git clone for the rig
- Contents: Full git clone of the project repository
- Beads: Holds the canonical
.beads/directory for the rig - Special role: Source of git worktrees for polecats
~/gt/ # Harness root
├── mayor/ # Town-level mayor home
│ ├── town.json # Town config (not project code)
│ ├── rigs.json
│ └── state.json
│
└── gastown/ # Rig container
└── mayor/ # Per-rig mayor presence
└── rig/ # CANONICAL git clone
├── .git/
├── .beads/ # Canonical rig beads
└── <project files>
Beads Architecture
Gas Town uses a two-tier beads architecture:
| Level | Location | Prefix | Purpose |
|---|---|---|---|
| Town | <harness>/.beads/ |
gm-* |
Mayor mail, cross-rig coordination, handoffs |
| Rig | <rig>/mayor/rig/.beads/ |
varies | Rig-local work tracking, agent communication |
Beads Resolution
Rather than using a .beads/redirect file, Gas Town uses:
- Symlinks: Rig root symlinks
.beads/→mayor/rig/.beads - Environment variable: Agents receive
BEADS_DIRpointing to the rig's beads
# When spawning agents
export BEADS_DIR=/path/to/rig/.beads
This ensures all agents in a rig share the same beads database, separate from any beads the project might have upstream.
Relationship to Rigs
A harness contains multiple rigs. Each rig is:
- A container directory (NOT a git clone itself)
- Added via
gt rig add <name> <git-url> - Registered in
mayor/rigs.json - Has its own agents (witness, refinery, polecats)
Harness (town)
├── Rig 1 (gastown/)
│ ├── witness/
│ ├── refinery/
│ ├── polecats/
│ └── mayor/rig/ ← canonical clone
│
├── Rig 2 (wyvern/)
│ ├── witness/
│ ├── refinery/
│ ├── polecats/
│ └── mayor/rig/ ← canonical clone
│
└── Rig N...
Naming Conventions
Recommended harness naming:
- Short, memorable name:
~/gt/(gas town) - Or project-specific:
~/workspace/ - Or user-specific:
~/ai/
Rig names typically match the project:
gastownfor the Gas Town projectwyvernfor the Wyvern project- Use lowercase, no spaces
Example: Complete Harness Setup
# 1. Install harness
gt install ~/gt
# 2. Add rigs
cd ~/gt
gt rig add gastown https://github.com/steveyegge/gastown
gt rig add wyvern https://github.com/steveyegge/wyvern
# 3. Verify structure
ls -la ~/gt/
# CLAUDE.md .beads/ mayor/ gastown/ wyvern/
# 4. Check town config
cat ~/gt/mayor/town.json
# {"type":"town","version":1,"name":"..."}
# 5. Check registered rigs
cat ~/gt/mayor/rigs.json
# {"version":1,"rigs":{"gastown":{...},"wyvern":{...}}}
See Also
- Architecture Overview - Full system architecture
- Federation Design - Multi-machine deployment
gt doctor- Health checks for harness and rigs