br - Beads Rust
A Rust port of Steve Yegge's beads, frozen at the "classic" SQLite + JSONL architecture I built my Agent Flywheel tooling around.
Quick Start | Commands | Configuration | VCS Integration | FAQ
|
Why This Project Exists
I (Jeffrey Emanuel) LOVE Steve Yegge's Beads project. Discovering it and seeing how well it worked together with my MCP Agent Mail was a truly transformative moment in my development workflows and professional life. This quickly also led to beads_viewer (bv), which added another layer of analysis to beads that gives swarms of agents the insight into what beads they should work on next to de-bottleneck the development process and increase velocity. I'm very grateful for finding beads when I did and to Steve for making it.
At this point, my Agent Flywheel System is built around beads operating in a specific way. As Steve continues evolving beads toward GasTown and beyond, our use cases have naturally diverged. The hybrid SQLite + JSONL-git architecture that I built my tooling around (and independently mirrored in MCP Agent Mail) is being replaced with approaches better suited to Steve's vision.
Rather than ask Steve to maintain a legacy mode for my niche use case, I created this Rust port that freezes the "classic beads" architecture I depend on. The command is br to distinguish it from the original bd.
This isn't a criticism of beads; Steve's taking it in exciting directions. It's simply that my tooling needs a stable snapshot of the architecture I built around, and maintaining my own fork is the right solution for that. Steve has given his full endorsement of this project.
TL;DR
The Problem
You need to track issues for your project, but:
- GitHub/GitLab Issues require internet, fragment context from code, and don't work offline
- TODO comments get lost, have no status tracking, and can't express dependencies
- External tools (Jira, Linear) add overhead, require context switching, and cost money
The Solution
br is a local-first issue tracker that stores issues in SQLite with JSONL export for git-friendly collaboration. It's 20K lines of Rust focused on one thing: tracking issues without getting in your way.
Why br?
| Feature | br | GitHub Issues | Jira | TODO comments |
|---|---|---|---|---|
| Works offline | Yes | No | No | Yes |
| Lives in repo | Yes | No | No | Yes |
| Tracks dependencies | Yes | Limited | Yes | No |
| Zero cost | Yes | Free tier | No | Yes |
| No account required | Yes | No | No | Yes |
| Machine-readable | Yes (--json) |
API only | API only | No |
| Git-friendly sync | Yes (JSONL) | N/A | N/A | N/A |
| Non-invasive | Yes | N/A | N/A | Yes |
| AI agent integration | Yes | Limited | Limited | No |
Quick Example
# Initialize br in your project
# Add agent instructions to AGENTS.md (creates file if needed)
# Create issues with priority (0=critical, 4=backlog)
# Created: bd-7f3a2c
# Created: bd-e9b1d4
# Auth depends on database schema
# See what's ready to work on (not blocked)
# bd-e9b1d4 P1 task Set up database schema
# Claim and complete work
# Now auth is unblocked
# bd-7f3a2c P1 feature Implement user auth
# Export to JSONL for git commit
&&
Design Philosophy
1. Non-Invasive by Default
br never touches your source code or runs git commands automatically. Other tools might auto-commit or install hooks without asking. br doesn't.
# br only touches .beads/ directory
# beads.db # SQLite database
# issues.jsonl # Git-friendly export
# config.yaml # Optional config
2. SQLite + JSONL Hybrid
SQLite for fast local queries. JSONL for git-friendly collaboration.
# Local: Fast queries via SQLite
# Collaboration: JSONL merges cleanly in git
# +{"id":"bd-abc123","title":"New feature",...}
3. Explicit Over Implicit
Every operation is explicit. No magic, no surprises.
# Export is explicit (not automatic)
# Import is explicit (not automatic)
# Git operations are YOUR responsibility
&&
4. Agent-First Design
Every command supports --json for AI coding agents:
|
5. Rich Terminal Output
Interactive terminals get enhanced visual output:
# Rich mode (default in TTY)
# Plain mode (piped or --no-color)
|
# JSON mode (--json or --robot)
Output mode is auto-detected:
- Rich: Interactive TTY with color support
- Plain: Piped output or
NO_COLORenvironment - JSON: Machine-readable (
--jsonflag) - Quiet: Minimal output (
--quietflag)
6. Minimal Footprint
~20K lines of Rust vs ~276K lines in the original Go beads. Faster compilation, smaller binary, fewer moving parts.
Comparison vs Alternatives
br vs Original beads (Go)
| Aspect | br (Rust) | beads (Go) |
|---|---|---|
| Lines of code | ~20,000 | ~276,000 |
| Git operations | Never (explicit) | Auto-commit, hooks |
| Storage | SQLite + JSONL | Dolt/SQLite |
| Background daemon | No | Yes |
| Hook installation | Manual | Automatic |
| Binary size | ~5-8 MB | ~30+ MB |
| Complexity | Focused | Feature-rich |
When to use br: You want a stable, minimal issue tracker that stays out of your way.
When to use beads: You want advanced features like Linear/Jira sync, RPC daemon, automatic hooks.
br vs GitHub Issues
| Aspect | br | GitHub Issues |
|---|---|---|
| Works offline | Yes | No |
| Lives in repo | Yes | Separate |
| Dependencies | Yes | Workarounds |
| Custom fields | Via labels | Limited |
| Machine API | --json flag |
REST API |
| Cost | Free | Free (limits) |
br vs Linear/Jira
| Aspect | br | Linear/Jira |
|---|---|---|
| Setup time | 1 command | Account + config |
| Cost | Free | $8-15/user/mo |
| Works offline | Yes | Limited |
| Learning curve | CLI | GUI + workflows |
| Git integration | Native | Webhooks |
Installation
Quick Install (Recommended)
|
From Source
# Requires Rust nightly
# Or install globally
Cargo Install
Note:
cargo installplaces binaries in~/.cargo/bin/, while the install script uses~/.local/bin/. If you have both in PATH, ensure the desired location has higher priority to avoid running an outdated version. Runwhich brto verify which binary is active.
Disable Self-Update
# Build without self-update feature
# Or install without it
Verify Installation
# br 0.1.0 (rustc 1.85.0-nightly)
Quick Start
1. Initialize in Your Project
# Initialized beads workspace in .beads/
2. Create Your First Issue
# Created: bd-a1b2c3
3. Add Labels
4. Check Ready Work
# Shows issues that are open, not blocked, not deferred
5. Claim and Work
6. Close When Done
7. Sync to Git
Commands
Issue Lifecycle
| Command | Description | Example |
|---|---|---|
init |
Initialize workspace | br init |
create |
Create issue | br create "Title" -p 1 --type bug |
q |
Quick capture (ID only) | br q "Fix typo" |
show |
Show issue details | br show bd-abc123 |
update |
Update issue | br update bd-abc123 --priority 0 |
close |
Close issue | br close bd-abc123 --reason "Done" |
reopen |
Reopen closed issue | br reopen bd-abc123 |
delete |
Delete issue (tombstone) | br delete bd-abc123 |
Querying
| Command | Description | Example |
|---|---|---|
list |
List issues | br list --status open --priority 0-1 |
ready |
Actionable work | br ready |
blocked |
Blocked issues | br blocked |
search |
Full-text search | br search "authentication" |
stale |
Stale issues | br stale --days 30 |
count |
Count with grouping | br count --by status |
Dependencies
| Command | Description | Example |
|---|---|---|
dep add |
Add dependency | br dep add bd-child bd-parent |
dep remove |
Remove dependency | br dep remove bd-child bd-parent |
dep list |
List dependencies | br dep list bd-abc123 |
dep tree |
Dependency tree | br dep tree bd-abc123 |
dep cycles |
Find cycles | br dep cycles |
Labels
| Command | Description | Example |
|---|---|---|
label add |
Add labels | br label add bd-abc123 backend urgent |
label remove |
Remove label | br label remove bd-abc123 urgent |
label list |
List issue labels | br label list bd-abc123 |
label list-all |
All labels in project | br label list-all |
Comments
| Command | Description | Example |
|---|---|---|
comments add |
Add comment | br comments add bd-abc123 "Found root cause" |
comments list |
List comments | br comments list bd-abc123 |
Sync & System
| Command | Description | Example |
|---|---|---|
sync |
Sync DB ↔ JSONL | br sync --flush-only |
doctor |
Run diagnostics | br doctor |
stats |
Project statistics | br stats |
config |
Manage config | br config list |
upgrade |
Self-update | br upgrade |
version |
Show version | br version |
Global Flags
| Flag | Description |
|---|---|
--json |
JSON output (machine-readable) |
--quiet / -q |
Suppress output |
--verbose / -v |
Increase verbosity (-vv for debug) |
--no-color |
Disable colored output |
--db <path> |
Override database path |
Configuration
br uses layered configuration:
- CLI flags (highest priority)
- Environment variables
- Project config:
.beads/config.yaml - User config:
~/.config/beads/config.yaml - Defaults (lowest priority)
Example Config
# .beads/config.yaml
# Issue ID prefix (default: "bd")
id:
prefix: "proj"
# Default values for new issues
defaults:
priority: 2
type: "task"
assignee: "team@example.com"
# Output formatting
output:
color: true
date_format: "%Y-%m-%d"
# Sync behavior
sync:
auto_import: false
auto_flush: false
Config Commands
# Show all config
# Get specific value
# Set value
# Open in editor
Environment Variables
| Variable | Description |
|---|---|
BEADS_DB |
Override database path |
BEADS_JSONL |
Override JSONL path (requires --allow-external-jsonl) |
RUST_LOG |
Logging level (debug, info, warn, error) |
Architecture
┌──────────────────────────────────────────────────────────────┐
│ CLI (br) │
│ Commands: create, list, ready, close, sync, etc. │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Storage Layer │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ SqliteStorage │◄────────────►│ JSONL Export/Import │ │
│ │ │ sync │ │ │
│ │ - WAL mode │ │ - Atomic writes │ │
│ │ - Dirty track │ │ - Content hashing │ │
│ │ - Blocked cache│ │ - Merge support │ │
│ └────────┬────────┘ └──────────┬──────────┘ │
└───────────│──────────────────────────────────│───────────────┘
│ │
▼ ▼
.beads/beads.db .beads/issues.jsonl
(Primary storage) (Git-friendly export)
Data Flow
User Action br Command Storage
───────────────────────────────────────────────────────────────
Create issue ──► br create ──► SQLite INSERT
──► Mark dirty
Update issue ──► br update ──► SQLite UPDATE
──► Mark dirty
Query issues ──► br list ──► SQLite SELECT
Export to git ──► br sync ──► Write JSONL
--flush-only ──► Clear dirty flags
Pull from git ──► git pull ──► JSONL updated
──► br sync ──► Merge to SQLite
--import-only
Safety Model
br is designed to be provably safe:
| Guarantee | Implementation |
|---|---|
| Never executes git | No Command::new("git") calls in sync code |
Only touches .beads/ |
Path validation before all writes |
| Atomic writes | Write to temp file, then rename |
| No data loss | Guards prevent overwriting non-empty JSONL with empty DB |
Troubleshooting
Error: "Database locked"
Cause: Another process has the database open.
# Check for other br processes
# Force close and retry
Error: "Issue not found"
Cause: Issue ID doesn't exist or was deleted.
# Check if issue exists
|
# Check for similar IDs
|
Error: "Prefix mismatch"
Cause: JSONL contains issues with different ID prefix.
# Check your prefix
# Import with validation skip (careful!)
If this appears during auto-import on read-only commands, re-run with
--allow-stale or --no-auto-import to proceed without importing.
Error: "Stale database"
Cause: JSONL has issues that don't exist in database.
# Check sync status
# Force import (may lose local changes)
Sync Issues After Git Merge
# 1. Check for JSONL merge conflicts
# 2. If conflicts, resolve manually then:
# 3. If database seems stale:
Command Output is Garbled
# Disable colors
# Or use JSON output
|
Limitations
br intentionally does not support:
| Feature | Reason |
|---|---|
| Automatic git commits | Non-invasive philosophy |
| Git hook installation | User-controlled, add manually if desired |
| Background daemon | Simple CLI, no processes to manage |
| Dolt backend | SQLite + JSONL only |
| Linear/Jira sync | Focused scope |
| Web UI | CLI-first (see beads_viewer for TUI) |
| Multi-repo sync | Single repo per workspace |
| Real-time collaboration | Git-based async collaboration |
FAQ
Q: How do I integrate with beads_viewer (bv)?
br works seamlessly with beads_viewer:
# Use bv for interactive TUI
# Use br for CLI/scripting
|
Q: Can I use br with AI coding agents?
Yes! br is designed for AI agent integration:
# Agents can use --json for structured output
# Create issues programmatically
See AGENTS.md for the complete agent integration guide.
Q: How do I migrate from the original beads?
br uses the same JSONL format as classic beads:
# Copy your existing issues.jsonl
# Import into br
Q: Why Rust instead of Go?
- Smaller binary: ~5-8 MB vs ~30+ MB
- Memory safety: No runtime garbage collection
- Stability: Fewer moving parts = fewer things to break
- Personal preference: The author's flywheel tooling is Rust-based
Q: How do dependencies work?
# Issue A depends on Issue B (A is blocked until B is closed)
# Now bd-A won't appear in `br ready` until bd-B is closed
# Close the blocker
# Now bd-A is ready
Q: How do I handle merge conflicts in JSONL?
JSONL is line-based, so conflicts are usually easy to resolve:
# After git merge with conflicts
# Edit to resolve (each line is one issue)
# Mark resolved and import
Q: Can I customize the issue ID prefix?
Yes:
# New issues: myproj-abc123
Q: Where is data stored?
.beads/
├── beads.db # SQLite database (primary storage)
├── issues.jsonl # JSONL export (for git)
├── config.yaml # Project configuration
└── metadata.json # Workspace metadata
AI Agent Integration
br is designed for AI coding agents. See AGENTS.md for:
- JSON output schemas
- Workflow patterns
- Integration with MCP Agent Mail
- Robot mode flags
- Best practices
You can also emit machine-readable JSON Schema documents directly:
|
VCS Integration
Using non-git version control? See VCS_INTEGRATION.md for equivalent commands and workflows.
Quick example:
# Agent workflow
| # ... do work ...
Community Projects
- Beads Task-Issue Tracker — A desktop GUI for
br, built with Tauri + Nuxt. Reads the same SQLite + JSONL files thatbrproduces, providing a graphical interface for browsing and managing issues.
About Contributions
Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
License
MIT License (with OpenAI/Anthropic Rider) — see LICENSE for details.