refactor(onboard): simplify to minimal snippet pointing to bd prime

bd onboard now outputs a ~10 line snippet for AGENTS.md that points to
"bd prime" for full workflow context. This replaces the previous ~200
line static content that:

- Bloated AGENTS.md with instructions that loaded every session
- Got stale when bd was upgraded
- Wasted tokens when beads was not actively being used

The new approach:
- AGENTS.md gets minimal pointer (~20 tokens vs ~2000)
- bd prime provides dynamic, always-current workflow details
- Hooks auto-inject bd prime at session start

Also removes the --output flag for BD_GUIDE.md generation (obsolete).

Closes bd-gxq
Addresses GH#604

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-18 11:47:16 -08:00
parent ecd46a6d6e
commit 125e36d529
2 changed files with 66 additions and 570 deletions

View File

@@ -2,8 +2,6 @@ package main
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
)
@@ -18,14 +16,12 @@ func TestOnboardCommand(t *testing.T) {
// Verify output contains expected sections
expectedSections := []string{
"bd Onboarding Instructions",
"Update AGENTS.md",
"Update CLAUDE.md",
"bd Onboarding",
"AGENTS.md",
"BEGIN AGENTS.MD CONTENT",
"END AGENTS.MD CONTENT",
"Issue Tracking with bd (beads)",
"Managing AI-Generated Planning Documents",
"history/",
"bd prime",
"How it works",
}
for _, section := range expectedSections {
@@ -35,155 +31,39 @@ func TestOnboardCommand(t *testing.T) {
}
})
t.Run("agents content includes slop management", func(t *testing.T) {
// Verify the agentsContent constant includes the new slop management section
if !strings.Contains(agentsContent, "Managing AI-Generated Planning Documents") {
t.Error("agentsContent should contain 'Managing AI-Generated Planning Documents' section")
t.Run("agents content is minimal and points to bd prime", func(t *testing.T) {
// Verify the agentsContent constant is minimal and points to bd prime
if !strings.Contains(agentsContent, "bd prime") {
t.Error("agentsContent should point to 'bd prime' for full workflow")
}
if !strings.Contains(agentsContent, "history/") {
t.Error("agentsContent should mention the 'history/' directory")
if !strings.Contains(agentsContent, "bd ready") {
t.Error("agentsContent should include quick reference to 'bd ready'")
}
if !strings.Contains(agentsContent, "PLAN.md") {
t.Error("agentsContent should mention example files like 'PLAN.md'")
if !strings.Contains(agentsContent, "bd create") {
t.Error("agentsContent should include quick reference to 'bd create'")
}
if !strings.Contains(agentsContent, "Do NOT clutter repo root with planning documents") {
t.Error("agentsContent should include rule about not cluttering repo root")
if !strings.Contains(agentsContent, "bd close") {
t.Error("agentsContent should include quick reference to 'bd close'")
}
if !strings.Contains(agentsContent, "bd sync") {
t.Error("agentsContent should include quick reference to 'bd sync'")
}
// Verify it's actually minimal (less than 500 chars)
if len(agentsContent) > 500 {
t.Errorf("agentsContent should be minimal (<500 chars), got %d chars", len(agentsContent))
}
})
t.Run("agents content includes bd workflow", func(t *testing.T) {
// Verify essential bd workflow content is present
essentialContent := []string{
"bd ready",
"bd create",
"bd update",
"bd close",
"discovered-from",
"--json",
"MCP Server",
t.Run("copilot instructions content is minimal", func(t *testing.T) {
// Verify copilotInstructionsContent is also minimal
if !strings.Contains(copilotInstructionsContent, "bd prime") {
t.Error("copilotInstructionsContent should point to 'bd prime'")
}
for _, content := range essentialContent {
if !strings.Contains(agentsContent, content) {
t.Errorf("agentsContent should contain '%s'", content)
}
}
})
}
func TestGenerateBDGuide(t *testing.T) {
t.Run("generates BD_GUIDE.md with version stamp", func(t *testing.T) {
// Create temp directory
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "BD_GUIDE.md")
// Generate BD_GUIDE.md
if err := generateBDGuide(outputPath); err != nil {
t.Fatalf("generateBDGuide() error = %v", err)
}
// Read generated file
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read generated file: %v", err)
}
output := string(content)
// Verify version stamp in header
if !strings.Contains(output, "Auto-generated by bd v"+Version) {
t.Error("Generated file should contain version stamp in header")
}
if !strings.Contains(output, "DO NOT EDIT MANUALLY") {
t.Error("Generated file should contain DO NOT EDIT warning")
}
// Verify regeneration instructions
if !strings.Contains(output, "bd onboard --output") {
t.Error("Generated file should contain regeneration instructions")
}
})
t.Run("includes agents content", func(t *testing.T) {
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "BD_GUIDE.md")
if err := generateBDGuide(outputPath); err != nil {
t.Fatalf("generateBDGuide() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read generated file: %v", err)
}
output := string(content)
// Verify key sections from agentsContent are present
expectedSections := []string{
"Issue Tracking with bd (beads)",
"bd ready",
"bd create",
"MCP Server",
}
for _, section := range expectedSections {
if !strings.Contains(output, section) {
t.Errorf("Generated file should contain '%s'", section)
}
}
})
t.Run("includes copilot instructions content", func(t *testing.T) {
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "BD_GUIDE.md")
if err := generateBDGuide(outputPath); err != nil {
t.Fatalf("generateBDGuide() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read generated file: %v", err)
}
output := string(content)
// Verify key sections from copilotInstructionsContent are present
expectedSections := []string{
"GitHub Copilot Instructions",
"Issue Tracking with bd",
"Essential Commands",
"Important Rules",
}
for _, section := range expectedSections {
if !strings.Contains(output, section) {
t.Errorf("Generated file should contain '%s'", section)
}
}
})
t.Run("has proper structure with separators", func(t *testing.T) {
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "BD_GUIDE.md")
if err := generateBDGuide(outputPath); err != nil {
t.Fatalf("generateBDGuide() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read generated file: %v", err)
}
output := string(content)
// Count separators (should have at least 3: after header, between sections, before footer)
separatorCount := strings.Count(output, "---")
if separatorCount < 3 {
t.Errorf("Expected at least 3 separators (---), got %d", separatorCount)
// Verify it's minimal (less than 500 chars)
if len(copilotInstructionsContent) > 500 {
t.Errorf("copilotInstructionsContent should be minimal (<500 chars), got %d chars", len(copilotInstructionsContent))
}
})
}