# br - Beads Rust
[](./LICENSE)
[](https://www.rust-lang.org/)
[](https://www.sqlite.org/)
A Rust port of Steve Yegge's [beads](https://github.com/steveyegge/beads), frozen at the "classic" SQLite + JSONL architecture I built my Agent Flywheel tooling around.
[Quick Start](#quick-start) | [Commands](#commands) | [Configuration](#configuration) | [VCS Integration](#vcs-integration) | [FAQ](#faq)
Quick Install
```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/beads_rust/main/install.sh?$(date +%s)" | bash
```
Works on Linux, macOS, and Windows (WSL). Auto-detects your platform and downloads the right binary.
---
## Why This Project Exists
I (Jeffrey Emanuel) LOVE [Steve Yegge's Beads project](https://github.com/steveyegge/beads). Discovering it and seeing how well it worked together with my [MCP Agent Mail](https://github.com/Dicklesworthstone/mcp_agent_mail) was a truly transformative moment in my development workflows and professional life. This quickly also led to [beads_viewer (bv)](https://github.com/Dicklesworthstone/beads_viewer), 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](http://agent-flywheel.com/tldr) System is built around beads operating in a specific way. As Steve continues evolving beads toward [GasTown](https://github.com/steveyegge/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.
```bash
br init # Initialize in your repo
br create "Fix login timeout" -p 1 # Create high-priority issue
br ready # See what's actionable
br close bd-abc123 # Close when done
br sync --flush-only # Export for git commit
```
### 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
```bash
# Initialize br in your project
cd my-project
br init
# Add agent instructions to AGENTS.md (creates file if needed)
br agents --add --force
# Create issues with priority (0=critical, 4=backlog)
br create "Implement user auth" --type feature --priority 1
# Created: bd-7f3a2c
br create "Set up database schema" --type task --priority 1
# Created: bd-e9b1d4
# Auth depends on database schema
br dep add bd-7f3a2c bd-e9b1d4
# See what's ready to work on (not blocked)
br ready
# bd-e9b1d4 P1 task Set up database schema
# Claim and complete work
br update bd-e9b1d4 --status in_progress
br close bd-e9b1d4 --reason "Schema implemented"
# Now auth is unblocked
br ready
# bd-7f3a2c P1 feature Implement user auth
# Export to JSONL for git commit
br sync --flush-only
git add .beads/ && git commit -m "Update issues"
```
---
## 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.
```bash
# br only touches .beads/ directory
ls -la .beads/
# 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.
```bash
# Local: Fast queries via SQLite
br list --priority 0-1 --status open --assignee alice
# Collaboration: JSONL merges cleanly in git
git diff .beads/issues.jsonl
# +{"id":"bd-abc123","title":"New feature",...}
```
### 3. Explicit Over Implicit
Every operation is explicit. No magic, no surprises.
```bash
# Export is explicit (not automatic)
br sync --flush-only
# Import is explicit (not automatic)
br sync --import-only
# Git operations are YOUR responsibility
git add .beads/ && git commit -m "..."
```
### 4. Agent-First Design
Every command supports `--json` for AI coding agents:
```bash
br list --json | jq '.issues[] | select(.priority <= 1)'
br ready --json # Structured output for agents
br show bd-abc123 --json
```
For routine operator or agent use, prefer `RUST_LOG=error br ...` to suppress internal Rust dependency logs while preserving normal stdout/JSON output:
```bash
RUST_LOG=error br ready --json
RUST_LOG=error br sync --flush-only
```
### 5. Rich Terminal Output
Interactive terminals get enhanced visual output:
```bash
# Rich mode (default in TTY)
br list # Formatted tables with colors
br show bd-abc # Styled panels with metadata
# Plain mode (piped or --no-color)
br list | cat # Clean text, no ANSI codes
# JSON mode (--json or --robot)
br list --json # Structured output for tools ({issues, total, limit, offset, has_more})
```
Output mode is auto-detected:
- **Rich**: Interactive TTY with color support
- **Plain**: Piped output or `NO_COLOR` environment
- **JSON**: Machine-readable (`--json` flag)
- **Quiet**: Minimal output (`--quiet` flag)
### 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)
```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/beads_rust/main/install.sh?$(date +%s)" | bash
```
### From Source
```bash
# Requires Rust nightly
git clone https://github.com/Dicklesworthstone/beads_rust.git
cd beads_rust
cargo build --release
./target/release/br --help
# Or install globally
cargo install --path .
```
### Cargo Install
```bash
cargo install --git https://github.com/Dicklesworthstone/beads_rust.git
```
> **Note:** `cargo install` places 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. Run `which br` to verify which binary is active.
### Disable Self-Update
```bash
# Build without self-update feature
cargo build --release --no-default-features
# Or install without it
cargo install --git https://github.com/Dicklesworthstone/beads_rust.git --no-default-features
```
### Verify Installation
```bash
br --version
# br 0.1.0 (rustc 1.85.0-nightly)
```
---
## Quick Start
### 1. Initialize in Your Project
```bash
cd my-project
br init
# Initialized beads workspace in .beads/
```
### 2. Create Your First Issue
```bash
br create "Fix login timeout bug" \
--type bug \
--priority 1 \
--description "Users report login times out after 30 seconds"
# Created: bd-a1b2c3
```
### 3. Add Labels
```bash
br label add bd-a1b2c3 backend auth
```
### 4. Check Ready Work
```bash
br ready
# Shows issues that are open, not blocked, not deferred
```
### 5. Claim and Work
```bash
br update bd-a1b2c3 --status in_progress --assignee "$(git config user.email)"
```
### 6. Close When Done
```bash
br close bd-a1b2c3 --reason "Increased timeout to 60s, added retry logic"
```
### 7. Sync to Git
```bash
br sync --flush-only # Export DB to JSONL
git add .beads/ # Stage changes
git commit -m "Fix: login timeout (bd-a1b2c3)"
```
---
## 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 ` | Override database path |
---
## Configuration
br uses layered configuration:
1. **CLI flags** (highest priority)
2. **Environment variables**
3. **Project config**: `.beads/config.yaml`
4. **User config**: `~/.config/beads/config.yaml`
5. **Defaults** (lowest priority)
### Example Config
```yaml
# .beads/config.yaml
# Default issue ID prefix for newly created issues
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
```bash
# Show all config
br config list
# Get specific value
br config get id.prefix
# Set value
br config set defaults.priority=1
# Open in editor
br config edit
```
### Environment Variables
| Variable | Description |
|----------|-------------|
| `BD_DB` / `BD_DATABASE` | Override database path |
| `BEADS_JSONL` | Override JSONL path (requires `--allow-external-jsonl`) |
| `RUST_LOG` | Logging level (debug, info, warn, error) |
Recommended default for normal CLI use:
```bash
export RUST_LOG=error
```
This keeps successful commands readable by suppressing low-level dependency logging. Remove or override it when debugging `br` internals.
---
## 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.
```bash
# Check for other br processes
pgrep -f "br "
# Force close and retry
br sync --status # Safe read-only check
```
### Error: "Issue not found"
**Cause:** Issue ID doesn't exist or was deleted.
```bash
# Check if issue exists
br list --json | jq '.issues[] | select(.id == "bd-abc123")'
# Check for similar IDs
br list | grep -i "abc"
```
### Error: "Prefix mismatch"
**Cause:** This now only applies when you explicitly ask br to enforce or rewrite
prefixes during import. Mixed prefixes in a project are supported by default.
```bash
# Check your default creation prefix
br config get id.prefix
# Import while rewriting IDs into your configured default prefix
br sync --import-only --rename-prefix
```
If you want to preserve imported IDs exactly as-is, omit `--rename-prefix`.
### Error: "Stale database"
**Cause:** JSONL has issues that don't exist in database.
```bash
# Check sync status
br sync --status
# Force import (may lose local changes)
br sync --import-only --force
```
### Sync Issues After Git Merge
```bash
# 1. Check for JSONL merge conflicts
git status .beads/
# 2. If conflicts, resolve manually then:
br sync --import-only
# 3. If database seems stale:
br doctor
```
### Command Output is Garbled
```bash
# Disable colors
br list --no-color
# Or use JSON output
br list --json | jq '.issues'
```
---
## 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](https://github.com/Dicklesworthstone/beads_viewer):
```bash
# Use bv for interactive TUI
bv
# Use br for CLI/scripting
br ready --json | jq
```
### Q: Can I use br with AI coding agents?
Yes! br is designed for AI agent integration:
```bash
# Agents can use --json for structured output
br list --json
br ready --json
br show bd-abc123 --json
# Create issues programmatically
br create "Title" --json # Returns created issue as JSON
```
See [AGENTS.md](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:
```bash
# Copy your existing issues.jsonl
cp /path/to/beads/.beads/issues.jsonl .beads/
# Import into br
br sync --import-only
```
### 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?
```bash
# Issue A depends on Issue B (A is blocked until B is closed)
br dep add bd-A bd-B
# Now bd-A won't appear in `br ready` until bd-B is closed
br ready # Only shows bd-B
# Close the blocker
br close bd-B
# Now bd-A is ready
br ready # Shows bd-A
```
### Q: How do I handle merge conflicts in JSONL?
JSONL is line-based, so conflicts are usually easy to resolve:
```bash
# After git merge with conflicts
git status .beads/issues.jsonl
# Edit to resolve (each line is one issue)
vim .beads/issues.jsonl
# Mark resolved and import
git add .beads/issues.jsonl
br sync --import-only
```
### Q: Can I customize the issue ID prefix?
Yes:
```bash
br config set id.prefix=myproj
# New issues: myproj-abc123
```
You can also mix multiple prefixes in the same project. The configured prefix is
the default for newly created issues, not a restriction on existing IDs.
### 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](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:
```bash
br schema all --format json | jq '.schemas.Issue'
br schema issue-details --format toon
```
---
## VCS Integration
Using non-git version control? See [VCS_INTEGRATION.md](VCS_INTEGRATION.md) for
equivalent commands and workflows.
Quick example:
```bash
# Agent workflow
br ready --json | jq '.[0]' # Get top priority
br update bd-abc --status in_progress # Claim work
# ... do work ...
br close bd-abc --reason "Completed" # Done
br sync --flush-only # Export for git
```
---
## Community Projects
- [**Beads Task-Issue Tracker**](https://github.com/w3dev33/beads-task-issue-tracker) — A desktop GUI for `br`, built with Tauri + Nuxt. Reads the same SQLite + JSONL files that `br` produces, 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](LICENSE) for details.
---
Built with Rust. Powered by SQLite. Synced with Git.