40 KiB
Instructions for AI Agents Working on Beads
Project Overview
This is beads (command: bd), an issue tracker designed for AI-supervised coding workflows. We dogfood our own tool!
Human Setup vs Agent Usage
IMPORTANT: If you need to initialize bd, use the --quiet flag:
bd init --quiet # Non-interactive, auto-installs git hooks, no prompts
Why --quiet? Regular bd init has interactive prompts (git hooks) that confuse agents. The --quiet flag makes it fully non-interactive:
- Automatically installs git hooks
- No prompts for user input
- Safe for agent-driven repo setup
If the human already initialized: Just use bd normally with bd create, bd ready, bd update, bd close, etc.
If you see "database not found": Run bd init --quiet yourself, or ask the human to run bd init.
Issue Tracking
We use bd (beads) for issue tracking instead of Markdown TODOs or external tools.
MCP Server (Recommended)
RECOMMENDED: Use the MCP (Model Context Protocol) server for the best experience! The beads MCP server provides native integration with Claude and other MCP-compatible AI assistants.
Installation:
# Install the MCP server
pip install beads-mcp
# Add to your MCP settings (e.g., Claude Desktop config)
{
"beads": {
"command": "beads-mcp",
"args": []
}
}
Benefits:
- Native function calls instead of shell commands
- Automatic workspace detection
- Better error handling and validation
- Structured JSON responses
- No need for
--jsonflags
All bd commands are available as MCP functions with the prefix mcp__beads-*__. For example:
bd ready→mcp__beads__ready()bd create→mcp__beads__create(title="...", priority=1)bd update→mcp__beads__update(issue_id="bd-42", status="in_progress")
See integrations/beads-mcp/README.md for complete documentation.
Multi-Repo Configuration (MCP Server)
RECOMMENDED: Use a single MCP server for all beads projects - it automatically routes to per-project local daemons.
Setup (one-time):
# MCP config in ~/.config/amp/settings.json or Claude Desktop config:
{
"beads": {
"command": "beads-mcp",
"args": []
}
}
How it works (LSP model): The single MCP server instance automatically:
- Checks for local daemon socket (
.beads/bd.sock) in your current workspace - Routes requests to the correct per-project daemon based on working directory
- Auto-starts the local daemon if not running (with exponential backoff)
- Each project gets its own isolated daemon serving only its database
Architecture:
MCP Server (one instance)
↓
Per-Project Daemons (one per workspace)
↓
SQLite Databases (complete isolation)
Why per-project daemons?
- ✅ Complete database isolation between projects
- ✅ No cross-project pollution or git worktree conflicts
- ✅ Simpler mental model: one project = one database = one daemon
- ✅ Follows LSP (Language Server Protocol) architecture
Note: The daemon auto-starts automatically when you run any bd command (v0.9.11+). To disable auto-start, set BEADS_AUTO_START_DAEMON=false.
Version Management: bd automatically handles daemon version mismatches (v0.16.0+):
- When you upgrade bd, old daemons are automatically detected and restarted
- Version compatibility is checked on every connection
- No manual intervention required after upgrades
- Works transparently with MCP server and CLI
- Use
bd daemons healthto check for version mismatches - Use
bd daemons killallto force-restart all daemons if needed
Alternative (not recommended): Multiple MCP Server Instances If you must use separate MCP servers:
{
"beads-webapp": {
"command": "beads-mcp",
"env": {
"BEADS_WORKING_DIR": "/Users/you/projects/webapp"
}
},
"beads-api": {
"command": "beads-mcp",
"env": {
"BEADS_WORKING_DIR": "/Users/you/projects/api"
}
}
}
⚠️ Problem: AI may select the wrong MCP server for your workspace, causing commands to operate on the wrong database.
CLI Quick Reference
If you're not using the MCP server, here are the CLI commands:
# Check database path and daemon status
bd info --json
# Find ready work (no blockers)
bd ready --json
# Find stale issues (not updated recently)
bd stale --days 30 --json # Default: 30 days
bd stale --days 90 --status in_progress --json # Filter by status
bd stale --limit 20 --json # Limit results
# Create new issue
# IMPORTANT: Always quote titles and descriptions with double quotes
bd create "Issue title" -t bug|feature|task -p 0-4 -d "Description" --json
# Create with explicit ID (for parallel workers)
bd create "Issue title" --id worker1-100 -p 1 --json
# Create with labels (--labels or --label work)
bd create "Issue title" -t bug -p 1 -l bug,critical --json
bd create "Issue title" -t bug -p 1 --label bug,critical --json
# Examples with special characters (all require quoting):
bd create "Fix: auth doesn't validate tokens" -t bug -p 1 --json
bd create "Add support for OAuth 2.0" -d "Implement RFC 6749 (OAuth 2.0 spec)" --json
# Create multiple issues from markdown file
bd create -f feature-plan.md --json
# Create epic with hierarchical child tasks
bd create "Auth System" -t epic -p 1 --json # Returns: bd-a3f8e9
bd create "Login UI" -p 1 --json # Auto-assigned: bd-a3f8e9.1
bd create "Backend validation" -p 1 --json # Auto-assigned: bd-a3f8e9.2
bd create "Tests" -p 1 --json # Auto-assigned: bd-a3f8e9.3
# Update one or more issues
bd update <id> [<id>...] --status in_progress --json
bd update <id> [<id>...] --priority 1 --json
# Edit issue fields in $EDITOR (HUMANS ONLY - not for agents)
bd edit <id> # Edit description
bd edit <id> --title # Edit title
bd edit <id> --design # Edit design notes
bd edit <id> --notes # Edit notes
bd edit <id> --acceptance # Edit acceptance criteria
# Link discovered work (old way)
bd dep add <discovered-id> <parent-id> --type discovered-from
# Create and link in one command (new way)
bd create "Issue title" -t bug -p 1 --deps discovered-from:<parent-id> --json
# Label management (supports multiple IDs)
bd label add <id> [<id>...] <label> --json
bd label remove <id> [<id>...] <label> --json
bd label list <id> --json
bd label list-all --json
# Filter and search issues
bd list --status open --priority 1 --json # Status and priority
bd list --assignee alice --json # By assignee
bd list --type bug --json # By issue type
bd list --label bug,critical --json # Labels (AND: must have ALL)
bd list --label-any frontend,backend --json # Labels (OR: has ANY)
bd list --id bd-123,bd-456 --json # Specific IDs
bd list --title "auth" --json # Title search (substring)
# Pattern matching (case-insensitive substring)
bd list --title-contains "auth" --json # Search in title
bd list --desc-contains "implement" --json # Search in description
bd list --notes-contains "TODO" --json # Search in notes
# Date range filters (YYYY-MM-DD or RFC3339)
bd list --created-after 2024-01-01 --json # Created after date
bd list --created-before 2024-12-31 --json # Created before date
bd list --updated-after 2024-06-01 --json # Updated after date
bd list --updated-before 2024-12-31 --json # Updated before date
bd list --closed-after 2024-01-01 --json # Closed after date
bd list --closed-before 2024-12-31 --json # Closed before date
# Empty/null checks
bd list --empty-description --json # Issues with no description
bd list --no-assignee --json # Unassigned issues
bd list --no-labels --json # Issues with no labels
# Priority ranges
bd list --priority-min 0 --priority-max 1 --json # P0 and P1 only
bd list --priority-min 2 --json # P2 and below
# Combine filters
bd list --status open --priority 1 --label-any urgent,critical --no-assignee --json
# Complete work (supports multiple IDs)
bd close <id> [<id>...] --reason "Done" --json
# Reopen closed issues (supports multiple IDs)
bd reopen <id> [<id>...] --reason "Reopening" --json
# Show dependency tree
bd dep tree <id>
# Get issue details (supports multiple IDs)
bd show <id> [<id>...] --json
# Rename issue prefix (e.g., from 'knowledge-work-' to 'kw-')
bd rename-prefix kw- --dry-run # Preview changes
bd rename-prefix kw- --json # Apply rename
# Restore compacted issue from git history
bd restore <id> # View full history at time of compaction
# Import issues from JSONL
bd import -i .beads/issues.jsonl --dry-run # Preview changes
bd import -i .beads/issues.jsonl # Import and update issues
bd import -i .beads/issues.jsonl --dedupe-after # Import + detect duplicates
# Note: Import automatically handles missing parents!
# - If a hierarchical child's parent is missing (e.g., bd-abc.1 but no bd-abc)
# - bd will search the JSONL history for the parent
# - If found, creates a tombstone placeholder (Status=Closed, Priority=4)
# - Dependencies are also resurrected on best-effort basis
# - This prevents import failures after parent deletion
# Find and merge duplicate issues
bd duplicates # Show all duplicates
bd duplicates --auto-merge # Automatically merge all
bd duplicates --dry-run # Preview merge operations
# Merge specific duplicate issues
bd merge <source-id...> --into <target-id> --json # Consolidate duplicates
bd merge bd-42 bd-43 --into bd-41 --dry-run # Preview merge
# Migrate databases after version upgrade
bd migrate # Detect and migrate old databases
bd migrate --dry-run # Preview migration
bd migrate --cleanup --yes # Migrate and remove old files
# AI-supervised migration (check before running bd migrate)
bd migrate --inspect --json # Show migration plan for AI agents
bd info --schema --json # Get schema, tables, config, sample IDs
# Workflow: AI agents should inspect first, then migrate
# 1. Run --inspect to see pending migrations and warnings
# 2. Check for missing_config (like issue_prefix)
# 3. Review invariants_to_check for safety guarantees
# 4. If warnings exist, fix config issues first
# 5. Then run bd migrate safely
Migration safety: The system verifies data integrity invariants after migrations:
- required_config_present: Ensures issue_prefix and schema_version are set
- foreign_keys_valid: No orphaned dependencies or labels
- issue_count_stable: Issue count doesn't decrease unexpectedly
These invariants prevent data loss and would have caught issues like GH #201 (missing issue_prefix after migration).
Managing Daemons
bd runs a background daemon per workspace for auto-sync and RPC operations. Use bd daemons to manage multiple daemons:
# List all running daemons
bd daemons list --json
# Check health (version mismatches, stale sockets)
bd daemons health --json
# Stop a specific daemon
bd daemons stop /path/to/workspace --json
bd daemons stop 12345 --json # By PID
# View daemon logs
bd daemons logs /path/to/workspace -n 100
bd daemons logs 12345 -f # Follow mode
# Stop all daemons
bd daemons killall --json
bd daemons killall --force --json # Force kill if graceful fails
When to use:
- After upgrading bd: Run
bd daemons healthto check for version mismatches, thenbd daemons killallto restart all daemons with the new version - Debugging: Use
bd daemons logs <workspace>to view daemon logs - Cleanup:
bd daemons listauto-removes stale sockets
Troubleshooting:
- Stale sockets:
bd daemons listauto-cleans them - Version mismatch:
bd daemons killallthen let daemons auto-start on next command - Daemon won't stop:
bd daemons killall --force
See commands/daemons.md for detailed documentation.
Event-Driven Daemon Mode (Experimental)
NEW in v0.16+: The daemon supports an experimental event-driven mode that replaces 5-second polling with instant reactivity.
Benefits:
- ⚡ <500ms latency (vs ~5000ms with polling)
- 🔋 ~60% less CPU usage (no continuous polling)
- 🎯 Instant sync on mutations and file changes
- 🛡️ Dropped events safety net prevents data loss
How it works:
- FileWatcher monitors
.beads/issues.jsonland.git/refs/headsusing platform-native APIs:- Linux:
inotify - macOS:
FSEvents(via kqueue) - Windows:
ReadDirectoryChangesW
- Linux:
- Mutation events from RPC operations (create, update, close) trigger immediate export
- Debouncer batches rapid changes (500ms window) to avoid export storms
- Polling fallback if fsnotify unavailable (e.g., network filesystems)
Opt-In (Phase 1):
Event-driven mode is opt-in during Phase 1. To enable:
# Enable event-driven mode for a single daemon
BEADS_DAEMON_MODE=events bd daemon start
# Or set globally in your shell profile
export BEADS_DAEMON_MODE=events
# Restart all daemons to apply
bd daemons killall
# Next bd command will auto-start daemon with new mode
Available modes:
poll(default) - Traditional 5-second polling, stable and battle-testedevents- New event-driven mode, experimental but thoroughly tested
Troubleshooting:
If the watcher fails to start:
- Check daemon logs:
bd daemons logs /path/to/workspace -n 100 - Look for "File watcher unavailable" warnings
- Common causes:
- Network filesystem (NFS, SMB) - fsnotify may not work
- Container environment - may need privileged mode
- Resource limits - check
ulimit -n(open file descriptors)
Fallback behavior:
- If
BEADS_DAEMON_MODE=eventsbut watcher fails, daemon falls back to polling automatically - Set
BEADS_WATCHER_FALLBACK=falseto disable fallback and require fsnotify
Disable polling fallback:
# Require fsnotify, fail if unavailable
BEADS_WATCHER_FALLBACK=false BEADS_DAEMON_MODE=events bd daemon start
Switch back to polling:
# Explicitly use polling mode
BEADS_DAEMON_MODE=poll bd daemon start
# Or unset to use default
unset BEADS_DAEMON_MODE
bd daemons killall # Restart with default (poll) mode
Future (Phase 2): Event-driven mode will become the default once it's proven stable in production use.
Workflow
- Check for ready work: Run
bd readyto see what's unblocked (orbd staleto find forgotten issues) - Claim your task:
bd update <id> --status in_progress - Work on it: Implement, test, document
- Discover new work: If you find bugs or TODOs, create issues:
- Old way (two commands):
bd create "Found bug in auth" -t bug -p 1 --jsonthenbd dep add <new-id> <current-id> --type discovered-from - New way (one command):
bd create "Found bug in auth" -t bug -p 1 --deps discovered-from:<current-id> --json
- Old way (two commands):
- Complete:
bd close <id> --reason "Implemented" - Sync at end of session:
bd sync(see "Agent Session Workflow" below)
Issue Types
bug- Something broken that needs fixingfeature- New functionalitytask- Work item (tests, docs, refactoring)epic- Large feature composed of multiple issues (supports hierarchical children)chore- Maintenance work (dependencies, tooling)
Hierarchical children: Epics can have child issues with dotted IDs (e.g., bd-a3f8e9.1, bd-a3f8e9.2). Children are auto-numbered sequentially. Up to 3 levels of nesting supported. The parent hash ensures unique namespace - no coordination needed between agents working on different epics.
Priorities
0- Critical (security, data loss, broken builds)1- High (major features, important bugs)2- Medium (nice-to-have features, minor bugs)3- Low (polish, optimization)4- Backlog (future ideas)
Dependency Types
blocks- Hard dependency (issue X blocks issue Y)related- Soft relationship (issues are connected)parent-child- Epic/subtask relationshipdiscovered-from- Track issues discovered during work (automatically inherits parent'ssource_repo)
Only blocks dependencies affect the ready work queue.
Note: When creating an issue with a discovered-from dependency, the new issue automatically inherits the parent's source_repo field. This ensures discovered work stays in the same repository as the parent task.
Duplicate Detection & Merging
AI agents should proactively detect and merge duplicate issues to keep the database clean:
Automated duplicate detection:
# Find all content duplicates in the database
bd duplicates
# Automatically merge all duplicates
bd duplicates --auto-merge
# Preview what would be merged
bd duplicates --dry-run
# During import
bd import -i issues.jsonl --dedupe-after
Detection strategies:
-
Before creating new issues: Search for similar existing issues
bd list --json | grep -i "authentication" bd show bd-41 bd-42 --json # Compare candidates -
Periodic duplicate scans: Review issues by type or priority
bd list --status open --priority 1 --json # High-priority issues bd list --issue-type bug --json # All bugs -
During work discovery: Check for duplicates when filing discovered-from issues
# Before: bd create "Fix auth bug" --deps discovered-from:bd-100 # First: bd list --json | grep -i "auth bug" # Then decide: create new or link to existing
Merge workflow:
# Step 1: Identify duplicates (bd-42 and bd-43 duplicate bd-41)
bd show bd-41 bd-42 bd-43 --json
# Step 2: Preview merge to verify
bd merge bd-42 bd-43 --into bd-41 --dry-run
# Step 3: Execute merge
bd merge bd-42 bd-43 --into bd-41 --json
# Step 4: Verify result
bd dep tree bd-41 # Check unified dependency tree
bd show bd-41 --json # Verify merged content
What gets merged:
- ✅ All dependencies from source → target
- ✅ Text references updated across ALL issues (descriptions, notes, design, acceptance criteria)
- ✅ Source issues closed with "Merged into bd-X" reason
- ❌ Source issue content NOT copied (target keeps its original content)
Important notes:
- Merge preserves target issue completely; only dependencies/references migrate
- If source issues have valuable content, manually copy it to target BEFORE merging
- Cannot merge in daemon mode yet (bd-190); use
--no-daemonflag - Operation cannot be undone (but git history preserves the original)
Best practices:
- Merge early to prevent dependency fragmentation
- Choose the oldest or most complete issue as merge target
- Add labels like
duplicateto source issues before merging (for tracking) - File a discovered-from issue if you found duplicates during work:
bd create "Found duplicates during bd-X" -p 2 --deps discovered-from:bd-X --json
Development Guidelines
Code Standards
- Go version: 1.21+
- Linting:
golangci-lint run ./...(baseline warnings documented in docs/LINTING.md) - Testing: All new features need tests (
go test ./...) - Documentation: Update relevant .md files
File Organization
beads/
├── cmd/bd/ # CLI commands
├── internal/
│ ├── types/ # Core data types
│ └── storage/ # Storage layer
│ └── sqlite/ # SQLite implementation
├── examples/ # Integration examples
└── *.md # Documentation
Before Committing
- Run tests:
go test ./... - Run linter:
golangci-lint run ./...(ignore baseline warnings) - Update docs: If you changed behavior, update README.md or other docs
- Commit: Issues auto-sync to
.beads/issues.jsonland import after pull
Git Workflow
Auto-sync provides batching! bd automatically:
- Exports to JSONL after CRUD operations (30-second debounce for batching)
- Imports from JSONL when it's newer than DB (e.g., after
git pull) - Daemon commits/pushes every 5 seconds (if
--auto-commit/--auto-pushenabled)
The 30-second debounce provides a transaction window for batch operations - multiple issue changes within 30 seconds get flushed together, avoiding commit spam.
Protected Branch Workflow
If your repository uses protected branches (GitHub, GitLab, etc.), beads can commit to a separate branch instead of main:
# Initialize with separate sync branch
bd init --branch beads-metadata
# Or configure existing setup
bd config set sync.branch beads-metadata
How it works:
- Beads commits issue updates to
beads-metadatainstead ofmain - Uses git worktrees (lightweight checkouts) in
.git/beads-worktrees/ - Your main working directory is never affected
- Periodically merge
beads-metadataback tomainvia pull request
Daily workflow (unchanged for agents):
# Agents work normally - no changes needed!
bd create "Fix authentication" -t bug -p 1
bd update bd-a1b2 --status in_progress
bd close bd-a1b2 "Fixed"
All changes automatically commit to beads-metadata branch (if daemon is running with --auto-commit).
Merging to main (humans):
# Check what's changed
bd sync --status
# Option 1: Create pull request
git push origin beads-metadata
# Then create PR on GitHub/GitLab
# Option 2: Direct merge (if allowed)
bd sync --merge
Benefits:
- ✅ Works with protected
mainbranches - ✅ No disruption to agent workflows
- ✅ Platform-agnostic (works on any git platform)
- ✅ Backward compatible (opt-in via config)
See docs/PROTECTED_BRANCHES.md for complete setup guide, troubleshooting, and examples.
Landing the Plane
When the user says "let's land the plane", follow this clean session-ending protocol:
- File beads issues for any remaining work that needs follow-up
- Ensure all quality gates pass (only if code changes were made) - run tests, linters, builds (file P0 issues if broken)
- Update beads issues - close finished work, update status
- Git pull & rebase
- bd sync - verify both import and export succeeded
- Git push - redo rebase if necessary until it succeeds
- Double-check for untracked files (beads files often get dirty again after git push)
- Ensure no untracked files remain
- Choose a follow-up issue for next session
- Provide a prompt for the user to give to you in the next session
- Format: "Continue work on bd-X: [issue title]. [Brief context about what's been done and what's next]"
Example "land the plane" session:
# 1. File remaining work
bd create "Add integration tests for sync" -t task -p 2 --json
# 2. Run quality gates
go test ./...
golangci-lint run ./...
# 3. Close finished issues
bd close bd-42 bd-43 --reason "Completed" --json
# 4. Pull & rebase
git pull --rebase
# 5. Sync beads
bd sync
# 6. Push
git push
# 7-8. Verify clean state
git status
# 9. Choose next work
bd ready --json
bd show bd-44 --json
Then provide the user with:
- Summary of what was completed this session
- What issues were filed for follow-up
- Status of quality gates (all passing / issues filed)
- Recommended prompt for next session
Agent Session Workflow
IMPORTANT for AI agents: When you finish making issue changes, always run:
bd sync
This immediately:
- Exports pending changes to JSONL (no 30s wait)
- Commits to git
- Pulls from remote
- Imports any updates
- Pushes to remote
Example agent session:
# Make multiple changes (batched in 30-second window)
bd create "Fix bug" -p 1
bd create "Add tests" -p 1
bd update bd-42 --status in_progress
bd close bd-40 --reason "Completed"
# Force immediate sync at end of session
bd sync
# Now safe to end session - everything is committed and pushed
Why this matters:
- Without
bd sync, changes sit in 30-second debounce window - User might think you pushed but JSONL is still dirty
bd syncforces immediate flush/commit/push
STRONGLY RECOMMENDED: Install git hooks for automatic sync (prevents stale JSONL problems):
# One-time setup - run this in each beads workspace
./examples/git-hooks/install.sh
This installs:
- pre-commit - Flushes pending changes immediately before commit (bypasses 30s debounce)
- post-merge - Imports updated JSONL after pull/merge (guaranteed sync)
- pre-push - Exports database to JSONL before push (prevents stale JSONL from reaching remote)
Why git hooks matter: Without the pre-push hook, you can have database changes committed locally but stale JSONL pushed to remote, causing multi-workspace divergence. The hooks guarantee DB ↔ JSONL consistency.
See examples/git-hooks/README.md for details.
Git Worktrees
⚠️ Important Limitation: Daemon mode does not work correctly with git worktree.
The Problem:
Git worktrees share the same .git directory and thus share the same .beads database. The daemon doesn't know which branch each worktree has checked out, which can cause it to commit/push to the wrong branch.
What you lose without daemon mode:
- Auto-sync - No automatic commit/push of changes (use
bd syncmanually) - MCP server - The beads-mcp server requires daemon mode for multi-repo support
- Background watching - No automatic detection of remote changes
Solutions for Worktree Users:
-
Use
--no-daemonflag (recommended):bd --no-daemon ready bd --no-daemon create "Fix bug" -p 1 bd --no-daemon update bd-42 --status in_progress -
Disable daemon via environment variable (for entire worktree session):
export BEADS_NO_DAEMON=1 bd ready # All commands use direct mode -
Disable auto-start (less safe, still warns):
export BEADS_AUTO_START_DAEMON=false
Automatic Detection:
bd automatically detects when you're in a worktree and shows a prominent warning if daemon mode is active. The --no-daemon mode works correctly with worktrees since it operates directly on the database without shared state.
Why It Matters:
The daemon maintains its own view of the current working directory and git state. When multiple worktrees share the same .beads database, the daemon may commit changes intended for one branch to a different branch, leading to confusion and incorrect git history.
Handling Git Merge Conflicts
With hash-based IDs (v0.20.1+), ID collisions are eliminated! Different issues get different hash IDs, so most git merges succeed cleanly.
When git merge conflicts occur:
Git conflicts in .beads/beads.jsonl happen when the same issue is modified on both branches (different timestamps/fields). This is a same-issue update conflict, not an ID collision. Conflicts are rare in practice since hash IDs prevent structural collisions.
Automatic detection:
bd automatically detects conflict markers (<<<<<<<, =======, >>>>>>>) and shows clear resolution steps:
bd importrejects files with conflict markers and shows resolution commandsbd validate --checks=conflictsscans for conflicts in JSONL
Resolution workflow:
# After git merge creates conflict in .beads/beads.jsonl
# Option 1: Accept their version (remote)
git checkout --theirs .beads/beads.jsonl
bd import -i .beads/beads.jsonl
# Option 2: Keep our version (local)
git checkout --ours .beads/beads.jsonl
bd import -i .beads/beads.jsonl
# Option 3: Manual resolution in editor
# Edit .beads/beads.jsonl to remove conflict markers
bd import -i .beads/beads.jsonl
# Commit the merge
git add .beads/beads.jsonl
git commit
Note: bd import automatically handles updates - same ID with different content is a normal update operation. No special flags needed. If you accidentally modified the same issue in both branches, just pick whichever version is more complete.
Advanced: Intelligent Merge Tools
For Git merge conflicts in .beads/issues.jsonl, use beads-merge - a production-ready 3-way merge tool by @neongreen that:
- Prevents conflicts proactively with field-level merging
- Matches issues by identity (id + created_at + created_by)
- Smart field merging: timestamps→max, dependencies→union, status/priority→3-way
- Outputs conflict markers only for unresolvable conflicts
- Works as Git/jujutsu merge driver (opt-in)
Setup (one-time):
# Install (requires Go 1.21+)
git clone https://github.com/neongreen/mono.git
cd mono/beads-merge
go install
# Configure Git merge driver
git config merge.beads.name "JSONL merge driver for beads"
git config merge.beads.driver "beads-merge %A %O %A %B"
# Enable for beads JSONL files (in your repo)
echo ".beads/beads.jsonl merge=beads" >> .gitattributes
git add .gitattributes
git commit -m "Enable beads-merge for JSONL files"
For Jujutsu users, add to ~/.jjconfig.toml:
[merge-tools.beads-merge]
program = "beads-merge"
merge-args = ["$output", "$base", "$left", "$right"]
merge-conflict-exit-codes = [1]
Then resolve with: jj resolve --tool=beads-merge
How it works: During git merge, beads-merge merges JSONL files issue-by-issue instead of line-by-line. This prevents spurious conflicts from line renumbering or timestamp updates. If conflicts remain, they're marked in standard format for manual resolution.
Current Project Status
Run bd stats to see overall progress.
Active Areas
- Core CLI: Mature, but always room for polish
- Examples: Growing collection of agent integrations
- Documentation: Comprehensive but can always improve
- MCP Server: Implemented at
integrations/beads-mcp/with Claude Code plugin - Migration Tools: Planned (see bd-6)
1.0 Milestone
We're working toward 1.0. Key blockers tracked in bd. Run:
bd dep tree bd-8 # Show 1.0 epic dependencies
Exclusive Lock Protocol (Advanced)
For external tools that need full database control (e.g., CI/CD, deterministic execution systems):
The bd daemon respects exclusive locks via .beads/.exclusive-lock file. When this lock exists:
- Daemon skips all operations for the locked database
- External tool has complete control over git sync and database operations
- Stale locks (dead process) are automatically cleaned up
Use case: Tools like VibeCoder that need deterministic execution without daemon interference.
See EXCLUSIVE_LOCK.md for:
- Lock file format (JSON schema)
- Creating and releasing locks (Go/shell examples)
- Stale lock detection behavior
- Integration testing guidance
Quick example:
# Create lock
echo '{"holder":"my-tool","pid":'$$',"hostname":"'$(hostname)'","started_at":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","version":"1.0.0"}' > .beads/.exclusive-lock
# Do work...
bd create "My issue" -p 1
# Release lock
rm .beads/.exclusive-lock
Common Tasks
Adding a New Command
- Create file in
cmd/bd/ - Add to root command in
cmd/bd/main.go - Implement with Cobra framework
- Add
--jsonflag for agent use - Add tests in
cmd/bd/*_test.go - Document in README.md
Adding Storage Features
- Update schema in
internal/storage/sqlite/schema.go - Add migration if needed
- Update
internal/types/types.goif new types - Implement in
internal/storage/sqlite/sqlite.go - Add tests
- Update export/import in
cmd/bd/export.goandcmd/bd/import.go
Adding Examples
- Create directory in
examples/ - Add README.md explaining the example
- Include working code
- Link from
examples/README.md - Mention in main README.md
Questions?
- Check existing issues:
bd list - Look at recent commits:
git log --oneline -20 - Read the docs: README.md, ADVANCED.md, EXTENDING.md
- Create an issue if unsure:
bd create "Question: ..." -t task -p 2
Important Files
- README.md - Main documentation (keep this updated!)
- EXTENDING.md - Database extension guide
- ADVANCED.md - JSONL format analysis
- CONTRIBUTING.md - Contribution guidelines
- SECURITY.md - Security policy
Pro Tips for Agents
- Always use
--jsonflags for programmatic use - Always run
bd syncat end of session to flush/commit/push immediately - Link discoveries with
discovered-fromto maintain context - Check
bd readybefore asking "what next?" - Auto-sync batches changes in 30-second window - use
bd syncto force immediate flush - Use
--no-auto-flushor--no-auto-importto disable automatic sync if needed - Use
bd dep treeto understand complex dependencies - Priority 0-1 issues are usually more important than 2-4
- Use
--dry-runto preview import changes before applying - Hash IDs eliminate collisions - same ID with different content is a normal update
- Use
--idflag withbd createto partition ID space for parallel workers (e.g.,worker1-100,worker2-500)
Checking GitHub Issues and PRs
IMPORTANT: When asked to check GitHub issues or PRs, use command-line tools like gh instead of browser/playwright tools.
Preferred approach:
# List open issues with details
gh issue list --limit 30
# List open PRs
gh pr list --limit 30
# View specific issue
gh issue view 201
Then provide an in-conversation summary highlighting:
- Urgent/critical issues (regressions, bugs, broken builds)
- Common themes or patterns
- Feature requests with high engagement
- Items that need immediate attention
Why this matters:
- Browser tools consume more tokens and are slower
- CLI summaries are easier to scan and discuss
- Keeps the conversation focused and efficient
- Better for quick triage and prioritization
Do NOT use: browser_navigate, browser_snapshot, or other playwright tools for GitHub PR/issue reviews unless specifically requested by the user.
Building and Testing
# Build
go build -o bd ./cmd/bd
# Test
go test ./...
# Test with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run locally
./bd init --prefix test
./bd create "Test issue" -p 1
./bd ready
Version Management
IMPORTANT: When the user asks to "bump the version" or mentions a new version number (e.g., "bump to 0.9.3"), use the version bump script:
# Preview changes (shows diff, doesn't commit)
./scripts/bump-version.sh 0.9.3
# Auto-commit the version bump
./scripts/bump-version.sh 0.9.3 --commit
git push origin main
What it does:
- Updates ALL version files (CLI, plugin, MCP server, docs) in one command
- Validates semantic versioning format
- Shows diff preview
- Verifies all versions match after update
- Creates standardized commit message
User will typically say:
- "Bump to 0.9.3"
- "Update version to 1.0.0"
- "Rev the project to 0.9.4"
- "Increment the version"
You should:
- Run
./scripts/bump-version.sh <version> --commit - Push to GitHub
- Confirm all versions updated correctly
Files updated automatically:
cmd/bd/version.go- CLI version.claude-plugin/plugin.json- Plugin version.claude-plugin/marketplace.json- Marketplace versionintegrations/beads-mcp/pyproject.toml- MCP server versionREADME.md- Documentation versionPLUGIN.md- Version requirements
Why this matters: We had version mismatches (bd-66) when only version.go was updated. This script prevents that by updating all components atomically.
See scripts/README.md for more details.
Release Process (Maintainers)
- Bump version with
./scripts/bump-version.sh <version> --commit - Update CHANGELOG.md with release notes
- Run full test suite:
go test ./... - Push version bump:
git push origin main - Tag release:
git tag v<version> - Push tag:
git push origin v<version> - GitHub Actions handles the rest
Remember: We're building this tool to help AI agents like you! If you find the workflow confusing or have ideas for improvement, create an issue with your feedback.
Happy coding! 🔗
Issue Tracking with bd (beads)
IMPORTANT: This project uses bd (beads) for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
Why bd?
- Dependency-aware: Track blockers and relationships between issues
- Git-friendly: Auto-syncs to JSONL for version control
- Agent-optimized: JSON output, ready work detection, discovered-from links
- Prevents duplicate tracking systems and confusion
Quick Start
FIRST TIME? Just run bd init - it auto-imports issues from git:
bd init --prefix bd
Check for ready work:
bd ready --json
Create new issues:
bd create "Issue title" -t bug|feature|task -p 0-4 --json
bd create "Issue title" -p 1 --deps discovered-from:bd-123 --json
Claim and update:
bd update bd-42 --status in_progress --json
bd update bd-42 --priority 1 --json
Complete work:
bd close bd-42 --reason "Completed" --json
Issue Types
bug- Something brokenfeature- New functionalitytask- Work item (tests, docs, refactoring)epic- Large feature with subtaskschore- Maintenance (dependencies, tooling)
Priorities
0- Critical (security, data loss, broken builds)1- High (major features, important bugs)2- Medium (default, nice-to-have)3- Low (polish, optimization)4- Backlog (future ideas)
Workflow for AI Agents
- Check ready work:
bd readyshows unblocked issues - Claim your task:
bd update <id> --status in_progress - Work on it: Implement, test, document
- Discover new work? Create linked issue:
bd create "Found bug" -p 1 --deps discovered-from:<parent-id>
- Complete:
bd close <id> --reason "Done"
Auto-Sync
bd automatically syncs with git:
- Exports to
.beads/issues.jsonlafter changes (5s debounce) - Imports from JSONL when newer (e.g., after
git pull) - No manual export/import needed!
MCP Server (Recommended)
If using Claude or MCP-compatible clients, install the beads MCP server:
pip install beads-mcp
Add to MCP config (e.g., ~/.config/claude/config.json):
{
"beads": {
"command": "beads-mcp",
"args": []
}
}
Then use mcp__beads__* functions instead of CLI commands.
Managing AI-Generated Planning Documents
AI assistants often create planning and design documents during development:
- PLAN.md, IMPLEMENTATION.md, ARCHITECTURE.md
- DESIGN.md, CODEBASE_SUMMARY.md, INTEGRATION_PLAN.md
- TESTING_GUIDE.md, TECHNICAL_DESIGN.md, and similar files
Best Practice: Use a dedicated directory for these ephemeral files
Recommended approach:
- Create a
history/directory in the project root - Store ALL AI-generated planning/design docs in
history/ - Keep the repository root clean and focused on permanent project files
- Only access
history/when explicitly asked to review past planning
Example .gitignore entry (optional):
# AI planning documents (ephemeral)
history/
Benefits:
- ✅ Clean repository root
- ✅ Clear separation between ephemeral and permanent documentation
- ✅ Easy to exclude from version control if desired
- ✅ Preserves planning history for archaeological research
- ✅ Reduces noise when browsing the project
Important Rules
- ✅ Use bd for ALL task tracking
- ✅ Always use
--jsonflag for programmatic use - ✅ Link discovered work with
discovered-fromdependencies - ✅ Check
bd readybefore asking "what should I work on?" - ✅ Store AI planning docs in
history/directory - ❌ Do NOT create markdown TODO lists
- ❌ Do NOT use external issue trackers
- ❌ Do NOT duplicate tracking systems
- ❌ Do NOT clutter repo root with planning documents
For more details, see README.md and QUICKSTART.md.