Profile
Back to NewsBack
GitHub Trending 35 min
Reader Mode
Dicklesworthstone/beads_viewer: Graph-aware TUI for the Beads issue tracker: PageRank, critical path, kanban, dependency DAG visualization, and robot-mode JSON API

Dicklesworthstone/beads_viewer: Graph-aware TUI for the Beads issue tracker: PageRank, critical path, kanban, dependency DAG visualization, and robot-mode JSON API

11 hours ago

Beads Viewer (bv)

!Release !Go Version !License Coverage</a>

The elegant, keyboard-driven terminal interface for the Beads issue tracker.

Main split view
Main split view: fast list + rich details
Kanban board
Kanban board (b) for flow at a glance
Insights view
Insights panel: PageRank, critical path, cycles
Graph view
Graph view (g): navigate the dependency DAG

Installation

Recommended: Homebrew (macOS/Linux)

brew install dicklesworthstone/tap/bv

This method provides:

  • Automatic updates via brew upgrade
  • Dependency management
  • Easy uninstall via brew uninstall

Windows: Scoop

scoop bucket add dicklesworthstone https://github.com/Dicklesworthstone/scoop-bucket
scoop install dicklesworthstone/bv

Homebrew and Scoop select the version in their published manifests. To pin v0.26.0, use a verified release archive below. See the distribution checks for version and checksum details.

Alternative: Direct Download

Pick the archive for your platform from the latest release page. Archives are named bv___.tar.gz (.zip on Windows), for example bv_0.26.0_linux_amd64.tar.gz, bv_0.26.0_darwin_arm64.tar.gz, bv_0.26.0_windows_amd64.zip, so a downloaded file always says which release it came from. Every release also ships checksums.txt; verify before extracting:

sha256sum -c --ignore-missing checksums.txt

Releases up to v0.22.0 used unversioned names (bv_linux_amd64.tar.gz); bv --update and install.sh accept both forms.

Alternative: Install Script

Linux/macOS: Prefer Homebrew, Scoop, or a checksum-verified release archive above. If you do pipe the script, pin it to a commit you have read instead of the moving main branch:

# Pinned to a reviewed commit; read it first: https://github.com/Dicklesworthstone/beads_viewer/blob/ee81c286e89ed6f9d5d10c62da307cafe95c710b/install.sh
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/beads_viewer/ee81c286e89ed6f9d5d10c62da307cafe95c710b/install.sh" | bash
Warning: curl ... | bash runs whatever the URL serves at that moment. The pinned form above cannot change under you; the main form can. install.sh downloads the release archive for your platform, verifies it against the release checksums.txt, and refuses to install on a mismatch.

Windows (PowerShell):

# Pinned to a reviewed commit; read it first: https://github.com/Dicklesworthstone/beads_viewer/blob/ee81c286e89ed6f9d5d10c62da307cafe95c710b/install.ps1
irm "https://raw.githubusercontent.com/Dicklesworthstone/beads_viewer/ee81c286e89ed6f9d5d10c62da307cafe95c710b/install.ps1" | iex
Note: The pinned installer above downloads the Windows release zip, verifies it against the release checksums.txt with Get-FileHash, and refuses anything that does not verify; no Go toolchain is needed. Pass -Version v0.26.0 to pin a release or -InstallDir to choose the folder (default %LOCALAPPDATA%\Programs\bv). Scoop installs the archive selected by its manifest. For best display, use Windows Terminal with a Nerd Font.

For a source build, use install.ps1 from this checkout (requires Git and Go 1.26+):

.\install.ps1 -FromSource -Version v0.26.0

This source path builds a verified checkout of the requested tag with that tag's vendored dependencies, checks the executable's version and Git revision before installation, and retains diagnostics on failure. The pinned installer above uses the same verified source-build path. Selecting an older release tag does not include later, unreleased fixes from this checkout.

Vendoring covers the Go module dependencies, not the compiler. When your Go differs from the toolchain directive in that tag's go.mod, Go downloads the pinned toolchain before compiling, so the source build needs network access even though the dependencies are vendored, and on a slow machine that download alone can take several minutes. The installer's progress line reports the Go it was launched with, not the toolchain it ends up building with; go version -m on the installed executable reports the one actually used.


Generating the JSONL File (br and bd)

bv reads Beads JSONL exports from .beads/. Current br and Dolt-backed bd workspaces use .beads/issues.jsonl; older legacy workspaces may use .beads/beads.jsonl. bv auto-discovers the supported file names.

Rust (br) users — run br sync --flush-only after Beads mutations so .beads/issues.jsonl is current.

Go (bd) users — run:

bd export -o .beads/issues.jsonl

Once the file exists, bv works identically regardless of which tool produced it.


🤖 Agent Quickstart (Robot Mode)

⚠️ Never run bare bv in an agent context — it launches the interactive TUI. Always use --robot-*.

# 1) Start with triage (single-call mega-command)
bv --robot-triage

2) Minimal mode: just the top pick + claim command

bv --robot-next

3) TOON output: smaller only for wide tabular payloads (--robot-graph); larger

for nested ones such as --robot-triage. Check with --stats before adopting.

bv --robot-graph --format toon bv --robot-triage --format toon --stats export BV_OUTPUT_FORMAT=toon

4) Full robot help

bv --robot-help

Output conventions

  • stdout = JSON/TOON data only
  • stderr = diagnostics
  • exit 0 = success
TOON uses an external toon_rust encoder. Discovery honors TOON_TRU_BIN or TOON_BIN, then looks for tru or toon on PATH and the library's known fallback paths; candidates are validated as toon_rust. If none is available, bv warns on stderr and emits JSON. A successful fallback is not evidence that TOON encoding ran. Keep the format set to JSON when copying the jq examples below.

