Consider adding UnderlyingConn(ctx) for safer scoped DB access

Currently UnderlyingDB() returns *sql.DB which is correct for most uses, but for extension migrations/DDL, a scoped connection might be safer.

**Proposal:** Add optional UnderlyingConn(ctx) (*sql.Conn, error) method that:
- Returns a scoped connection via s.db.Conn(ctx)
- Encourages lifetime-bounded usage
- Reduces temptation to tune global pool settings
- Better for one-time DDL operations like CREATE TABLE

**Implementation:**
```go
// UnderlyingConn returns a single connection from the pool for scoped use
// Useful for migrations and DDL. Close the connection when done.
func (s *SQLiteStorage) UnderlyingConn(ctx context.Context) (*sql.Conn, error) {
    return s.db.Conn(ctx)
}
```

**Benefits:**
- Safer for migrations (explicit scope)
- Complements UnderlyingDB() for different use cases
- Low implementation cost

**Trade-off:** Adds another method to maintain, but Oracle considers this balanced compromise between safety and flexibility.

**Decision:** This is optional - evaluate based on VC's actual usage patterns.


MCP close tool method signature error - takes 1 positional argument but 2 were given

The close approval routing fix in beads-mcp v0.11.0 works correctly and successfully routes update(status="closed") calls to close() tool. However, the close() tool has a Python method signature bug that prevents execution.

Impact: All MCP-based close operations are broken. Workaround: Use bd CLI directly.

Error: BdDaemonClient.close() takes 1 positional argument but 2 were given

Root cause: BdDaemonClient.close() only accepts self, but MCP tool passes issue_id and reason.

Additional issue: CLI close has FOREIGN KEY constraint error when recording reason parameter.

See GitHub issue #107 for full details.


Test close issue


Fix pre-existing MCP test failures - show/update return arrays not dicts

9 tests fail in beads-mcp because bd CLI commands return arrays but MCP client expects dicts:

Failing tests:
- test_create_and_show_issue: show returns array, expects dict
- test_update_issue: update returns array, expects dict
- test_add_dependency: show returns array, expects dict
- test_invalid_issue_id: show returns empty dict instead of error
- test_dependency_types: show returns array, expects dict
- test_show_issue_tool: show returns array, expects dict
- test_update_issue_tool: update returns array, expects dict
- test_update_partial_fields: update returns array, expects dict
- test_client_lazy_initialization: BdClient import issue

Root cause: bd CLI commands like 'bd show' and 'bd update' output JSON arrays, but BdCliClient.show() and BdCliClient.update() expect single dict objects.

Example:
```bash
bd show test-1 --json
[{"id":"test-1",...}]  # Array, not dict
```

Fix needed: Update bd_client.py to handle array responses and extract first element, or change CLI to return single object for single-ID operations.


Compact command fails with daemon - requires --no-daemon workaround

The 'bd compact' command fails with 'Error: compact requires SQLite storage' when used with the daemon (default mode), but works correctly with the '--no-daemon' flag.

The daemon RPC interface doesn't properly expose the compact command, even though the daemon itself uses SQLite storage.

Reproduction:
1. Ensure daemon is running (bd daemon status)
2. Run: bd compact --stats
   Result: Error: compact requires SQLite storage
3. Run: bd compact --stats --no-daemon
   Result: Works correctly, shows statistics

Expected behavior:
The compact command should work through the daemon RPC interface just like other commands (list, create, update, delete, renumber, etc.)

Impact:
Users cannot use compact operations in the normal workflow. They must use --no-daemon which bypasses the daemon entirely.

Suggested fix:
Add compact operation support to the daemon RPC interface, similar to how renumber and other operations are exposed.


Fix bd sync prefix mismatch error message suggesting non-existent flag

GH #103: bd sync suggests using --rename-on-import flag that doesn't exist. Need to either implement the flag or fix the error message to suggest the correct workflow.


Fix MCP close tool method signature error

GH #107: MCP close() tool fails with "BdDaemonClient.close() takes 1 positional argument but 2 were given". Need to fix method signature in beads-mcp server.


Test auto-export timing


Consider implementing pre-commit hooks for Storage interface changes

The documentation (INTERFACE_CHANGES.md) suggests adding pre-commit hooks that automatically check for Storage interface changes and verify all mocks are updated. This would prevent similar issues in the future where interface changes break mock implementations.

