bd-doctor
Check and fix common Beads workflow issues across all repos.
When & Why to Use This Skill
The bd-doctor skill is a specialized diagnostic and automation utility designed to streamline the Beads workflow. It proactively identifies and resolves common synchronization issues, such as JSONL timestamp skews and unstaged metadata changes, effectively eliminating manual toil and ensuring repository health across complex development environments.
Use Cases
- Resolving 'JSONL is newer than database' errors automatically by handling timestamp skews through forced exports.
- Detecting and staging unstaged .beads/issues.jsonl changes to ensure workflow metadata is consistently committed.
- Validating branch-to-issue alignment to prevent developers from working in mismatched feature contexts.
- Performing pre-commit health checks to verify the presence of required Feature-Key trailers and proper commit formatting.
- Automating the recovery process when 'bd sync' fails due to protected branch restrictions on the master branch.
| name | bd-doctor |
|---|---|
| description | Check and fix common Beads workflow issues across all repos. |
bd-doctor
Description
Check and fix common Beads workflow issues across all repos.
Use when:
- Beads sync fails ("JSONL is newer than database", "Push to master blocked")
- Unstaged .beads/issues.jsonl changes
- User says "fix beads", "beads sync failing", "check beads", "beads health"
- Before important operations (commits, syncs, PRs)
Problem solved: Eliminates "Manual Beads operations" pattern (7/69 toil commits, 10% of analyzed toil).
Auto-Activation
This skill activates when:
- bd sync fails with common errors
- User mentions Beads issues ("beads", "bd sync", "JSONL")
- Unstaged .beads/issues.jsonl detected
- Branch/issue mismatch detected
Implementation
The skill performs comprehensive Beads health checks and auto-fixes common issues.
Check Script
#!/bin/bash
# ~/.agent/skills/bd-doctor/check.sh
set -e
echo "🔍 Beads Doctor - Health Check"
ISSUES_FOUND=0
# Check 1: JSONL timestamp skew (most common issue)
echo ""
echo "📋 Checking Beads JSONL sync..."
if bd sync --dry-run 2>&1 | grep -q "JSONL is newer"; then
echo "⚠️ JSONL timestamp skew detected"
echo " Cause: Daemon auto-exported between your changes and sync"
echo " Fix: bd export --force (resolves timing issue)"
ISSUES_FOUND=$((ISSUES_FOUND + 1))
elif bd sync --dry-run 2>&1 | grep -q "Pushing directly to master is blocked"; then
echo "⚠️ Attempting to push JSONL to protected branch"
echo " Cause: Running bd sync on master branch"
echo " Fix: Use 'bd export --force' on master (no push), or switch to feature branch"
ISSUES_FOUND=$((ISSUES_FOUND + 1))
else
echo "✅ Beads JSONL in sync with database"
fi
# Check 2: Unstaged JSONL changes
echo ""
echo "📋 Checking for unstaged Beads changes..."
if git status --porcelain 2>/dev/null | grep -q ".beads/issues.jsonl"; then
echo "⚠️ .beads/issues.jsonl has unstaged changes"
echo " Stage with: git add .beads/issues.jsonl"
ISSUES_FOUND=$((ISSUES_FOUND + 1))
else
echo "✅ No unstaged Beads changes"
fi
# Check 3: Branch/Issue mismatch
echo ""
echo "📋 Checking branch/issue alignment..."
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
if [[ $BRANCH =~ ^feature-bd-([a-z0-9]+) ]]; then
ISSUE_ID="${BASH_REMATCH[1]}"
if bd show "bd-$ISSUE_ID" &>/dev/null; then
echo "✅ Branch feature-bd-$ISSUE_ID matches Beads issue bd-$ISSUE_ID"
else
echo "⚠️ On branch feature-bd-$ISSUE_ID but issue bd-$ISSUE_ID not found"
echo " Possible causes:"
echo " - Issue was closed/deleted"
echo " - Working on wrong branch"
echo " - Need to create issue: bd create \"Task name\" --type task"
ISSUES_FOUND=$((ISSUES_FOUND + 1))
fi
elif [[ $BRANCH == "master" ]] || [[ $BRANCH == "main" ]]; then
echo "ℹ️ On $BRANCH branch (no Beads issue expected)"
else
echo "ℹ️ On non-Beads branch: $BRANCH (custom branch, no issue tracking)"
fi
# Check 4: Feature-Key trailer in recent commits
echo ""
echo "📋 Checking Feature-Key trailers..."
RECENT_COMMIT=$(git log -1 --format=%B 2>/dev/null || echo "")
if [[ -n "$RECENT_COMMIT" ]] && ! echo "$RECENT_COMMIT" | grep -q "Feature-Key:"; then
# Only warn if on feature branch
if [[ $BRANCH =~ ^feature- ]]; then
echo "⚠️ Recent commit missing Feature-Key trailer"
echo " Use sync-feature-branch skill for proper commit format"
ISSUES_FOUND=$((ISSUES_FOUND + 1))
else
echo "✅ Not on feature branch (Feature-Key not required)"
fi
else
echo "✅ Feature-Key trailer present or not required"
fi
echo ""
echo "═══════════════════════════════════════"
if [[ $ISSUES_FOUND -eq 0 ]]; then
echo "✅ All Beads checks passed! Healthy workflow."
exit 0
else
echo "❌ Found $ISSUES_FOUND Beads issue(s)"
echo ""
echo "Run: ~/.agent/skills/bd-doctor/fix.sh # to auto-fix"
exit 1
fi
Fix Script
#!/bin/bash
# ~/.agent/skills/bd-doctor/fix.sh
set -e
echo "🔧 Beads Doctor - Fixing issues..."
FIXED=0
# Fix 1: JSONL timestamp skew
echo ""
echo "📋 Fixing JSONL sync..."
if bd sync --dry-run 2>&1 | grep -q "JSONL is newer"; then
echo "Running: bd export --force"
bd export --force
echo "✅ JSONL exported (timestamp skew resolved)"
FIXED=$((FIXED + 1))
elif bd sync --dry-run 2>&1 | grep -q "Pushing directly to master is blocked"; then
echo "Running: bd export --force (no push on master)"
bd export --force
echo "✅ JSONL exported without pushing to master"
FIXED=$((FIXED + 1))
else
echo "✅ JSONL already in sync"
fi
# Fix 2: Stage unstaged JSONL
echo ""
echo "📋 Staging Beads changes..."
if git status --porcelain 2>/dev/null | grep -q ".beads/issues.jsonl"; then
echo "Running: git add .beads/issues.jsonl"
git add .beads/issues.jsonl
echo "✅ Beads JSONL staged"
FIXED=$((FIXED + 1))
else
echo "✅ No unstaged Beads changes"
fi
# Fix 3: Branch/Issue mismatch - can't auto-fix, only warn
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
if [[ $BRANCH =~ ^feature-bd-([a-z0-9]+) ]]; then
ISSUE_ID="${BASH_REMATCH[1]}"
if ! bd show "bd-$ISSUE_ID" &>/dev/null; then
echo ""
echo "⚠️ Cannot auto-fix: Branch feature-bd-$ISSUE_ID but issue bd-$ISSUE_ID not found"
echo " Manual action required:"
echo " - Create issue: bd create \"Task name\" --type task"
echo " - OR switch branch: git checkout feature-bd-{correct-id}"
fi
fi
echo ""
echo "═══════════════════════════════════════"
if [[ $FIXED -eq 0 ]]; then
echo "ℹ️ Nothing to fix (already healthy)"
else
echo "✅ Fixed $FIXED Beads issue(s)"
echo ""
echo "Next: Verify with 'bd sync' or continue workflow"
fi
Usage Examples
Check Beads health
bd-doctor check
Auto-fix all Beads issues
bd-doctor fix
Agent workflow integration
Before bd sync:
bd-doctor check || bd-doctor fix
bd sync
Before committing:
bd-doctor check # Verify JSONL staged, branch/issue aligned
git commit ...
When bd sync fails:
# Error: "JSONL is newer than database"
bd-doctor fix # Auto-resolves with bd export --force
bd sync # Should now succeed
Common Issues & Fixes
Issue 1: "JSONL is newer than database"
Cause: Beads daemon auto-exported between your changes and bd sync (timestamp skew)
Fix: bd export --force then bd sync
Prevention: bd-doctor auto-detects and fixes this
Issue 2: "Pushing directly to master is blocked"
Cause: Running bd sync on master branch (pre-push hook blocks)
Fix: Use bd export --force on master (exports without pushing), or switch to feature branch
Prevention: bd-doctor detects and guides to correct fix
Issue 3: Unstaged .beads/issues.jsonl
Cause: Beads operations modified JSONL but not staged for commit
Fix: git add .beads/issues.jsonl
Prevention: bd-doctor auto-stages when detected
Issue 4: Branch/Issue mismatch
Cause: On feature-bd-xyz but issue bd-xyz doesn't exist Fix: Create issue or switch to correct branch Prevention: bd-doctor warns early
Integration with Other Skills
sync-feature-branch Enhancement
Modify sync-feature-branch to call bd-doctor first:
1. Run bd-doctor check
2. If fails, run bd-doctor fix
3. Verify all checks pass
4. Proceed with commit
create-pull-request Enhancement
Call bd-doctor before creating PR:
1. Run bd-doctor check (ensure JSONL in sync)
2. Close Beads issue if work complete
3. Run bd export --force (atomic with code)
4. Create PR
Cross-Repo Deployment
This skill deploys to ~/.agent/skills/ and works across:
- ✅ All repos (prime-radiant-ai, affordabot, any Beads-enabled repo)
- ✅ All AI agents (Claude Code, Codex CLI, Antigravity)
- ✅ All VMs (shared via Universal Skills MCP)
Success Metrics
Baseline: 7 commits (10% of toil) wasted on Beads sync issues Target: <1 commit per 60-commit cycle Impact: ~30 minutes/month saved, reduced frustration
Notes
Design Philosophy:
- Auto-fix where possible (JSONL sync, staging)
- Clear guidance where manual action needed (branch/issue mismatch)
- Non-blocking checks (doesn't prevent work)
- Agent-friendly (clear messages, actionable commands)
Why not auto-amend commits?
- Multi-agent context: auto-amend causes history conflicts
- Explicit > Implicit: agents should explicitly sync via skills
- Skills provide control: invoke when needed, not on every commit
Complementary with:
- sync-feature-branch skill (commits with proper Beads metadata)
- create-pull-request skill (atomic JSONL merge pattern)