💡 TL;DR

bv is a high-performance Terminal User Interface (TUI) for browsing and managing tasks in projects that use the Beads issue tracking system.

Why you'd care:

  • Local browsing: Browse thousands of issues without a network round trip. Response time depends on the graph, selected view, and host.
  • Focus: Stay in your terminal and use Vim-style keys (j/k) to navigate.
  • Intelligence: It visualizes your project as a dependency graph, automatically highlighting bottlenecks, cycles, and critical paths that traditional list-based trackers miss.
  • AI-Ready: It provides structured, pre-computed insights for AI coding agents, acting as a "brain" for your project's task management.

📖 The Core Experience

At its heart, bv is about viewing your work nicely.

⚡ Fast, Fluid Browsing

Browse your issue backlog in the terminal using standard Vim keys (j/k). Startup and navigation time depend on the workload; measured limits are described under Performance.
  • Split-View Dashboard: On wider screens, see your list on the left and full details on the right.
  • Markdown Rendering: Issue descriptions, comments, and notes are beautifully rendered with syntax highlighting, headers, and lists.
  • Keyboard Filtering: Press o for Open, c for Closed, or r for Ready (unblocked) tasks.
  • Live Reload: Watches the active Beads JSONL or SQLite source and refreshes lists, details, and insights automatically. SQLite updates are detected even while committed changes remain in its write-ahead log (WAL).

🔎 Rich Context

Don't just read the title. bv gives you the full picture:
  • Comments & History: Scroll through the full conversation history of any task.
  • Metadata: Instantly see Assignees, Labels, Priority badges, and creation dates.
  • Search: Fuzzy list filtering (/) matches the title, ID, status, issue type, assignee, labels and repo prefix, whether or not the current terminal width displays them. CLI keyword search (--search) also indexes descriptions and can combine text scores with graph metrics.
  • Dependency Details: The detail pane shows dependencies up to three edges from the selected issue. Each issue's dependencies appear once along a shortest path; other occurrences say (reference: shown elsewhere). Every relationship within that limit retains its type and target metadata. Cycle-closing edges carry a separate (cycle) marker.

🎯 Focused Workflows

  • Kanban Board: Press b to switch to a columnar view (Open, In Progress, Blocked, Closed) to visualize flow.
  • Visual Graph: Press g to explore the dependency tree visually.
  • Insights: Press i to see graph metrics and bottlenecks.
  • History View: Press h to see the timeline of changes, correlating git commits with bead modifications. On wider terminals, enjoy a responsive three-pane layout showing commits, affected beads, and details.
  • Ultra-Wide Mode: On large monitors, the list expands to show extra columns like sparklines and label tags.

🛠️ Quick Actions

  • Export: Press x to export all issues to a timestamped Markdown file with Mermaid diagrams (E opens the tree view).
  • Graph Export (CLI): bv --robot-graph outputs the dependency graph as JSON, DOT (Graphviz), or Mermaid format. Use --graph-format=dot for rendering with Graphviz, or --graph-root=ID --graph-depth=3 to extract focused subgraphs.
  • Copy: Press C to copy the selected issue as formatted Markdown to your clipboard.
  • Edit: Press O to open the loaded source in a GUI editor, or edit the focused issue's frontmatter in a terminal editor while the TUI is suspended.
  • Time-Travel: Press t to compare against any git revision, or T for quick HEAD~5 comparison. Combined with History view (h), you can navigate to any commit and see exactly what changed.

🔌 Automation Hooks

Configure pre- and post-export hooks in .bv/hooks.yaml to run validations, notifications, or uploads. Project hooks require explicit approval by the invoking user. Report exports (--export / --export-md) and direct Pages exports (--export-pages) fail before running hooks or writing the export when configured hooks have not been approved. Projects without hooks export normally. To export without running any project hooks, pass --no-hooks; this also bypasses hook configuration parsing, so it works with invalid YAML.

A runnable hook selects exactly one execution form: command for a shell command, or argv to invoke a program directly. argv must be a nonempty list of strings with a nonempty executable name as its first element. Each subsequent element is one literal argument, including empty strings or values containing spaces. For example:

hooks:
  pre-export:
    - name: check-whitespace
      argv: [git, diff, --check]
  post-export:
    - name: describe-export
      argv: [python3, ./scripts/describe_export.py]
      timeout: 30s

The project script can read export context directly from its environment. For the Python example above, scripts/describe_export.py could contain:

import os

print(f"{os.environ['BV_EXPORT_FORMAT']} export: {os.environ['BV_EXPORT_PATH']}") print(f"Issues: {os.environ['BV_ISSUE_COUNT']}; created: {os.environ['BV_TIMESTAMP']}")

Choose the interpreter executable installed on your machine. bv performs no expansion or shell parsing of argv: $VAR, ${VAR}, %VAR%, wildcards, pipes, redirection, and command substitution remain literal argument text. It does not split an argument on spaces. To use shell syntax, keep the existing command form; no implicit shell fallback occurs if a direct invocation fails. On Windows, .bat and .cmd files require command mode or an explicitly selected interpreter.

Bare executable names such as git are resolved using the invoking user's PATH, with Go's ErrDot protection against implicit current-directory lookup. A hook's env: {PATH: ...} affects the launched program's environment but does not change this initial executable lookup. Explicit relative executable paths such as ./tools/publish (or .\tools\publish.exe on Windows) resolve from the project directory. Windows drive-relative paths such as C:tool.exe and root-relative paths such as \tools\tool.exe are rejected. The program also runs with the project directory as its working directory.

