A web dashboard for Beads projects.
Beadsmith reads your Beads issue databases from a Dolt SQL server and shows
every project, issue, dependency, and recent change in one place, for you and
the people you work with. Agents keep doing the work with bd; Beadsmith only
reads.

- Every project at once. Parade, list, and board views per project, a cross-project Ready deck of unblocked work, and an activity log.
- Accounts. Email and password sign-in with admin and member roles.
- Backups. Scheduled dumps of every project to any S3-compatible bucket, optionally encrypted with your passphrase.
- Agents, optionally. Send an issue to an agent to discuss, elaborate, close, or tackle it, through any runner that speaks a signed webhook.
- Keyboard first (
?lists the keys) and usable at phone width.
Early and changing. Beadsmith runs its author's own Beads server every day, but there are no versioned releases yet:
mainis what ships, and anything can change. Self-host it if that suits you.
Quickstart
You need Docker with Compose v2. From a clone of this repository:
docker compose -f quickstart/compose.yaml up -d --build --wait
docker compose -f quickstart/compose.yaml exec beadsmith cat /state/setup-token
Open http://localhost:4321, paste the token, and create your admin account.
Three sample projects (lighthouse, pantry, trailhead) are waiting, with a
few weeks of made-up history and two agents mid-task.
The first start downloads two base images and builds Beadsmith, usually one
to three minutes; later starts take seconds. Everything stays on your machine: Beadsmith listens on 127.0.0.1 only, Dolt is not
published at all, and every secret is generated on first start. Stop with
docker compose -f quickstart/; add -v to delete the sample
data and your account.
Use your own Beads projects
Beadsmith connects to the Dolt sql-server your projects already use
(bd init --server) and shows every Beads database on it. It needs read
access only, so give it its own user:
CREATE USER 'beadsmith'@'%' IDENTIFIED BY 'a long random password';
GRANT SELECT ON *.* TO 'beadsmith'@'%';
On Dolt, SELECT ON *.* also covers mysql.user, so Beadsmith can read every
SQL account's password hash (unsalted mysql_); Dolt 2.1 and
2.5 ignore REVOKE SELECT ON mysql.* after it. Give every account on that
server a long random password, which makes the hashes useless offline. To keep
Beadsmith away from them instead, grant per project
(GRANT SELECT ON `my_): Beadsmith then shows
only those projects, and each new one needs its own grant.
Then, from the repository root:
cp .env.example .env # set BEADSMITH_UID/GID and the Dolt host
mkdir -p data secrets
(umask 077; cat > secrets/dolt-password) # paste the password, then Ctrl-D
(umask 077; openssl rand -base64 32 > secrets/better-auth-secret)
docker compose up -d --build
cat data/setup-token # one-time token for the first admin account
Open http://localhost:4321 and create the admin account with the token. On a server, put Beadsmith behind a reverse proxy or tunnel on the same machine; see docs/server-deployment.md. Every variable is listed in docs/configuration.md.
Upgrade by pinning a new BEADSMITH_ tag in .env, then
docker compose pull && docker compose up -d. CI publishes
ghcr.io/ and :latest on each green push to main.
Beads compatibility
Beadsmith reads the Beads schema directly, so it checks each project before
reading it. Every column it selects must exist; the bd version that last
wrote the database (local_) is shown in the console.
A project missing a column gets a clear "unsupported schema" error instead
of broken pages; other projects keep working.
| bd release | Schema migrations | Status |
|---|---|---|
| 1.1.x | 53 | Supported, tested in CI (1.1.2) |
| 1.2.x | 53 | Supported, tested in CI (1.2.2) |
| 1.3.x | 66 | Supported, tested in CI (1.3.1) |
| newer | — | Read if every column exists; shown as untested |
CI seeds a project with each release (scripts/) and runs
src/ against it. Add a release by extending
the bd-compat matrix in .github/ and TESTED_
in src/.
Accounts
Beadsmith has built-in accounts (Better Auth, email and password), turned on
by BETTER_. Without them the service serves one implicit
operator and must stay on loopback (optionally behind Cloudflare Access).
- First admin. While no account exists, the server writes a one-time token
to
setup-tokenin the state directory (data/under Compose) and logs where it is. Open/, paste it, and the account you create is the admin. The file is deleted afterwards.auth - Roles.
adminuses the console (dispatch policy, checkout maps, accounts, backups) and launches agents.memberreads every project and issue. Both can change their own password under Account. - More people. In Console → Accounts an admin adds accounts with an initial password, changes roles, resets passwords, and removes accounts. Self sign-up is closed unless an admin opens it (new accounts are then members).
- Cloudflare Access stays optional. When configured it runs before
sign-in, and an allowlisted service token keeps read-only
/access for machines (docs/agent-access.md, docs/public-access.md).api
Lost the last admin's password? The console cannot reset it, so do it from the machine that holds the state directory:
docker compose exec beadsmith node scripts/accounts.ts set-password you@example.com
It asks for the new password twice, shows nothing as you type, and signs that
account out everywhere. Beadsmith can keep running. Two more commands:
promote you@example.com makes an existing account an admin (also signing it
out), and list shows every account and its role. They run the same way.
- The password is never an argument, since arguments end up in shell history.
To script it, pipe one line in:
docker compose exec -T beadsmith node scripts/.accounts.ts set-password you@example.com < password-file - If the container is stopped, use
docker compose run --rm beadsmith node scripts/. For the quickstart, addaccounts.ts ... -f quickstart/.compose.yaml - Without Docker, run
pnpm run accounts ...from a clone (afterpnpm install) withBDX_set to the state directory.STATE_ DIR
Design: ADR-0011.
Backups
Console → Backups dumps every project database to any S3-compatible bucket
(Railway, S3, R2, B2, MinIO) on a schedule, optionally encrypted with your
passphrase; pnpm run restore loads a run back into Dolt. See
docs/backups.md.
Agents
Beadsmith never runs bd or writes issue rows. When an admin sends an issue
to an agent (the Agent action, a, or File/Tackle), Beadsmith records the
request and hands it to the configured provider, today your own runner over a
signed webhook (BDX_). The agent then
changes Beads with bd like any other contributor. See
docs/file-tackle-dispatch.md.
Security model
The process has no local project filesystem, no Beads CLI, and no credential helper or dotenv-loader dependency. It keeps the Dolt password out of state databases, logs, URLs, browser storage, and API responses. SQL reads are parameterized and single-statement; direct lifecycle writes are refused. Host-header, same-origin, CSRF, session, CSP, rate-limit, and response-secret-scrubbing controls are part of the service boundary.
Development
With Node 24 and pnpm 12 (versions in .node-version and package.json):
pnpm install
pnpm run serve # builds, then serves 127.0.0.1:4321
Or let Nix pin the toolchain (devenv; the same
nix/ feeds CI, the image and the VM test):
devenv shell # Node, pnpm, bd and Dolt at the pinned versions
devenv test # pnpm install, check, test
nix flake check # the same gates in the Nix sandbox (+ the NixOS VM test on Linux)
Point it at a Dolt server with BEADS_ and friends; see
Running from source. Before a
pull request:
pnpm run check
pnpm run test
pnpm run build
pnpm run format:check
pnpm run audit
pnpm run audit fails on high/critical advisories; pins are in
docs/dependency-audit.md. The quickstart sample
projects live in quickstart/;
pnpm run quickstart:sample / regenerates the SQL from them.
The maintainer's own deployment is declared here too, in the
ghuntley/overalls layout:
fleet/ with sops-encrypted secrets in
fleet/. A green push to main moves the deploy
branch, and the host updates itself from it
(ADR-0014,
operations guides).
Architecture: specs/, with numbered decisions in
specs/ and the product and security contract
in docs/.
The project website, beadsmith.ericevans.dev
(a landing page plus this README and docs/ as pages), is a static site in
site/.
Security
Please report vulnerabilities through a private security advisory, not a public issue. See SECURITY.md.
Contributing
Issues and outside pull requests are closed for now; questions and ideas are
welcome in Discussions.
The reasoning behind the code lives in this repository: start with
specs/ and the decisions it links.
License
MIT, see LICENSE. Bundled dependencies are listed in THIRD_PARTY_NOTICES.md.