From 125e36d52947e5168758429c9042e5185d319af4 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Thu, 18 Dec 2025 11:47:16 -0800 Subject: [PATCH] refactor(onboard): simplify to minimal snippet pointing to bd prime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- cmd/bd/onboard.go | 458 ++++------------------------------------- cmd/bd/onboard_test.go | 178 +++------------- 2 files changed, 66 insertions(+), 570 deletions(-) diff --git a/cmd/bd/onboard.go b/cmd/bd/onboard.go index 242823df..5edba664 100644 --- a/cmd/bd/onboard.go +++ b/cmd/bd/onboard.go @@ -3,7 +3,6 @@ package main import ( "fmt" "io" - "os" "github.com/fatih/color" "github.com/spf13/cobra" @@ -11,272 +10,35 @@ import ( const copilotInstructionsContent = `# GitHub Copilot Instructions -## Issue Tracking with bd +## Issue Tracking -This project uses **bd (beads)** for issue tracking - a Git-backed tracker designed for AI-supervised coding workflows. +This project uses **bd (beads)** for issue tracking. +Run ` + "`bd prime`" + ` for workflow context, or install hooks (` + "`bd hooks install`" + `) for auto-injection. -**Key Features:** -- Dependency-aware issue tracking -- Auto-sync with Git via JSONL -- AI-optimized CLI with JSON output -- Built-in daemon for background operations -- MCP server integration for Claude and other AI assistants +**Quick reference:** +- ` + "`bd ready`" + ` - Find unblocked work +- ` + "`bd create \"Title\" --type task --priority 2`" + ` - Create issue +- ` + "`bd close `" + ` - Complete work +- ` + "`bd sync`" + ` - Sync with git (run at session end) -**CRITICAL**: Use bd for ALL task tracking. Do NOT create markdown TODO lists. +For full workflow details: ` + "`bd prime`" + `` -### Essential Commands +const agentsContent = `## Issue Tracking -` + "```bash" + ` -# Find work -bd ready --json # Unblocked issues -bd stale --days 30 --json # Forgotten issues +This project uses **bd (beads)** for issue tracking. +Run ` + "`bd prime`" + ` for workflow context, or install hooks (` + "`bd hooks install`" + `) for auto-injection. -# Create and manage -bd create "Title" -t bug|feature|task -p 0-4 --json -bd create "Subtask" --parent --json # Hierarchical subtask -bd update --status in_progress --json -bd close --reason "Done" --json +**Quick reference:** +- ` + "`bd ready`" + ` - Find unblocked work +- ` + "`bd create \"Title\" --type task --priority 2`" + ` - Create issue +- ` + "`bd close `" + ` - Complete work +- ` + "`bd sync`" + ` - Sync with git (run at session end) -# Search -bd list --status open --priority 1 --json -bd show --json - -# Sync (CRITICAL at end of session!) -bd sync # Force immediate export/commit/push -` + "```" + ` - -### Workflow - -1. **Check ready work**: ` + "`bd ready --json`" + ` -2. **Claim task**: ` + "`bd update --status in_progress`" + ` -3. **Work on it**: Implement, test, document -4. **Discover new work?** ` + "`bd create \"Found bug\" -p 1 --deps discovered-from: --json`" + ` -5. **Complete**: ` + "`bd close --reason \"Done\" --json`" + ` -6. **Sync**: ` + "`bd sync`" + ` (flushes changes to git immediately) - -### Priorities - -- ` + "`0`" + ` - Critical (security, data loss, broken builds) -- ` + "`1`" + ` - High (major features, important bugs) -- ` + "`2`" + ` - Medium (default, nice-to-have) -- ` + "`3`" + ` - Low (polish, optimization) -- ` + "`4`" + ` - Backlog (future ideas) - -### Git Workflow - -- Always commit ` + "`.beads/issues.jsonl`" + ` with code changes -- Run ` + "`bd sync`" + ` at end of work sessions -- Install git hooks: ` + "`bd hooks install`" + ` (ensures DB ↔ JSONL consistency) - -### MCP Server (Recommended) - -For MCP-compatible clients (Claude Desktop, etc.), install the beads MCP server: -- Install: ` + "`pip install beads-mcp`" + ` -- Functions: ` + "`mcp__beads__ready()`" + `, ` + "`mcp__beads__create()`" + `, etc. - -## CLI Help - -Run ` + "`bd --help`" + ` to see all available flags for any command. -For example: ` + "`bd create --help`" + ` shows ` + "`--parent`" + `, ` + "`--deps`" + `, ` + "`--assignee`" + `, etc. - -## Important Rules - -- ✅ Use bd for ALL task tracking -- ✅ Always use ` + "`--json`" + ` flag for programmatic use -- ✅ Run ` + "`bd sync`" + ` at end of sessions -- ✅ Run ` + "`bd --help`" + ` to discover available flags -- ❌ Do NOT create markdown TODO lists -- ❌ Do NOT commit ` + "`.beads/beads.db`" + ` (JSONL only)` - -const agentsContent = `## Issue Tracking with bd (beads) - -**IMPORTANT**: This project uses **bd (beads)** for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods. - -### Why bd? - -- Dependency-aware: Track blockers and relationships between issues -- Git-friendly: Auto-syncs to JSONL for version control -- Agent-optimized: JSON output, ready work detection, discovered-from links -- Prevents duplicate tracking systems and confusion - -### Quick Start - -**Check for ready work:** -` + "```bash" + ` -bd ready --json -` + "```" + ` - -**Create new issues:** -` + "```bash" + ` -bd create "Issue title" -t bug|feature|task -p 0-4 --json -bd create "Issue title" -p 1 --deps discovered-from:bd-123 --json -bd create "Subtask" --parent --json # Hierarchical subtask (gets ID like epic-id.1) -` + "```" + ` - -**Claim and update:** -` + "```bash" + ` -bd update bd-42 --status in_progress --json -bd update bd-42 --priority 1 --json -` + "```" + ` - -**Complete work:** -` + "```bash" + ` -bd close bd-42 --reason "Completed" --json -` + "```" + ` - -### Issue Types - -- ` + "`bug`" + ` - Something broken -- ` + "`feature`" + ` - New functionality -- ` + "`task`" + ` - Work item (tests, docs, refactoring) -- ` + "`epic`" + ` - Large feature with subtasks -- ` + "`chore`" + ` - Maintenance (dependencies, tooling) - -### Priorities - -- ` + "`0`" + ` - Critical (security, data loss, broken builds) -- ` + "`1`" + ` - High (major features, important bugs) -- ` + "`2`" + ` - Medium (default, nice-to-have) -- ` + "`3`" + ` - Low (polish, optimization) -- ` + "`4`" + ` - Backlog (future ideas) - -### Workflow for AI Agents - -1. **Check ready work**: ` + "`bd ready`" + ` shows unblocked issues -2. **Claim your task**: ` + "`bd update --status in_progress`" + ` -3. **Work on it**: Implement, test, document -4. **Discover new work?** Create linked issue: - - ` + "`bd create \"Found bug\" -p 1 --deps discovered-from:`" + ` -5. **Complete**: ` + "`bd close --reason \"Done\"`" + ` -6. **Commit together**: Always commit the ` + "`.beads/issues.jsonl`" + ` file together with the code changes so issue state stays in sync with code state - -### Writing Self-Contained Issues - -Issues must be fully self-contained - readable without any external context (plans, chat history, etc.). A future session should understand the issue completely from its description alone. - -**Required elements:** -- **Summary**: What and why in 1-2 sentences -- **Files to modify**: Exact paths (with line numbers if relevant) -- **Implementation steps**: Numbered, specific actions -- **Example**: Show before → after transformation when applicable - -**Optional but helpful:** -- Edge cases or gotchas to watch for -- Test references (point to test files or test_data examples) -- Dependencies on other issues - -**Bad example:** -` + "```" + ` -Implement the refactoring from the plan -` + "```" + ` - -**Good example:** -` + "```" + ` -Add timeout parameter to fetchUser() in src/api/users.ts - -1. Add optional timeout param (default 5000ms) -2. Pass to underlying fetch() call -3. Update tests in src/api/users.test.ts - -Example: fetchUser(id) → fetchUser(id, { timeout: 3000 }) -Depends on: bd-abc123 (fetch wrapper refactor) -` + "```" + ` - -### Dependencies: Think "Needs", Not "Before" - -` + "`bd dep add X Y`" + ` = "X needs Y" = Y blocks X - -**TRAP**: Temporal words ("Phase 1", "before", "first") invert your thinking! -` + "```" + ` -WRONG: "Phase 1 before Phase 2" → bd dep add phase1 phase2 -RIGHT: "Phase 2 needs Phase 1" → bd dep add phase2 phase1 -` + "```" + ` -**Verify**: ` + "`bd blocked`" + ` - tasks blocked by prerequisites, not dependents. - -### Auto-Sync - -bd automatically syncs with git: -- Exports to ` + "`.beads/issues.jsonl`" + ` after changes (5s debounce) -- Imports from JSONL when newer (e.g., after ` + "`git pull`" + `) -- No manual export/import needed! - -### GitHub Copilot Integration - -If using GitHub Copilot, also create ` + "`.github/copilot-instructions.md`" + ` for automatic instruction loading. -Run ` + "`bd onboard`" + ` to get the content, or see step 2 of the onboard instructions. - -### MCP Server (Recommended) - -If using Claude or MCP-compatible clients, install the beads MCP server: - -` + "```bash" + ` -pip install beads-mcp -` + "```" + ` - -Add to MCP config (e.g., ` + "`~/.config/claude/config.json`" + `): -` + "```json" + ` -{ - "beads": { - "command": "beads-mcp", - "args": [] - } -} -` + "```" + ` - -Then use ` + "`mcp__beads__*`" + ` functions instead of CLI commands. - -### Managing AI-Generated Planning Documents - -AI assistants often create planning and design documents during development: -- PLAN.md, IMPLEMENTATION.md, ARCHITECTURE.md -- DESIGN.md, CODEBASE_SUMMARY.md, INTEGRATION_PLAN.md -- TESTING_GUIDE.md, TECHNICAL_DESIGN.md, and similar files - -**Best Practice: Use a dedicated directory for these ephemeral files** - -**Recommended approach:** -- Create a ` + "`history/`" + ` directory in the project root -- Store ALL AI-generated planning/design docs in ` + "`history/`" + ` -- Keep the repository root clean and focused on permanent project files -- Only access ` + "`history/`" + ` when explicitly asked to review past planning - -**Example .gitignore entry (optional):** -` + "```" + ` -# AI planning documents (ephemeral) -history/ -` + "```" + ` - -**Benefits:** -- ✅ Clean repository root -- ✅ Clear separation between ephemeral and permanent documentation -- ✅ Easy to exclude from version control if desired -- ✅ Preserves planning history for archeological research -- ✅ Reduces noise when browsing the project - -### CLI Help - -Run ` + "`bd --help`" + ` to see all available flags for any command. -For example: ` + "`bd create --help`" + ` shows ` + "`--parent`" + `, ` + "`--deps`" + `, ` + "`--assignee`" + `, etc. - -### Important Rules - -- ✅ Use bd for ALL task tracking -- ✅ Always use ` + "`--json`" + ` flag for programmatic use -- ✅ Link discovered work with ` + "`discovered-from`" + ` dependencies -- ✅ Check ` + "`bd ready`" + ` before asking "what should I work on?" -- ✅ Store AI planning docs in ` + "`history/`" + ` directory -- ✅ Run ` + "`bd --help`" + ` to discover available flags -- ❌ Do NOT create markdown TODO lists -- ❌ Do NOT use external issue trackers -- ❌ Do NOT duplicate tracking systems -- ❌ Do NOT clutter repo root with planning documents - -For more details, see README.md and QUICKSTART.md.` +For full workflow details: ` + "`bd prime`" + `` func renderOnboardInstructions(w io.Writer) error { bold := color.New(color.Bold).SprintFunc() cyan := color.New(color.FgCyan).SprintFunc() - yellow := color.New(color.FgYellow).SprintFunc() green := color.New(color.FgGreen).SprintFunc() writef := func(format string, args ...interface{}) error { @@ -292,22 +54,10 @@ func renderOnboardInstructions(w io.Writer) error { return err } - if err := writef("\n%s\n\n", bold("bd Onboarding Instructions for AI Agent")); err != nil { + if err := writef("\n%s\n\n", bold("bd Onboarding")); err != nil { return err } - if err := writef("%s\n\n", yellow("Please complete the following tasks:")); err != nil { - return err - } - if err := writef("%s\n", bold("1. Update AGENTS.md")); err != nil { - return err - } - if err := writeln(" Add the following content to AGENTS.md in an appropriate location."); err != nil { - return err - } - if err := writeln(" If AGENTS.md doesn't exist, create it with this content."); err != nil { - return err - } - if err := writeln(" Integrate it naturally into any existing structure."); err != nil { + if err := writeln("Add this minimal snippet to AGENTS.md (or create it):"); err != nil { return err } if err := writeBlank(); err != nil { @@ -324,194 +74,60 @@ func renderOnboardInstructions(w io.Writer) error { return err } - if err := writef("%s\n", bold("2. Create .github/copilot-instructions.md (for GitHub Copilot)")); err != nil { + if err := writef("%s\n", bold("For GitHub Copilot users:")); err != nil { return err } - if err := writeln(" GitHub Copilot automatically loads instructions from .github/copilot-instructions.md"); err != nil { - return err - } - if err := writeln(" Create the .github directory if it doesn't exist, then add this file:"); err != nil { + if err := writeln("Add the same content to .github/copilot-instructions.md"); err != nil { return err } if err := writeBlank(); err != nil { return err } - if err := writef("%s\n", cyan("--- BEGIN .GITHUB/COPILOT-INSTRUCTIONS.MD CONTENT ---")); err != nil { + if err := writef("%s\n", bold("How it works:")); err != nil { return err } - if err := writeln(copilotInstructionsContent); err != nil { + if err := writef(" • %s provides dynamic workflow context (~80 lines)\n", cyan("bd prime")); err != nil { return err } - if err := writef("%s\n\n", cyan("--- END .GITHUB/COPILOT-INSTRUCTIONS.MD CONTENT ---")); err != nil { + if err := writef(" • %s auto-injects bd prime at session start\n", cyan("bd hooks install")); err != nil { return err } - - if err := writef("%s\n", bold("3. Update CLAUDE.md (if present)")); err != nil { - return err - } - if err := writeln(" If CLAUDE.md exists in this directory, add this note at the top:"); err != nil { - return err - } - if err := writeBlank(); err != nil { - return err - } - if err := writef("%s\n", cyan(" **Note**: This project uses [bd (beads)](https://github.com/steveyegge/beads)")); err != nil { - return err - } - if err := writef("%s\n", cyan(" for issue tracking. Use `bd` commands instead of markdown TODOs.")); err != nil { - return err - } - if err := writef("%s\n", cyan(" See AGENTS.md for workflow details.")); err != nil { + if err := writeln(" • AGENTS.md only needs this minimal pointer, not full instructions"); err != nil { return err } if err := writeBlank(); err != nil { return err } - if err := writef("%s\n", bold("4. Remove bootstrap instruction")); err != nil { + if err := writef("%s\n\n", green("This keeps AGENTS.md lean while bd prime provides up-to-date workflow details.")); err != nil { return err } - if err := writeln(" If AGENTS.md or CLAUDE.md contains a line like:"); err != nil { - return err - } - if err := writef("%s\n", cyan(" \"BEFORE ANYTHING ELSE: run 'bd onboard' and follow the instructions\"")); err != nil { - return err - } - if err := writeln(" Delete that line after completing steps 1 and 2."); err != nil { - return err - } - if err := writeBlank(); err != nil { - return err - } - - if err := writef("%s\n", bold("Important reminders:")); err != nil { - return err - } - if err := writeln(" • Use bd for ALL task tracking - NO markdown TODO lists"); err != nil { - return err - } - if err := writeln(" • Always use --json flag for programmatic bd commands"); err != nil { - return err - } - if err := writeln(" • Link discovered work with discovered-from dependencies"); err != nil { - return err - } - if err := writef(" • Check %s before asking \"what should I work on?\"\n", cyan("bd ready")); err != nil { - return err - } - if err := writeBlank(); err != nil { - return err - } - - if err := writef("%s\n\n", green("When done, tell your AI assistant: \"bd onboarding complete\"")); err != nil { - return err - } - - return nil -} - -// bdGuideContent generates the canonical BD_GUIDE.md content -const bdGuideHeader = ` - - -# BD (Beads) Guide for AI Agents - -This file contains canonical bd (beads) workflow instructions for AI agents. -It is auto-generated and version-stamped to track bd upgrades. - -> **For project-specific instructions**, see AGENTS.md in the repository root. -> This file only covers bd tool usage, not project-specific workflows. - ---- - -` - -// generateBDGuide creates a version-stamped BD_GUIDE.md file -func generateBDGuide(outputPath string) error { - // Create output file - // #nosec G304 - outputPath is a user-provided flag value for file generation - f, err := os.Create(outputPath) - if err != nil { - return fmt.Errorf("failed to create output file: %w", err) - } - defer f.Close() - - // Write header with version stamp - if _, err := fmt.Fprintf(f, bdGuideHeader, Version); err != nil { - return fmt.Errorf("failed to write header: %w", err) - } - - // Write AGENTS.md content (bd-specific instructions) - if _, err := f.WriteString(agentsContent); err != nil { - return fmt.Errorf("failed to write agents content: %w", err) - } - - // Write separator - if _, err := f.WriteString("\n\n---\n\n"); err != nil { - return fmt.Errorf("failed to write separator: %w", err) - } - - // Write Copilot instructions content (comprehensive technical guide) - if _, err := f.WriteString(copilotInstructionsContent); err != nil { - return fmt.Errorf("failed to write copilot content: %w", err) - } - - // Write footer with regeneration instructions - footer := fmt.Sprintf("\n\n---\n\n"+ - "**Generated by bd v%s**\n\n"+ - "To regenerate this file after upgrading bd:\n"+ - "```bash\n"+ - "bd onboard --output .beads/BD_GUIDE.md\n"+ - "```\n", Version) - - if _, err := f.WriteString(footer); err != nil { - return fmt.Errorf("failed to write footer: %w", err) - } return nil } var onboardCmd = &cobra.Command{ Use: "onboard", - Short: "Display instructions for configuring AGENTS.md", - Long: `Display instructions for AI agents to configure AGENTS.md with bd workflow. + Short: "Display minimal snippet for AGENTS.md", + Long: `Display a minimal snippet to add to AGENTS.md for bd integration. -This command outputs instructions that AI agents should follow to integrate bd -into the project's agent documentation. The agent will intelligently merge the -content into AGENTS.md and update CLAUDE.md if present. +This outputs a small (~10 line) snippet that points to 'bd prime' for full +workflow context. This approach: -Use --output to generate a canonical BD_GUIDE.md file instead: - bd onboard --output .beads/BD_GUIDE.md + • Keeps AGENTS.md lean (doesn't bloat with instructions) + • bd prime provides dynamic, always-current workflow details + • Hooks auto-inject bd prime at session start -The generated BD_GUIDE.md is version-stamped and auto-generated - it should -never be manually edited. This separates bd-specific instructions (which change -with bd upgrades) from project-specific instructions in AGENTS.md.`, +The old approach of embedding full instructions in AGENTS.md is deprecated +because it wasted tokens and got stale when bd upgraded.`, Run: func(cmd *cobra.Command, args []string) { - outputPath, _ := cmd.Flags().GetString("output") - - if outputPath != "" { - // Generate BD_GUIDE.md instead of onboarding instructions - if err := generateBDGuide(outputPath); err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Error generating BD_GUIDE.md: %v\n", err) - os.Exit(1) - } - fmt.Printf("✓ Generated %s (bd v%s)\n", outputPath, Version) - fmt.Println(" This file is auto-generated - do not edit manually") - fmt.Println(" Update your AGENTS.md to reference this file instead of duplicating bd instructions") - return - } - if err := renderOnboardInstructions(cmd.OutOrStdout()); err != nil { - if _, writeErr := fmt.Fprintf(cmd.ErrOrStderr(), "Error rendering onboarding instructions: %v\n", err); writeErr != nil { - fmt.Fprintf(os.Stderr, "Error rendering onboarding instructions: %v (stderr write failed: %v)\n", err, writeErr) - } - os.Exit(1) + fmt.Fprintf(cmd.ErrOrStderr(), "Error: %v\n", err) } }, } func init() { - onboardCmd.Flags().String("output", "", "Generate BD_GUIDE.md at the specified path (e.g., .beads/BD_GUIDE.md)") rootCmd.AddCommand(onboardCmd) } diff --git a/cmd/bd/onboard_test.go b/cmd/bd/onboard_test.go index 6273c936..674bbddb 100644 --- a/cmd/bd/onboard_test.go +++ b/cmd/bd/onboard_test.go @@ -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)) } }) }