Review the hooks from the project directory before approving them:

# Inspect only: prints JSON; does not run hooks or export anything.
bv --hooks-info

After review, replace this placeholder with the complete digest from that output.

bv --export-md report.md --trust-hooks 'sha256:REVIEWED_64_HEX_DIGEST'

The same approval mechanism works for direct Pages exports and CI.

bv --export-pages ./bv-pages --trust-hooks 'sha256:REVIEWED_64_HEX_DIGEST'

--hooks-info shows the canonical project directory, configuration file path, execution platform, exact command or argv declarations, declared environment values, normalized timeouts and error policies, warnings, the default inherited environment variable names (inherited_env), and a digest. Environment declarations are shown without expanding values from your process. Review both hook phases and the scripts or programs they invoke. The digest covers the YAML bytes, effective hook configuration, default inherited environment names, execution platform, and trust-policy version. Changes to commands, executables, arguments, execution form, environment declarations, ordering, timeouts, error policies, or even YAML comments invalidate the previous digest.

The current trust policy is v4. Digests approved under v1, v2, or v3 are rejected even when the YAML is unchanged. Review the execution forms and the process-lifetime and environment rules below, run bv --hooks-info again, and explicitly supply the new digest. Automation that previously relied on custom inherited variables must grant each required source explicitly with --hook-env.

--trust-hooks authorizes only the current invocation. It creates no persistent approval file and has no project-YAML or environment-variable equivalent. --yes does not approve hooks, and noninteractive exports never prompt for approval. For automation, keep the reviewed, fixed digest in configuration controlled by the invoking user, and supply it explicitly on each run. Do not automatically compute the current digest and immediately pass it back as approval: that would approve any newly introduced commands without review. The digest does not include the checkout's absolute path, so a reviewed digest can be reused explicitly in ephemeral CI checkouts on the same platform. With --watch-export, each export checks the newly loaded hooks against the same fixed digest; changed hooks require a fresh invocation with renewed approval.

Environment grants are separate from hook approval. Hooks inherit a small, explicit set of operating-system path, locale, time-zone, and terminal variables. Every other parent-process variable requires an invoking-user grant, regardless of its name. This withholds credentials in GITHUB_TOKEN, SSH_AUTH_SOCK, DATABASE_URL, PIP_INDEX_URL, or an arbitrary custom name alike. Hook YAML cannot restore an ungranted source through renamed variables or chains of ${VAR} expansions. A hook that needs an additional parent-process variable requires an explicit invoking-user grant:

# Grant only the named variable already present in the invoking process environment.
bv --export-pages ./bv-pages \
  --trust-hooks 'sha256:REVIEWED_64_HEX_DIGEST' \
  --hook-env GITHUB_TOKEN

Repeat --hook-env NAME to grant additional variables; supply names, never NAME=value assignments or wildcards. Grants apply to all approved hooks in this invocation and do not themselves authorize hooks. YAML env entries remain useful for literal values and $VAR/${VAR} expansion, but expansion sees only the filtered environment, user-granted variables, export context, and earlier entries in sorted key order. Environment name matching follows the platform: case-sensitive on Unix and case-insensitive on Windows. Hook context still provides BV_EXPORT_PATH, BV_EXPORT_FORMAT, BV_ISSUE_COUNT, and BV_TIMESTAMP.

The default inherited names are PATH, HOME, TMPDIR, TMP, TEMP, LANG, LANGUAGE, TZ, TERM, LC_ALL, and the exact locale categories LC_ADDRESS, LC_COLLATE, LC_CTYPE, LC_IDENTIFICATION, LC_MEASUREMENT, LC_MESSAGES, LC_MONETARY, LC_NAME, LC_NUMERIC, LC_PAPER, LC_TELEPHONE, and LC_TIME. XDG_CONFIG_HOME, XDG_CACHE_HOME, XDG_DATA_HOME, and XDG_STATE_HOME preserve user-selected configuration and data locations. Windows also inherits SYSTEMROOT, WINDIR, SYSTEMDRIVE, COMSPEC, PATHEXT, USERPROFILE, HOMEDRIVE, HOMEPATH, APPDATA, LOCALAPPDATA, and valid per-drive working-directory entries such as =C:. These names are exact; arbitrary LC_ or XDG_ variables are not admitted. No other ambient tool settings, proxy URLs, runtime startup options, or session capabilities are inherited without a grant.

Credential containers such as DOCKER_AUTH_CONFIG, GIT_CONFIG_PARAMETERS, GIT_CONFIG_COUNT, and numbered GIT_CONFIG_KEY_ / GIT_CONFIG_VALUE_ variables remain withheld unless explicitly granted. To forward indexed Git configuration, grant GIT_CONFIG_COUNT and each required key/value variable by its exact name. Granting the count does not grant the entries; an incomplete set can make Git reject its configuration. A value-only grant can support a YAML alias without enabling the indexed Git configuration. The packed GIT_CONFIG_PARAMETERS format requires its own explicit grant. Tool-specific settings such as GIT_CONFIG_GLOBAL, proxy variables, or a custom build-mode variable also require grants if your automation uses them.

Both execution forms require the same explicit approval and credential grants and receive the same export context. Existing command hooks retain their shell syntax. Timeouts and failure policies apply to both forms: by default, pre-export hooks fail fast on errors (on_error: fail), while post-export hooks log and continue (on_error: continue). A post-export hook declared on_error: fail makes the export exit 1 even though the output has already been written. Combining a nonempty command with argv, or supplying an empty, null, or malformed argv, rejects the configuration before any hook runs. Legacy entries with an empty command and no argv are still omitted with normalization warnings in --hooks-info. --no-hooks takes precedence over approval and credential grants.