Discovered during execution of vc-228 (dogfooding run #14/15).

Implement a pre-commit hook that:
1. Detects changes to internal/storage/storage.go
2. Runs scripts/find-storage-mocks.sh to find all mock implementations
3. Attempts to compile all test files with mocks
4. Blocks commit if compilation fails

Tools: husky, pre-commit framework, or simple .git/hooks/pre-commit script

- Pre-commit hook installed and documented
- Hook detects Storage interface changes
- Hook validates all mocks compile
- Hook can be bypassed with --no-verify if needed
- Documentation updated with installation instructions


Add customizable time threshold for compact command

Currently compact uses fixed 30-day and 90-day tiers. Add support for custom time thresholds like '--older-than 60h' or '--older-than 2.5d' to allow more flexible compaction policies.

Examples:
  bd compact --all --older-than 60h
  bd compact --all --older-than 2.5d
  bd compact --all --tier 1 --age 48h

This would allow users to set their own compaction schedules based on their workflow needs.


Add --id flag to bd list for filtering by specific issue IDs

Add --id flag accepting comma-separated IDs. Usage: bd list --id wy-11,wy-12. Combines with other filters. From filter-flag-design.md.


Test issue 2


Make merge command idempotent for safe retry after partial failures

The merge command currently performs 3 operations without an outer transaction:
1. Migrate dependencies from source → target
2. Update text references across all issues
3. Close source issues

If merge fails mid-operation (network issue, daemon crash, etc.), a retry will fail or produce incorrect results because some operations already succeeded.

**Goal:** Make merge idempotent so retrying after partial failure is safe and completes the remaining work.

**Idempotency checks needed:**
- Skip dependency migration if target already has the dependency
- Skip text reference updates if already updated
- Skip closing source issues if already closed
- Report which operations were skipped vs performed

**Example output:**
```
✓ Merged 2 issue(s) into bd-193
  - Dependencies: 3 migrated, 2 already existed
  - Text references: 5 updated, 0 already correct
  - Source issues: 1 closed, 1 already closed
```

**Related:** bd-192 originally requested transaction support, but idempotency is a better solution for this use case since individual operations are already atomic.

Current merge code already has some idempotency:
- Dependency migration checks `alreadyExists` before adding (line ~145-151 in merge.go)
- Text reference updates are naturally idempotent (replacing bd-X with bd-Y twice has same result)

Missing idempotency:
- CloseIssue fails if source already closed
- Error messages don't distinguish "already done" from "real failure"

Implementation:
1. Check source issue status before closing - skip if already closed
2. Track which operations succeeded/skipped
3. Return detailed results for user visibility
4. Consider adding --dry-run output showing what would be done vs skipped


Document merge command and AI integration

Update README, AGENTS.md with merge command examples. Document AI agent duplicate detection workflow.


Add EXPLAIN QUERY PLAN tests for ready work query

Verify that the hierarchical blocking query uses proper indexes and doesn't do full table scans.

**Queries to analyze:**
1. The recursive CTE (both base case and recursive case)
2. The final SELECT with NOT EXISTS
3. Impact of various filters (status, priority, assignee)

**Implementation:**
Add test function that:
- Runs EXPLAIN QUERY PLAN on GetReadyWork query
- Parses output to verify no SCAN TABLE operations
- Documents expected query plan in comments
- Fails if query plan degrades

**Benefits:**
- Catch performance regressions in tests
- Document expected query behavior
- Ensure indexes are being used

Related to: bd-87 (composite index on depends_on_id, type)


Investigate stress test database pollution (vc-248)

Investigation of stress tests polluting production database with 1,600+ test issues on Oct 21 at 20:24-20:25. Root cause analysis completed. Tests now verified to work correctly with proper isolation.

Bug confirmed! Tests DO pollute production DB. 1,000 test issues created at 20:46:01-20:46:02 during TestStressNoUniqueConstraintViolations. Root cause: test goroutines connect to production daemon at .beads/bd.sock instead of test daemon.


Optimize export dependency queries (N+1 problem)

Export triggers separate GetDependencyRecords() per issue. For large DBs (1000+ issues), this is N+1 queries. Add GetAllDependencyRecords() to fetch all dependencies in one query. Location: cmd/bd/export.go:52-59, import.go:138-142


Add workspace config file for multi-repo management (optional enhancement)

For users who want explicit control over multi-repo setup without daemon, add optional workspace config file.

Config file: ~/.beads/workspaces.toml

Example:
[workspaces]
current = "global"

[workspace.global]
db = "~/.beads/global.db"
description = "System-wide tasks"

[workspace.project1]
db = "~/src/project1/.beads/db.sqlite"
description = "Main product"

[workspace.project2]
db = "~/src/project2/.beads/db.sqlite"
description = "Internal tools"

Commands:
bd workspace list                    # Show all workspaces
bd workspace add NAME PATH           # Add workspace
bd workspace remove NAME             # Remove workspace
bd workspace use NAME                # Switch active workspace
bd workspace current                 # Show current workspace
bd --workspace NAME <command>        # Override for single command

Implementation:
- Load config in PersistentPreRun
- Override dbPath based on current workspace
- Store workspace state in config file
- Support both workspace config AND auto-discovery
- Workspace config takes precedence over auto-discovery

Priority rationale:
- Priority 3 (low) because daemon approach already solves this
- Only implement if users request explicit workspace management
- Adds complexity vs daemon's automatic discovery

Alternative: Users can use BEADS_DB env var for manual workspace switching today.


Use safer placeholder pattern in replaceIDReferences

Currently uses bd-313 which could theoretically collide with user text. Use a truly unique placeholder like null bytes: \x00REMAP\x00_0_\x00 which are unlikely to appear in normal text. Located in collision.go:324. Very low probability issue but worth fixing for completeness.


Implement full cross-type cycle prevention in AddDependency

Expand cycle prevention in AddDependency to check for cycles across ALL dependency types, not just 'blocks'. Currently only 'blocks' type dependencies are checked for cycles, allowing cross-type circular dependencies to form (e.g., A blocks B, B parent-child A). This can cause semantic confusion and is a maintenance hazard for future operations that traverse dependencies.

Implementation approach:
1. Modify the cycle check in AddDependency (postgres.go:559-599)
2. Remove the 'type = blocks' filter from the recursive CTE
3. Check for cycles regardless of dependency type being added
4. Return a clear error message indicating which types form the cycle

Trade-offs to consider:
- This is more mathematically correct (no cycles in dependency DAG)
- May break legitimate use cases where cross-type cycles are intentional
- Need to evaluate whether ANY cross-type cycles are valid in practice
- Alternative: make this configurable with a --allow-cycle flag

Before implementing, should investigate:
- Are there legitimate reasons for cross-type cycles?
- What's the performance impact on large graphs (1000+ issues)?
- Should certain type combinations be allowed to cycle?

- AddDependency prevents cycles across all dependency types, not just 'blocks'
- Clear error message when cycle would be created, including dependency types
- All existing tests pass
- Performance benchmarked on large dependency graphs (100+ issues)
- Decision documented on whether to add --allow-cycle flag or exception rules


Refactor duplicate flush logic in PersistentPostRun

PersistentPostRun contains a complete copy of the flush logic instead of calling flushToJSONL(). This violates DRY principle and makes maintenance harder. Refactor to use flushToJSONL() with a force parameter to bypass isDirty check, or extract shared logic into a helper function. Located in cmd/bd/main.go:104-138.


Optimize auto-flush to use incremental updates

Every flush exports ALL issues and ALL dependencies, even if only one issue changed. For large projects (1000+ issues), this could be expensive. Current approach guarantees consistency, which is fine for MVP, but future optimization could track which issues changed and use incremental updates. Located in cmd/bd/main.go:255-276.


Make auto-flush debounce duration configurable

flushDebounce is hardcoded to 5 seconds. Make it configurable via environment variable BEADS_FLUSH_DEBOUNCE (e.g., '500ms', '10s'). Current 5-second value is reasonable for interactive use, but CI/automated scenarios might want faster flush. Add getDebounceDuration() helper function. Located in cmd/bd/main.go:31.


Document label best practices and use cases

Create documentation covering:
- When to use labels vs structured fields
- Common label sets (coding agents, open source, product dev, SRE)
- Naming conventions (kebab-case, specificity, present tense)
- Anti-patterns (too many labels, overlapping, personal labels)
- Label lifecycle management

Content from LABELS.md analysis document.


Add rule-based compaction (e.g., compact children of closed epics)

Support semantic compaction rules beyond just time-based, such as:
- Compact all children of closed epics
- Compact by priority level (e.g., all P3/P4 closed issues)
- Compact by label (e.g., all issues labeled 'archive')
- Compact by type (e.g., all closed chores)

This would allow smarter database size management based on semantic meaning rather than just age.


Test issue 1


Implement text reference scanning and replacement

Scan all issues for text references to merged IDs (bd-X patterns) and update to target ID. Reuse logic from import collision resolution.


Improve error handling in dependency removal during remapping

In updateDependencyReferences(), RemoveDependency errors are caught and ignored with continue (line 392). Comment says 'if dependency doesn't exist' but this catches ALL errors including real failures. Should check error type with errors.Is(err, ErrDependencyNotFound) and only ignore not-found errors, returning other errors properly.


Global daemon should warn/reject --auto-commit and --auto-push

When user runs 'bd daemon --global --auto-commit', it's unclear which repo the daemon will commit to (especially after fixing bd-195 where global daemon won't open a DB).

