Merge polecat/Dementus: harness design documentation (gt-cr9)

This commit is contained in:
Steve Yegge
2025-12-19 12:50:26 -08:00
4 changed files with 401 additions and 356 deletions
+45 -22
View File
@@ -45,16 +45,28 @@ graph TB
## Core Concepts
### Harness
### Harness (Town)
A **Harness** is the installation directory for Gas Town - the top-level workspace containing all components. The canonical GGT harness is at `~/gt/`. See [harness.md](harness.md) for setup details and migration from legacy configurations.
A **Harness** is the installation directory where Gas Town lives - the physical root of your workspace. The terms "harness" and "town" are often used interchangeably:
- **Harness** = physical (the directory at `~/gt/`)
- **Town** = logical (the Gas Town workspace concept)
### Town
A harness contains:
- `CLAUDE.md` - Mayor role context (Mayor runs from harness root)
- `mayor/` - Mayor configuration, state, and registry
- `.beads/` - Town-level beads (gm-* prefix for mayor mail)
- `rigs/` or rig directories - Managed project containers
A **Town** is a complete Gas Town installation - the workspace where everything lives. A town contains:
- Town configuration (`config/` directory)
- Mayor's home (`mayor/` directory at town level)
- One or more **Rigs** (managed project repositories)
Create a harness with `gt install`:
```bash
gt install ~/gt --git # Create harness with git
```
**See**: [docs/harness.md](harness.md) for comprehensive harness documentation, including:
- Beads redirect patterns for complex setups
- Multi-system sharing (PGT/GGT coexistence)
- Harness templates for organizations
- Migration between harnesses
### Rig
@@ -220,25 +232,33 @@ This enables "Engineer in a Box" - polecats that execute structured workflows wi
## Directory Structure
### Town Level
### Harness Level
The harness (town root) is created by `gt install`:
```
~/gt/ # Town root (Gas Town harness)
├── CLAUDE.md # Mayor role prompting (at town root)
~/gt/ # HARNESS ROOT (Gas Town installation)
├── CLAUDE.md # Mayor role context (runs from here)
├── .beads/ # Town-level beads (prefix: gm-)
│ ├── beads.db # Mayor mail, coordination, handoffs
│ └── config.yaml
├── mayor/ # Mayor's HOME at town level
├── mayor/ # Mayor configuration and state
│ ├── town.json # {"type": "town", "name": "..."}
│ ├── rigs.json # Registry of managed rigs
│ └── state.json # Mayor state (NO mail/ directory)
│ └── state.json # Mayor agent state
├── gastown/ # A rig (project container)
└── wyvern/ # Another rig
├── rigs/ # Standard location for rigs
│ ├── gastown/ # A rig (project container)
│ └── wyvern/ # Another rig
└── <rig>/ # OR rigs at harness root (legacy)
```
**Note**: Mayor's mail is now in town beads (`gm-*` issues), not JSONL files.
**Notes**:
- Mayor's mail is in town beads (`gm-*` issues), not JSONL files
- Rigs can be in `rigs/` or at harness root (both work)
- See [docs/harness.md](harness.md) for advanced harness configurations
### Rig Level
@@ -320,19 +340,19 @@ graph TB
### ASCII Directory Layout
For reference without mermaid rendering:
For reference without mermaid rendering (see [harness.md](harness.md) for creation/setup):
```
~/gt/ # TOWN ROOT (Gas Town harness)
├── CLAUDE.md # Mayor role prompting
~/gt/ # HARNESS ROOT (Gas Town installation)
├── CLAUDE.md # Mayor role context
├── .beads/ # Town-level beads (gm-* prefix)
│ ├── beads.db # Mayor mail, coordination
│ └── config.yaml
├── mayor/ # Mayor's home (at town level)
├── mayor/ # Mayor configuration and state
│ ├── town.json # {"type": "town", "name": "..."}
│ ├── rigs.json # Registry of managed rigs
│ └── state.json # Mayor state (no mail/ dir)
│ └── state.json # Mayor agent state
├── gastown/ # RIG (container, NOT a git clone)
│ ├── config.json # Rig configuration
@@ -1046,10 +1066,13 @@ This ensures all agents in the rig share a single beads database, separate from
## CLI Commands
### Town Management
### Harness Management
```bash
gt install [path] # Install Gas Town at path
gt install [path] # Create Gas Town harness (see harness.md)
gt install --git # Also initialize git with .gitignore
gt install --github=u/r # Also create GitHub repo
gt git-init # Initialize git for existing harness
gt doctor # Check workspace health
gt doctor --fix # Auto-fix issues
```
+274 -259
View File
@@ -1,316 +1,331 @@
# Gas Town Harness
# Gas Town Harness Design
A **harness** is a private repository that contains your Gas Town installation with managed rigs gitignored. This document explains what harnesses are, why you'd want one, and how to configure beads redirects.
A **harness** is the top-level directory where Gas Town is installed - the workspace that contains all your rigs, agents, and coordination infrastructure.
## What is a Harness?
## What Is a Harness?
A harness is the top-level directory where Gas Town is installed. It serves as:
Think of a harness as the "mount point" for Gas Town. It's the root directory where:
- The Mayor operates from
- Rigs are registered and managed
- Town-level beads coordinate mail and handoffs
- The entire workspace is versioned as a git repository
1. **Your workspace root**: Where the Mayor runs and coordinates all work
2. **Configuration home**: Contains town-level settings, Mayor state, and role prompts
3. **Private envelope**: Lets you work on public projects while keeping your GT config private
A harness is NOT:
- A git clone of any project (rigs contain the clones)
- A hidden directory (it's visible and user-controlled)
- Tied to any specific project (it can manage multiple rigs)
### Harness vs Rig
| Concept | What it is | Git tracked? |
|---------|------------|--------------|
| **Harness** | Gas Town installation directory | Yes (your private repo) |
| **Rig** | Project container within harness | No (gitignored) |
| **Rig clone** | Git checkout of a project | No (gitignored) |
The harness is YOUR repo. Rigs are containers for OTHER repos (the projects you work on).
### Harness Structure
## Harness Structure
```
~/gt/ # Harness root (your private repo)
├── .git/ # Your harness repo
├── .gitignore # Ignores rig contents
├── .beads/ # Town-level beads (Mayor mail)
│ ├── redirect # Points to active rig beads
│ └── ...
├── CLAUDE.md # Mayor role context
~/gt/ # HARNESS ROOT
├── .git/ # Harness is a git repo
├── .gitignore # Generated by gt git-init
├── .beads/ # Town-level beads (gm-* prefix)
│ ├── beads.db # Mayor mail, coordination, handoffs
│ └── config.yaml # Beads config with prefix: gm
├── CLAUDE.md # Mayor role context (runs from here)
├── mayor/ # Mayor config and state
│ ├── town.json
│ ├── rigs.json
│ └── state.json
├── gastown/ # A rig (gitignored)
│ ├── config.json
│ ├── .beads/ # Rig beads
── mayor/rig/ # Mayor's clone
├── polecats/ # Worker clones
│ └── ...
└── wyvern/ # Another rig (gitignored)
│ ├── town.json # {"type": "town", "name": "..."}
│ ├── rigs.json # Registry of managed rigs
│ └── state.json # Mayor state
├── rigs/ # Managed rig containers
│ ├── gastown/ # A rig (project container)
── wyvern/ # Another rig
└── <rig-name>/ # OR rigs at harness root (legacy)
```
## Why Use a Harness?
## Creating a Harness
### 1. Work on Public Projects Privately
You might be contributing to open source projects but want to keep your AI workflow private. The harness lets you:
- Track your Gas Town configuration in a private repo
- Work on any project (public or private) as a rig
- Keep project-specific beads and agent state separate from the upstream
### 2. Unified Workspace
One harness can manage multiple rigs:
Use `gt install` to create a new harness:
```bash
~/gt/ # Your harness
├── gastown/ # The Gas Town Go port
├── wyvern/ # A game engine
├── beads/ # The beads CLI tool
└── client-project/ # Private client work
```
Each rig is independent but shares the same Mayor and town-level coordination.
### 3. Portable Configuration
Your harness repo captures:
- Mayor role prompts (CLAUDE.md)
- Town configuration
- Rig registry (which projects you're managing)
- Town-level beads (handoff messages, coordination)
Clone your harness to a new machine and `gt rig add` to restore your workspace.
## Setting Up a Harness
### 1. Install Gas Town
```bash
# Create harness at ~/gt
# Create a new harness
gt install ~/gt
# Or initialize current directory
cd ~/gt
gt install .
# Create with git initialization
gt install ~/gt --git
# Create and push to GitHub
gt install ~/gt --github=username/my-gastown --private
# Initialize current directory as harness
gt install . --name my-workspace
```
### 2. Initialize Git
The install command:
1. Creates the directory structure (`mayor/`, `rigs/`)
2. Writes configuration files (`town.json`, `rigs.json`, `state.json`)
3. Generates `CLAUDE.md` with Mayor role context
4. Initializes town-level beads with `gm-` prefix
5. Optionally initializes git with `.gitignore`
## Harness vs Town vs Rig
| Concept | Description | Example |
|---------|-------------|---------|
| **Harness** | Installation directory | `~/gt/` |
| **Town** | Logical workspace (same as harness) | The Gas Town instance |
| **Rig** | Project container within harness | `~/gt/gastown/` |
The terms "harness" and "town" are often used interchangeably. A harness IS a town. The distinction is physical (harness = directory) vs logical (town = workspace concept).
## Beads in a Harness
A harness has **two levels** of beads:
### Town-Level Beads
Located at `<harness>/.beads/` with `gm-` prefix:
- Mayor mail and inbox
- Cross-rig coordination messages
- Session handoff notes
### Rig-Level Beads
Each rig has its own `.beads/` with a project-specific prefix:
- Work issues (bugs, features, tasks)
- Merge requests
- Agent-local mail within the rig
The Mayor sees both: town beads for mail, rig beads for work coordination.
## Beads Redirect Pattern
In complex setups, you may want the harness root's `.beads/` to redirect to a rig's beads. This is useful when:
- Multiple systems share a harness
- You want a single source of truth for beads
- Migration scenarios
Create a redirect file:
```bash
# Create local git repo
gt git-init
# Or create with GitHub remote
gt git-init --github=username/my-gt-harness --private
# Instead of .beads/ directory, create .beads/redirect file
mkdir .beads
echo "path/to/actual/.beads" > .beads/redirect
```
### 3. Add Rigs
```bash
cd ~/gt
gt rig add gastown https://github.com/steveyegge/gastown
gt rig add wyvern https://github.com/steveyegge/wyvern
Example from a real setup:
```
# ~/ai/.beads/redirect
# Redirect to gastown beads (Mayor workspace)
# The Mayor runs in ~/ai but manages gastown issues in mayor/rigs/gastown
mayor/rigs/gastown/.beads
```
Rigs are automatically gitignored. Your harness tracks THAT you have a gastown rig (in `mayor/rigs.json`), but not its contents.
**When to use redirects:**
- Shared harness between different Gas Town versions (PGT/GGT)
- When rig beads should be the canonical town beads
- Hybrid setups where agents work in different locations
## Beads Redirects
## Multiple Gas Towns in One Location
Sometimes you need to run multiple Gas Town systems from the same parent directory. This creates a "shared harness" scenario.
### The Problem
When the Mayor runs from the harness root (`~/gt/`), where should beads commands go?
- The harness has its own `.beads/` for town-level mail
- But most work happens in rig-level beads (issues, tasks, epics)
- Running `bd list` from `~/gt/` should show rig issues, not just Mayor mail
### The Solution: Redirect Files
The `.beads/redirect` file tells beads to look elsewhere for issues:
If Python Gas Town (PGT) and Go Gas Town (GGT) both use `~/ai/`:
```
# ~/gt/.beads/redirect
# Redirect beads queries to the gastown rig
gastown/mayor/.beads
~/ai/
├── .gastown/ # PGT config
├── .beads/ # Which system owns this?
├── mayor/ # PGT mayor? GGT mayor?
└── gastown/ # PGT rig? GGT rig?
```
With this redirect:
- `bd list` from `~/gt/` shows gastown issues
- `bd mail inbox` from `~/gt/` shows Mayor mail (uses town beads)
- Mayor can manage rig work without `cd`ing into the rig
### Solutions
### Configuring Redirects
**Option 1: Separate harnesses (recommended)**
```
~/ai/ # PGT harness
~/gt/ # GGT harness (separate)
```
The redirect file contains a single relative path to the target beads directory:
**Option 2: Namespaced directories**
```
~/ai/
├── pgt/ # PGT harness
│ ├── mayor/
│ └── gastown/
└── ggt/ # GGT harness
├── mayor/
└── gastown/
```
**Option 3: Beads redirect (advanced)**
```
~/ai/
├── .beads/redirect # Points to canonical location
├── pgt-mayor/ # PGT-specific
├── ggt-mayor/ # GGT-specific
└── gastown/ # Shared rig
```
## Harness Configuration Files
### mayor/town.json
Identifies this as a Gas Town installation:
```json
{
"type": "town",
"version": 1,
"name": "stevey-gastown",
"created_at": "2024-01-15T10:30:00Z"
}
```
### mayor/rigs.json
Registry of 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-16T09:00:00Z"
}
}
}
```
### mayor/state.json
Mayor agent state:
```json
{
"role": "mayor",
"last_active": "2024-01-17T14:30:00Z"
}
```
## Git for Harnesses
A harness should be a git repository. This enables:
- Versioning of configuration
- Beads sync across machines
- Session handoff via beads commits
- Recovery after failures
### Initialize git
```bash
# Edit the redirect
echo "gastown/mayor/.beads" > ~/gt/.beads/redirect
# Or for a different rig
echo "wyvern/mayor/.beads" > ~/gt/.beads/redirect
gt git-init # Basic git setup
gt git-init --github=user/repo # Create GitHub repo
gt git-init --github=user/repo --private # Private repo
```
### Directory Structure with Redirect
### Standard .gitignore
```
~/gt/.beads/ # Town beads
├── redirect # → gastown/mayor/.beads
├── config.yaml # Town beads config
├── beads.db # Town beads (Mayor mail)
└── issues.jsonl # Town issues
The `gt git-init` command creates:
~/gt/gastown/mayor/.beads/ # Rig beads (redirect target)
├── config.yaml # Rig beads config
├── beads.db # Rig beads
└── issues.jsonl # Rig issues (gt-* prefix)
```gitignore
# Gas Town harness gitignore
# Agent sessions and logs
*.log
*.pid
/sessions/
# Rig working directories (managed separately)
/rigs/*/polecats/*/
/rigs/*/refinery/rig/
/rigs/*/crew/*/
# Sensitive files
.env
*.key
*.pem
credentials.json
# Editor and OS
.DS_Store
*.swp
*~
.idea/
.vscode/
# Beads daemon
.beads/beads.sock
.beads/*.pid
```
### Multi-Rig Workflow
## Harness Health Checks
If you're working on multiple rigs, change the redirect to focus on different projects:
Run `gt doctor` to check harness health:
```bash
# Working on gastown today
echo "gastown/mayor/.beads" > ~/gt/.beads/redirect
# Switching to wyvern
echo "wyvern/mayor/.beads" > ~/gt/.beads/redirect
gt doctor # Check all
gt doctor --fix # Auto-fix issues
```
Or stay in rig directories where beads naturally finds the local `.beads/`:
Checks include:
- Configuration file validity
- Mayor state consistency
- Rig registry accuracy
- Beads database health
- Git state cleanliness
## Harness Templates
For organizations wanting consistent Gas Town setups, create a template repository:
```bash
cd ~/gt/gastown/polecats/MyPolecat
bd list # Uses rig beads automatically
# Create template harness
gt install ~/gt-template --git --no-beads
# Customize CLAUDE.md, add standard rigs
# Push to GitHub as template repo
# Users clone template
gh repo create my-gastown --template org/gt-template
cd my-gastown
gt install . --force # Reinitialize with fresh beads
```
## The GGT Directory Structure
## Migration Between Harnesses
The Go Gas Town (GGT) uses a specific convention for rig beads:
To move Gas Town to a new location:
```
gastown/ # Rig container
├── mayor/ # Mayor's per-rig presence
│ ├── .beads/ # Canonical rig beads
│ └── rig/ # Mayor's clone (if separate)
└── .beads/ → mayor/.beads # Symlink (optional)
```
1. **Export beads state:**
```bash
bd export > beads-backup.jsonl
```
The redirect path for GGT rigs is: `<rig>/mayor/.beads`
2. **Create new harness:**
```bash
gt install ~/new-harness --git
```
This differs from older structures where beads might be at `mayor/rigs/<rig>/.beads`. When updating from older setups, change your redirect accordingly:
3. **Add rigs:**
```bash
cd ~/new-harness
gt rig add gastown https://github.com/user/gastown
```
```bash
# Old structure
echo "mayor/rigs/gastown/.beads" > ~/.beads/redirect
# GGT structure
echo "gastown/mayor/.beads" > ~/.beads/redirect
```
## Harness Git Workflow
### What Gets Tracked
The harness `.gitignore` (created by `gt git-init`) tracks:
**Tracked:**
- `CLAUDE.md` - Mayor role context
- `mayor/*.json` - Town and rig registry
- `.beads/config.yaml` - Beads configuration
- `.beads/issues.jsonl` - Town-level beads (Mayor mail)
**Ignored:**
- `*/` - All rig directories
- `.beads/*.db` - SQLite databases (regenerated from JSONL)
- `**/rig/` - All git clones
- `**/polecats/` - All worker directories
### Committing Changes
```bash
cd ~/gt
git add .
git commit -m "Update Mayor context"
git push
```
Rig work is committed IN the rig clones, not the harness.
## Troubleshooting
### "Not in a beads repo"
Check that `.beads/` exists and has either issues.jsonl or a redirect:
```bash
ls -la .beads/
cat .beads/redirect
```
### Redirect points to wrong location
Verify the redirect path is relative to the harness root and the target exists:
```bash
# Check current redirect
cat ~/gt/.beads/redirect
# Verify target exists
ls -la ~/gt/$(cat ~/gt/.beads/redirect)
```
### Wrong issues showing
If you see unexpected issues, check which beads directory is active:
```bash
# Where is beads looking?
bd doctor
# Override with explicit path
BEADS_DIR=~/gt/gastown/mayor/.beads bd list
```
4. **Import beads:**
```bash
cd ~/new-harness
bd import < beads-backup.jsonl
```
## Summary
- **Harness**: Your private Gas Town installation repo
- **Rigs**: Project containers, gitignored from harness
- **Redirect**: Tells town-level beads where to find rig issues
- **GGT path**: `<rig>/mayor/.beads` for Go Gas Town structure
The harness gives you a unified workspace for managing multiple projects while keeping your AI coordination infrastructure private.
## Historical Context: PGT/GGT Separation
During initial GGT (Go Gas Town) development, both implementations briefly shared `~/ai/`:
```
~/ai/ (legacy mixed harness - DO NOT USE for GGT)
├── gastown/
│ ├── .gastown/ # PGT marker
│ └── mayor/ # OLD GGT clone (deprecated)
├── mayor/ # PGT Mayor home
└── .beads/redirect # OLD redirect (deprecated)
```
This caused confusion because:
- `~/ai/gastown/` contained both PGT markers AND GGT code
- `~/ai/mayor/` was PGT's Mayor home, conflicting with GGT concepts
- The beads redirect pointed at GGT beads from a PGT harness
The separation was completed by creating `~/gt/` as the dedicated GGT harness.
### Cleanup Steps for ~/ai/
If you have the legacy mixed harness, clean it up:
```bash
# Remove old GGT clone (beads are no longer here)
rm -rf ~/ai/gastown/mayor/
# Remove old beads redirect
rm ~/ai/.beads/redirect
# Keep PGT-specific files:
# - ~/ai/mayor/ (PGT Mayor home)
# - ~/ai/gastown/.gastown/ (PGT marker)
```
| Action | Command |
|--------|---------|
| Create harness | `gt install <path>` |
| Initialize git | `gt git-init` |
| Add rig | `gt rig add <name> <git-url>` |
| Check health | `gt doctor` |
| View status | `gt status` |