Hooks run synchronously on Linux, macOS, and Windows. Remaining processes in the hook's process group (Linux/macOS) or Job Object (Windows) are terminated when the initial shell or program exits or its timeout expires, including background children that keep output pipes open. Start long-lived services outside the export hook pipeline. On Linux/macOS, a command that deliberately leaves its process group can escape that cleanup; approved code retains your operating-system privileges. Hook execution on other platforms is refused; use --no-hooks to export there.

Each hook retains at most 1 MiB (1,048,576 bytes) of stdout and 1 MiB of stderr. Excess output is drained and discarded. Hook results expose StdoutTruncated and StderrTruncated, and the execution summary identifies truncated streams. Truncation alone does not fail a hook or change its on_error policy.

Approval permits arbitrary code execution with your operating-system privileges. Direct argv execution and environment filtering are not sandboxes: an approved program or explicitly selected interpreter can access files, launch programs, and use the network. The digest approves hook declarations, not the transitive contents of referenced scripts or executables. Review changes to those dependencies before running approved hooks again. The interactive --pages wizard, TUI exports, and robot analysis do not run this hook pipeline.


🤖 Ready-made Blurb to Drop Into Your AGENTS.md or CLAUDE.md Files

The text below is exactly what bv --agents-add (and the TUI's AGENTS.md prompt) installs (pkg/agents/blurb.go, AgentBlurb); a docs parity test keeps this copy identical to it.

<!-- bv-agent-instructions-v7 -->


Beads Workflow Integration

This project uses a Beads tracker—either the Go bd CLI or the Rust br CLI—for issue tracking, plus beads_viewer (bv) for graph-aware triage. Issues are stored in .beads/. bv auto-discovers supported JSONL exports, including .beads/issues.jsonl and legacy .beads/beads.jsonl.

Choose the tracker CLI from this repository's instructions and configuration. Use bd commands in a Go Beads workspace and br commands in a beads_rust workspace. Do not run both trackers against the same workspace or infer the tracker solely from the JSONL filename.

Using bv as an AI sidecar

bv is a graph-aware triage engine for Beads projects. Instead of parsing .beads/issues.jsonl / .beads/beads.jsonl directly or hallucinating graph traversal, use robot flags for deterministic, dependency-aware outputs with precomputed metrics (PageRank, betweenness, critical path, cycles, HITS, eigenvector, k-core).

Scope boundary: bv handles what to work on (triage, priority, planning). The selected tracker CLI (bd or br) handles creating, claiming, modifying, and closing beads.

CRITICAL: Use ONLY --robot-* flags. Bare bv launches an interactive TUI that blocks your session.

The Workflow: Start With Triage

bv --robot-triage is your single entry point. Its triage object contains:

  • quick_ref: at-a-glance counts + top 3 picks
  • recommendations: ranked actionable items with scores, reasons, unblock info
  • quick_wins: low-effort high-impact items
  • blockers_to_clear: items that unblock the most downstream work
  • project_health: status/type/priority distributions, graph metrics
  • commands: copy-paste shell commands for next steps
bashbv --robot-triage # THE MEGA-COMMAND: start here bv --robot-next # Minimal: just the single top pick + claim command

TOON output (--format toon): a compact tabular encoding. Measured on this

repository it is 7% smaller than JSON for --robot-graph but 9-15% LARGER for

nested payloads (--robot-triage, --robot-plan, --robot-insights,

--robot-label-health); use --stats to see both sizes before adopting it.

TOON encoding shells out to the tru binary. With no encoder installed,

--format toon prints a fallback warning, emits JSON with output_format "json",

and --stats prints no sizes at all.

bv --robot-graph --format toon bv --robot-triage --format toon --stats
Recommendations can include blocked or assigned work; triage.quick_ref.top_picks reflects snapshot readiness. A suggested action records its original local ID, working directory, and tracker route. Use that route rather than a namespaced display ID or an unrelated current directory. Inspect current tracker state before execution: analysis does not reserve work or guarantee that a later claim succeeds.

Other bv Commands

| Command | Returns | |---------|---------| | --robot-plan | Parallel execution tracks with unblocks lists | | --robot-priority | Priority misalignment detection with confidence | | --robot-insights | Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core | | --robot-alerts | Stale issues, blocking cascades, priority mismatches | | --robot-suggest | Hygiene: duplicates, missing deps, label suggestions, cycle breaks | | --robot-diff --diff-since <ref> | Changes since ref: new/closed/modified issues | | --robot-graph [--graph-format=json\|dot\|mermaid] | Dependency graph export |

Robot analysis commands default to JSON; --format toon selects TOON, and --robot-help defaults to text. In JSON mode, --graph-format=dot or mermaid puts diagram text in the graph field (bv --robot-graph --graph-format=dot | jq -r .graph).

Scoping & Filtering

bash bv --robot-plan --label backend # Scope to label's subgraph bv --robot-insights --as-of HEAD~30 # Historical point-in-time bv --recipe actionable --robot-plan # Pre-filter: ready to work (no blockers) bv --recipe high-impact --robot-triage # Pre-filter: top PageRank scores
### Tracker Commands for Issue Management

Use exactly one command family, matching the tracker configured for the repository.

Rust beads_rust (br)

Use br 0.6.0 or newer when executing saved claim commands. It rechecks deferred status and future defer_until values when the claim runs, so a recommendation captured before a deferral cannot bypass it. This requirement applies to executing tracker claims.

bash br ready --json # Show issues ready to work (no blockers) br list --status=open --json # All open issues br show --json # Full issue details with dependencies br create --title="..." --type=task --priority=2 --json br update --claim --json # Claim for the current actor and start work br close --reason="Completed" --json br close --reason="Completed" --json br sync --flush-only # Export DB to JSONL after Beads mutations
#### Go Beads (bd)
bash bd ready --json # Show issues ready to work bd show --json # Full issue details bd create "..." -t task -p 2 --json bd update --claim --json # Atomically claim work bd close --json bd dep add bd export -o .beads/issues.jsonl # Refresh the compatibility export read by bv
### Workflow Pattern

  1. Triage: Run bv --robot-triage to find the highest-impact actionable work
  2. Verify: Check the selected tracker's show/ready output before claiming
  3. Claim: Use br update <id> --claim --json or bd update <id> --claim --json
  4. Work: Implement the task
  5. Complete: Use the selected tracker's close command
  6. Refresh for bv: Run br sync --flush-only or the bd export command above so the JSONL export is current

Key Concepts

  • Dependencies: Issues can block other issues. br ready --json and bd ready --json show unblocked work.
  • Priority: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers 0-4, not words)
  • Types: task, bug, feature, epic, chore, docs, question
  • Blocking: Use br dep add <issue> <depends-on> or bd dep add <issue> <depends-on> to add dependencies

