beads_viewer_rust (bvr)
JSONL / workspace config / git history
│
▼
loader + model validation
│
▼
IssueGraph + Analyzer + graph metrics
│
┌──────────┼──────────┬───────────────┐
▼ ▼ ▼ ▼
robot JSON TOON FrankenTUI static pages
bvr is a graph-aware issue triage engine for .beads data that gives you machine-friendly robot output, an interactive terminal UI, and a self-contained static dashboard export from the same binary.
Quick Install
TL;DR
The Problem: issue backlogs are easy to store but hard to prioritize. Once dependencies, blockers, stale work, cross-label bottlenecks, workspace layouts, and git history enter the picture, manual sorting or ad-hoc jq scripts stop being trustworthy.
The Solution: bvr loads .beads issue data, builds a dependency graph, computes centrality and planning metrics, and then exposes the result through robot commands, a TUI, markdown briefs, graph export, and static pages bundles.
Why Use bvr?
| Capability | What It Does |
|---|---|
| Robot-first triage | Emits structured JSON or TOON for agents, scripts, and automation via --robot-* commands. |
| Graph-aware planning | Computes PageRank, betweenness, HITS, eigenvector, k-core, cycles, critical path, articulation points, and slack. |
| Multiple operator surfaces | Supports automation, a FrankenTUI, markdown briefs, graph export, and pages export from one codebase. |
| Workspace-aware loading | Understands .beads/ layouts, compatibility filenames, and .bv/workspace.yaml aggregation. |
| History and feedback loops | Correlates git history, supports drift baselines, recommendation feedback, and correlation review commands. |
| Evidence-heavy testing | Backed by conformance, schema, e2e, workspace/history, export, snapshot, and stress tests. |
Quick Example
# 1. Ask for the single best next move
# 2. Get a compact orientation snapshot
# 3. Get the full triage payload
# 4. Inspect graph metrics and cycles
# 5. See an execution plan grouped into parallel tracks
# 6. Search across issue text and metadata
# 7. Export a static bundle for sharing
# 8. Preview it locally
What bvr Solves
bvr is the Rust port of the legacy Go bv tool, but the current codebase is no longer just a straight porting spike. Today it includes:
- Robot-mode parity work for the legacy CLI surface.
- A much larger analysis surface than simple ranking.
- A functional FrankenTUI with the main issue view plus 11 specialized modes.
- Static pages export, preview, watch mode, and a pages deployment wizard.
- Workspace-aware loading and git-history-aware analysis.
The current direction is to lock down parity first, then extend from there:
- Keep the machine-facing behavior compatible and evidence-driven.
- Recover operator confidence in the interactive workflows.
- Extend the Rust version with capabilities that make sense natively here.
Problem Cases bvr Handles Well
bvr is most useful when a backlog has enough structure that naive sorting starts lying to you. Common cases:
1. A high-priority issue is noisy, but not actually central
An issue can be marked urgent and still not unblock much of anything. bvr distinguishes declared priority from structural importance, which is why the triage surface includes both priority signals and graph-derived signals.
2. A mediocre-looking issue is the real bottleneck
Sometimes the most important work is a root blocker, a bridge between clusters, or an articulation point that keeps whole branches connected. Those rarely stand out in a plain list view.
3. A team is drowning in stale work and cannot tell what is safely ignorable
Staleness alone is not enough. A stale leaf item and a stale central blocker are very different problems. bvr combines freshness, dependency structure, and blocker counts, so stale-work review does not collapse into "oldest first."
4. Multiple repos act like one delivery system
In a workspace layout, the API repo, frontend repo, and shared library repo can form one planning graph. bvr can aggregate that via .bv/workspace.yaml instead of forcing you to triage each repo in isolation.
5. Operators need different surfaces for the same underlying truth
Agents want structured output. Humans want TUI workflows. Stakeholders may want a static dashboard. bvr exists so those do not drift into separate, contradictory tools.
6. "What changed?" matters as much as "What exists?"
Baselines, diffs, history correlation, and export/watch flows exist because triage is usually about movement over time, not a single snapshot of open issues.
Design Philosophy
1. One source of truth, many surfaces
The loader and analyzer feed everything else. Robot output, TUI screens, markdown briefs, and pages export all work from the same issue graph instead of reimplementing their own logic.
2. Graph structure matters more than raw counts
Priority is only one field on an issue. bvr also looks at blockers, centrality, flow, and path structure so it can distinguish a noisy task from a true bottleneck.
3. Automation should not scrape terminal output
Robot commands are first-class. If you are integrating with agents or scripts, use --robot-* and optionally --format toon instead of screen-scraping the TUI.
4. Workspace and path semantics are product behavior
This project treats .beads discovery, workspace aggregation, repo-path handling, watch paths, preview serving, and history resolution as part of the real contract, not implementation trivia.
5. Parity claims need evidence
The repo carries conformance fixtures, schema validation, e2e coverage, snapshots, and stress fixtures because "probably compatible" is not a useful standard for a triage engine.
Why Graph-Aware Triage Beats Naive Sorting
A normal issue list encourages bad habits:
- sort by declared priority
- maybe filter by status
- maybe scan titles by hand
That works until dependencies matter. Once issues block each other, connect teams, span repos, or form cycles, the backlog becomes a graph problem rather than a spreadsheet problem.
bvr treats the backlog that way. Instead of asking only "what is marked important?", it also asks:
- what work influences the most downstream work?
- what issues sit on the bridges between clusters?
- what items are central but not obviously loud?
- what gets value moving fastest if finished now?
- what work is risky because it is in cycles or behind blockers?
That is why --robot-next and --robot-triage are graph-aware ranking outputs, not dressed-up sort orders.
How Scoring Works
The recommendation engine does not rely on a single metric. The current impact score combines multiple normalized components and then renormalizes them into a single score.
At a high level, the scoring model considers:
| Component | What It Captures | Why It Matters |
|---|---|---|
| PageRank | Global centrality in the dependency graph | Finds issues that influence a lot of important work |
| Betweenness | Bridge importance between regions of the graph | Finds chokepoints and routing issues |
| BlockerRatio | How much open work this issue blocks | Rewards high-unblock items |
| Staleness | How recently the issue moved | Prevents long-dead work from floating to the top by default |
| PriorityBoost | Declared issue priority | Respects operator intent without blindly obeying it |
| TimeToImpact | How quickly value propagates after completion | Rewards work near the roots of dependency chains |
| Urgency | Status-based urgency signal | Distinguishes active, open, review, blocked, and deferred states |
| Risk | Open blockers, cycle membership, articulation-point risk | Discounts work that is structurally risky to execute now |
Two important design choices:
- The model is multi-signal, so no single bad field dominates the ranking.
- The model is explainable, because recommendations carry reasons rather than just a score.
This is also why bvr can support recommendation feedback: the score is composed from named components, not a black-box classifier.
Algorithms Under the Hood
The analysis engine uses standard graph algorithms, but it applies them to issue planning rather than academic toy graphs.
Core metrics
| Algorithm | Used For |
|---|---|
| PageRank | Global influence / importance |
| Betweenness centrality | Bridge and bottleneck detection |
| Eigenvector centrality | Influence based on influential neighbors |
| HITS | Hub and authority style ranking |
| K-core decomposition | Dense structural cores in the graph |
| Articulation point detection | Single points of structural failure |
| Critical depth / critical path signals | Long dependency-chain importance |
| Slack computation | How much scheduling flexibility exists |
| Strongly connected component cycle detection | Detecting circular dependencies |
Related analysis families
Beyond pure graph centrality, the repo also includes:
- forecast analysis
- execution plan grouping
- label health and cross-label flow
- git-history correlation
- drift against saved baselines
- search and recipe filtering
- file-to-bead and hotspot analysis
- blocker-chain, impact-network, and causality views
Practical note on scale
The code intentionally treats some metrics as more expensive than others. Faster metrics can be computed immediately, while slower metrics can be deferred or sampled on larger graphs.
Why These Algorithms Matter for Issue Triage
Listing algorithms is not enough. Their value in this repo is operational:
- PageRank helps surface issues that matter globally, not just locally.
- Betweenness highlights bridge work that sits between clusters or teams.
- Articulation points expose single issues whose removal would fragment the dependency graph.
- K-core helps distinguish deep structural clusters from shallow leaves.
- Cycle detection catches planning deadlocks that look normal in a flat list.
- Critical depth and slack make scheduling more defensible than gut feel.
If you have ever asked "why is this weird-looking issue ranked so high?", the answer is usually one of those structural effects.
How bvr Compares
| Feature | bvr |
legacy Go bv |
ad-hoc jq / scripts |
manual triage |
|---|---|---|---|---|
| Structured robot output | ✅ JSON + TOON | ✅ JSON-style robot output | ⚠️ custom per script | ❌ |
| Interactive TUI | ✅ functional, expanding | ✅ mature baseline | ❌ | ❌ |
| Static pages export | ✅ built in | ✅ | ❌ | ❌ |
| Workspace-aware loading | ✅ .bv/workspace.yaml + repo-path semantics |
✅ baseline behavior | ❌ usually custom | ❌ |
| Graph metrics | ✅ broad built-in set | ✅ core set | ⚠️ manual and brittle | ❌ |
| Drift/correlation/file intel surfaces | ✅ built in | ⚠️ mixed / legacy-dependent | ❌ | ❌ |
| Best fit today | automation + analysis + export | legacy operator muscle memory | one-off filtering | small backlogs |
Use bvr when:
- You want a single binary for triage, diagnostics, dashboards, and automation.
- You are working in a
.beads-based repo and need dependency-aware ranking. - You want machine output that is easier to consume than terminal text.
Prefer something else when:
- You only need one quick text filter on a tiny file.
- You require exact legacy TUI feel today and do not want parity-in-progress behavior.
Installation
1. Install from GitHub with Cargo
2. Build from a local checkout
When validating the current checkout, prefer the binary built from that checkout (./target/debug/bvr or ./target/release/bvr). Do not assume a global bv wrapper or previously installed binary matches the source tree you are editing.
3. Install from a local checkout into your Cargo bin dir
Toolchain
- Rust edition:
2024 - Minimum Rust version:
1.85 - Binary name:
bvr
Quick Start
1. Point bvr at issue data
By default, bvr looks for .beads/ data in the current repository. It also supports compatibility filenames such as issues.jsonl and beads.base.jsonl.
If you want to bypass auto-discovery:
2. Use workspace mode when one repo is not enough
bvr can aggregate multiple repos through .bv/workspace.yaml.
repos:
- path: services/api
- path: apps/web
3. Start with the high-signal robot commands
4. Use the TUI for operator workflows
5. Export a shareable dashboard bundle
Input Model
Default data sources
bvr loads issues from .beads by default, with compatibility for:
beads.jsonlissues.jsonlbeads.base.jsonl
It can also aggregate repositories via .bv/workspace.yaml.
Output formats
Robot commands can emit:
jsonvia--format jsontoonvia--format toon
Examples:
BV_OUTPUT_FORMAT=toon
Robot Output Philosophy
The robot surface exists so external automation does not have to guess at terminal text.
Design goals
- Deterministic structure for scripts and agents
- Shared envelope fields such as generation timestamp, data hash, output format, and version
- Discoverability through
--robot-help,--robot-docs, and--robot-schema - Compact output through TOON when JSON is too expensive for agent loops
Why both JSON and TOON exist
JSON is the safest default for downstream tooling. TOON exists because agent workflows often care about token cost and readability more than strict JSON syntax.
Why the schema/docs commands matter
The repo emits payloads and machine-readable descriptions of their contracts. That matters for:
- agent integration
- regression detection
- contract review
- new command discovery
Workspace and Path Semantics
Path handling is one of the subtle but critical parts of bvr.
What can be discovered automatically
bvr can look for:
.beads/in the current repo or ancestors- compatibility JSONL filenames
.bv/workspace.yamlfor multi-repo aggregation
Why this gets its own section
In this project, path resolution affects:
- which issues are loaded
- whether workspace aggregation happens
- where watch mode listens for changes
- where historical loads and diffs resolve from
- where pages workflows and persisted state live
Practical usage rules
- Use
--beads-filewhen you want an exact source file and do not want discovery. - Use
--workspacewhen you want an exact workspace config and do not want discovery. - Let auto-discovery work when the repo layout is conventional and you want convenience.
Static Pages, Preview, Watch, and Wizard
The pages system is a first-class surface, not an afterthought.
What export produces
The bundle includes:
index.html- local viewer assets
- JSON payloads for issues, metadata, triage, and optional history
- a SQLite database bundle
- static-host helper files such as
_headers - a deploy-facing bundle README
Why pages export exists
It solves a different problem than robot mode:
- robot mode is for agents and automation
- the TUI is for interactive operators
- pages export is for sharing, review, and lightweight dashboard publishing
Preview server
The preview flow provides a local HTTP server for the exported bundle, a status endpoint, and optional live reload. It is intentionally geared toward testing the real exported artifact rather than a separate dev-only web app.
Watch mode
--watch-export exists for a fast edit-refresh cycle when the issue data changes and you want the static bundle to keep up.
Pages wizard
--pages is an interactive deployment-oriented workflow that helps collect export options, target settings, preview choices, and deployment instructions without requiring the operator to remember every flag.
Command Reference
For the machine-readable inventory, use:
Core triage and planning
Use these when you want a fast orientation snapshot, ranked recommendations, quick wins, blockers to clear, grouped tracks, or priority mismatch detection.
Graph analysis and forecasting
Use these when you need graph metrics, projected execution, sprint state, or graph exports for downstream tools.
History, diff, drift, and correlation
Use these when you want git-aware change tracking, baseline comparisons, or a feedback loop for commit-to-bead correlations.
Label, search, and file intelligence
Use these when you need label health, workspace search, orphan detection, file-to-bead mapping, or impact analysis.
Export, reports, and automation helpers
These commands generate static artifacts, local previews, and operator-facing deployment guidance.
TUI and diagnostics
Use these when you want the interactive UI, deterministic render output for debugging, or startup timing diagnostics.
AGENTS.md workflow helpers
These commands inspect or manage the beads workflow blurb inside AGENTS.md.
TUI Overview
Bare bvr launches the interactive terminal UI. For automation, do not run the bare command; use --robot-*.
Main view plus 11 specialized modes
| Key | Mode | Purpose |
|---|---|---|
| default | Main | Issue list with detail pane |
b |
Board | Kanban-style lane view |
i |
Insights | Metric and explanation panels |
g |
Graph | Dependency graph and edge inspection |
h |
History | Bead/git timeline and file tree |
a |
Actionable | Parallel execution tracks |
! |
Attention | Label attention ranking |
T |
Tree | Dependency tree |
[ |
Labels | Label health dashboard |
] |
Flow | Cross-label flow matrix |
t |
Time Travel | Diff-against-ref view |
S |
Sprint | Sprint planning/detail view |
Common keys
| Key | Action |
|---|---|
? |
Toggle help overlay |
Tab |
Toggle list/detail focus |
Esc |
Back, clear, or quit confirm |
j / k |
Move within the focused pane |
/ |
Search in supported views |
TUI Design Goals
The TUI is not trying to be a pretty wrapper around one list. Its job is to support different operator tasks without making the user mentally re-derive the graph from a table every time.
Why there are many modes
Different planning questions need different visual structures:
- Main for backlog scanning and detail reading
- Board for lane-based operational overview
- Insights for metric interpretation
- Graph for structural debugging
- History for time and git context
- Actionable for "what can teams do in parallel right now?"
- Attention / Labels / Flow for label-centric health and bottleneck analysis
- Tree / Time Travel / Sprint for dependency, comparison, and planning workflows
Why the TUI is still evolving
The project explicitly treats operator trust as something that has to be earned. The Rust TUI is already useful, but parity and workflow polish are still active goals rather than a finished story.
Configuration
Workspace config: .bv/workspace.yaml
repos:
- path: services/api
- path: apps/web
discovery:
patterns:
- services/*
- apps/*
User config for TUI background reload: ~/.config/bv/config.yaml
experimental:
background_mode: true
Useful environment variables
| Variable | Purpose |
|---|---|
BV_OUTPUT_FORMAT |
Default robot output format: json or toon |
TOON_DEFAULT_FORMAT |
Fallback output format if BV_OUTPUT_FORMAT is unset |
TOON_STATS |
Print JSON vs TOON token estimates on stderr |
TOON_KEY_FOLDING |
Configure TOON key folding |
TOON_INDENT |
Configure TOON indentation |
BV_SEARCH_PRESET |
Default hybrid search preset |
BVR_PREVIEW_PORT |
Preferred preview server port |
BVR_PREVIEW_MAX_REQUESTS |
Auto-stop the preview server after N requests |
BV_BACKGROUND_MODE |
Enable or disable TUI background reload |
BVR_E2E_ARTIFACT_DIR |
Persist e2e regression artifacts for test runs |
Architecture
┌────────────────────────────────────────────────────────────────────┐
│ Input layer │
│ - .beads/*.jsonl │
│ - compatibility filenames │
│ - .bv/workspace.yaml │
│ - git history / baselines / feedback files │
└────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────┐
│ Loader + model validation │
│ - path discovery │
│ - workspace aggregation │
│ - issue parsing + validation │
│ - warning suppression for robot mode │
└────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────┐
│ Analyzer │
│ - IssueGraph build │
│ - fast metrics phase │
│ - optional slow metrics phase in background thread │
│ - triage / plan / alerts / search / history / drift / file intel │
└────────────────────────────────────────────────────────────────────┘
│
┌───────────────────────┼────────────────────────┐
▼ ▼ ▼
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ Robot surfaces │ │ Operator surfaces │ │ Export surfaces │
│ JSON / TOON │ │ FrankenTUI │ │ MD / pages / SQLite│
└────────────────────┘ └────────────────────┘ └────────────────────┘
Performance Model
Not all analysis work costs the same amount, and the code reflects that.
Two-phase analysis
The engine distinguishes between:
- fast structural work that is cheap enough to do immediately
- slower graph work that can be deferred, backgrounded, or sampled on larger graphs
This lets the tool stay responsive without pretending expensive graph algorithms are free.
Large-graph behavior
For larger graphs, some computations change strategy instead of doing the most expensive exact version every time. One example is sampled betweenness on larger graphs.
Why background mode exists
Background mode exists to keep the TUI usable while deeper analysis catches up.
Data and Artifact Layout
Input-side layout
| Path / Artifact | Role |
|---|---|
.beads/ |
Primary issue-data home |
beads.jsonl / issues.jsonl / beads.base.jsonl |
Supported JSONL issue sources |
.bv/workspace.yaml |
Multi-repo aggregation config |
| git history | History correlation and timeline input |
Output-side layout
| Artifact | Produced By |
|---|---|
| robot JSON / TOON payloads | --robot-* |
| markdown reports and briefs | --export-md, --priority-brief, --agent-brief |
| graph exports | --export-graph, --robot-graph |
| static pages bundle | --export-pages |
| preview server responses | --preview-pages |
| baseline comparisons | --save-baseline, --robot-drift, --check-drift |
Pages bundle layout
At a high level, exported bundles contain:
- a root HTML entry point
- local viewer assets
data/payloads- a SQLite database export
- deployment helper files
That layout is intentionally self-contained so preview and static hosting use the same artifact shape.
Testing and Verification
This repo carries multiple verification layers rather than relying on a single happy-path suite:
- Conformance tests against a Go reference harness.
- JSON schema validation for robot output contracts.
- E2E robot, export, and workspace/history integration tests.
- TUI snapshots and keyflow journeys.
- Stress fixtures for large and pathological graphs.
- Benchmarks for the analysis pipeline.
Useful commands:
Optional artifact capture for robot regressions:
BVR_E2E_ARTIFACT_DIR=target/bvr-e2e-artifacts
Workflow Recipes
I am an agent and need the next best move
Start narrow, then expand. --robot-next gives the top pick, --robot-overview gives a compact project snapshot, --robot-triage gives deeper context, and --robot-plan tells you whether parallel work exists.
I am a human operator triaging a sprint
# then use Main, Actionable, Sprint, and History modes
Use this when you need to move between ranking, dependency structure, and recent changes interactively.
I need to understand dependency bottlenecks
Use graph metrics for global context and blocker-chain output for a specific issue.
I need to review what changed since the last checkpoint
# later
Use baselines for structural drift and --robot-diff for issue-level change summaries.
I need a shareable dashboard
Use this when you want to share triage output with someone who is not going to run the CLI locally.
Testing Philosophy
The test strategy exists because this tool has several different contracts at once.
1. Parity contract
Conformance tests protect behavior that is supposed to match legacy expectations.
2. Robot contract
Schema validation protects machine-facing output shape. This matters because agents and scripts are less forgiving than humans.
3. Operator contract
Snapshot and journey tests protect the TUI from accidental regressions in navigation and rendering.
4. Integration contract
Workspace/history/export tests exist because path semantics, workspace promotion, preview behavior, and pages flows are easy to break accidentally.
5. Stress contract
Stress fixtures protect the tool from becoming "correct only on toy graphs."
Troubleshooting
"My script hung"
You probably ran bare bvr, which launches the TUI.
# Use robot mode for automation
"No issues were found"
Be explicit about the source instead of relying on discovery.
"Workspace auto-discovery is ambiguous"
Tell bvr exactly which workspace or beads file you want.
# or
"Preview pages failed to bind a port"
Pick an explicit port.
BVR_PREVIEW_PORT=9010
"Robot output is too verbose"
Use TOON.
BV_OUTPUT_FORMAT=toon
Non-Goals
bvr is intentionally not trying to be all things:
- It is not a hosted project-management platform.
- It is not a replacement for issue creation or collaboration systems.
- It is not just a pretty terminal wrapper around
jq. - It is not optimized around community contribution workflows.
Those boundaries help keep the project focused on triage, analysis, automation, and export.
Roadmap and Current Priorities
The current high-level priorities are:
1. Preserve verified legacy parity
Robot, CLI, export, workspace, and interactive TUI behavior now have a parity proof surface. The job is to keep that contract stable as the code evolves.
2. Harden regression evidence
Conformance, schema, snapshot, keyflow, journey, stress, and integration suites are part of the product contract, not optional maintenance.
3. Extend only where Rust-native additions stay coherent
Search, label intelligence, drift, correlation review, file-intel, and future async/runtime upgrades should build on top of the locked parity baseline rather than destabilize it.
4. Keep pages/export/workspace workflows polished
Export, preview, watch mode, wizard flows, and workspace path semantics remain high-value operator workflows and should stay first-class.
Why This Exists
Issue data is easy to store. The harder problem is turning it into trustworthy action.
Flat issue lists fail in predictable ways:
- they hide structural blockers behind cosmetic metadata
- they over-trust stale priority fields
- they fragment multi-repo work into separate local truths
- they make humans and agents consume different, often contradictory, surfaces
bvr exists because the underlying problem is bigger than printing a list of issues. The real question is how to reason about dependency-shaped work across multiple consumers without duplicating logic everywhere.
For that reason, the project is built around a shared analyzer and projected into multiple surfaces, instead of building one-off ranking logic for each output mode.
System Tour
One straightforward way to understand bvr is to follow one issue through the system.
Step 1. The issue is discovered and loaded
The loader finds .beads data, compatibility JSONL sources, or workspace repo inputs, then parses and validates issues into the in-memory model.
Step 2. The issue enters the graph
Its dependencies become edges in IssueGraph, which means the issue is no longer treated as an isolated row. It now has predecessors, successors, graph depth, blocker relationships, and possible cycle membership.
Step 3. Metrics are computed around it
The analyzer computes centrality, blocker counts, critical depth, slack, cycle membership, and other structural signals. At this point, the issue stops being "just title + priority + status."
Step 4. Triage synthesizes a recommendation
The triage layer combines graph signals with declared metadata such as priority, status, freshness, and risk signals. This is where the issue may become a top pick, a blocker to clear, a quick win, or a lower-confidence candidate.
Step 5. The same truth is projected outward
That result can then appear as:
- a
--robot-nexttop recommendation - one row inside
--robot-triage - a node in the graph view
- a detail pane entry in the TUI
- a track item in Actionable mode
- a row in exported pages JSON / SQLite payloads
These are not separate systems with separate logic. They are projections of the same analyzed issue state.
From Data to Recommendation
Here is the end-to-end pipeline in slightly more explicit form:
- Discover inputs
- locate
.beadsdata, compatibility JSONL files, or.bv/workspace.yaml
- locate
- Parse and validate
- read JSONL
- normalize issue fields
- validate timestamps, statuses, and dependency references
- Build the graph
- construct
IssueGraphwith IDs, edges, successors, and predecessors
- construct
- Compute metrics
- run fast structural analysis first
- run deeper graph metrics when appropriate
- Synthesize analysis products
- triage
- planning
- forecasting
- alerts
- search
- label/file/history/drift/correlation outputs
- Project into surfaces
- robot JSON / TOON
- TUI
- markdown reports and briefs
- graph export
- pages bundle and preview flows
That pipeline is the real architecture of the project. The flags are just ways of selecting which projection you want.
Metric Glossary
PageRank
Mathematically: a recursive influence score over the dependency graph.
Operationally: "if I care about globally important work, how central is this issue?"
Can mislead when: a graph is tiny or nearly flat, where everything is structurally similar.
Betweenness
Mathematically: how often a node lies on shortest paths between other nodes.
Operationally: "is this issue a bridge or chokepoint between clusters?"
Can mislead when: there are many equivalent alternate routes or the graph is too small to make bridging meaningful.
Eigenvector Centrality
Mathematically: influence weighted by the influence of neighbors.
Operationally: "is this issue connected to other important issues?"
HITS
Mathematically: separates hub-like and authority-like roles in a graph.
Operationally: useful for distinguishing issues that point to many important dependencies from issues that are important dependency targets themselves.
K-Core
Mathematically: the deepest dense subgraph layer a node belongs to.
Operationally: "how embedded is this issue in the core of the dependency structure?"
Articulation Point
Mathematically: a node whose removal disconnects part of the graph.
Operationally: "is this a single point of structural failure?"
Critical Depth
Mathematically: a depth-like measure over dependency structure.
Operationally: "if this moves, how far does value propagate down the chain?"
Slack
Mathematically: scheduling flexibility relative to critical structure.
Operationally: "how little room for delay does this issue have?"
Cycle Membership
Mathematically: membership in a strongly connected component with a cycle.
Operationally: "is this issue trapped in a circular dependency?"
Scoring Breakdown Example
Imagine an issue with this profile:
- blocks several open items
- sits near the root of a dependency chain
- has decent declared priority
- is not currently blocked itself
- is part of an important bridge between two graph regions
Its score might look conceptually like this:
| Component | Interpretation |
|---|---|
| PageRank: high | globally central work |
| Betweenness: high | connects otherwise separate work streams |
| BlockerRatio: medium-high | unblocks real downstream work |
| PriorityBoost: medium | operator intent supports it but is not the only reason |
| TimeToImpact: high | finishing it moves value quickly |
| Urgency: medium | status says it is live work, not deferred noise |
| Risk discount: low penalty | no blockers or cycles holding it back |
The final recommendation is strong not because one number said so, but because several independent signals agree.
Design Tradeoffs
Several design choices shape the project:
Explainable ranking over black-box ranking
It would be easier to make the ranking opaque than to make it transparent. This project chooses transparency and defensibility.
Deterministic outputs over clever nondeterminism
For agent workflows, stable output shape and ordering are more valuable than vaguely smarter but unstable behavior.
Shared analyzer over per-surface duplication
Robot mode, TUI, and export all use the same core analysis instead of each surface inventing its own rules.
Single binary over service sprawl
bvr is intentionally a CLI/TUI/export tool, not a distributed backend with several moving processes.
Cargo-first distribution over premature packaging sprawl
Right now, the project supports Cargo and source installation cleanly. It does not claim a broader packaging story than it actually has.
Why TOON Exists
TOON exists because machine-facing output has two competing goals:
- strict machine readability
- compactness and lower token cost
JSON wins the first goal. TOON helps with the second.
Prefer TOON when:
- an agent is repeatedly consuming large robot payloads
- you want a more compact representation for iterative loops
- strict JSON parsing is not required by the caller
Prefer JSON when:
- another tool expects JSON directly
- you want maximal interoperability
- the payload will be fed into standard JSON tooling
TOON exists because agent ergonomics are part of the product surface.
Failure Modes and Defensive Behavior
Many failure cases are treated as part of the real contract.
Malformed JSONL lines
The loader does not assume pristine input forever. Robot mode also treats warning behavior differently because leaking noisy warnings into machine-facing stderr can break automation expectations.
Empty datasets
An empty issue set is handled as a real scenario, not as a crash-worthy anomaly.
Missing or ambiguous workspace configs
When discovery becomes ambiguous, the tool prefers explicit guidance over silently loading the wrong project shape.
Changed path / filename conventions across history
Historical and workspace-aware loading are real concerns in this repo because path semantics affect correctness, not convenience alone.
Large graphs
The engine does not pretend every metric is equally cheap. It uses staged computation and alternate strategies where appropriate.
Preview server conflicts
The preview workflow explicitly handles port conflicts and exposes overrides, because export-preview loops are meant to be operational, not toy demos.
Historical and Temporal Analysis
bvr is not only about ranking the current graph snapshot.
The temporal surfaces include:
--robot-history--robot-diff- saved baselines
--robot-drift- human-readable
--check-drift - correlation explanation / confirmation / rejection
Together, those features answer a broader class of questions:
- what changed?
- what drifted?
- what newly matters?
- what used to be true but is no longer true?
- which commit history seems to explain this issue movement?
Together, those features make bvr more of a backlog-analysis engine than a static ranking script.
Why Static Pages Matter
Static pages solve a product problem that robot mode and the TUI do not.
Robot mode is ideal for automation. The TUI is ideal for operators. Static pages matter because sometimes you need:
- a shareable artifact
- a dashboard for someone who will not run the CLI
- a reproducible snapshot of analysis
- something previewable locally and publishable to a static host
That is also why export includes the real viewer assets and SQLite/data payloads instead of dumping one JSON file and calling it done.
Operator Personas
Agent / automation consumer
Wants deterministic machine-readable outputs, schema truthfulness, and low-friction command surfaces.
Solo engineer
Wants a fast answer to "what should I do next?" and "what is actually blocked?"
Tech lead / sprint planner
Wants prioritization, parallelization, bottleneck detection, label flow, and planning visibility across a broader surface area.
Stakeholder consuming pages export
Wants a shareable view of the analyzed state without learning the CLI or gaining repo access.
Real Query and Workflow Examples
Find high-signal next work
Inspect structural bottlenecks
Audit one label area
Search with graph-aware ranking
Review temporal change
Produce a stakeholder-facing snapshot
Module-by-Module Architecture Map
| Module / File | Responsibility |
|---|---|
src/loader.rs |
issue discovery, workspace loading, path semantics, JSONL parsing |
src/model.rs |
core issue data model and validation rules |
src/analysis/graph.rs |
graph construction and centrality / structural metrics |
src/analysis/triage.rs |
ranking, impact score, recommendations, project health |
src/analysis/plan.rs |
parallel execution-track grouping |
src/analysis/history.rs / git_history.rs |
history and git correlation support |
src/analysis/label_intel.rs |
label health, flow, and attention analysis |
src/analysis/file_intel.rs |
file-bead mapping, hotspots, related work, orphans |
src/analysis/search.rs |
text and hybrid search logic, presets, weights |
src/analysis/drift.rs |
baseline comparison and drift reporting |
src/robot.rs |
envelopes, docs, schemas, TOON rendering, payload contracts |
src/tui.rs |
interactive multi-mode terminal UI |
src/export_pages.rs |
static bundle export, preview, and watch flows |
src/pages_wizard.rs |
interactive pages deployment-oriented wizard |
src/export_md.rs / src/export_sqlite.rs |
report and export artifact generation |
src/main.rs |
CLI dispatch and surface orchestration |
What Makes This Hard
Several parts of this project are harder than they first look:
Behavioral parity is not a cosmetic problem
If robot output, warning behavior, path semantics, or workspace resolution drift, users and agents can make wrong decisions even when the binary "works."
Path semantics are a product feature
This repo has repeatedly surfaced subtle bugs around workspace roots, repo paths, historical loads, preview behavior, and related state resolution. Those are correctness problems, not housekeeping.
Graph metrics must become action, not ornament
It is easy to compute centrality and still fail to tell the user what to do. Turning metrics into usable recommendations is the harder job.
Multiple surfaces must agree
Robot mode, TUI, markdown export, graph export, and pages export all need to present coherent projections of the same analysis.
Responsiveness and depth are in tension
The richer the graph analysis gets, the easier it is to make the operator experience laggy. The staged computation model exists because this tension is real.
Determinism and Trust
The project leans hard on determinism because trust is the whole game in a triage tool.
Deterministic ordering matters
Agents, tests, and humans all benefit when repeated runs over the same input produce stable ordering and payload shape.
Data hashing matters
The shared envelope includes a data hash because "what exact source state generated this?" is a legitimate operational question.
Docs and schemas matter
--robot-docs and --robot-schema are not decorative. They help make the machine-facing surface inspectable and regression-resistant.
Test layers matter
Conformance, schema tests, e2e coverage, and snapshots are all part of building trust that the tool means what it says.
Future Research and Expansion Ideas
These are not promises; they are plausible directions that fit the design of the system:
- richer search ranking and explainability
- deeper causal / impact-path reasoning
- stronger recommendation feedback loops
- broader workspace-scale planning and aggregation views
- more operator workflows in the TUI
- more analysis surfaces that stay coherent with the shared analyzer model
Limitations
What bvr does not do perfectly yet
- Legacy TUI parity is still in progress. The TUI is functional and much broader than a toy interface, but the project is still actively refining operator workflows relative to legacy
bv. - Distribution is still Cargo-centric. The repo does not currently ship a dedicated curl installer, Homebrew formula, or packaged release manager workflow in this README.
- Some surfaces are newer than the older README era. Search, correlation feedback, drift, file intel, and some label flows are current capabilities, but they are evolving quickly.
- This is a CLI/TUI/dashboard tool, not a hosted service. You bring the
.beadsdata, git history, and deployment target.
FAQ
Is bvr just a Rust rewrite of bv?
It started there, but the current repo now includes Rust-native surfaces such as richer pages export workflows, drift and baseline tooling, correlation review commands, file intelligence, and a broader TUI.
Should agents use the TUI?
Usually not. Agents and scripts should prefer --robot-* with json or toon; the TUI is for humans.
What should I run first?
Start with:
Can it work across multiple repos?
Yes. Use .bv/workspace.yaml, then either let bvr discover it or pass --workspace explicitly.
Does it only read .beads/beads.jsonl?
No. It also supports compatibility filenames such as issues.jsonl and beads.base.jsonl, along with workspace aggregation.
Can I share results without giving people the repo?
Yes. Export a static bundle:
Is TOON optional?
Yes. JSON remains the default. TOON is there for more compact agent-facing output.
Development Notes
Build metadata
build.rs embeds build timestamp, target triple, and rustc metadata via vergen-gix.
CI
GitHub Actions currently runs:
- format + clippy
- unit + snapshot verification
- conformance + schema validation
- e2e and integration suites
- benchmark smoke
- release build artifact creation
About Contributions
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
ghand 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 the OpenAI/Anthropic rider. See LICENSE.