beads_dart
A pure-Dart client for the beads (bd) issue tracker — the M1 kernel of
the_grid, wearing its ecosystem name (recorded in the repo's
alignment amendment).
It knows beads facts only: the Bead/GraphSnapshot value models, the
enveloped-JSON codec, the bd CLI wrapper, workspace discovery
(server/embedded), the pooled Dolt SQL read path + @@<db>_working probe,
dirty-signal watchers, structural diff, and the typed GraphEvent runtime.
the_grid's own opinions on top of those facts — ownership predicates,
driveability narrowing, session-bead semantics — live in grid_engine, not
here.
Seat: the base of the workspace. grid_engine, grid_runtime,
grid_cli, grid_sdk, and grid_exploration all depend on it directly
(grid_devtools deliberately does not — it consumes the engine only,
package-topology docs). It is framework-free at the package boundary
: Futures for acts, Streams for observations, a synchronous
current where a seed value is needed; no riverpod, no StateNotifier —
consumers build their notifiers/providers on top.
Key entry points
BdRunner(src/services/bd_runner.dart) — the single subprocess seam: runs onebdinvocation underBD_JSON_ENVELOPE=1and returns aBdResult. Real implProcessBdRunner; tests inject aFakeBdRunner.BdEnvelope(src/codecs/envelope.dart) — decodes bd's--jsonenvelope{schema_version, data}, assertingschema_version == 1; drift throwsBdSchemaDriftException, malformed JSON throwsBdParseException.BdCliService(src/services/bd_cli_service.dart) — everybdsubcommand as a typed Future over aBdRunner. Mutations go throughbdonly — never SQL — and carry--actor grid-controller; multi-id reads are chunked so a large id set never becomes one spawn per id.BeadsWorkspace(src/services/beads_workspace.dart) — discovers a workspace, reads bd'smetadata.json, and passes a workspace-scopedEndpointResolutionRequestto an injectedEndpointResolver. The default resolves only bd's proxied-server artifacts;endpointDiagnosticexplains every null endpoint before consumers use the CLI read path.diffSnapshots/GraphEvent(src/diff/) — structural diff of twoGraphSnapshots into a sealed, exhaustively-matchable event hierarchy (BeadCreated/Updated/Closed/Reopened,DependencyAdded/Removed,ReadySetChanged, …).GridRuntimeFactory/GridControllerRuntime(src/reactivity/) — the composed reactive runtime: aBeadsRepositoryover aSnapshotReader(SqlSnapshotReaderpreferred — ~1–5ms pooled SQL, falling back to the authoritativeCliSnapshotReader'sbd export --all+bd readyon any SQL failure), fed by mergedDirtySignalSources (workspace watcher, working-set probe, polling ticker) through theGraphSyncInteractor.
Proxied-server SQL endpoint
The built-in resolver is per workspace: it reads
.beads/proxied_server_client_info.json, then <proxy root>/proxy.pid, and
connects to that proxy's loopback port. SQL also requires an operator-managed,
dedicated read-only beads_dart user with a non-empty password stored at
<proxy root>/beads_dart.secret with mode 0600. The resolver never creates
that user or secret.
If an artifact is missing, malformed, or empty, workspace.endpoint is null
and the runtime uses the bd CLI. Inspect workspace.endpointDiagnostic (or the
full workspace.endpointResolution) for the exact path and remedy. A consumer
with another server topology injects its own EndpointResolver into
BeadsWorkspace.discover; the request is keyed by that workspace's root, raw
dolt_mode, and database, so multi-store processes do not share one ambient
endpoint.
src/ready/ additionally ports beads' ready-work predicate to SELECT-only SQL
(ReadyWorkQuery/ReadyWorkFilter) with ReadyWorkDifferential diffing it
against the bd ready --json oracle (the ready-work port's differential contract).
Version-compat contract
Supports bd >= 1.0.5 — a RANGE, not a pin. Verified against bd 1.0.5
(f9fe4ef2a, schema v50), bd 1.1.0 (Homebrew, schema v53), and bd 1.3.0-rc.1
(9c6a69ec1, schema v66 — rehearsal: fixtures + drift audit, no store moved;
fixtures/upstream/2026-09-02-bd-1.3.0-rc.1/).
Two independent guards back that claim. Every decode path asserts the bd
envelope's schema_version; a mismatch fails loud rather than silently
coercing. The pooled SQL read path probes the store's actual table/column
SHAPE at connect (DoltSchemaShape, one information_schema SELECT) and
builds its dependency-target expression from the columns that are really
there — the migration version is recorded for diagnostics and never compared,
so a newer 1.x store that still carries the read path's columns just works,
and a store that genuinely drifted stands down to the bd CLI naming exactly
what it lost. The bd CLI path (BD_JSON_ENVELOPE=1) is the version-stable
fallback for anything the SQL path will not serve. The full contract is in the
library doc (lib/beads_dart.dart).
Operator hazard — bd doctor --fix and cross-store edges. bd 1.1's
bd doctor --fix treats a raw cross-store bead-id dependency (a foreign bead id stored in
dependencies.depends_on_external, which the origin store's own is_blocked
recompute never reads) as an ORPHAN and removes it. Never run
bd doctor --fix against an org store without excluding cross-store edges.
beads_dart does not inherit that interpretation: depends_on_external is a
REQUIRED column in the shape probe and is always COALESCE'd into the
depends_on_id alias, so a cross-store edge reads back as an ordinary
BeadDependency instead of disappearing.
Tests
Fakes, not mocks: the offline suite drives
BdCliService through a FakeBdRunner with programmed results, and the
reactivity core through FakeSnapshotReader/FakeChangeProbe (+
fake_async). test/integration/ (tagged integration) exercises a real
bd binary: the SQL-vs-CLI equivalence gate and the ready-work differential
run against a live workspace (self-skipping on schema drift or a mid-read
cross-workspace write rather than flaking); the no-SQL-writes/no-hooks
invariants run in a hermetic temp workspace.
cd packages/beads_dart && dart analyze && dart test
Docs
Layering and decisions live at the repo level: the technical-foundation docs (technical
foundations — the envelope pin, bd-only writes, fakes-not-mocks),
the package-topology docs (what stays here vs grid_engine), and
the ready-work-port docs. The repo's build-order notes record
the order this package was built in.
Libraries
- beads_dart
- beads_dart — a pure-Dart beads client.