Git Policy

Tracker commands do not grant permission to commit or push application code. Follow this repository's own git and tracker instructions before staging, committing, syncing, or pushing. If the repository says "commit only when asked," that rule overrides any generic workflow advice.

<!-- end-bv-agent-instructions -->

Version Tracking:

The blurb uses HTML comment markers for version tracking:

<!-- bv-agent-instructions-v7 -->
... content ...
<!-- end-bv-agent-instructions -->

When a new version of the blurb is released, bv can detect the outdated version and offer to update it.


📐 Architecture & Design

bv treats your project as a directed dependency graph, including cycles when present. Its graph metrics help identify blockers and structural importance.

graph TD
    %% Soft Pastel Theme — Refined
    classDef data fill:#e3f2fd,stroke:#90caf9,stroke-width:2px,color:#1565c0,rx:8
    classDef logic fill:#fff8e1,stroke:#ffcc80,stroke-width:2px,color:#e65100,rx:8
    classDef ui fill:#f3e5f5,stroke:#ce93d8,stroke-width:2px,color:#6a1b9a,rx:8
    classDef output fill:#e8f5e9,stroke:#a5d6a7,stroke-width:2px,color:#2e7d32,rx:8

subgraph storage [" 📂 Data Layer "] A[".beads/issues.jsonl<br/>or legacy beads.jsonl<br/>JSONL Issue Store"]:::data end

subgraph engine [" ⚙️ Analysis Engine "] B["Loader"]:::logic C["Graph Builder"]:::logic D["9 Metrics<br/>PageRank · Betweenness · HITS..."]:::logic end

subgraph interface [" 🖥️ TUI Layer "] E["Bubble Tea Model"]:::ui F["List View"]:::ui G["Graph View"]:::ui G2["Tree View"]:::ui H["Insights Dashboard"]:::ui end

subgraph outputs [" 📤 Outputs "] I["--robot-insights<br/>JSON for AI Agents"]:::output J["--export-md<br/>Markdown Report"]:::output end

A --> B B --> C C --> D D --> E D --> I D --> J E --> F E --> G E --> G2 E --> H

linkStyle 0,1,2 stroke:#90caf9,stroke-width:2px linkStyle 3,4,5 stroke:#ffcc80,stroke-width:2px linkStyle 6,7,8,9 stroke:#ce93d8,stroke-width:2px

Key Metrics & Algorithms

bv computes 9 graph-theoretic metrics to surface hidden project dynamics:

| # | Metric | What It Measures | Key Insight | |---|--------|------------------|-------------| | 1 | PageRank | Recursive dependency importance | Foundational blockers | | 2 | Betweenness | Shortest-path traffic | Bottlenecks & bridges | | 3 | HITS | Hub/Authority duality | Epics vs. utilities | | 4 | Critical Path | Longest dependent chain in task counts | Prerequisites supporting long chains | | 5 | Eigenvector | Influence via neighbors | Strategic dependencies | | 6 | Degree | Direct connection counts | Immediate blockers/blocked | | 7 | Density | Directed edges / possible edges: E / (N × (N−1)) for N > 1 | Project coupling health | | 8 | Cycles | Circular dependencies | Structural errors | | 9 | Topo Sort | Prerequisites-first order for acyclic graphs | Structural order; readiness still requires lifecycle and dependency checks |

1. PageRank (Dependency Authority)

The Math: Originally designed to rank web pages by "importance" based on incoming links, PageRank models a "random surfer" walking the graph. In our dependency graph (u → v implies u depends on v), we treat dependencies as "votes" of importance. $$ PR(v) = \frac{1-d}{N} + d \sum_{u \in M(v)} \frac{PR(u)}{L(u)} $$

The Intuition: If many tasks depend on Task A, or if a single very important Task B depends on Task A, then Task A implicitly becomes "heavy." A random walker following dependency links will frequently get stuck at Task A.

Pragmatic Meaning: Foundational Blocks. High PageRank tasks are the bedrock of your project. They are rarely "features" in the user-facing sense; they are often schemas, core libraries, or architectural decisions. Breaking them breaks the graph.

2. Betweenness Centrality (Bottlenecks)

