research: analyze role template management strategy
Findings: - Two competing mechanisms: embedded templates vs local-fork edits - Local-fork created ~200 lines of divergent content in mayor/CLAUDE.md - TOML config overrides exist but only handle operational config Recommendation: Extend TOML override system to support [content] sections for template customization, unifying all override mechanisms.
This commit is contained in:
273
thoughts/shared/research/role-template-strategy.md
Normal file
273
thoughts/shared/research/role-template-strategy.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Role Template Management Strategy
|
||||
|
||||
**Research Date:** 2026-01-26
|
||||
**Researcher:** kerosene (gastown/crew)
|
||||
**Status:** Analysis complete, recommendation provided
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Gas Town currently has **two competing mechanisms** for managing role context, leading to divergent content and maintenance complexity:
|
||||
|
||||
1. **Embedded templates** (`internal/templates/roles/*.md.tmpl`) - source of truth in binary
|
||||
2. **Local-fork edits** - direct modifications to runtime `CLAUDE.md` files
|
||||
|
||||
Additionally, there's a **third mechanism** for operational config that works well:
|
||||
|
||||
3. **Role config overrides** (`internal/config/roles.go`) - TOML-based config override chain
|
||||
|
||||
**Recommendation:** Extend the TOML override pattern to support template content sections, unifying all customization under one mechanism.
|
||||
|
||||
---
|
||||
|
||||
## Inventory: Current Mechanisms
|
||||
|
||||
### 1. Embedded Templates (internal/templates/roles/*.md.tmpl)
|
||||
|
||||
**Location:** `internal/templates/roles/`
|
||||
|
||||
**Files:**
|
||||
- `mayor.md.tmpl` (337 lines)
|
||||
- `crew.md.tmpl` (17,607 bytes)
|
||||
- `polecat.md.tmpl` (17,527 bytes)
|
||||
- `witness.md.tmpl` (11,746 bytes)
|
||||
- `refinery.md.tmpl` (13,525 bytes)
|
||||
- `deacon.md.tmpl` (13,727 bytes)
|
||||
- `boot.md.tmpl` (4,445 bytes)
|
||||
|
||||
**How it works:**
|
||||
- Templates are embedded into the binary via `//go:embed` directive
|
||||
- `gt prime` command renders templates with role-specific data (TownRoot, RigName, etc.)
|
||||
- Output is printed to stdout, where Claude picks it up as context
|
||||
- Uses Go template syntax: `{{ .TownRoot }}`, `{{ .RigName }}`, etc.
|
||||
|
||||
**Code path:** `templates.New()` → `tmpl.RenderRole()` → stdout
|
||||
|
||||
### 2. Local-Fork Edits (Runtime CLAUDE.md)
|
||||
|
||||
**Location:** Various agent directories (e.g., `mayor/CLAUDE.md`, `<rig>/crew/<name>/CLAUDE.md`)
|
||||
|
||||
**How it works:**
|
||||
- `gt install` creates minimal bootstrap CLAUDE.md (~15 lines) via `createMayorCLAUDEmd()`
|
||||
- Bootstrap content just says "Run `gt prime` for full context"
|
||||
- THEN humans/agents directly edit these files with custom content
|
||||
- These edits are committed to the town's git repo
|
||||
|
||||
**Example:** Mayor's CLAUDE.md grew from bootstrap to 532 lines
|
||||
|
||||
**Key local-fork commit:**
|
||||
```
|
||||
1cdbc27 docs: Enhance Mayor role template with coordination system knowledge (sc-n2oiz)
|
||||
```
|
||||
|
||||
This commit added ~500 lines to `mayor/CLAUDE.md` including:
|
||||
- Colony Model (why Gas Town uses coordinated specialists)
|
||||
- Escalation Patterns (Witness vs Mayor responsibilities)
|
||||
- Decision Flow (when to use polecats vs crew)
|
||||
- Multi-phase Orchestration
|
||||
- Monitoring without Micromanaging
|
||||
- Teaching GUPP patterns
|
||||
- Communication Patterns
|
||||
- Speed Asymmetry
|
||||
|
||||
**None of this content exists in the embedded template** - it's purely local-fork.
|
||||
|
||||
### 3. Role Config Overrides (TOML files)
|
||||
|
||||
**Location:**
|
||||
- Built-in: `internal/config/roles/*.toml` (embedded in binary)
|
||||
- Town-level: `<town>/roles/<role>.toml` (optional override)
|
||||
- Rig-level: `<rig>/roles/<role>.toml` (optional override)
|
||||
|
||||
**Resolution order (later wins):**
|
||||
1. Built-in defaults (embedded)
|
||||
2. Town-level overrides
|
||||
3. Rig-level overrides
|
||||
|
||||
**What it handles:**
|
||||
```toml
|
||||
# Example: mayor.toml
|
||||
role = "mayor"
|
||||
scope = "town"
|
||||
nudge = "Check mail and hook status, then act accordingly."
|
||||
prompt_template = "mayor.md.tmpl"
|
||||
|
||||
[session]
|
||||
pattern = "hq-mayor"
|
||||
work_dir = "{town}"
|
||||
needs_pre_sync = false
|
||||
start_command = "exec claude --dangerously-skip-permissions"
|
||||
|
||||
[env]
|
||||
GT_ROLE = "mayor"
|
||||
GT_SCOPE = "town"
|
||||
|
||||
[health]
|
||||
ping_timeout = "30s"
|
||||
consecutive_failures = 3
|
||||
kill_cooldown = "5m"
|
||||
stuck_threshold = "1h"
|
||||
```
|
||||
|
||||
**What it DOES NOT handle:**
|
||||
- Template content (the actual markdown context)
|
||||
- The `prompt_template` field just names which .md.tmpl to use
|
||||
|
||||
**Implementation:** `LoadRoleDefinition()` in `roles.go` handles the override chain with `mergeRoleDefinition()`.
|
||||
|
||||
---
|
||||
|
||||
## Analysis: Trade-offs
|
||||
|
||||
### Embedded Templates
|
||||
|
||||
| Pros | Cons |
|
||||
|------|------|
|
||||
| Single source of truth in binary | Requires recompile for changes |
|
||||
| Consistent across all installations | No per-town customization |
|
||||
| Supports placeholder substitution | Can't add town-specific sections |
|
||||
| Version-controlled in gastown repo | Changes don't propagate to existing installs |
|
||||
|
||||
### Local-Fork Edits
|
||||
|
||||
| Pros | Cons |
|
||||
|------|------|
|
||||
| Per-installation customization | Diverges from template source |
|
||||
| No recompile needed | Manual sync to keep up with template changes |
|
||||
| Town-specific content | Each install is unique snowflake |
|
||||
| Immediate effect | Template improvements don't propagate |
|
||||
|
||||
### Role Config Overrides
|
||||
|
||||
| Pros | Cons |
|
||||
|------|------|
|
||||
| Clean override chain | Only handles operational config |
|
||||
| Town/rig level customization | Doesn't handle template content |
|
||||
| Merge semantics (not replace) | - |
|
||||
| No recompile needed | - |
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
The current situation creates **three-way divergence**:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Embedded Template (mayor.md.tmpl) │
|
||||
│ 337 lines - "official" content │
|
||||
└──────────────────────────────────────────┘
|
||||
│
|
||||
│ gt prime renders
|
||||
│ BUT doesn't include
|
||||
│ local-fork additions
|
||||
v
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Runtime CLAUDE.md (mayor/CLAUDE.md) │
|
||||
│ 532 lines - has ~200 lines of local-fork content │
|
||||
│ INCLUDING: Colony Model, Escalation Patterns, etc. │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
1. When `gt prime` runs, it outputs the embedded template (337 lines)
|
||||
2. The local-fork content (Colony Model, etc.) is in `mayor/CLAUDE.md`
|
||||
3. Claude Code reads BOTH via `CLAUDE.md` + startup hooks
|
||||
4. But the embedded template and local CLAUDE.md overlap/conflict
|
||||
5. Template improvements in new gt versions don't include local-fork content
|
||||
6. Local-fork improvements aren't shared with other installations
|
||||
|
||||
---
|
||||
|
||||
## Recommendation: Unified Override System
|
||||
|
||||
**Extend the existing TOML override mechanism to support template content sections.**
|
||||
|
||||
### Proposed Design
|
||||
|
||||
```toml
|
||||
# <town>/roles/mayor.toml (town-level override)
|
||||
|
||||
# Existing operational overrides work as-is
|
||||
[health]
|
||||
stuck_threshold = "2h" # Town needs longer threshold
|
||||
|
||||
# NEW: Template content sections
|
||||
[content]
|
||||
# Append sections after the embedded template
|
||||
append = """
|
||||
## The Colony Model: Why Gas Town Works
|
||||
|
||||
Gas Town rejects the "super-ant" model... [rest of content]
|
||||
"""
|
||||
|
||||
# OR reference a file
|
||||
append_file = "mayor-additions.md"
|
||||
|
||||
# OR override specific sections by ID
|
||||
[content.sections.escalation]
|
||||
replace = """
|
||||
## Escalation Patterns: What to Handle vs Delegate
|
||||
...[custom content]...
|
||||
"""
|
||||
```
|
||||
|
||||
### Why This Works
|
||||
|
||||
1. **Single source of truth**: Embedded templates remain canonical
|
||||
2. **Clean override semantics**: Town/rig can append or replace sections
|
||||
3. **Existing infrastructure**: Uses the same TOML loading + merge pattern
|
||||
4. **No recompile**: Content overrides are runtime files
|
||||
5. **Shareable**: Town-level overrides can be committed to town repo
|
||||
6. **Migrateable**: Existing local-fork content can move to `[content]` sections
|
||||
|
||||
### Implementation Path
|
||||
|
||||
1. **Phase 1**: Add `[content]` support to role config
|
||||
- Parse `append`, `append_file`, `replace_sections` fields
|
||||
- Apply after template rendering in `outputPrimeContext()`
|
||||
|
||||
2. **Phase 2**: Migrate local-fork content
|
||||
- Extract custom sections from `mayor/CLAUDE.md`
|
||||
- Move to `<town>/roles/mayor.toml` `[content]` section
|
||||
- Reduce `mayor/CLAUDE.md` back to bootstrap pointer
|
||||
|
||||
3. **Phase 3**: Document the pattern
|
||||
- How to add town-specific guidance
|
||||
- How to share improvements back to embedded templates
|
||||
|
||||
---
|
||||
|
||||
## Alternative Considered: Pure Template Approach
|
||||
|
||||
**Idea:** Move all content into embedded templates, remove local CLAUDE.md entirely.
|
||||
|
||||
**Rejected because:**
|
||||
- Can't support per-town customization (e.g., different escalation policies)
|
||||
- Requires recompile for any content change
|
||||
- Forces all installations to be identical
|
||||
- Doesn't leverage existing override infrastructure
|
||||
|
||||
---
|
||||
|
||||
## Files Involved
|
||||
|
||||
For implementation, these files would need modification:
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `internal/config/roles.go` | Add `[content]` parsing to `RoleDefinition` |
|
||||
| `internal/cmd/prime_output.go` | Apply content overrides after template render |
|
||||
| `internal/templates/templates.go` | Potentially add section markers for replace |
|
||||
| `internal/cmd/install.go` | Update bootstrap to not create full CLAUDE.md |
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Approach | Verdict |
|
||||
|----------|---------|
|
||||
| **Embedded templates only** | Insufficient - no customization |
|
||||
| **Local-fork edits** | Current state - creates divergence |
|
||||
| **TOML content overrides** | **Recommended** - unifies all customization |
|
||||
|
||||
The TOML content override approach leverages existing infrastructure, provides clean semantics, and allows both standardization (embedded templates) and customization (override sections).
|
||||
Reference in New Issue
Block a user