diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 7db14185..431f792f 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -37,12 +37,13 @@ {"id":"bd-d4i","title":"Create tip system infrastructure for contextual hints","description":"Implement a tip/hint system that shows helpful contextual messages after successful commands. This is different from the existing error-path \"Hint:\" messages - tips appear on success paths to educate users about features they might not know about.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-11T23:29:15.693956-08:00","updated_at":"2025-11-25T17:47:30.747566-08:00","closed_at":"2025-11-25T17:47:30.747566-08:00"} {"id":"bd-dmb","title":"Fresh clone: bd should suggest 'bd init' when no database exists","description":"On a fresh clone of a repo using beads, running `bd stats` or `bd list` gives a cryptic error:\n\n```\nError: failed to open database: post-migration validation failed: migration invariants failed:\n - required_config_present: required config key missing: issue_prefix (database has 2 issues)\n```\n\n**Expected**: A helpful message like:\n```\nNo database found. This appears to be a fresh clone.\nRun 'bd init --prefix \u003cprefix\u003e' to hydrate from the committed JSONL file.\nFound: .beads/beads.jsonl (38 issues)\n```\n\n**Why this matters**: The current UX is confusing for new contributors or fresh clones. The happy path should be obvious.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-11-27T20:21:04.947959-08:00","updated_at":"2025-11-27T22:40:11.654051-08:00","closed_at":"2025-11-27T22:40:11.654051-08:00"} {"id":"bd-e166","title":"Improve timestamp comparison readability in import","description":"The timestamp comparison logic uses double-negative which can be confusing:\n\nCurrent code:\nif !incoming.UpdatedAt.After(existing.UpdatedAt) {\n // skip update\n}\n\nMore readable:\nif incoming.UpdatedAt.After(existing.UpdatedAt) {\n // perform update\n} else {\n // skip (local is newer)\n}\n\nThis is a minor refactor for code clarity.\n\nRelated: bd-1022\nFiles: internal/importer/importer.go:411, 488","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-11-02T15:32:12.27108-08:00","updated_at":"2025-11-26T22:25:27.124071-08:00","closed_at":"2025-11-26T22:25:27.124071-08:00"} +{"id":"bd-e3w","title":"bd sync: use worktree for sync.branch commits (non-daemon mode)","description":"## Summary\n\nWhen `sync.branch` is configured (e.g., `beads-sync`), `bd sync` should commit beads changes to that branch via git worktree, even when the user's working directory is on a different branch (e.g., `main`).\n\nCurrently:\n- `bd sync` always commits to the current branch\n- Daemon with `--auto-commit` uses worktrees to commit to sync branch\n- Gap: `bd sync` ignores sync.branch config\n\n## Goal\n\nWorkers stay on `main` (or feature branches) while beads metadata automatically flows to `beads-sync` branch. No daemon required.\n\n## Design Considerations\n\n1. **Worktree lifecycle**: Create on first use, reuse thereafter\n2. **Daemon interaction**: Ensure daemon and bd sync don't conflict\n3. **MCP server**: Uses daemon or direct mode - needs same behavior\n4. **Pull semantics**: Pull from sync branch, not current branch\n5. **Push semantics**: Push to sync branch remote\n6. **Error handling**: Worktree corruption, missing branch, etc.\n\n## Affected Components\n\n- `cmd/bd/sync.go` - Main changes\n- `cmd/bd/daemon_sync_branch.go` - Reuse existing functions\n- `internal/git/worktree.go` - Already implemented\n- MCP server (if it bypasses daemon)\n\n## Edge Cases\n\n- Fresh clone (no sync branch exists yet)\n- Worktree exists but is corrupted\n- Concurrent bd sync from multiple processes\n- sync.branch configured but remote doesn't have that branch\n- User switches sync.branch config mid-session","design":"## Architecture Analysis\n\n### Current State\n\n**bd sync (sync.go)**:\n- Exports DB → JSONL\n- Commits with `gitCommitBeadsDir()` to CURRENT branch\n- Pulls with `gitPull()` from current branch's upstream\n- Pushes with `gitPush()`\n- **Does NOT check sync.branch config**\n\n**Daemon (daemon_sync.go + daemon_sync_branch.go)**:\n- On auto-commit, calls `syncBranchCommitAndPush()` FIRST\n- Falls back to regular commit if sync.branch not configured\n- Uses worktrees correctly for isolated commits\n\n**MCP Server (beads-mcp)**:\n- Python, shells out to `bd` CLI commands\n- Will inherit whatever `bd sync` does\n- No special handling needed\n\n### Proposed Changes\n\n**sync.go modifications**:\n\n1. **After export, before commit (line ~312-324)**:\n Check sync.branch and use worktree if configured:\n ```go\n syncBranch, _ := syncbranch.Get(ctx, store)\n if syncBranch \\!= \"\" {\n committed, err := syncToWorktreeBranch(ctx, syncBranch, jsonlPath, \\!noPush)\n // Skip regular commit/push logic\n } else {\n // Existing gitCommitBeadsDir() logic\n }\n ```\n\n2. **Before pull (line ~328-505)**:\n If sync branch configured, pull from worktree:\n ```go\n if syncBranch \\!= \"\" {\n pullFromWorktreeBranch(ctx, syncBranch, jsonlPath)\n } else {\n gitPull(ctx)\n }\n ```\n\n**New functions in sync.go** (or extract to sync_worktree.go):\n\n```go\n// syncToWorktreeBranch commits JSONL to sync branch via worktree\nfunc syncToWorktreeBranch(ctx context.Context, branch, jsonlPath string, push bool) error\n\n// pullFromWorktreeBranch pulls sync branch and copies JSONL to main repo\nfunc pullFromWorktreeBranch(ctx context.Context, branch, jsonlPath string) error\n```\n\n### Function Reuse\n\nCan reuse from daemon_sync_branch.go:\n- `gitHasChangesInWorktree()`\n- `gitCommitInWorktree()`\n- `gitPushFromWorktree()`\n\nCan reuse from internal/git/worktree.go:\n- `WorktreeManager.CreateBeadsWorktree()`\n- `WorktreeManager.CheckWorktreeHealth()`\n- `WorktreeManager.SyncJSONLToWorktree()`\n\n### Daemon Consistency\n\nThe daemon's `syncBranchCommitAndPush()` and `syncBranchPull()` functions should be moved to a shared location or their logic extracted, so both daemon and `bd sync` use identical code paths.\n\n**Recommendation**: Create `internal/syncbranch/worktree.go` with:\n- `CommitToSyncBranch(ctx, branch, jsonlPath, push) error`\n- `PullFromSyncBranch(ctx, branch, jsonlPath) error`\n\nBoth daemon and sync.go call these.\n\n### Edge Cases\n\n| Scenario | Handling |\n|----------|----------|\n| Fresh clone, no sync branch | `CreateBeadsWorktree()` creates branch |\n| Worktree corrupted | `CheckWorktreeHealth()` auto-repairs |\n| Concurrent bd sync | Git's own lock mechanism |\n| Remote missing branch | First push creates it with `--set-upstream` |\n| Config changed mid-session | Old worktree harmless, new one created |\n| No remote configured | Skip worktree commit, local-only mode |\n| bd sync in worktree dir | Check if already IN a worktree, skip |\n\n### Testing Plan\n\n1. Unit tests for new sync branch functions\n2. Integration test: `bd sync` with sync.branch configured\n3. Test concurrent `bd sync` from multiple processes\n4. Test fresh clone → first sync creates branch\n5. Test pull from remote with new issues\n6. Test conflict resolution in worktree\n\n### Rollout\n\n1. Add config validation: warn if sync.branch set but worktree functions fail\n2. Add `--verbose` logging for worktree operations\n3. Add `bd doctor` check for worktree health\n4. Document in PROTECTED_BRANCHES.md that daemon is no longer required","acceptance_criteria":"## Acceptance Criteria\n\n### Must Have\n\n- [ ] `bd sync` uses worktree when `sync.branch` is configured\n- [ ] Workers stay on their current branch (main, feature, etc.)\n- [ ] Commits go to configured sync branch (e.g., `beads-sync`)\n- [ ] Pull fetches from sync branch, not current branch\n- [ ] Push goes to sync branch remote\n- [ ] No daemon required for this to work\n- [ ] Existing daemon behavior unchanged (still uses worktrees)\n\n### Should Have\n\n- [ ] Shared code between daemon and `bd sync` (DRY)\n- [ ] Clear error messages if worktree operations fail\n- [ ] `bd sync --status` works with new workflow\n- [ ] `bd sync --merge` works with new workflow\n\n### Nice to Have\n\n- [ ] `bd doctor` validates worktree health\n- [ ] Verbose logging option for debugging\n- [ ] MCP server inherits behavior automatically (verified)\n\n### Testing\n\n- [ ] Fresh clone creates sync branch on first sync\n- [ ] Multiple workers can sync concurrently\n- [ ] Worktree auto-repairs if corrupted\n- [ ] Config change mid-session works correctly","status":"open","priority":1,"issue_type":"feature","created_at":"2025-11-30T00:31:20.026356-08:00","updated_at":"2025-11-30T00:33:12.359245-08:00"} {"id":"bd-e6x","title":"bd sync --squash: batch multiple syncs into single commit","description":"For solo developers who don't need real-time multi-agent coordination, add a --squash option to bd sync that accumulates changes and commits them in a single commit rather than one commit per sync.\n\nThis addresses the git history pollution concern (many 'bd sync: timestamp' commits) while preserving the default behavior needed for orchestration.\n\n**Proposed behavior:**\n- `bd sync --squash` accumulates pending exports without committing\n- Commits accumulated changes on session end or explicit `bd sync` (without --squash)\n- Default behavior unchanged (immediate commits for orchestration)\n\n**Use case:** Solo developers who want cleaner git history but don't need real-time coordination between agents.\n\n**Related:** PR #411 (docs: reduce bd sync commit pollution)\n**See also:** Multi-repo support as alternative solution (docs/MULTI_REPO_AGENTS.md)","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-11-28T18:21:47.789887-08:00","updated_at":"2025-11-28T22:17:12.608286-08:00","closed_at":"2025-11-28T21:56:57.608777-08:00"} {"id":"bd-e92","title":"Add test coverage for internal/autoimport package","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T21:21:22.338577-05:00","updated_at":"2025-11-28T22:17:12.608565-08:00","closed_at":"2025-11-28T21:52:34.222127-08:00","dependencies":[{"issue_id":"bd-e92","depends_on_id":"bd-ge7","type":"blocks","created_at":"2025-11-20T21:21:31.128625-05:00","created_by":"daemon"}]} {"id":"bd-emg","title":"bd init should refuse when JSONL already has issues (safety guard)","description":"When running `bd init` in a directory with an existing JSONL containing issues, bd should refuse and suggest the correct action instead of proceeding.\n\n## The Problem\n\nCurrent behavior when database is missing but JSONL exists:\n```\n$ bd create \"test\"\nError: no beads database found\nHint: run 'bd init' to create a database...\n```\n\nThis leads users (and AI agents) to reflexively run `bd init`, which can cause:\n- Prefix mismatch if wrong prefix specified\n- Data corruption if JSONL is damaged\n- Confusion about what actually happened\n\n## Proposed Behavior\n\n```\n$ bd init --prefix bd\n\n⚠ Found existing .beads/issues.jsonl with 76 issues.\n\nThis appears to be a fresh clone, not a new project.\n\nTo hydrate the database from existing JSONL:\n bd doctor --fix\n\nTo force re-initialization (may cause data loss):\n bd init --prefix bd --force\n\nAborting.\n```\n\n## Trigger Conditions\n\n- `.beads/issues.jsonl` or `.beads/beads.jsonl` exists\n- File contains \u003e 0 valid issue lines\n- No `--force` flag provided\n\n## Edge Cases\n\n- Empty JSONL (0 issues) → allow init (new project)\n- Corrupted JSONL → warn but allow with confirmation\n- Existing `.db` file → definitely refuse (weird state)\n\n## Related\n\n- bd-dmb: Fresh clone should suggest hydration (better error messages)\n- bd-4ew: bd doctor should detect fresh clone\n\nThis issue is about the safety guard on `bd init` itself, not the error messages from other commands.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-28T18:21:41.149304-08:00","updated_at":"2025-11-28T22:17:18.849507-08:00","closed_at":"2025-11-28T22:17:18.849507-08:00"} {"id":"bd-f0n","title":"Git history fallback missing timeout - could hang on large repos","description":"## Problem\n\nThe git commands in `checkGitHistoryForDeletions` have no timeout. On large repos with extensive history, `git log --all -S` or `git log --all -G` can take a very long time (minutes).\n\n## Location\n`internal/importer/importer.go:899` and `:930`\n\n## Impact\n- Import could hang indefinitely\n- User has no feedback that git search is running\n- No way to cancel except killing the process\n\n## Fix\nAdd context with timeout to git commands:\n\n```go\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\ncmd := exec.CommandContext(ctx, \"git\", ...)\n```\n\nAlso consider adding a `--since` flag to bound the git history search.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-25T12:48:24.388639-08:00","updated_at":"2025-11-25T15:04:53.669714-08:00","closed_at":"2025-11-25T15:04:53.669714-08:00"} {"id":"bd-f2f","title":"CRITICAL: bd sync exports before pull, allowing stale DB to corrupt JSONL statuses","description":"## Root Cause\n\nThe fix in bd-53c (reverse ZFC check) only checks COUNTS, not content. The real corruption happens when:\n\n1. Polecat A has stale DB with old status values (e.g., status=closed for issues that are now open on remote)\n2. Polecat A runs bd sync:\n - **Export FIRST**: DB (status=closed) → JSONL (overwrites correct status=open)\n - Commit: Stale JSONL committed\n - Pull: 3-way merge with remote\n - Merge uses 'closed wins' rule → status stays closed\n3. Polecat A pushes → Remote now corrupted with status=closed\n\n## Why bd-53c didn't fix it\n\nThe reverse ZFC check compares COUNTS:\n```go\nif jsonlCount \u003e dbCount // Only catches count mismatch\n```\n\nBut in the corruption scenario:\n- JSONL count = 5, DB count = 5 (same count!)\n- Only the STATUS field differs\n\n## The Real Fix\n\n**PULL BEFORE EXPORT**. The sync order must be:\n1. Pull from remote (get latest state)\n2. Import merged JSONL to DB\n3. THEN export DB changes (if any)\n\nCurrent order is: Export → Commit → Pull → Import → Push\n\nThis is a fundamental architecture change to the sync flow.\n\n## Workaround\n\nUse --no-auto-flush and manually control the sync order, or disable daemon auto-export.\n\n## Evidence\n\nFrom user investigation:\n- At 595b7943 (13:20:30): 5 open issues\n- At 10239812 (13:28:39): 0 open issues\n- All 5 issues had their status changed from open to closed\n- Count stayed at 5 (not a deletion issue)","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-29T17:33:26.744766-08:00","updated_at":"2025-11-29T19:24:31.010075-08:00","closed_at":"2025-11-29T19:24:31.010075-08:00"} -{"id":"bd-fl4","title":"Test sync branch setup","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-30T00:26:47.520507-08:00","updated_at":"2025-11-30T00:26:47.520507-08:00"} +{"id":"bd-fl4","title":"Test sync branch setup","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-30T00:26:47.520507-08:00","updated_at":"2025-11-30T00:33:23.105998-08:00","closed_at":"2025-11-30T00:33:23.105998-08:00","close_reason":"Test issue for sync branch setup, no longer needed"} {"id":"bd-ge7","title":"Improve Beads test coverage from 46% to 80%","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-20T21:21:03.700271-05:00","updated_at":"2025-11-28T22:17:12.608871-08:00","closed_at":"2025-11-28T21:56:04.085939-08:00"} {"id":"bd-ghb","title":"Add --yes flag to bd doctor --fix for non-interactive mode","description":"## Feature Request\n\nAdd a `--yes` or `-y` flag to `bd doctor --fix` that automatically confirms all prompts, enabling non-interactive usage in scripts and CI/CD pipelines.\n\n## Current Behavior\n`bd doctor --fix` prompts for confirmation before applying fixes, which blocks automated workflows.\n\n## Desired Behavior\n`bd doctor --fix --yes` should apply all fixes without prompting.\n\n## Use Cases\n- CI/CD pipelines that need to auto-fix issues\n- Scripts that automate repository setup\n- Pre-commit hooks that want to silently fix issues","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-11-26T23:22:45.486584-08:00","updated_at":"2025-11-28T22:17:12.609134-08:00","closed_at":"2025-11-28T21:55:06.895066-08:00"} {"id":"bd-gqo","title":"Implement health checks in daemon event loop","description":"Add health checks to checkDaemonHealth() function in daemon_event_loop.go:170:\n- Database integrity check\n- Disk space check\n- Memory usage check\n\nCurrently it's just a no-op placeholder.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-11-21T18:55:07.534304-05:00","updated_at":"2025-11-29T22:06:06.330972-08:00","closed_at":"2025-11-28T23:10:19.946063-08:00"}