fix(priming): use bootstrap pointers instead of full CLAUDE.md templates
Fresh installs and rig adds were creating full CLAUDE.md files (285 lines for mayor, ~100 lines for other roles), causing gt doctor to fail the priming check immediately. Per the priming architecture, CLAUDE.md should be a minimal bootstrap pointer (<30 lines) that tells agents to run gt prime. Full context is injected ephemerally at session start. Changes: - install.go: createMayorCLAUDEmd now writes 12-line bootstrap pointer - manager.go: createRoleCLAUDEmd now writes role-specific bootstrap pointers for mayor, refinery, crew, and polecat roles Note: The AGENTS.md issue mentioned in #316 could not be reproduced - the code does not appear to create AGENTS.md at rig level. May be from an older version or different configuration. Partial fix for #316 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/steveyegge/gastown/internal/config"
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
"github.com/steveyegge/gastown/internal/deps"
|
"github.com/steveyegge/gastown/internal/deps"
|
||||||
"github.com/steveyegge/gastown/internal/formula"
|
"github.com/steveyegge/gastown/internal/formula"
|
||||||
"github.com/steveyegge/gastown/internal/session"
|
|
||||||
"github.com/steveyegge/gastown/internal/shell"
|
"github.com/steveyegge/gastown/internal/shell"
|
||||||
"github.com/steveyegge/gastown/internal/state"
|
"github.com/steveyegge/gastown/internal/state"
|
||||||
"github.com/steveyegge/gastown/internal/style"
|
"github.com/steveyegge/gastown/internal/style"
|
||||||
@@ -310,14 +309,23 @@ func runInstall(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createMayorCLAUDEmd(mayorDir, townRoot string) error {
|
func createMayorCLAUDEmd(mayorDir, townRoot string) error {
|
||||||
townName, _ := workspace.GetTownName(townRoot)
|
// Create a minimal bootstrap pointer instead of full context.
|
||||||
return templates.CreateMayorCLAUDEmd(
|
// Full context is injected ephemerally by `gt prime` at session start.
|
||||||
mayorDir,
|
// This keeps the on-disk file small (<30 lines) per priming architecture.
|
||||||
townRoot,
|
bootstrap := `# Mayor Context
|
||||||
townName,
|
|
||||||
session.MayorSessionName(),
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
session.DeaconSessionName(),
|
|
||||||
)
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
- Check mail: ` + "`gt mail inbox`" + `
|
||||||
|
- Check rigs: ` + "`gt rig list`" + `
|
||||||
|
- Start patrol: ` + "`gt patrol start`" + `
|
||||||
|
`
|
||||||
|
claudePath := filepath.Join(mayorDir, "CLAUDE.md")
|
||||||
|
return os.WriteFile(claudePath, []byte(bootstrap), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeJSON(path string, data interface{}) error {
|
func writeJSON(path string, data interface{}) error {
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ import (
|
|||||||
"github.com/steveyegge/gastown/internal/constants"
|
"github.com/steveyegge/gastown/internal/constants"
|
||||||
"github.com/steveyegge/gastown/internal/config"
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
"github.com/steveyegge/gastown/internal/git"
|
"github.com/steveyegge/gastown/internal/git"
|
||||||
"github.com/steveyegge/gastown/internal/templates"
|
|
||||||
"github.com/steveyegge/gastown/internal/workspace"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common errors
|
// Common errors
|
||||||
@@ -900,46 +898,75 @@ func (m *Manager) ListRigNames() []string {
|
|||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRoleCLAUDEmd creates a CLAUDE.md file with role-specific context.
|
// createRoleCLAUDEmd creates a minimal bootstrap pointer CLAUDE.md file.
|
||||||
// This ensures each workspace (crew, refinery, mayor) gets the correct prompting,
|
// Full context is injected ephemerally by `gt prime` at session start.
|
||||||
// overriding any CLAUDE.md that may exist in the cloned repository.
|
// This keeps on-disk files small (<30 lines) per the priming architecture.
|
||||||
func (m *Manager) createRoleCLAUDEmd(workspacePath string, role string, rigName string, workerName string) error {
|
func (m *Manager) createRoleCLAUDEmd(workspacePath string, role string, rigName string, workerName string) error {
|
||||||
tmpl, err := templates.New()
|
// Create role-specific bootstrap pointer
|
||||||
if err != nil {
|
var bootstrap string
|
||||||
return err
|
switch role {
|
||||||
}
|
case "mayor":
|
||||||
|
bootstrap = `# Mayor Context (` + rigName + `)
|
||||||
|
|
||||||
// Get town name for session names
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
townName, _ := workspace.GetTownName(m.townRoot)
|
|
||||||
|
|
||||||
// Get default branch from rig config (default to "main" if not set)
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
defaultBranch := "main"
|
`
|
||||||
if rigName != "" {
|
case "refinery":
|
||||||
rigPath := filepath.Join(m.townRoot, rigName)
|
bootstrap = `# Refinery Context (` + rigName + `)
|
||||||
if rigCfg, err := LoadRigConfig(rigPath); err == nil && rigCfg.DefaultBranch != "" {
|
|
||||||
defaultBranch = rigCfg.DefaultBranch
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
|
|
||||||
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
- Check MQ: ` + "`gt mq list`" + `
|
||||||
|
- Process next: ` + "`gt mq process`" + `
|
||||||
|
`
|
||||||
|
case "crew":
|
||||||
|
name := workerName
|
||||||
|
if name == "" {
|
||||||
|
name = "worker"
|
||||||
}
|
}
|
||||||
}
|
bootstrap = `# Crew Context (` + rigName + `/` + name + `)
|
||||||
|
|
||||||
data := templates.RoleData{
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
Role: role,
|
|
||||||
RigName: rigName,
|
|
||||||
TownRoot: m.townRoot,
|
|
||||||
TownName: townName,
|
|
||||||
WorkDir: workspacePath,
|
|
||||||
DefaultBranch: defaultBranch,
|
|
||||||
Polecat: workerName, // Used for crew member name as well
|
|
||||||
MayorSession: fmt.Sprintf("gt-%s-mayor", townName),
|
|
||||||
DeaconSession: fmt.Sprintf("gt-%s-deacon", townName),
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := tmpl.RenderRole(role, data)
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
if err != nil {
|
|
||||||
return err
|
## Quick Reference
|
||||||
|
|
||||||
|
- Check hook: ` + "`gt hook`" + `
|
||||||
|
- Check mail: ` + "`gt mail inbox`" + `
|
||||||
|
`
|
||||||
|
case "polecat":
|
||||||
|
name := workerName
|
||||||
|
if name == "" {
|
||||||
|
name = "worker"
|
||||||
|
}
|
||||||
|
bootstrap = `# Polecat Context (` + rigName + `/` + name + `)
|
||||||
|
|
||||||
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
|
|
||||||
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
- Check hook: ` + "`gt hook`" + `
|
||||||
|
- Report done: ` + "`gt done`" + `
|
||||||
|
`
|
||||||
|
default:
|
||||||
|
bootstrap = `# Agent Context
|
||||||
|
|
||||||
|
> **Recovery**: Run ` + "`gt prime`" + ` after compaction, clear, or new session
|
||||||
|
|
||||||
|
Full context is injected by ` + "`gt prime`" + ` at session start.
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
claudePath := filepath.Join(workspacePath, "CLAUDE.md")
|
claudePath := filepath.Join(workspacePath, "CLAUDE.md")
|
||||||
return os.WriteFile(claudePath, []byte(content), 0644)
|
return os.WriteFile(claudePath, []byte(bootstrap), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createPatrolHooks creates .claude/settings.json with hooks for patrol roles.
|
// createPatrolHooks creates .claude/settings.json with hooks for patrol roles.
|
||||||
|
|||||||
Reference in New Issue
Block a user