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

@@ -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 <id>`" + ` - 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 <epic-id> --json # Hierarchical subtask
bd update <id> --status in_progress --json
bd close <id> --reason "Done" --json
**Quick reference:**
- ` + "`bd ready`" + ` - Find unblocked work
- ` + "`bd create \"Title\" --type task --priority 2`" + ` - Create issue
- ` + "`bd close <id>`" + ` - Complete work
- ` + "`bd sync`" + ` - Sync with git (run at session end)
# Search
bd list --status open --priority 1 --json
bd show <id> --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 <id> --status in_progress`" + `
3. **Work on it**: Implement, test, document
4. **Discover new work?** ` + "`bd create \"Found bug\" -p 1 --deps discovered-from:<parent-id> --json`" + `
5. **Complete**: ` + "`bd close <id> --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 <command> --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 <cmd> --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 <epic-id> --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 <id> --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:<parent-id>`" + `
5. **Complete**: ` + "`bd close <id> --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 <command> --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 <cmd> --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 = `<!-- Auto-generated by bd v%s - DO NOT EDIT MANUALLY -->
<!-- Run 'bd onboard --output .beads/BD_GUIDE.md' to regenerate -->
# 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)
}

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))
}
})
}