A small collection of Python CLI scripts that augment
bd (the beads issue
tracker) and its Dolt-backed storage. No package, no build step —
each script lives at the repo root alongside a shared bdutils.py
helper and runs with python3 (or uv for the one script that
needs rich).
| Script | What it does |
|---|---|
bd-export-csv |
Export the bead database to a flat CSV for spreadsheet review |
bd-dolt-check |
Verify the Dolt data behind a bd repo is actually pushed to its git remote |
bd-dolt-diff |
Preview what a bd dolt push would send: issue-level diff between local and remote Dolt state |
bd-log |
Git-log-style timeline of bead and memory lifecycle events — created, changed, ended (color-coded, auto-paged) |
claude-session-find |
Substring search across ~/.claude/projects/*.jsonl to find old Claude Code sessions |
claude-session-list |
Git-log-style listing of Claude Code sessions (default: current project; -g for all) |
claude-session-rename |
Set a Claude Code session's title from the shell, like /rename, without starting the session |
bd-view |
Pretty-print a single bead with rendered Markdown |
claude-session-report |
Render a Claude Code session as a Markdown discussion transcript |
bd-complete |
Emit completion candidates (bead ids, session uuids) — the helper behind shell tab completion |
Run any script with --help for full usage. Per-script details and
conventions live in CLAUDE.md; see
CONTRIBUTING.md to contribute.
The scripts fall into two families: tools for looking at your beads, and tools for looking at your Claude Code sessions. Either way the theme is the same — the data is already on your disk; these make it pleasant to read.
When an issue carries a long description — design notes, acceptance
criteria, nested lists — bd show prints the raw Markdown as one long
wall of text. bd-view beads-utils-s4s (that's an issue id) renders it
instead: real headings, real code blocks, dependencies and comments
included, paged like git log. Field coverage is a superset of bd show's — labels, external refs, the metadata dict, parent and children
each shown as themselves — and anything bd grows later lands in a
trailing Other Fields section rather than silently disappearing.
Agentic coding changes what an issue tracker has to answer. A Claude
session can create, claim, and close half a dozen beads while your
attention was on the code, and afterwards you want to know what it
actually did. bd-log shows the lifecycle events — created, started,
closed — newest first, git-log style. bd-log --open narrows to beads
still open: the to-do list the session left behind (--no-deferred drops
the ones parked with bd defer, and --no-blocked the ones waiting on
something else to finish), and bd-log --id <id> --children narrows the other way — one bead, or one epic and
everything under it, from creation to close. --oneline collapses each
event to a single row when you want the shape of the week rather than
the detail of any one entry.
Beads are only half of what a session leaves behind. The other half is
what it learned — the memories bd remember accumulates, which shape
every future session and which nothing otherwise shows you the history
of. bd remember stores no timestamps, so bd-log reconstructs them
from the Dolt commits underneath and folds them into the same timeline:
--about=memories for that history on its own, --about=memories --only=end for the ones that were dropped. Events are a small grid —
--only picks the verb (create, change, end), --about picks
whether it happened to a bead or to a memory — and both default to
everything, so a plain bd-log now answers "what happened here" for
both. This one part needs the dolt CLI; without it the bead half still
works exactly as before.
Sometimes the right reading tool is a spreadsheet — sorting issues for a
triage meeting, or sharing the list with someone who doesn't live in a
terminal. bd-export-csv --sort=-priority,created_at flattens the whole
database to a CSV, presorted before the spreadsheet even opens.
The last pair guards against a quiet failure mode. Beads keeps its data
in Dolt and pushes it to your git remote under refs/dolt/data — a ref
GitHub's UI never shows, so the repo page looks identical whether or not
your issues actually made it to the remote. bd-dolt-check answers
"did they?", comparing local state against the remote and exiting
non-zero on drift (which also makes it a CI gate). bd-dolt-diff
answers the follow-up — what exactly would a bd dolt push send? —
with an issue-level diff: added and removed beads, field-by-field
changes, dependency and comment edits.
claude --resume offers a picker of recent sessions, but the picker is
cramped and can't be scripted. claude-session-list is the long-form
version: the sessions for the current project (or every project, with -g),
each with its full UUID ready to paste, a timestamp range with the
active span, prompt/reply counts, and the session title. --oneline
gives a compact table; claude-session-list -q | head -1 hands a
script the newest UUID.
That covers "which session was most recent"; claude-session-find
covers "which session was it where we discussed the pager?" It greps
the transcripts for a substring and lists the matching sessions with
snippets for context — or, with --oneline, just the sessions and their
hit counts. claude --resume $(claude-session-find -q pager | head -1)
drops you straight back into the conversation.
And when a session turns out to be worth keeping — a design discussion,
a long debugging hunt — claude-session-report renders it as a
Markdown transcript: your prompts, Claude's replies, and (with --all)
the tool calls and every other channel too. The result is a document you can
review at leisure, commit next to the code it produced, or hand to a
colleague who asks "how did you get Claude to do that?"
Titles are what make the picker and these scripts navigable, and
/rename only works from inside a running session. claude-session-rename
sets one from the shell — claude-session-rename <uuid> 'Pager design' —
so an old session can be labelled after the fact, or a batch of them from
a loop, without resuming each one. It writes exactly what /rename would,
and refuses a session that is currently running, where /rename itself is
the right tool.
There's still no package and no build step — but there is a Makefile, so you
don't have to remember any of the invocations. make help lists everything:
make test # run the test suite
make check # ruff, plus a --version smoke test of every script
make ci # everything CI runs
make dolt-check # verify this repo's own beads data is pushedDependencies resolve through uv into a throwaway environment, so nothing is
installed globally. CI runs these same targets, so a green make ci locally
means a green CI.
The suite in tests/ is fixtures all the way down: bd and dolt
are replaced by programmable fakes on PATH, and Claude session history by
synthetic .jsonl trees under a temporary HOME. Nothing touches a real beads
project or your session history.
Tab completion for zsh and bash lives in completions/.
bd-view completes bead ids (with titles shown in zsh),
claude-session-report completes session uuids/titles, the project-path
scripts complete directories, and every script completes its flags.
Options that take a value complete in either spelling (--id beads-1 or
--id=beads-1), and the comma-separated ones with a known vocabulary
(bd-log's --id, --only, --about and --status;
claude-session-list --sort) complete one element at a time, so
--only=create,ch finishes as --only=create,change.
Source the file for your shell from your rc file:
# ~/.zshrc (oh-my-zsh users: put this *after* `source $ZSH/oh-my-zsh.sh`)
source /path/to/beads-utils/completions/beads-utils.zsh
# ~/.bashrc
source /path/to/beads-utils/completions/beads-utils.bashThe scripts (including bd-complete, which feeds the dynamic candidates)
must be on your $PATH. The file is read when the shell starts, so after
pulling a release that adds a flag, start a new shell — an existing one
still holds the old definitions and will complete nothing for it.
Prefer the autoload convention instead? Drop
beads-utils.zsh into a directory on your $fpath, or beads-utils.bash
into your bash-completion.d.
Released under the MIT License.