Options:
1. Warn and ignore the flags in global mode
2. Error out with clear message

Line 87-91 already checks autoPush, but should skip check entirely for global mode. Add user-friendly messaging about flag incompatibility.


Add performance benchmarks document

Document actual performance metrics with hyperfine tests


Investigate vector/semantic search for issue discovery

From GH issue #2 RFC discussion: Evaluate if vector/semantic search over issues would provide value for beads.

**Use case:** Find semantically related issues (e.g., 'login broken' finds 'authentication failure', 'session expired').

**Questions to answer:**
1. What workflows would this enable that we can't do now?
2. Is dataset size (typically 50-200 issues) large enough to benefit?
3. Do structured features (deps, tags, types) already provide better relationships?
4. What's the maintenance cost (embeddings, storage, recomputation)?

**Alternatives to consider:**
- Improve 'bd list' filtering with regex/boolean queries
- Add 'bd related <id>' showing deps + mentions + same tags
- Export to JSON and pipe to external AI tools

**Decision:** Only implement if clear use case emerges. Don't add complexity for theoretical benefits.

**Context:** Part of evaluating Turso RFC ideas (GH #2). Vector search was proposed but unclear if needed for typical beads usage.


Add visual indicators for nodes with multiple parents in dep tree

When a node appears in the dependency tree via multiple paths (diamond dependencies), add a visual indicator like (*) or (multiple parents) to help users understand the graph structure. This would make it clear when deduplication has occurred. Example: 'bd-503: Shared dependency (*) [P1] (open)'


Add --show-all-paths flag to bd dep tree

Currently bd dep tree deduplicates nodes when multiple paths exist (diamond dependencies). Add optional --show-all-paths flag to display the full graph with all paths, showing duplicates. Useful for debugging complex dependency structures and understanding all relationships.


Refactor parseMarkdownFile to reduce cyclomatic complexity

The parseMarkdownFile function in cmd/bd/markdown.go has a cyclomatic complexity of 38, which exceeds the recommended threshold of 30. This makes the function harder to understand, test, and maintain.

Split the function into smaller, focused units:

1. parseMarkdownFile(filepath) - Main entry point, handles file I/O
2. parseMarkdownContent(scanner) - Core parsing logic
3. processIssueSection(issue, section, content) - Handle section finalization (current switch statement)
4. parseLabels(content) []string - Extract labels from content
5. parseDependencies(content) []string - Extract dependencies from content
6. parsePriority(content) int - Parse and validate priority

Benefits:
- Each function has a single responsibility
- Easier to test individual components
- Lower cognitive load when reading code
- Better encapsulation of parsing logic

- parseMarkdownFile complexity < 15
- New helper functions each have complexity < 10
- All existing tests still pass
- No change in functionality or behavior
- Code coverage maintained or improved


Simplify getNextID SQL query parameters

Query passes prefix four times to same SQL query. Works but fragile if query changes. Consider simplifying SQL to require fewer parameters. Location: internal/storage/sqlite/sqlite.go:73-78


Write tests for merge functionality

Unit tests: validation, merge logic, data integrity. Integration tests: end-to-end workflow, export/import. Edge case tests: chains, circular refs, epics.


Remove unused issueMap in scoreCollisions

scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.