From 27c0c331acdc543ef3be8e0d94bdd55212d238bc Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Thu, 20 Nov 2025 20:58:56 -0500 Subject: [PATCH] Fix #349: Improve compact error messages, remove bogus merge suggestion, add daemon/maintenance docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bd-1h8: Add --no-daemon hint to compact error messages - bd-8ql: Replace non-existent merge command with actionable guidance - bd-ayw: Add 'When to use daemon mode' decision tree to daemon.md - bd-keb: Add database maintenance section to QUICKSTART.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- cmd/bd/compact.go | 8 ++++++-- cmd/bd/duplicates.go | 26 ++++++++++++++++---------- commands/daemon.md | 18 ++++++++++++++++++ docs/QUICKSTART.md | 25 +++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/cmd/bd/compact.go b/cmd/bd/compact.go index 93470f3b..0d668630 100644 --- a/cmd/bd/compact.go +++ b/cmd/bd/compact.go @@ -105,11 +105,13 @@ Examples: if compactAnalyze { if err := ensureDirectMode("compact --analyze requires direct database access"); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) + fmt.Fprintf(os.Stderr, "Hint: Use --no-daemon flag to bypass daemon and access database directly\n") os.Exit(1) } sqliteStore, ok := store.(*sqlite.SQLiteStorage) if !ok { - fmt.Fprintf(os.Stderr, "Error: compact requires SQLite storage\n") + fmt.Fprintf(os.Stderr, "Error: failed to open database in direct mode\n") + fmt.Fprintf(os.Stderr, "Hint: Ensure .beads/beads.db exists and is readable\n") os.Exit(1) } runCompactAnalyze(ctx, sqliteStore) @@ -120,6 +122,7 @@ Examples: if compactApply { if err := ensureDirectMode("compact --apply requires direct database access"); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) + fmt.Fprintf(os.Stderr, "Hint: Use --no-daemon flag to bypass daemon and access database directly\n") os.Exit(1) } if compactID == "" { @@ -132,7 +135,8 @@ Examples: } sqliteStore, ok := store.(*sqlite.SQLiteStorage) if !ok { - fmt.Fprintf(os.Stderr, "Error: compact requires SQLite storage\n") + fmt.Fprintf(os.Stderr, "Error: failed to open database in direct mode\n") + fmt.Fprintf(os.Stderr, "Hint: Ensure .beads/beads.db exists and is readable\n") os.Exit(1) } runCompactApply(ctx, sqliteStore) diff --git a/cmd/bd/duplicates.go b/cmd/bd/duplicates.go index 3a36f516..4d01ba82 100644 --- a/cmd/bd/duplicates.go +++ b/cmd/bd/duplicates.go @@ -82,9 +82,13 @@ Example: sources = append(sources, issue.ID) } } - // TODO: performMerge implementation pending - // For now, just generate the command suggestion - cmd := fmt.Sprintf("bd merge %s --into %s", strings.Join(sources, " "), target.ID) + // Generate actionable command suggestion + cmd := fmt.Sprintf("# Duplicate: %s (same content as %s)\n# Suggested action: bd close %s && bd dep add %s %s --type related", + strings.Join(sources, " "), + target.ID, + strings.Join(sources, " "), + strings.Join(sources, " "), + target.ID) mergeCommands = append(mergeCommands, cmd) if autoMerge || dryRun { @@ -134,8 +138,9 @@ Example: sources = append(sources, issue.ID) } } - fmt.Printf(" %s bd merge %s --into %s\n\n", - cyan("Suggested:"), strings.Join(sources, " "), target.ID) + fmt.Printf(" %s Duplicate: %s (same content as %s)\n", cyan("Note:"), strings.Join(sources, " "), target.ID) + fmt.Printf(" %s bd close %s && bd dep add %s %s --type related\n\n", + cyan("Suggested:"), strings.Join(sources, " "), strings.Join(sources, " "), target.ID) } if autoMerge { if dryRun { @@ -245,11 +250,12 @@ func formatDuplicateGroupsJSON(groups [][]*types.Issue, refCounts map[string]int } } result = append(result, map[string]interface{}{ - "title": group[0].Title, - "issues": issues, - "suggested_target": target.ID, - "suggested_sources": sources, - "suggested_merge_cmd": fmt.Sprintf("bd merge %s --into %s", strings.Join(sources, " "), target.ID), + "title": group[0].Title, + "issues": issues, + "suggested_target": target.ID, + "suggested_sources": sources, + "suggested_action": fmt.Sprintf("bd close %s && bd dep add %s %s --type related", strings.Join(sources, " "), strings.Join(sources, " "), target.ID), + "note": fmt.Sprintf("Duplicate: %s (same content as %s)", strings.Join(sources, " "), target.ID), }) } return result diff --git a/commands/daemon.md b/commands/daemon.md index a0f52a2d..e2f2c59d 100644 --- a/commands/daemon.md +++ b/commands/daemon.md @@ -19,6 +19,24 @@ Each project runs its own daemon at `.beads/bd.sock` for complete database isola **Note:** Global daemon support was removed in v0.16.0. The `--global` flag is no longer functional. +## When to Use Daemon Mode + +**✅ You SHOULD use daemon mode if:** +- Working in a team with git remote sync +- Want automatic commit/push of issue changes +- Need background auto-sync (5-second debounce) +- Making frequent bd commands (performance benefit from connection pooling) + +**❌ You DON'T need daemon mode if:** +- Solo developer with local-only tracking +- Working in git worktrees (use --no-daemon to avoid conflicts) +- Running one-off commands or scripts +- Debugging database issues (direct mode is simpler) + +**Local-only users:** Direct mode (default without daemon) is perfectly fine. The daemon mainly helps with git sync automation. You can still use `bd sync` manually when needed. + +**Performance note:** For most operations, the daemon provides minimal performance benefit. The main value is automatic JSONL export (5s debounce) and optional git sync (--auto-commit, --auto-push). + ## Common Operations - **Start**: `bd daemon` (auto-starts on first `bd` command) diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 645fc398..bb23143d 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -172,6 +172,31 @@ After upgrading bd, use `bd migrate` to check for and migrate old database files **AI agents:** Use `--inspect` to analyze migration safety before running. The system verifies required config keys and data integrity invariants. +## Database Maintenance + +As your project accumulates closed issues, the database grows. Manage size with these commands: + +```bash +# View compaction statistics +bd compact --stats + +# Preview compaction candidates (30+ days closed) +bd compact --analyze --json --no-daemon + +# Apply agent-generated summary +bd compact --apply --id bd-42 --summary summary.txt --no-daemon + +# Immediately delete closed issues (CAUTION: permanent!) +bd cleanup --force +``` + +**When to compact:** +- Database file > 10MB with many old closed issues +- After major project milestones when old issues are no longer relevant +- Before archiving a project phase + +**Note:** Compaction is permanent graceful decay. Original content is discarded but viewable via `bd restore ` from git history. + ## Advanced: Agent Mail (Optional) For **multi-agent workflows** (2+ AI agents working concurrently), Agent Mail provides real-time coordination: