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>
240 lines
6.7 KiB
Markdown
240 lines
6.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
1. **Primary marker**: `mayor/town.json` - Definitive proof of harness root
|
|
2. **Secondary marker**: `mayor/` directory - Less definitive, continues searching upward
|
|
|
|
This two-tier search prevents false matches on rig-level `mayor/` directories.
|
|
|
|
```go
|
|
// 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/` with `gm-*` 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:
|
|
|
|
1. **Symlinks**: Rig root symlinks `.beads/` → `mayor/rig/.beads`
|
|
2. **Environment variable**: Agents receive `BEADS_DIR` pointing to the rig's beads
|
|
|
|
```bash
|
|
# 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:
|
|
- `gastown` for the Gas Town project
|
|
- `wyvern` for the Wyvern project
|
|
- Use lowercase, no spaces
|
|
|
|
## Example: Complete Harness Setup
|
|
|
|
```bash
|
|
# 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](architecture.md) - Full system architecture
|
|
- [Federation Design](federation-design.md) - Multi-machine deployment
|
|
- `gt doctor` - Health checks for harness and rigs
|