fix(deps): improve parent-child dependency UX (GH #440)

- Fix DEPENDENCIES.md: correct parent-child syntax (child depends on parent)
- Update bd show: display Children instead of Blocks for parent-child deps
- Group dependents by type with distinct labels

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-01 21:06:43 -08:00
parent 4c5d90cf46
commit 0456e784f4
5 changed files with 105 additions and 14 deletions

View File

@@ -0,0 +1,3 @@
{"id":"bd-3pd","ts":"2025-12-02T05:05:53.732197Z","by":"stevey","reason":"batch delete"}
{"id":"bd-ksc","ts":"2025-12-02T05:05:53.742343Z","by":"stevey","reason":"batch delete"}
{"id":"bd-360","ts":"2025-12-02T05:05:53.74642Z","by":"stevey","reason":"batch delete"}

View File

@@ -9,7 +9,7 @@
{"id":"bd-35o","title":"Add --yes flag to bd doctor --fix","description":"bd doctor --fix prompts for confirmation, which blocks automation (CI/CD, scripts, hooks).\n\nRequirements:\n1. Add --yes or -y flag to bd doctor command\n2. When --yes is passed, skip confirmation prompts\n3. Still log what's being fixed (don't go completely silent)","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-30T21:14:08.696905-08:00","updated_at":"2025-11-30T21:14:49.867041-08:00","closed_at":"2025-11-30T21:14:49.867041-08:00"} {"id":"bd-35o","title":"Add --yes flag to bd doctor --fix","description":"bd doctor --fix prompts for confirmation, which blocks automation (CI/CD, scripts, hooks).\n\nRequirements:\n1. Add --yes or -y flag to bd doctor command\n2. When --yes is passed, skip confirmation prompts\n3. Still log what's being fixed (don't go completely silent)","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-30T21:14:08.696905-08:00","updated_at":"2025-11-30T21:14:49.867041-08:00","closed_at":"2025-11-30T21:14:49.867041-08:00"}
{"id":"bd-39o","title":"Rename last_import_hash metadata key to jsonl_content_hash","description":"The metadata key 'last_import_hash' is misleading because it's updated on both import AND export (sync.go:614, import.go:320).\n\nBetter names:\n- jsonl_content_hash (more accurate)\n- last_sync_hash (clearer intent)\n\nThis is a breaking change requiring migration of existing metadata values.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T21:31:07.568739-05:00","updated_at":"2025-11-29T22:06:06.329653-08:00","closed_at":"2025-11-28T23:13:46.885978-08:00"} {"id":"bd-39o","title":"Rename last_import_hash metadata key to jsonl_content_hash","description":"The metadata key 'last_import_hash' is misleading because it's updated on both import AND export (sync.go:614, import.go:320).\n\nBetter names:\n- jsonl_content_hash (more accurate)\n- last_sync_hash (clearer intent)\n\nThis is a breaking change requiring migration of existing metadata values.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T21:31:07.568739-05:00","updated_at":"2025-11-29T22:06:06.329653-08:00","closed_at":"2025-11-28T23:13:46.885978-08:00"}
{"id":"bd-3gc","title":"Audit remaining cmd/bd files for error handling consistency","description":"Extend ERROR_HANDLING_AUDIT.md to cover: daemon_sync.go, update.go, list.go, show.go, close.go, reopen.go, dep.go, label.go, comments.go, delete.go, compact.go, config.go, validate.go and other high-usage command files","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-24T00:28:55.890991-08:00","updated_at":"2025-11-29T22:06:06.32994-08:00","closed_at":"2025-11-28T23:37:52.251887-08:00"} {"id":"bd-3gc","title":"Audit remaining cmd/bd files for error handling consistency","description":"Extend ERROR_HANDLING_AUDIT.md to cover: daemon_sync.go, update.go, list.go, show.go, close.go, reopen.go, dep.go, label.go, comments.go, delete.go, compact.go, config.go, validate.go and other high-usage command files","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-24T00:28:55.890991-08:00","updated_at":"2025-11-29T22:06:06.32994-08:00","closed_at":"2025-11-28T23:37:52.251887-08:00"}
{"id":"bd-3s8","title":"Imperator clone on beads-sync branch causes bd sync failures","description":"","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-11-30T22:53:51.056763-08:00","updated_at":"2025-12-01T21:05:20.328222-08:00"} {"id":"bd-3s8","title":"Imperator clone on beads-sync branch causes bd sync failures","description":"","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-11-30T22:53:51.056763-08:00","updated_at":"2025-12-01T21:05:28.518697-08:00"}
{"id":"bd-44e","title":"Ensure deletions.jsonl is tracked in git","description":"Parent: bd-imj\n\nEnsure deletions.jsonl is tracked in git (not ignored).\n\nUpdate bd init and gitignore upgrade logic to:\n1. NOT add deletions.jsonl to .gitignore\n2. Ensure it is committed alongside beads.jsonl\n\nThe file must be in git for cross-clone propagation to work.\n\nAcceptance criteria:\n- bd init does not ignore deletions.jsonl\n- Existing .gitignore files are not broken\n- File appears in git status when modified","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-25T09:57:21.663196-08:00","updated_at":"2025-11-25T14:55:43.225883-08:00","closed_at":"2025-11-25T14:55:43.225883-08:00"} {"id":"bd-44e","title":"Ensure deletions.jsonl is tracked in git","description":"Parent: bd-imj\n\nEnsure deletions.jsonl is tracked in git (not ignored).\n\nUpdate bd init and gitignore upgrade logic to:\n1. NOT add deletions.jsonl to .gitignore\n2. Ensure it is committed alongside beads.jsonl\n\nThe file must be in git for cross-clone propagation to work.\n\nAcceptance criteria:\n- bd init does not ignore deletions.jsonl\n- Existing .gitignore files are not broken\n- File appears in git status when modified","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-25T09:57:21.663196-08:00","updated_at":"2025-11-25T14:55:43.225883-08:00","closed_at":"2025-11-25T14:55:43.225883-08:00"}
{"id":"bd-4aao","title":"Fix failing integration tests in beads-mcp","description":"The `beads-mcp` test suite has failures in `tests/test_bd_client_integration.py` (assertion error in `test_init_creates_beads_directory`) and errors in `tests/test_worktree_separate_dbs.py` (setup failures finding database). These need to be investigated and fixed to ensure a reliable CI baseline.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T18:53:28.4803-05:00","updated_at":"2025-11-25T21:39:20.967106-08:00","closed_at":"2025-11-25T21:39:20.967106-08:00"} {"id":"bd-4aao","title":"Fix failing integration tests in beads-mcp","description":"The `beads-mcp` test suite has failures in `tests/test_bd_client_integration.py` (assertion error in `test_init_creates_beads_directory`) and errors in `tests/test_worktree_separate_dbs.py` (setup failures finding database). These need to be investigated and fixed to ensure a reliable CI baseline.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T18:53:28.4803-05:00","updated_at":"2025-11-25T21:39:20.967106-08:00","closed_at":"2025-11-25T21:39:20.967106-08:00"}
{"id":"bd-4ew","title":"bd doctor should detect fresh clone and recommend 'bd init'","description":"When running `bd doctor` on a fresh clone (JSONL exists, no .db file), it should:\n\n1. Detect this is a fresh clone situation\n2. Recommend `bd init --prefix \u003cdetected-prefix\u003e` as the fix\n3. Show the prefix detected from the JSONL file\n\nCurrently it shows various warnings (git hooks, merge driver, etc.) but doesn't address the fundamental issue: the database needs to be hydrated.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-27T20:21:15.691764-08:00","updated_at":"2025-11-28T22:14:49.092112-08:00","closed_at":"2025-11-28T22:14:49.092112-08:00"} {"id":"bd-4ew","title":"bd doctor should detect fresh clone and recommend 'bd init'","description":"When running `bd doctor` on a fresh clone (JSONL exists, no .db file), it should:\n\n1. Detect this is a fresh clone situation\n2. Recommend `bd init --prefix \u003cdetected-prefix\u003e` as the fix\n3. Show the prefix detected from the JSONL file\n\nCurrently it shows various warnings (git hooks, merge driver, etc.) but doesn't address the fundamental issue: the database needs to be hydrated.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-27T20:21:15.691764-08:00","updated_at":"2025-11-28T22:14:49.092112-08:00","closed_at":"2025-11-28T22:14:49.092112-08:00"}
@@ -29,6 +29,7 @@
{"id":"bd-8an","title":"bd import auto-detects wrong prefix from directory name instead of issue IDs","description":"When importing issues.jsonl into a fresh database, 'bd import' prints:\n\n ✓ Initialized database with prefix 'beads' (detected from issues)\n\nBut the issues all have prefix 'bd-' (e.g., bd-03r). It appears to be detecting the prefix from the directory name (.beads/) rather than from the actual issue IDs in the JSONL.\n\nThis causes import to fail with:\n validate ID prefix for bd-03r: issue ID 'bd-03r' does not match configured prefix 'beads'\n\nWorkaround: Run 'bd config set issue_prefix bd' before import, or use 'bd init --prefix bd'.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-26T22:28:01.582564-08:00","updated_at":"2025-11-28T22:17:12.607316-08:00","closed_at":"2025-11-27T22:38:48.971617-08:00"} {"id":"bd-8an","title":"bd import auto-detects wrong prefix from directory name instead of issue IDs","description":"When importing issues.jsonl into a fresh database, 'bd import' prints:\n\n ✓ Initialized database with prefix 'beads' (detected from issues)\n\nBut the issues all have prefix 'bd-' (e.g., bd-03r). It appears to be detecting the prefix from the directory name (.beads/) rather than from the actual issue IDs in the JSONL.\n\nThis causes import to fail with:\n validate ID prefix for bd-03r: issue ID 'bd-03r' does not match configured prefix 'beads'\n\nWorkaround: Run 'bd config set issue_prefix bd' before import, or use 'bd init --prefix bd'.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-26T22:28:01.582564-08:00","updated_at":"2025-11-28T22:17:12.607316-08:00","closed_at":"2025-11-27T22:38:48.971617-08:00"}
{"id":"bd-8ib","title":"Update git hooks to be sync.branch aware","description":"## Problem\n\nThe pre-push hook blocks pushes when .beads/issues.jsonl has uncommitted changes. But with sync.branch configured, those changes are intentionally NOT committed to main - they go to the sync branch via worktree.\n\n## Current Behavior\n\n1. User configures sync.branch=beads-sync\n2. bd sync commits changes to beads-sync via worktree \n3. Local .beads/issues.jsonl is updated (needed for import)\n4. git push to main triggers pre-push hook\n5. Hook sees uncommitted .beads changes and blocks push\n6. User must use --no-verify to push\n\n## Expected Behavior\n\nWhen sync.branch is configured, the pre-push hook should:\n1. Check if sync.branch is set (bd config get sync.branch)\n2. If set, skip the .beads uncommitted check OR\n3. Verify changes are committed to the sync branch instead\n\n## Affected Files\n\n- examples/git-hooks/pre-push\n- examples/git-hooks/pre-commit (may also need update)\n\n## Workaround\n\nUse git push --no-verify","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-30T00:43:40.991951-08:00","updated_at":"2025-11-30T11:12:09.91242-08:00","closed_at":"2025-11-30T11:12:09.91242-08:00"} {"id":"bd-8ib","title":"Update git hooks to be sync.branch aware","description":"## Problem\n\nThe pre-push hook blocks pushes when .beads/issues.jsonl has uncommitted changes. But with sync.branch configured, those changes are intentionally NOT committed to main - they go to the sync branch via worktree.\n\n## Current Behavior\n\n1. User configures sync.branch=beads-sync\n2. bd sync commits changes to beads-sync via worktree \n3. Local .beads/issues.jsonl is updated (needed for import)\n4. git push to main triggers pre-push hook\n5. Hook sees uncommitted .beads changes and blocks push\n6. User must use --no-verify to push\n\n## Expected Behavior\n\nWhen sync.branch is configured, the pre-push hook should:\n1. Check if sync.branch is set (bd config get sync.branch)\n2. If set, skip the .beads uncommitted check OR\n3. Verify changes are committed to the sync branch instead\n\n## Affected Files\n\n- examples/git-hooks/pre-push\n- examples/git-hooks/pre-commit (may also need update)\n\n## Workaround\n\nUse git push --no-verify","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-30T00:43:40.991951-08:00","updated_at":"2025-11-30T11:12:09.91242-08:00","closed_at":"2025-11-30T11:12:09.91242-08:00"}
{"id":"bd-8q0","title":"Add Claude Code web installation docs to README","description":"GH #439 reported installation issues in Claude Code web environment. The go install fallback works, but users need guidance. Add a section to README documenting the workaround: go install + PATH export.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-01T21:02:24.511955-08:00","updated_at":"2025-12-01T21:02:24.511955-08:00"} {"id":"bd-8q0","title":"Add Claude Code web installation docs to README","description":"GH #439 reported installation issues in Claude Code web environment. The go install fallback works, but users need guidance. Add a section to README documenting the workaround: go install + PATH export.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-01T21:02:24.511955-08:00","updated_at":"2025-12-01T21:02:24.511955-08:00"}
{"id":"bd-91x","title":"Fix dependency naming inconsistencies (GH #440)","description":"Parent-child dependency documentation is backwards and UI labels are confusing.\\n\\nProblems:\\n1. DEPENDENCIES.md says 'bd dep add PARENT CHILD' but this is rejected\\n2. bd show displays epic children under 'Blocks' instead of 'Children'\\n3. bd dep tree EPIC shows nothing (need --direction=up)\\n4. Inconsistent with 'bd epic status' which uses 'children'\\n\\nSee: https://github.com/steveyegge/beads/issues/440","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-01T21:01:41.63295-08:00","updated_at":"2025-12-01T21:06:17.866688-08:00","closed_at":"2025-12-01T21:06:17.866688-08:00"}
{"id":"bd-93d","title":"Jira export script (jsonl2jira.py)","description":"Create a Python script to push beads issues to Jira.\n\n**Requires**: Jira import script to be complete first (need external_ref matching logic working)\n\n**Features needed**:\n- Create new Jira issues from beads issues without external_ref\n- Update existing Jira issues matched by external_ref\n- Map beads fields back to Jira fields\n- Handle Jira workflow transitions (status changes may need transitions)\n- Support custom field mapping for design/acceptance_criteria/notes\n\n**Challenges**:\n- Jira status changes often require workflow transitions, not direct updates\n- Need to discover valid transitions via API\n- Custom fields vary by Jira instance\n\n**Usage**:\n```bash\nbd export | python jsonl2jira.py --create-only # Only create, don't update\nbd export | python jsonl2jira.py # Create and update\n```\n\n**After creation**: Sets external_ref on beads issue to link back","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-30T12:56:14.266357-08:00","updated_at":"2025-11-30T15:19:40.264737-08:00","closed_at":"2025-11-30T15:19:40.264737-08:00","dependencies":[{"issue_id":"bd-93d","depends_on_id":"bd-qvj","type":"parent-child","created_at":"2025-11-30T12:56:44.652391-08:00","created_by":"stevey"},{"issue_id":"bd-93d","depends_on_id":"bd-tjn","type":"blocks","created_at":"2025-11-30T12:56:54.941116-08:00","created_by":"stevey"}]} {"id":"bd-93d","title":"Jira export script (jsonl2jira.py)","description":"Create a Python script to push beads issues to Jira.\n\n**Requires**: Jira import script to be complete first (need external_ref matching logic working)\n\n**Features needed**:\n- Create new Jira issues from beads issues without external_ref\n- Update existing Jira issues matched by external_ref\n- Map beads fields back to Jira fields\n- Handle Jira workflow transitions (status changes may need transitions)\n- Support custom field mapping for design/acceptance_criteria/notes\n\n**Challenges**:\n- Jira status changes often require workflow transitions, not direct updates\n- Need to discover valid transitions via API\n- Custom fields vary by Jira instance\n\n**Usage**:\n```bash\nbd export | python jsonl2jira.py --create-only # Only create, don't update\nbd export | python jsonl2jira.py # Create and update\n```\n\n**After creation**: Sets external_ref on beads issue to link back","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-30T12:56:14.266357-08:00","updated_at":"2025-11-30T15:19:40.264737-08:00","closed_at":"2025-11-30T15:19:40.264737-08:00","dependencies":[{"issue_id":"bd-93d","depends_on_id":"bd-qvj","type":"parent-child","created_at":"2025-11-30T12:56:44.652391-08:00","created_by":"stevey"},{"issue_id":"bd-93d","depends_on_id":"bd-tjn","type":"blocks","created_at":"2025-11-30T12:56:54.941116-08:00","created_by":"stevey"}]}
{"id":"bd-9e23","title":"Optimize Memory backend GetIssueByExternalRef with index","description":"Currently GetIssueByExternalRef in Memory storage uses O(n) linear search through all issues.\n\nCurrent code (memory.go:282-308):\nfor _, issue := range m.issues {\n if issue.ExternalRef != nil \u0026\u0026 *issue.ExternalRef == externalRef {\n return \u0026issueCopy, nil\n }\n}\n\nProposed optimization:\n- Add externalRefToID map[string]string to MemoryStorage\n- Maintain it in CreateIssue, UpdateIssue, DeleteIssue\n- Achieve O(1) lookup like SQLite's index\n\nImpact: Low (--no-db mode typically has smaller datasets)\nRelated: bd-1022","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-11-02T15:32:30.242357-08:00","updated_at":"2025-11-26T11:14:49.172418-08:00","closed_at":"2025-11-26T11:14:49.172418-08:00"} {"id":"bd-9e23","title":"Optimize Memory backend GetIssueByExternalRef with index","description":"Currently GetIssueByExternalRef in Memory storage uses O(n) linear search through all issues.\n\nCurrent code (memory.go:282-308):\nfor _, issue := range m.issues {\n if issue.ExternalRef != nil \u0026\u0026 *issue.ExternalRef == externalRef {\n return \u0026issueCopy, nil\n }\n}\n\nProposed optimization:\n- Add externalRefToID map[string]string to MemoryStorage\n- Maintain it in CreateIssue, UpdateIssue, DeleteIssue\n- Achieve O(1) lookup like SQLite's index\n\nImpact: Low (--no-db mode typically has smaller datasets)\nRelated: bd-1022","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-11-02T15:32:30.242357-08:00","updated_at":"2025-11-26T11:14:49.172418-08:00","closed_at":"2025-11-26T11:14:49.172418-08:00"}
{"id":"bd-9li4","title":"Create Docker image for Agent Mail","description":"Containerize Agent Mail server for easy deployment.\n\nAcceptance Criteria:\n- Dockerfile with Python 3.14\n- Health check endpoint\n- Volume mount for storage\n- Environment variable configuration\n- Multi-arch builds (amd64, arm64)\n\nFile: deployment/agent-mail/Dockerfile","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-07T22:43:43.231964-08:00","updated_at":"2025-11-25T17:47:30.777486-08:00","closed_at":"2025-11-25T17:47:30.777486-08:00"} {"id":"bd-9li4","title":"Create Docker image for Agent Mail","description":"Containerize Agent Mail server for easy deployment.\n\nAcceptance Criteria:\n- Dockerfile with Python 3.14\n- Health check endpoint\n- Volume mount for storage\n- Environment variable configuration\n- Multi-arch builds (amd64, arm64)\n\nFile: deployment/agent-mail/Dockerfile","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-07T22:43:43.231964-08:00","updated_at":"2025-11-25T17:47:30.777486-08:00","closed_at":"2025-11-25T17:47:30.777486-08:00"}
@@ -59,7 +60,7 @@
{"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"} {"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"}
{"id":"bd-guc","title":"bd sync should not stage gitignored snapshot files","description":"## Problem\n\n`gitCommitBeadsDir` in `cmd/bd/sync.go` runs `git add .beads/` which stages all files in the directory, including snapshot files that are listed in `.beads/.gitignore`.\n\nIf a snapshot file (e.g., `beads.left.meta.json`) was ever committed before being added to `.gitignore`, git continues to track it. This causes merge conflicts when multiple polecats run `bd sync` concurrently, since each one modifies and commits these temporary files.\n\n## Root Cause\n\nLine ~568 in sync.go:\n```go\naddCmd := exec.CommandContext(ctx, \"git\", \"add\", beadsDir)\n```\n\nThis stages everything in `.beads/`, but `.gitignore` only prevents *untracked* files from being added - it doesn't affect already-tracked files.\n\n## Suggested Fix\n\nOption A: After `git add .beads/`, run `git reset` on snapshot files:\n```go\nexec.Command(\"git\", \"reset\", \"HEAD\", \".beads/beads.*.jsonl\", \".beads/*.meta.json\")\n```\n\nOption B: Stage only specific files instead of the whole directory:\n```go\nexec.Command(\"git\", \"add\", \".beads/issues.jsonl\", \".beads/deletions.jsonl\", \".beads/metadata.json\")\n```\n\nOption C: Detect and untrack snapshot files if they're tracked:\n```go\n// Check if file is tracked: git ls-files --error-unmatch \u003cfile\u003e\n// If tracked, run: git rm --cached \u003cfile\u003e\n```\n\nOption B is probably cleanest - explicitly add only the files that should be committed.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-27T20:47:14.603799-08:00","updated_at":"2025-11-28T17:28:55.54563-08:00","closed_at":"2025-11-27T22:34:23.336713-08:00"} {"id":"bd-guc","title":"bd sync should not stage gitignored snapshot files","description":"## Problem\n\n`gitCommitBeadsDir` in `cmd/bd/sync.go` runs `git add .beads/` which stages all files in the directory, including snapshot files that are listed in `.beads/.gitignore`.\n\nIf a snapshot file (e.g., `beads.left.meta.json`) was ever committed before being added to `.gitignore`, git continues to track it. This causes merge conflicts when multiple polecats run `bd sync` concurrently, since each one modifies and commits these temporary files.\n\n## Root Cause\n\nLine ~568 in sync.go:\n```go\naddCmd := exec.CommandContext(ctx, \"git\", \"add\", beadsDir)\n```\n\nThis stages everything in `.beads/`, but `.gitignore` only prevents *untracked* files from being added - it doesn't affect already-tracked files.\n\n## Suggested Fix\n\nOption A: After `git add .beads/`, run `git reset` on snapshot files:\n```go\nexec.Command(\"git\", \"reset\", \"HEAD\", \".beads/beads.*.jsonl\", \".beads/*.meta.json\")\n```\n\nOption B: Stage only specific files instead of the whole directory:\n```go\nexec.Command(\"git\", \"add\", \".beads/issues.jsonl\", \".beads/deletions.jsonl\", \".beads/metadata.json\")\n```\n\nOption C: Detect and untrack snapshot files if they're tracked:\n```go\n// Check if file is tracked: git ls-files --error-unmatch \u003cfile\u003e\n// If tracked, run: git rm --cached \u003cfile\u003e\n```\n\nOption B is probably cleanest - explicitly add only the files that should be committed.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-27T20:47:14.603799-08:00","updated_at":"2025-11-28T17:28:55.54563-08:00","closed_at":"2025-11-27T22:34:23.336713-08:00"}
{"id":"bd-hdt","title":"Implement auto-merge functionality in duplicates command","description":"The duplicates.go file has a TODO at line 95 to implement the performMerge function for automatic duplicate merging. Currently it just prints a warning message. This would automate the merge process instead of just suggesting commands.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-21T18:55:02.828619-05:00","updated_at":"2025-11-28T19:50:01.115881-08:00","closed_at":"2025-11-27T22:36:11.517878-08:00"} {"id":"bd-hdt","title":"Implement auto-merge functionality in duplicates command","description":"The duplicates.go file has a TODO at line 95 to implement the performMerge function for automatic duplicate merging. Currently it just prints a warning message. This would automate the merge process instead of just suggesting commands.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-21T18:55:02.828619-05:00","updated_at":"2025-11-28T19:50:01.115881-08:00","closed_at":"2025-11-27T22:36:11.517878-08:00"}
{"id":"bd-hm8","title":"Add uninstall documentation (GH #445)","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-01T21:04:30.313637-08:00","updated_at":"2025-12-01T21:04:57.943192-08:00","closed_at":"2025-12-01T21:04:57.943192-08:00","close_reason":"Created UNINSTALLING.md with comprehensive uninstall steps","labels":["docs"]} {"id":"bd-hm8","title":"Add uninstall documentation (GH #445)","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-01T21:04:30.313637-08:00","updated_at":"2025-12-01T21:04:57.943192-08:00","closed_at":"2025-12-01T21:04:57.943192-08:00","labels":["docs"]}
{"id":"bd-ho5","title":"Add 'town report' command for aggregated swarm status","description":"## Problem\nGetting a full swarm status requires running 6+ commands:\n- `town list \u003crig\u003e` for each rig\n- `town mail inbox` as Boss\n- `bd list --status=open/in_progress` per rig\n\nThis is slow and error-prone for both humans and agents.\n\n## Proposed Solution\nAdd `town report [RIG]` command that aggregates:\n- All rigs with polecat states (running/stopped, awake/asleep)\n- Boss inbox summary (unread count, recent senders)\n- Aggregate issue counts per rig (open/in_progress/blocked)\n\nExample output:\n```\n=== beads ===\nPolecats: 5 (5 running, 0 stopped)\nIssues: 20 open, 0 in_progress, 0 blocked\n\n=== gastown ===\nPolecats: 6 (4 running, 2 stopped)\nIssues: 0 open, 0 in_progress, 0 blocked\n\n=== Boss Mail ===\nUnread: 10 | Total: 22\nRecent: rictus (21:19), scrotus (21:14), immortanjoe (21:14)\n```\n\n## Acceptance Criteria\n- [ ] `town report` shows all rigs\n- [ ] `town report \u003crig\u003e` shows single rig detail\n- [ ] Output is concise and scannable\n- [ ] Completes in \u003c2 seconds","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-27T22:55:36.8919-08:00","updated_at":"2025-11-27T22:56:08.071838-08:00","closed_at":"2025-11-27T22:56:08.071838-08:00"} {"id":"bd-ho5","title":"Add 'town report' command for aggregated swarm status","description":"## Problem\nGetting a full swarm status requires running 6+ commands:\n- `town list \u003crig\u003e` for each rig\n- `town mail inbox` as Boss\n- `bd list --status=open/in_progress` per rig\n\nThis is slow and error-prone for both humans and agents.\n\n## Proposed Solution\nAdd `town report [RIG]` command that aggregates:\n- All rigs with polecat states (running/stopped, awake/asleep)\n- Boss inbox summary (unread count, recent senders)\n- Aggregate issue counts per rig (open/in_progress/blocked)\n\nExample output:\n```\n=== beads ===\nPolecats: 5 (5 running, 0 stopped)\nIssues: 20 open, 0 in_progress, 0 blocked\n\n=== gastown ===\nPolecats: 6 (4 running, 2 stopped)\nIssues: 0 open, 0 in_progress, 0 blocked\n\n=== Boss Mail ===\nUnread: 10 | Total: 22\nRecent: rictus (21:19), scrotus (21:14), immortanjoe (21:14)\n```\n\n## Acceptance Criteria\n- [ ] `town report` shows all rigs\n- [ ] `town report \u003crig\u003e` shows single rig detail\n- [ ] Output is concise and scannable\n- [ ] Completes in \u003c2 seconds","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-27T22:55:36.8919-08:00","updated_at":"2025-11-27T22:56:08.071838-08:00","closed_at":"2025-11-27T22:56:08.071838-08:00"}
{"id":"bd-imj","title":"Deletion propagation via deletions manifest","description":"## Problem\n\nWhen `bd cleanup -f` or `bd delete` removes issues in one clone, those deletions don't propagate to other clones. The import logic only creates/updates, never deletes. This causes \"resurrection\" where deleted issues reappear.\n\n## Root Cause\n\nImport sees DB issues not in JSONL and assumes they're \"local unpushed work\" rather than \"intentionally deleted upstream.\"\n\n## Solution: Deletions Manifest\n\nAdd `.beads/deletions.jsonl` - an append-only log of deleted issue IDs with metadata.\n\n### Format\n```jsonl\n{\"id\":\"bd-xxx\",\"ts\":\"2025-11-25T10:00:00Z\",\"by\":\"stevey\"}\n{\"id\":\"bd-yyy\",\"ts\":\"2025-11-25T10:05:00Z\",\"by\":\"claude\",\"reason\":\"duplicate of bd-zzz\"}\n```\n\n### Fields\n- `id`: Issue ID (required)\n- `ts`: ISO 8601 UTC timestamp (required)\n- `by`: Actor who deleted (required)\n- `reason`: Optional context (\"cleanup\", \"duplicate of X\", etc.)\n\n### Import Logic\n```\nFor each DB issue not in JSONL:\n 1. Check deletions manifest → if found, delete from DB\n 2. Fallback: check git history → if found, delete + backfill manifest\n 3. Neither → keep (local unpushed work)\n```\n\n### Conflict Resolution\nSimultaneous deletions from multiple clones are handled naturally:\n- Append-only design means both clones append their deletion records\n- On merge, file contains duplicate entries (same ID, different timestamps)\n- `LoadDeletions` deduplicates by ID (keeps any/first entry)\n- Result: deletion propagates correctly, duplicates are harmless\n\n### Pruning Policy\n- Default retention: 7 days (configurable via `deletions.retention_days`)\n- Auto-compact during `bd sync` is **opt-in** (disabled by default)\n- Hard cap: `deletions.max_entries` (default 50000)\n- Git fallback handles pruned entries (self-healing)\n\n### Self-Healing\nWhen git fallback catches a resurrection (pruned entry), it backfills the manifest. One-time git scan cost, then fast again.\n\n### Size Estimates\n- ~80 bytes/entry\n- 7-day retention with 100 deletions/day = ~56KB\n- Git compressed: ~10KB\n\n## Benefits\n- ✅ Deletions propagate across clones\n- ✅ O(1) lookup (no git scan in normal case)\n- ✅ Works in shallow clones\n- ✅ Survives history rewrite\n- ✅ Audit trail (who deleted what when)\n- ✅ Self-healing via git fallback\n- ✅ Bounded size via time-based pruning\n\n## References\n- Investigation session: 2025-11-25\n- Related: bd-2q6d (stale database warnings)","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-11-25T09:56:01.98027-08:00","updated_at":"2025-11-25T16:36:27.965168-08:00","closed_at":"2025-11-25T16:36:27.965168-08:00","dependencies":[{"issue_id":"bd-imj","depends_on_id":"bd-qsm","type":"blocks","created_at":"2025-11-25T09:57:42.821911-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-x2i","type":"blocks","created_at":"2025-11-25T09:57:42.851712-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-44e","type":"blocks","created_at":"2025-11-25T09:57:42.88154-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-bhd","type":"blocks","created_at":"2025-11-25T14:56:23.675787-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-bgs","type":"blocks","created_at":"2025-11-25T14:56:23.744648-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-f0n","type":"blocks","created_at":"2025-11-25T14:56:23.80649-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-v29","type":"blocks","created_at":"2025-11-25T14:56:23.864569-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-mdw","type":"blocks","created_at":"2025-11-25T14:56:48.592492-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-03r","type":"blocks","created_at":"2025-11-25T14:56:54.295851-08:00","created_by":"daemon"}]} {"id":"bd-imj","title":"Deletion propagation via deletions manifest","description":"## Problem\n\nWhen `bd cleanup -f` or `bd delete` removes issues in one clone, those deletions don't propagate to other clones. The import logic only creates/updates, never deletes. This causes \"resurrection\" where deleted issues reappear.\n\n## Root Cause\n\nImport sees DB issues not in JSONL and assumes they're \"local unpushed work\" rather than \"intentionally deleted upstream.\"\n\n## Solution: Deletions Manifest\n\nAdd `.beads/deletions.jsonl` - an append-only log of deleted issue IDs with metadata.\n\n### Format\n```jsonl\n{\"id\":\"bd-xxx\",\"ts\":\"2025-11-25T10:00:00Z\",\"by\":\"stevey\"}\n{\"id\":\"bd-yyy\",\"ts\":\"2025-11-25T10:05:00Z\",\"by\":\"claude\",\"reason\":\"duplicate of bd-zzz\"}\n```\n\n### Fields\n- `id`: Issue ID (required)\n- `ts`: ISO 8601 UTC timestamp (required)\n- `by`: Actor who deleted (required)\n- `reason`: Optional context (\"cleanup\", \"duplicate of X\", etc.)\n\n### Import Logic\n```\nFor each DB issue not in JSONL:\n 1. Check deletions manifest → if found, delete from DB\n 2. Fallback: check git history → if found, delete + backfill manifest\n 3. Neither → keep (local unpushed work)\n```\n\n### Conflict Resolution\nSimultaneous deletions from multiple clones are handled naturally:\n- Append-only design means both clones append their deletion records\n- On merge, file contains duplicate entries (same ID, different timestamps)\n- `LoadDeletions` deduplicates by ID (keeps any/first entry)\n- Result: deletion propagates correctly, duplicates are harmless\n\n### Pruning Policy\n- Default retention: 7 days (configurable via `deletions.retention_days`)\n- Auto-compact during `bd sync` is **opt-in** (disabled by default)\n- Hard cap: `deletions.max_entries` (default 50000)\n- Git fallback handles pruned entries (self-healing)\n\n### Self-Healing\nWhen git fallback catches a resurrection (pruned entry), it backfills the manifest. One-time git scan cost, then fast again.\n\n### Size Estimates\n- ~80 bytes/entry\n- 7-day retention with 100 deletions/day = ~56KB\n- Git compressed: ~10KB\n\n## Benefits\n- ✅ Deletions propagate across clones\n- ✅ O(1) lookup (no git scan in normal case)\n- ✅ Works in shallow clones\n- ✅ Survives history rewrite\n- ✅ Audit trail (who deleted what when)\n- ✅ Self-healing via git fallback\n- ✅ Bounded size via time-based pruning\n\n## References\n- Investigation session: 2025-11-25\n- Related: bd-2q6d (stale database warnings)","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-11-25T09:56:01.98027-08:00","updated_at":"2025-11-25T16:36:27.965168-08:00","closed_at":"2025-11-25T16:36:27.965168-08:00","dependencies":[{"issue_id":"bd-imj","depends_on_id":"bd-qsm","type":"blocks","created_at":"2025-11-25T09:57:42.821911-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-x2i","type":"blocks","created_at":"2025-11-25T09:57:42.851712-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-44e","type":"blocks","created_at":"2025-11-25T09:57:42.88154-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-bhd","type":"blocks","created_at":"2025-11-25T14:56:23.675787-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-bgs","type":"blocks","created_at":"2025-11-25T14:56:23.744648-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-f0n","type":"blocks","created_at":"2025-11-25T14:56:23.80649-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-v29","type":"blocks","created_at":"2025-11-25T14:56:23.864569-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-mdw","type":"blocks","created_at":"2025-11-25T14:56:48.592492-08:00","created_by":"daemon"},{"issue_id":"bd-imj","depends_on_id":"bd-03r","type":"blocks","created_at":"2025-11-25T14:56:54.295851-08:00","created_by":"daemon"}]}
{"id":"bd-io0","title":"sync.branch config lost on clone - should be in config.yaml","description":"## Problem\n\nThe sync.branch configuration is stored in the SQLite database, which is gitignored. When contributors clone a repo that uses beads:\n\n1. They get .beads/issues.jsonl (tracked)\n2. They don't get .beads/beads.db (gitignored)\n3. They lose the sync.branch config\n\nWhen they run 'bd init' or 'bd doctor --fix', sync.branch gets auto-set to the current branch (usually 'main'), but if the project uses a dedicated sync branch like 'beads-sync', they'll be committing to the wrong branch.\n\n## Root Cause\n\nsyncbranch.Get() only checks:\n1. BEADS_SYNC_BRANCH env var\n2. Database config (store.GetConfig)\n\nIt never reads from config.yaml, which IS tracked in git and persists across clones.\n\n## Proposed Solution\n\nAdd sync-branch support to config.yaml with this precedence:\n1. BEADS_SYNC_BRANCH env var (highest)\n2. config.yaml sync-branch setting\n3. Database config (legacy/local override)\n4. Auto-detect from current branch (lowest)\n\nChanges needed:\n1. Update syncbranch.Get() to check config.GetString('sync-branch') between env and database\n2. Update config.yaml template in init.go to include sync-branch\n3. Update docs to recommend setting sync-branch in config.yaml for team projects\n4. Consider: bd init --branch should also write to config.yaml, not just database","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-30T10:51:29.594627-08:00","updated_at":"2025-11-30T10:54:14.198025-08:00","closed_at":"2025-11-30T10:54:14.198025-08:00"} {"id":"bd-io0","title":"sync.branch config lost on clone - should be in config.yaml","description":"## Problem\n\nThe sync.branch configuration is stored in the SQLite database, which is gitignored. When contributors clone a repo that uses beads:\n\n1. They get .beads/issues.jsonl (tracked)\n2. They don't get .beads/beads.db (gitignored)\n3. They lose the sync.branch config\n\nWhen they run 'bd init' or 'bd doctor --fix', sync.branch gets auto-set to the current branch (usually 'main'), but if the project uses a dedicated sync branch like 'beads-sync', they'll be committing to the wrong branch.\n\n## Root Cause\n\nsyncbranch.Get() only checks:\n1. BEADS_SYNC_BRANCH env var\n2. Database config (store.GetConfig)\n\nIt never reads from config.yaml, which IS tracked in git and persists across clones.\n\n## Proposed Solution\n\nAdd sync-branch support to config.yaml with this precedence:\n1. BEADS_SYNC_BRANCH env var (highest)\n2. config.yaml sync-branch setting\n3. Database config (legacy/local override)\n4. Auto-detect from current branch (lowest)\n\nChanges needed:\n1. Update syncbranch.Get() to check config.GetString('sync-branch') between env and database\n2. Update config.yaml template in init.go to include sync-branch\n3. Update docs to recommend setting sync-branch in config.yaml for team projects\n4. Consider: bd init --branch should also write to config.yaml, not just database","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-30T10:51:29.594627-08:00","updated_at":"2025-11-30T10:54:14.198025-08:00","closed_at":"2025-11-30T10:54:14.198025-08:00"}
@@ -79,7 +80,7 @@
{"id":"bd-p6vp","title":"Clarify .beads/.gitattributes handling in Protected Branches docs","description":"Protected Branches docs quick start leaves untracked `.beads` directory and `.gitattributes`.\nQuestion: Are these changes meant to be checked into the protected branch?\nNeed to clarify if these should be ignored or committed, or if the instructions are missing a step.\n","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T18:56:25.79407-05:00","updated_at":"2025-11-26T22:25:47.574326-08:00","closed_at":"2025-11-26T22:25:47.574326-08:00"} {"id":"bd-p6vp","title":"Clarify .beads/.gitattributes handling in Protected Branches docs","description":"Protected Branches docs quick start leaves untracked `.beads` directory and `.gitattributes`.\nQuestion: Are these changes meant to be checked into the protected branch?\nNeed to clarify if these should be ignored or committed, or if the instructions are missing a step.\n","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T18:56:25.79407-05:00","updated_at":"2025-11-26T22:25:47.574326-08:00","closed_at":"2025-11-26T22:25:47.574326-08:00"}
{"id":"bd-pg1","title":"[CRITICAL] Sync validation false positive - legitimate deletions trigger 'data loss detected'","description":"Sync preflight validation incorrectly detects 'data loss' when legitimate deletions occur. This blocks all syncs and is the highest priority fix.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-28T17:27:42.179281-08:00","updated_at":"2025-11-28T18:36:52.088427-08:00","closed_at":"2025-11-28T17:42:49.92251-08:00"} {"id":"bd-pg1","title":"[CRITICAL] Sync validation false positive - legitimate deletions trigger 'data loss detected'","description":"Sync preflight validation incorrectly detects 'data loss' when legitimate deletions occur. This blocks all syncs and is the highest priority fix.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-28T17:27:42.179281-08:00","updated_at":"2025-11-28T18:36:52.088427-08:00","closed_at":"2025-11-28T17:42:49.92251-08:00"}
{"id":"bd-qsm","title":"Auto-compact deletions during bd sync","description":"Parent: bd-imj\n\n## Task\nOptionally prune deletions manifest during sync when threshold exceeded.\n\n**Note: Opt-in feature** - disabled by default to avoid sync latency.\n\n## Implementation\n\nIn `bd sync`:\n```go\nfunc (s *Syncer) Sync() error {\n // ... existing sync logic ...\n \n // Auto-compact only if enabled\n if s.config.GetBool(\"deletions.auto_compact\", false) {\n deletionCount := deletions.Count(\".beads/deletions.jsonl\")\n threshold := s.config.GetInt(\"deletions.auto_compact_threshold\", 1000)\n \n if deletionCount \u003e threshold {\n retentionDays := s.config.GetInt(\"deletions.retention_days\", 7)\n if err := s.compactor.PruneDeletions(retentionDays); err != nil {\n log.Warnf(\"Failed to auto-compact deletions: %v\", err)\n // Non-fatal, continue sync\n }\n }\n }\n \n // ... rest of sync ...\n}\n```\n\n## Configuration\n```yaml\ndeletions:\n retention_days: 7\n auto_compact: false # Opt-in, disabled by default\n auto_compact_threshold: 1000 # Trigger when \u003e N entries (if enabled)\n```\n\n## Acceptance Criteria\n- [ ] Auto-compact disabled by default\n- [ ] Enabled via config `deletions.auto_compact: true`\n- [ ] Sync checks deletion count only when enabled\n- [ ] Auto-prunes when threshold exceeded\n- [ ] Failure is non-fatal (logged warning)\n- [ ] Test: no compaction when disabled\n- [ ] Test: compaction triggers when enabled and threshold exceeded","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-25T09:57:04.522795-08:00","updated_at":"2025-11-25T15:03:01.469629-08:00","closed_at":"2025-11-25T15:03:01.469629-08:00"} {"id":"bd-qsm","title":"Auto-compact deletions during bd sync","description":"Parent: bd-imj\n\n## Task\nOptionally prune deletions manifest during sync when threshold exceeded.\n\n**Note: Opt-in feature** - disabled by default to avoid sync latency.\n\n## Implementation\n\nIn `bd sync`:\n```go\nfunc (s *Syncer) Sync() error {\n // ... existing sync logic ...\n \n // Auto-compact only if enabled\n if s.config.GetBool(\"deletions.auto_compact\", false) {\n deletionCount := deletions.Count(\".beads/deletions.jsonl\")\n threshold := s.config.GetInt(\"deletions.auto_compact_threshold\", 1000)\n \n if deletionCount \u003e threshold {\n retentionDays := s.config.GetInt(\"deletions.retention_days\", 7)\n if err := s.compactor.PruneDeletions(retentionDays); err != nil {\n log.Warnf(\"Failed to auto-compact deletions: %v\", err)\n // Non-fatal, continue sync\n }\n }\n }\n \n // ... rest of sync ...\n}\n```\n\n## Configuration\n```yaml\ndeletions:\n retention_days: 7\n auto_compact: false # Opt-in, disabled by default\n auto_compact_threshold: 1000 # Trigger when \u003e N entries (if enabled)\n```\n\n## Acceptance Criteria\n- [ ] Auto-compact disabled by default\n- [ ] Enabled via config `deletions.auto_compact: true`\n- [ ] Sync checks deletion count only when enabled\n- [ ] Auto-prunes when threshold exceeded\n- [ ] Failure is non-fatal (logged warning)\n- [ ] Test: no compaction when disabled\n- [ ] Test: compaction triggers when enabled and threshold exceeded","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-25T09:57:04.522795-08:00","updated_at":"2025-11-25T15:03:01.469629-08:00","closed_at":"2025-11-25T15:03:01.469629-08:00"}
{"id":"bd-qvj","title":"Jira import/export integration","description":"Add ability to import issues from Jira and export beads issues to Jira. See GitHub discussion #430 for user request.\n\n**Background**: User @kaihendry configured jira.* settings but found bd sync doesn't sync with Jira - only with git. The config namespace exists but the integration doesn't.\n\n**Existing infrastructure**:\n- external_ref field for linking to external systems\n- Import logic matches by external_ref first (priority over ID matching)\n- Config namespace jira.* documented in CONFIG.md\n- GitHub import example (examples/github-import/gh2jsonl.py) provides pattern\n\n**Schema mapping challenges**:\n- Jira workflows are highly customizable (status mapping)\n- Jira has more field types (components, versions, custom fields)\n- Two-way sync needs conflict resolution\n- Jira Cloud vs Server/Data Center have different APIs\n\n**Approach**: Phased implementation starting with import, then export, then bidirectional sync.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-11-30T12:55:44.835009-08:00","updated_at":"2025-12-01T21:00:17.916386-08:00","closed_at":"2025-12-01T10:44:53.454483-08:00"} {"id":"bd-qvj","title":"Jira import/export integration","description":"Add ability to import issues from Jira and export beads issues to Jira. See GitHub discussion #430 for user request.\n\n**Background**: User @kaihendry configured jira.* settings but found bd sync doesn't sync with Jira - only with git. The config namespace exists but the integration doesn't.\n\n**Existing infrastructure**:\n- external_ref field for linking to external systems\n- Import logic matches by external_ref first (priority over ID matching)\n- Config namespace jira.* documented in CONFIG.md\n- GitHub import example (examples/github-import/gh2jsonl.py) provides pattern\n\n**Schema mapping challenges**:\n- Jira workflows are highly customizable (status mapping)\n- Jira has more field types (components, versions, custom fields)\n- Two-way sync needs conflict resolution\n- Jira Cloud vs Server/Data Center have different APIs\n\n**Approach**: Phased implementation starting with import, then export, then bidirectional sync.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-11-30T12:55:44.835009-08:00","updated_at":"2025-12-01T21:00:17.859754-08:00","closed_at":"2025-12-01T10:44:53.454483-08:00"}
{"id":"bd-s0z","title":"Consider extracting error handling helpers","description":"Evaluate creating FatalError() and WarnError() helpers as suggested in ERROR_HANDLING.md to reduce boilerplate and enforce consistency. Prototype in a few files first to validate the approach.","status":"closed","priority":4,"issue_type":"task","created_at":"2025-11-24T00:28:57.248959-08:00","updated_at":"2025-11-29T22:06:06.332176-08:00","closed_at":"2025-11-28T23:28:00.886536-08:00"} {"id":"bd-s0z","title":"Consider extracting error handling helpers","description":"Evaluate creating FatalError() and WarnError() helpers as suggested in ERROR_HANDLING.md to reduce boilerplate and enforce consistency. Prototype in a few files first to validate the approach.","status":"closed","priority":4,"issue_type":"task","created_at":"2025-11-24T00:28:57.248959-08:00","updated_at":"2025-11-29T22:06:06.332176-08:00","closed_at":"2025-11-28T23:28:00.886536-08:00"}
{"id":"bd-t3b","title":"Add test coverage for internal/config package","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T21:21:22.91657-05:00","updated_at":"2025-11-28T22:17:12.609614-08:00","closed_at":"2025-11-28T21:54:15.009889-08:00","dependencies":[{"issue_id":"bd-t3b","depends_on_id":"bd-ge7","type":"blocks","created_at":"2025-11-20T21:21:31.201036-05:00","created_by":"daemon"}]} {"id":"bd-t3b","title":"Add test coverage for internal/config package","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-20T21:21:22.91657-05:00","updated_at":"2025-11-28T22:17:12.609614-08:00","closed_at":"2025-11-28T21:54:15.009889-08:00","dependencies":[{"issue_id":"bd-t3b","depends_on_id":"bd-ge7","type":"blocks","created_at":"2025-11-20T21:21:31.201036-05:00","created_by":"daemon"}]}
{"id":"bd-t5m","title":"CRITICAL: git-history-backfill purges entire database when JSONL reset","description":"When a clone gets reset (git reset --hard origin/main), the git-history-backfill logic incorrectly adds ALL issues to the deletions manifest, then sync purges the entire database.\\n\\nFix adds safety guard: never delete more than 50% of issues via git-history-backfill. If threshold exceeded, abort with warning message.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-30T21:24:47.397394-08:00","updated_at":"2025-11-30T21:24:52.710971-08:00","closed_at":"2025-11-30T21:24:52.710971-08:00"} {"id":"bd-t5m","title":"CRITICAL: git-history-backfill purges entire database when JSONL reset","description":"When a clone gets reset (git reset --hard origin/main), the git-history-backfill logic incorrectly adds ALL issues to the deletions manifest, then sync purges the entire database.\\n\\nFix adds safety guard: never delete more than 50% of issues via git-history-backfill. If threshold exceeded, abort with warning message.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-30T21:24:47.397394-08:00","updated_at":"2025-11-30T21:24:52.710971-08:00","closed_at":"2025-11-30T21:24:52.710971-08:00"}

View File

@@ -2,4 +2,4 @@
"database": "beads.db", "database": "beads.db",
"jsonl_export": "issues.jsonl", "jsonl_export": "issues.jsonl",
"last_bd_version": "0.27.2" "last_bd_version": "0.27.2"
} }