The Math: Defined as the fraction of all shortest paths in the network that pass through a given node $v$. $$C_B(v) = \sum_{s \neq v \neq t} \frac{\sigma_{st}(v)}{\sigma_{st}}$$

The Intuition: Imagine information (or progress) flowing from every task to every other task along the most efficient route. "Bridge nodes" that connect otherwise isolated clusters (e.g., the Frontend cluster and the Backend cluster) will see a massive amount of traffic.

Pragmatic Meaning: Gatekeepers & Bottlenecks. A task with high Betweenness is a choke point. It might be an API contract that both the mobile app and the server team are waiting on. If this task is delayed, it doesn't just block one thread; it prevents entire sub-teams from synchronizing.

3. HITS (Hubs & Authorities)

The Math: An iterative algorithm that defines two scores for every node:
  • Authority: The sum of Hub scores of nodes pointing to it.
  • Hub: The sum of Authority scores of nodes it points to.
The Intuition: This models a "mutually reinforcing" relationship. Good libraries (Authorities) are used by many applications. Good applications (Hubs) use many good libraries.

Pragmatic Meaning: Epics vs. Infrastructure.

  • High Hub Score: These are your Epics or Product Features. They aggregate many dependencies to deliver value.
  • High Authority Score: These are your Utilities. They provide value to many consumers.

4. Critical Path (Longest Path in DAG)

The Math: In a DAG, bv measures unweighted chain depth in tasks. Edges point from a dependent to its prerequisite, so the score is: $$Impact(u) = 1 + \max(\{Impact(v) \mid v \to u\} \cup \{0\})$$ The implementation evaluates this in topological order. This node-count metric does not use task durations or establish a minimum project completion time.

The Intuition: If you hold the graph by its "leaf" nodes (tasks with no dependencies) and let it dangle, the tasks at the very top that support the longest chains are carrying the most weight.

Pragmatic Meaning: Keystones. High scores identify prerequisites supporting long dependent chains. Inspect the separate Slack metric for structural scheduling flexibility; neither metric proves that a delay translates one-for-one into delivery time. Cyclic graphs can leave critical-path metrics unavailable, as reported by .status.Critical.

5. Eigenvector Centrality (Influential Neighbors)

The Math: Eigenvector centrality measures a node's influence by considering not just its connections, but the importance of those connections. A node with few but highly influential neighbors can score higher than a node with many unimportant neighbors. $$x_i = \frac{1}{\lambda} \sum_{j \in N(i)} x_j$$

Where $\lambda$ is the largest eigenvalue of the adjacency matrix and $N(i)$ are neighbors of node $i$.

The Intuition: It's not just how many connections you have, but who you're connected to. Being depended on by a critical task makes you more important than being depended on by many trivial tasks.

Pragmatic Meaning: Strategic Dependencies. High Eigenvector tasks are connected to the "power players" in your graph. They may not have many direct dependents, but their dependents are themselves critical.

6. Degree Centrality (Direct Connections)

The Math: The simplest centrality measure—just count the edges. $$C_D^{in}(v) = |\{u : u \to v\}|$$

$$C_D^{out}(v) = |\{u : v \to u\}|$$

The Intuition:

  • In-Degree: How many tasks depend on me? (I am a blocker)
  • Out-Degree: How many tasks do I depend on? (I am blocked)
Pragmatic Meaning: Immediate Impact.
  • High In-Degree: This task is a direct blocker for many others. Completing it can make its dependents ready when their remaining prerequisites and eligibility conditions are satisfied.
  • High Out-Degree: This task has many prerequisites. It's likely to be blocked and should be scheduled later in the execution plan.

7. Graph Density (Interconnectedness)

The Math: Density measures how "connected" the graph is relative to its maximum possible connections. $$D = \frac{|E|}{|V|(|V|-1)}$$

Where $|E|$ is the edge count and $|V|$ is the node count. For a directed graph, the maximum edges is $|V|(|V|-1)$.

The Intuition: A density of 0.0 means no dependencies exist (isolated tasks). A density approaching 1.0 means everything depends on everything (pathological complexity).

Pragmatic Meaning: Project Health Indicator.

  • Low Density (< 0.05): Healthy. Tasks are relatively independent and can be parallelized.
  • Medium Density (0.05 - 0.15): Normal. Reasonable interconnection reflecting real-world dependencies.
  • High Density (> 0.15): Warning. Overly coupled project. Consider breaking into smaller modules.

8. Cycle Detection (Circular Dependencies)

The Math: A cycle in a directed graph is a path v₁ → v₂ → ⋯ → vₖ → v₁ where the start and end nodes are identical. bv uses Tarjan's strongly connected components algorithm and extracts one representative cycle from each cyclic component. It analyzes blocking edges among non-closed, non-tombstoned issues, applies a storage cap, and reports truncation in .status.Cycles.reason. It does not enumerate every elementary cycle; breaking one reported cycle can leave others in the same component.

The Intuition: If A depends on B, and B depends on A, neither can ever be completed. This is a logical impossibility that must be resolved.

