bd
bd - Git-Native Issue Tracking
Core Principle
Use bd for all task and issue operations—it's git-native and agent-friendly.
Issues live where your code lives: in git. No external API, no network dependency, no vendor lock-in. Just files, tracked by git, queryable via SQLite, and optimized for AI agent workflows.
When to Use bd
Primary Use Cases
- Task Tracking: Create, update, close issues for any work item
- Issue Management: Organize bugs, features, chores with labels and priorities
- Project Planning: Break down epics into subtasks with dependencies
- Dependency Modeling: Express work relationships as a DAG
- Sprint Planning: Assign work, set priorities, track progress
- Bug Triage: Classify, assign, and track defects
- AI Agent Workflows: Autonomous task execution with dependency awareness
When NOT to Use bd
- Public issue tracking (use GitHub Issues for public visibility)
- Customer-facing support tickets (use dedicated support systems)
- Marketing/sales workflows (use CRM tools)
- Document management (use proper DMS)
Quick Start
Installation Check
# Verify bd is installed
which bd
# Expected: /opt/homebrew/bin/bd (or similar)
bd --version
# Expected: bd version 0.28.0+
Initialize in Repository
# Initialize bd in current git repo
bd init
# Configure project-specific prefix (optional)
bd config set prefix myapp
# Verify setup
bd status
Basic Operations
# Create an issue
bd create "Add user authentication"
# Create with metadata
bd create "Fix login bug" \
--type bug \
--priority 1 \
--assignee alice \
--labels backend,security
# List issues
bd list
bd list --status open --assignee alice
bd list --label urgent --priority-min 0 --priority-max 1
# Update issue
bd update bd-1 --status in_progress
bd update bd-1 --priority 0
bd update bd-1 --assignee bob
# Add comment
bd comment bd-1 "Started investigating root cause"
# Close issue
bd close bd-1
# Show details
bd show bd-1
bd show bd-1 --json # Structured output for parsing
Core Concepts
Issue Structure
Every issue has:
- ID: Hash-based (e.g.,
bd-a3f8e9) or sequential (legacy) - Title: Brief summary (required)
- Description: Detailed explanation (markdown)
- Type: bug | feature | task | epic | chore
- Status: open | in_progress | blocked | closed
- Priority: 0-4 (0=highest, 4=lowest)
- Assignee: Username or actor
- Labels: Tags for organization
- Dependencies: Relationships to other issues
- Timestamps: created_at, updated_at, closed_at
Dual Persistence
bd uses TWO storage formats:
-
SQLite (
.beads/*.db)- Fast queries and filtering
- Full-text search
- Indexed relationships
- Ephemeral: rebuilds from JSONL
-
JSONL (
.beads/beads.jsonl)- Git-friendly line-by-line format
- Complete audit history
- Source of truth for sync
- Human-readable events
Key insight: SQLite is for speed, JSONL is for git. Changes are written to both automatically.
Dependency DAG
Issues form a Directed Acyclic Graph (no cycles allowed):
bd-1 (Design) → bd-2 (Backend) → bd-3 (Frontend) → bd-4 (Tests)
Dependency types:
blocks/blocked_by: Hard dependenciesdiscovered-from: Context trackingparent/child: Hierarchical relationships
Why DAG?
- Prevents deadlocks (no circular dependencies)
- Enables critical path analysis
- Clear work ordering
- Parallel work identification
Issue Lifecycle
┌─────────────────────────────────────────┐
│ │
│ open ──> in_progress ──> closed │
│ │ │ │
│ └────> blocked │
│ │ │
│ └──> in_progress │
│ │
│ closed ──> reopen ──> open │
│ │
└─────────────────────────────────────────┘
Common Workflows
Daily Developer Workflow
# Morning: Review work
git pull # Sync issues from team
bd ready # Show unblocked work
bd list --assignee $USER # Your assigned issues
# During work: Update status
bd update bd-5 --status in_progress # Start work
bd comment bd-5 "Implementing JWT" # Progress notes
# Found a bug? Create it
bd create "Fix null pointer in auth" \
--type bug \
--priority 1 \
--deps discovered-from:bd-5
# End of day: Sync
git add .beads/
git commit -m "Progress on bd-5"
git push
Epic Decomposition
# 1. Create epic
bd create "Redesign authentication" \
--type epic \
--priority 0
EPIC_ID="bd-1" # Replace with actual ID
# 2. Create subtasks
bd create "Design auth schema" --parent $EPIC_ID --priority 0
bd create "Implement backend" --parent $EPIC_ID --deps bd-2
bd create "Update frontend" --parent $EPIC_ID --deps bd-3
bd create "Write tests" --parent $EPIC_ID --deps bd-3,bd-4
# 3. Visualize plan
bd dep tree $EPIC_ID --long
Sprint Planning
# 1. Review backlog
bd list --status open --no-assignee --sort priority
# 2. Assign sprint work
bd update bd-10,bd-11,bd-12 --assignee alice
bd label add sprint-5 bd-10,bd-11,bd-12
# 3. Set priorities
bd update bd-10,bd-11 --priority 0 # Critical
# 4. Review sprint
bd list --label sprint-5 --long
Bug Triage
# 1. Create bug with full context
bd create "Login fails with special chars" \
--type bug \
--priority 2 \
--description "Steps: 1) Use p@ss\$word! 2) Try login 3) Fails" \
--labels backend,security
# 2. Assign and track
bd update bd-20 --assignee backend-team --status in_progress
# 3. Add investigation notes
bd update bd-20 --notes "Root cause: encoding issue in auth/password.go"
# 4. Close when fixed
bd close bd-20
Dependency Management
Adding Dependencies
# Single dependency
bd dep add bd-1 blocks bd-2
# Multiple at creation
bd create "New feature" --deps bd-1,bd-2,bd-3
# Explicit types
bd create "Bug fix" --deps discovered-from:bd-5,blocks:bd-10
# Hierarchical
bd create "Subtask" --parent bd-1
Viewing Dependencies
# Dependency tree
bd dep tree bd-1
# All blocked issues
bd blocked
# All ready work (no blockers)
bd ready
# Export as graph
bd list --format dot | dot -Tpng -o issues.png
bd list --format digraph > issues.txt
Removing Dependencies
# Remove specific dependency
bd dep remove bd-1 blocks bd-2
Cycle Detection
# Find cycles (deadlocks)
bd dep cycles
# Output example:
# Cycle detected: bd-5 -> bd-7 -> bd-9 -> bd-5
Advanced Features
Daemon Mode
Long-running RPC server for hot database and multi-workspace:
# Start daemon (auto-started by default)
bd daemon start
# Check status
bd daemon status
# Stop daemon
bd daemon stop
# Force direct mode (bypass daemon)
bd --no-daemon list
Benefits:
- <10ms create/update operations (vs ~100ms direct)
- Hot SQLite cache
- Multi-workspace support
- Background sync
- JSON-RPC protocol
Templates
# Create template
bd template create bug-report \
--type bug \
--priority 2 \
--description "## Steps to Reproduce\n\n## Expected\n\n## Actual"
# Use template
bd create "New bug" --from-template bug-report
Labels
# Add labels
bd label add urgent bd-5
bd label add backend,security bd-5
# Remove labels
bd label remove urgent bd-5
# Query by labels
bd list --label backend # AND: must have ALL
bd list --label-any urgent,high # OR: must have AT LEAST ONE
Search & Filtering
# Text search
bd search "authentication"
# Filter by multiple criteria
bd list \
--status open,in_progress \
--priority-min 0 --priority-max 1 \
--assignee alice \
--label backend \
--created-after 2024-01-01 \
--sort priority \
--reverse
# Empty description (needs work)
bd list --empty-description
# No assignee (needs owner)
bd list --no-assignee --status open
Comments
# Add comment
bd comment bd-5 "Started implementation"
bd comment bd-5 --body "Multi-line comment"
# View comments
bd comments list bd-5
# Add inline (via update)
bd update bd-5 --notes "Design notes here"
Export/Import
# Export to JSONL
bd export > backup.jsonl
bd export --status closed --created-after 2024-01-01 > archive.jsonl
# Import from JSONL
bd import backup.jsonl
# Migrate between repos
bd migrate-issues --from ~/old-repo --to ~/new-repo
Multi-Repository
# Configure multiple repos
bd repo add backend ~/repos/backend --prefix api
bd repo add frontend ~/repos/frontend --prefix ui
# Create in specific repo
bd create "Add endpoint" --repo backend
# Auto-routing (based on cwd)
cd ~/repos/backend
bd create "Add endpoint" # Automatically creates in backend repo
Git Integration
Automatic Sync
# bd auto-syncs with JSONL on operations
bd create "New issue"
# Writes to SQLite AND .beads/beads.jsonl
git add .beads/
git commit -m "Add issue"
git push
Git Hooks
# Install hooks for auto-sync
bd hooks install
# Hooks added:
# pre-commit: Validate issue references in commits
# post-commit: Auto-export to JSONL
Manual Sync
# Pull from remote
git pull # Merges .beads/beads.jsonl
# Push to remote
git add .beads/
git commit -m "Update issues"
git push
# Or use bd sync
bd sync pull
bd sync push
Merge Conflicts
bd includes custom merge driver:
# .gitattributes (auto-configured by bd init)
.beads/beads.jsonl merge=beads
# Conflicts are resolved by:
# 1. Preserving both changes in JSONL
# 2. Rebuilding SQLite from merged JSONL
# 3. Detecting cycles if any
Visualization
bv (Interactive Graph)
# Open interactive visualization
bv .beads/beads.jsonl
# Features:
# - Colored nodes by status
# - Dependency edges with types
# - Filter by labels, status, assignee
# - Click nodes for details
# - Export as PNG/SVG
Graphviz
# Generate DOT format
bd list --format dot > issues.dot
# Render with Graphviz
dot -Tpng -o issues.png issues.dot
dot -Tsvg -o issues.svg issues.dot
# Customize layout
neato -Tpng -o issues-neato.png issues.dot # Force-directed
circo -Tpng -o issues-circo.png issues.dot # Circular
Text-Based Tree
# ASCII dependency tree
bd dep tree bd-1
# Long format (more details)
bd dep tree bd-1 --long
Health & Maintenance
Validation
# Full database health check
bd validate
# Check for issues:
# - Orphaned dependencies
# - Cycles in DAG
# - Corrupted records
# - JSONL/SQLite inconsistencies
Doctor
# Comprehensive health check
bd doctor
# Checks:
# - Installation integrity
# - Database schema
# - Config validity
# - Git integration
# - Daemon status
Repair
# Fix orphaned dependencies
bd repair-deps
bd repair-deps --dry-run # Preview only
# Detect and clean test pollution
bd detect-pollution
bd detect-pollution --clean
# Find and merge duplicates
bd duplicates
bd duplicates --auto-merge
Cleanup
# Compact old closed issues (save space, keep git history)
bd compact --older-than 90d
# Delete closed issues from DB (keep in JSONL for sync)
bd cleanup --older-than 30d
# Purge deleted issues entirely (careful!)
bd delete bd-1 --purge # Removes from JSONL too
AI Agent Workflows
Autonomous Task Loop
#!/bin/bash
# agent-work-loop.sh
while true; do
# Get ready work
READY=$(bd ready --json --assignee agent)
if [ "$READY" = "[]" ]; then
sleep 60
continue
fi
# Pick highest priority
ISSUE_ID=$(echo $READY | jq -r '.[0].id')
# Mark in progress
bd update $ISSUE_ID --status in_progress
# Execute work (agent-specific)
agent-execute $ISSUE_ID
# Mark complete
bd close $ISSUE_ID
# Sync
git add .beads/
git commit -m "Completed $ISSUE_ID"
git push
done
Context-Aware Creation
#!/bin/bash
# agent-discover-issues.sh
# Find TODOs in code
rg "TODO:" --json | jq -c '.[] | select(.type == "match")' | \
while read line; do
FILE=$(echo $line | jq -r '.data.path.text')
TEXT=$(echo $line | jq -r '.data.lines.text' | sed 's/.*TODO: //')
bd create "$TEXT" \
--type task \
--priority 2 \
--description "Found in $FILE" \
--labels auto-generated
done
Dependency-Aware Planning
#!/bin/bash
# agent-plan-work.sh
# Build dependency graph
GRAPH=$(bd list --format digraph)
# Compute work order (topological sort)
echo "$GRAPH" | golang.org/x/tools/cmd/digraph allpaths | \
while read path; do
echo "Execution order: $path"
done
JSON Output & Parsing
Structured Output
# Get JSON output (all commands support --json)
bd list --json
bd show bd-1 --json
bd ready --json
bd blocked --json
Example Parsing
# Get all high-priority open issues
bd list --status open --json | \
jq '.[] | select(.priority <= 1) | {id, title, priority}'
# Find issues with no assignee
bd list --json | \
jq '.[] | select(.assignee == null or .assignee == "") | .id'
# Count issues by status
bd list --json | \
jq 'group_by(.status) | map({status: .[0].status, count: length})'
# Extract dependency graph
bd list --json | \
jq '.[] | {id, blocks: [.dependencies[] | select(.type=="blocks") | .target_id]}'
JSONL Direct Access
Reading JSONL
For direct file access (e.g., in agent scripts):
# Read all events
cat .beads/beads.jsonl | jq -c '.'
# Filter by event type
cat .beads/beads.jsonl | jq -c 'select(.type == "create")'
# Get latest issue state
cat .beads/beads.jsonl | \
jq -c 'select(.type == "create" or .type == "update")' | \
jq -s 'group_by(.issue.id) | map(sort_by(.issue.updated_at) | last | .issue)'
JSONL Event Types
{"type":"create","issue":{...}}
{"type":"update","issue":{...}}
{"type":"close","id":"bd-1","closed_at":"...","actor":"..."}
{"type":"reopen","id":"bd-1","actor":"..."}
{"type":"delete","id":"bd-1","deleted_at":"...","actor":"..."}
{"type":"comment","comment":{...}}
{"type":"dep_add","dependency":{...}}
{"type":"dep_remove","dependency":{...}}
Configuration
Config Commands
# View current config
bd config list
# Set values
bd config set prefix myapp
bd config set default_priority 2
bd config set default_type task
# Git settings
bd config set git.auto_sync true
bd config set git.remote origin
bd config set git.sync_branch main
# Daemon settings
bd config set daemon.enabled true
bd config set daemon.sync_interval 300
Config File
Location: .beads/config.json (per-repo) or ~/.config/bd/config.json (global)
{
"prefix": "myapp",
"default_priority": 2,
"default_type": "task",
"daemon": {
"enabled": true,
"port": 9876,
"sync_interval": 300
},
"git": {
"auto_sync": true,
"sync_branch": "main",
"remote": "origin"
},
"repos": {
"backend": {
"path": "/Users/user/repos/backend",
"prefix": "api",
"auto_route": true
},
"frontend": {
"path": "/Users/user/repos/frontend",
"prefix": "ui",
"auto_route": true
}
}
}
Statistics & Reporting
# Overall stats
bd stats
# Count issues
bd count
bd count --status open
bd count --label urgent
# Stale issues
bd stale --older-than 30d
# Export stats
bd list --json | \
jq '{
total: length,
by_status: group_by(.status) | map({(.[0].status): length}) | add,
by_type: group_by(.type) | map({(.[0].type): length}) | add,
by_priority: group_by(.priority) | map({("\(.priority)"): length}) | add
}'
Global Flags
--json # JSON output for all commands
--db <path> # Specify database path
--no-daemon # Force direct mode (bypass daemon)
--no-db # JSONL-only mode (no SQLite)
--no-auto-flush # Disable auto-sync to JSONL
--no-auto-import # Disable auto-import from JSONL
--sandbox # Sandbox mode (no daemon, no auto-sync)
--quiet # Suppress output
--verbose # Debug output
--actor <name> # Override actor name (audit trail)
--allow-stale # Skip staleness check
Best Practices
1. Commit Issues with Code
git checkout -b feature/new-auth
bd create "Implement new auth" --type feature
# ... write code ...
bd update bd-1 --status in_progress
git add .
git commit -m "Implement new auth (bd-1)"
bd close bd-1
git add .beads/
git commit -m "Close bd-1"
git push
2. Use Dependencies Liberally
Model real work dependencies—it unlocks:
- Critical path analysis
- Parallel work identification
- Automatic ready/blocked tracking
3. Label Consistently
Establish taxonomy early:
backend,frontend,infraurgent,high,medium,lowsprint-Nfor sprint trackingtech-debt,security,performance
4. Comment Frequently
Context decays over time. Comments preserve:
- Why decisions were made
- What was tried and failed
- Links to resources
- Status updates
5. Sync Daily
# Pull in morning
git pull
# Push at end of day
git add .beads/
git commit -m "Daily issue updates"
git push
6. Clean Up Regularly
# Weekly: review stale issues
bd stale --older-than 30d
# Monthly: compact old closed issues
bd compact --older-than 90d
# Quarterly: cleanup deleted issues
bd cleanup --older-than 90d
7. Validate Health
# Weekly: run validation
bd validate
# Fix issues immediately
bd repair-deps
bd dep cycles
Troubleshooting
Issues Not Appearing
# Check database exists
ls -la .beads/
# Validate JSONL
cat .beads/beads.jsonl | jq '.' > /dev/null
# Rebuild SQLite from JSONL
bd migrate
Daemon Not Starting
# Check daemon status
bd daemon status
# View logs
bd daemon logs
# Stop and restart
bd daemon stop
bd daemon start
Merge Conflicts
# After git pull with conflicts in .beads/beads.jsonl
git status
# bd's merge driver should handle automatically
# If not, rebuild from JSONL
rm .beads/*.db
bd migrate
# Validate
bd validate
Performance Issues
# Use daemon mode (default)
bd daemon status
# Compact old issues
bd compact --older-than 90d
# Check database size
du -sh .beads/
# Profile operations
bd --profile list
Related Tools
- git: Version control (bd integrates natively)
- bv: Interactive graph visualization for bd issues
- sqlite3: Direct database queries if needed
- jq: JSON processing for structured output
- graphviz: Render dependency graphs (dot, neato, circo)
- rg (ripgrep): Fast text search in issues
- fd: Fast file search for bd files
References
For complete details, see:
- Type Definitions:
@bd-codebase/types/core.ts - Git-Native Principles:
@bd-codebase/principles/git-native.md - DAG Dependencies:
@bd-codebase/principles/dag-dependencies.md - Task Workflows:
@bd-codebase/templates/task-workflow.md - Codebase README:
@bd-codebase/README.md
Quick Reference
See assets/cheatsheet.md for one-page reference.
Remember: bd is designed to work like git because it is git. Think of issues as files, operations as commits, and sync as push/pull. It's that simple.