View File

@@ -185,9 +185,46 @@ var showCmd = &cobra.Command{
} }
if len(details.Dependents) > 0 { if len(details.Dependents) > 0 {
fmt.Printf("\nBlocks (%d):\n", len(details.Dependents)) // Group by dependency type for clarity
var blocks, children, related, discovered []*types.IssueWithDependencyMetadata
for _, dep := range details.Dependents { for _, dep := range details.Dependents {
fmt.Printf(" ← %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority) switch dep.DependencyType {
case types.DepBlocks:
blocks = append(blocks, dep)
case types.DepParentChild:
children = append(children, dep)
case types.DepRelated:
related = append(related, dep)
case types.DepDiscoveredFrom:
discovered = append(discovered, dep)
default:
blocks = append(blocks, dep)
}
}
if len(children) > 0 {
fmt.Printf("\nChildren (%d):\n", len(children))
for _, dep := range children {
fmt.Printf(" ↳ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(blocks) > 0 {
fmt.Printf("\nBlocks (%d):\n", len(blocks))
for _, dep := range blocks {
fmt.Printf(" ← %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(related) > 0 {
fmt.Printf("\nRelated (%d):\n", len(related))
for _, dep := range related {
fmt.Printf(" ↔ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(discovered) > 0 {
fmt.Printf("\nDiscovered (%d):\n", len(discovered))
for _, dep := range discovered {
fmt.Printf(" ◊ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
} }
} }
@@ -334,12 +371,62 @@ var showCmd = &cobra.Command{
} }
} }
// Show dependents // Show dependents - grouped by dependency type for clarity
dependents, _ := store.GetDependents(ctx, issue.ID) // Use GetDependentsWithMetadata to get the dependency type
if len(dependents) > 0 { sqliteStore, ok := store.(*sqlite.SQLiteStorage)
fmt.Printf("\nBlocks (%d):\n", len(dependents)) if ok {
for _, dep := range dependents { dependentsWithMeta, _ := sqliteStore.GetDependentsWithMetadata(ctx, issue.ID)
fmt.Printf(" ← %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority) if len(dependentsWithMeta) > 0 {
// Group by dependency type
var blocks, children, related, discovered []*types.IssueWithDependencyMetadata
for _, dep := range dependentsWithMeta {
switch dep.DependencyType {
case types.DepBlocks:
blocks = append(blocks, dep)
case types.DepParentChild:
children = append(children, dep)
case types.DepRelated:
related = append(related, dep)
case types.DepDiscoveredFrom:
discovered = append(discovered, dep)
default:
blocks = append(blocks, dep) // Default to blocks
}
}
if len(children) > 0 {
fmt.Printf("\nChildren (%d):\n", len(children))
for _, dep := range children {
fmt.Printf(" ↳ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(blocks) > 0 {
fmt.Printf("\nBlocks (%d):\n", len(blocks))
for _, dep := range blocks {
fmt.Printf(" ← %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(related) > 0 {
fmt.Printf("\nRelated (%d):\n", len(related))
for _, dep := range related {
fmt.Printf(" ↔ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
if len(discovered) > 0 {
fmt.Printf("\nDiscovered (%d):\n", len(discovered))
for _, dep := range discovered {
fmt.Printf(" ◊ %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
}
}
} else {
// Fallback for non-SQLite storage
dependents, _ := store.GetDependents(ctx, issue.ID)
if len(dependents) > 0 {
fmt.Printf("\nBlocks (%d):\n", len(dependents))
for _, dep := range dependents {
fmt.Printf(" ← %s: %s [P%d]\n", dep.ID, dep.Title, dep.Priority)
}
} }
} }

View File

@@ -332,10 +332,10 @@ Effect: Can track progress across all investigations
### Creating parent-child Dependencies ### Creating parent-child Dependencies
```bash ```bash
bd dep add parent-epic-id child-task-id --type parent-child bd dep add child-task-id parent-epic-id --type parent-child
``` ```
**Direction matters**: `from_id` is parent, `to_id` is child. **Direction matters**: The child depends on the parent. Think: "child depends on parent" or "task is part of epic".
### Combining with blocks ### Combining with blocks