Pragmatic Meaning: Structural Errors. Cycles are bugs in your project plan, not just warnings. They indicate:

  • Misclassified dependencies (A doesn't really block B, or vice versa)
  • Missing intermediate tasks (A and B both depend on an unstated C)
  • Scope confusion (A and B should be merged into a single task)

9. Topological Sort (Execution Order)

The Math: A topological ordering of a DAG is a linear sequence of all vertices such that for every edge u → v, vertex u appears before v in the sequence. Only acyclic graphs have valid topological orderings.

The Intuition: Edge direction matters. In bv's stored graph, A → B means A depends on B. A raw topological ordering of those edges puts A before B; bv reverses that ordering so its published order puts prerequisites first. The cross-label Flow Matrix presents the opposite edge direction, from blocker to dependent.

Pragmatic Meaning: Work Queue. --robot-plan checks dependency eligibility and groups actionable work into tracks. Raw topological order alone does not establish readiness: lifecycle status, unresolved blockers and deferral also matter.


🤖 The Robot Protocol (AI Interface)

bv bridges the gap between raw data and AI agents. Agents struggle with graph algorithms; bv solves this by acting as a deterministic "sidecar" that offloads the cognitive burden of graph traversal.

sequenceDiagram
    %%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#e8f5e9', 'primaryTextColor': '#2e7d32', 'primaryBorderColor': '#81c784', 'lineColor': '#90a4ae', 'secondaryColor': '#fff8e1', 'tertiaryColor': '#fce4ec'}}}%%

participant User participant Agent as 🤖 AI Agent participant BV as ⚡ bv participant File as 📄 Beads JSONL

User->>Agent: "Fix the next blocked task"

rect rgba(232, 245, 233, 0.4) Note over Agent, BV: Cognitive Offloading Agent->>BV: bv --robot-plan BV->>File: Read & Parse BV->>BV: PageRank + Topo Sort BV-->>Agent: { next: "TASK-123", unblocks: 5 } end

rect rgba(255, 243, 224, 0.3) Note over Agent: Implementation Phase Agent->>Agent: Fix TASK-123 Agent->>BV: bv --robot-insights BV-->>Agent: Updated graph metrics end

The "Cognitive Offloading" Strategy

The primary design goal of the Robot Protocol is Cognitive Offloading. Large Language Models (LLMs) are probabilistic engines; they are excellent at semantic reasoning (coding, writing) but notoriously unreliable at algorithmic graph traversal (finding cycles, computing shortest paths). The two-phase analyzer returns degree/topo/density first and computes the remaining metrics asynchronously with size-aware timeouts. Graph-stat caches are keyed by issue data and analysis configuration; readiness and ranking also depend on the selected scope and reference clock. Check each metric's status before interpreting its values.

If you feed an Agent raw Beads JSONL data, you are forcing the Agent to:

  1. Parse thousands of lines of JSON.
  2. Reconstruct the dependency graph in its context window.
  3. "Hallucinate" a path traversal or cycle check.
bv solves this by providing a deterministic graph engine sidecar.

Why bv vs. Raw Beads?

Using beads directly gives an agent data. Using bv --robot-insights gives an agent intelligence.

| Capability | Raw Beads (JSONL) | bv Robot Mode | | :--- | :--- | :--- | | Query | "List all issues." | "List the top 5 bottlenecks blocking the release." | | Context Cost | Full issue records grow with issue count. | Compact summaries and capped metric maps; source diagnostics and graph output can still grow with the project. | | Graph Logic | Agent must infer/compute. | Pre-computed (PageRank/Brandes). | | Safety | Agent might miss a cycle. | Cycles explicitly flagged. |

Agent Usage Patterns

Agents typically use bv in three phases:
  1. Triage & Orientation:
Before starting a session, the agent runs bv --robot-insights. It receives a lightweight JSON summary of the project's structural health. It immediately knows: * "I should not work on Task C yet because it depends on Task B, which is a Bottleneck." * "The graph has a cycle (A->B->A); I must fix this structural error before adding new features."
  1. Impact Analysis:
When asked to "refactor the login module," the agent checks the PageRank and Impact Scores of the relevant beads. If the scores are high, the agent knows this is a high-risk change with many downstream dependents, prompting it to run more comprehensive tests.
  1. Execution Planning:
The agent uses --robot-plan to select currently actionable work and group it into dependency-connected tracks. Items are ordered by priority, then ID within each track; the plan does not assign agents or establish freedom from file conflicts.

JSON Output Excerpt (--robot-insights): Field names are case-sensitive. This excerpt uses illustrative values and omits the source envelope and other metrics; bv --robot-schema describes the complete contract.

{
  "Bottlenecks": [
    { "ID": "CORE-123", "Value": 0.45 }
  ],
  "Keystones": [
    { "ID": "API-001", "Value": 12.0 }
  ],
  "Influencers": [
    { "ID": "AUTH-007", "Value": 0.82 }
  ],
  "Hubs": [
    { "ID": "EPIC-100", "Value": 0.67 }
  ],
  "Authorities": [
    { "ID": "UTIL-050", "Value": 0.91 }
  ],
  "Cycles": [
    ["TASK-A", "TASK-B", "TASK-A"]
  ],
  "ClusterDensity": 0.045,
  "full_stats": {
    "pagerank": { "CORE-123": 0.15 },
    "betweenness": { "CORE-123": 0.45 },
    "eigenvector": { "AUTH-007": 0.82 },
    "critical_path_score": { "API-001": 12.0 }
  },
  "status": {
    "PageRank": { "state": "computed" },
    "Cycles": { "state": "computed" }
  }
}

| Field | Metric | What It Contains | |-------|--------|------------------| | Bottlenecks | Betweenness | Top nodes bridging graph clusters (ID/Value records) | | Keystones | Critical Path | Top nodes on longest dependency chains | | Influencers | Eigenvector | Top nodes connected to important neighbors | | Hubs | HITS Hub | Top dependency aggregators (Epics) | | Authorities | HITS Authority | Top prerequisite providers (Utilities) | | Cycles | Cycle Detection | Stored representative cycles; inspect status.Cycles for skips, timeouts and truncation | | ClusterDensity | Density | Overall graph interconnectedness | | full_stats | Metric maps | Per-issue values, capped by BV_INSIGHTS_MAP_LIMIT (default 200) |


🎨 TUI Engineering & Craftsmanship

bv is built with the Bubble Tea framework. Its adaptive layout responds to terminal resize events, and its custom graph renderer supports ASCII and Unicode. A 60fps frame budget is a design target; actual interaction latency depends on the graph, view, terminal, and host.

flowchart LR
    classDef core fill:#fef3e2,stroke:#f5d0a9,stroke-width:2px,color:#8b5a2b
    classDef engine fill:#f0e6f6,stroke:#d4b8e0,stroke-width:2px,color:#5d3a6b
    classDef ui fill:#e6f3e6,stroke:#b8d9b8,stroke-width:2px,color:#2d5a2d
    classDef output fill:#e8f4f8,stroke:#b8d4e3,stroke-width:2px,color:#2c5f7c

INPUT["⌨️ Input<br/>Keys · Mouse · Resize"]:::core MODEL["🫖 Model<br/>Issues · Stats · Focus"]:::core GRAPH["🧮 Graph Engine<br/>PageRank · HITS · Cycles"]:::engine VIEWS["🖼️ Views<br/>List · Board · Graph · Tree · Insights"]:::ui LAYOUT["📐 Layout<br/>Mobile · Split · Wide"]:::ui TERM["🖥️ Terminal<br/>Rendered Output"]:::output

INPUT -->|tea.Msg| MODEL GRAPH -->|metrics| MODEL MODEL -->|state| VIEWS VIEWS --> LAYOUT LAYOUT --> TERM

linkStyle 0 stroke:#f5d0a9,stroke-width:2px linkStyle 1 stroke:#d4b8e0,stroke-width:2px linkStyle 2 stroke:#b8d9b8,stroke-width:2px linkStyle 3,4 stroke:#b8d4e3,stroke-width:2px

1. Adaptive Layout Engine

bv doesn't just dump text; it calculates geometry on every render cycle.
  • Dynamic Resizing: Update() handles terminal-size messages and resizes the views.
  • Terminal Breakpoint: At 100 columns or fewer, the list uses a single pane. Above 100 columns, the default split allocates 40% of the available content width to the list and 60% to details, after panel overhead. The pane ratio is adjustable.
  • Optional Row Columns: The default list delegate uses the actual list-row width, not terminal width: above 100 cells it can show an assignee, above 120 a graph-score sparkline, and above 140 label tags. A 140-column terminal with the default split does not have room for these columns.
  • Padding Awareness: The layout engine explicitly accounts for borders (2 chars) and padding (2 chars) to prevent "off-by-one" wrapping errors that plague many TUIs.

2. Viewport Virtualization

bv limits list rendering to visible rows, including when browsing 10,000 issues:
  • Windowing: We only render the slice of rows currently visible in the terminal window.
  • Pre-Computation: Expensive graph metrics are computed asynchronously at startup and when source snapshots change. Navigation reuses the completed results.
  • Detail Caching: The Markdown renderer is reused. It can retain the last exact render within a 512 KiB input/output budget; selecting a different issue renders its actual details. Virtualizing the list does not eliminate the cost of rendering long details or analyzing a large graph.

3. Visual Graph Engine (pkg/ui/graph.go)

We built a custom 2D ASCII/Unicode rendering engine from scratch to visualize the dependency graph.
  • Line Canvas: The renderer assembles styled strings into a line-based canvas and clips it to the viewport.
  • Dependency Neighborhood: The selected issue appears between its blockers above and its dependents below, joined by Unicode connectors. Impact scores order the node selector; this is not a whole-graph topological layout.
  • Panning: Horizontal and vertical scrolling reveal portions of the selected neighborhood outside the viewport.

4. Thematic Consistency

We use Lipgloss to enforce a strict design system.
  • Semantic Colors: Colors are defined semantically (Theme.Blocked, Theme.Open) rather than hardcoded hex values. This allows bv to switch between "Dracula" (Dark) and "Light" modes seamlessly.
  • Status Indicators: We use Nerd Font glyphs (🐛, ✨, 🔥) paired with color coding to convey status instantly without reading text.

📈 Visual Data Encoding: Sparklines & Heatmaps

In dense information environments like the terminal, text is expensive. bv employs high-density data visualization techniques (pkg/ui/visuals.go) inspired by Edward Tufte to convey complex metrics in minimal space.

1. Unicode Sparklines

When viewing the list in Ultra-Wide mode, bv renders a "Graph Score" column using Unicode block characters ( , ▂, ▃, ▄, ▅, ▆, ▇, █).
  • The Math: RenderSparkline(val, width) normalizes a float value (0.0 - 1.0) against the available character width. It calculates the precise block height for each character cell to create a continuous bar chart effect.
  • The Utility: This allows you to scan a list of 50 issues and instantly spot the "spikes" in complexity or centrality without reading a single number.

2. Semantic Heatmaps

GetHeatmapColor in pkg/ui/visuals.go maps scores to four discrete themed bands:
  • ≤ 0.2: Low (Theme.Secondary)
  • > 0.2 through 0.5: Mid (Theme.InProgress)
  • > 0.5 through 0.8: High (Theme.Feature)
  • > 0.8: Peak (Theme.Primary)
These colors style the list's graph-score sparklines; they indicate score bands, not an independent urgency classification.

🔍 Search Architecture

The TUI's / filter performs local fuzzy matching over a composite string for each list item. This differs from --search, which uses hashed keyword vectors ov

... (README truncated for length)

Chat with me