Expand description
The link.md client — the five interconnect verbs dbmd speaks against
a hub: resolve, sync, grant, propose, subscribe.
One binary, two specs (the git precedent: one binary carries both the
object format and the wire protocol). The db.md FORMAT is untouched by this
module: a store never needs link.md to be valid db.md, record files stay
plain markdown, and SPEC.md reserves only the @brain/id address shape.
Everything with a wire or a trust boundary — addressing across stores,
pulling/pushing a hosted copy, capability grants, the propose door, feed
polling and signed-entry verification — lives here, as a client
capability, never a format requirement.
§What this client speaks
The v0 HTTP binding a hub serves under its base URL:
| verb | binding |
|---|---|
resolve | GET /api/hub/brains/<brain> (the brain card) and GET /api/hub/brains/<brain>/resolve?id=… / ?path=… (a record) |
sync (pull) | GET /api/hub/brains/<brain>/export?format=pack — an immutable pack, or the granted slice as plain files |
sync (push) | POST /api/hub/brains/<brain>/push for small snapshots; presign/upload/commit for large snapshots |
grant | GET / POST /api/hub/brains/<brain>/grants, DELETE /api/hub/brains/<brain>/grants/<id> |
propose | POST /api/hub/sites/<handle>/inbox — evidence in, without trust (unauthenticated by design) |
subscribe | GET /api/hub/brains/<brain> + /feed for a locally verified signed head |
§Configuration — no default hub, credential never in the store
There is no built-in hub endpoint: the toolkit is neutral and a hub is whatever the user points it at. Resolution order for the hub URL:
- the
--hub <URL>flag, - the
DBMD_HUB_URLenvironment variable, - the
hub = <URL>line in the store-local.dbmd/configfile (toolkit state, not store content — the walkers already skip hidden directories, so.dbmd/never syncs, indexes, or validates).
The credential is the DBMD_HUB_KEY environment variable, full stop. It is
deliberately not read from .dbmd/config: a secret inside the store
tree is one commit or one push away from leaking, so the file carries only
non-secret targets and the agent’s environment carries the key.
Non-HTTPS hubs are refused (the bearer key must never travel in cleartext) with a loopback exemption for local development.
§v0 honesty
This client binds to what a hub enforces today: grantees are hub
principals (an email), grant scopes are store-path prefixes, pushes are
whole-store snapshots, and subscribe reports feed-head movement. The hub
signs each committed snapshot in a hash-chained feed with a per-brain
Ed25519 identity; this client verifies the content-addressed pack before it
touches disk and verifies the signed feed head on every subscription read.
Structs§
- Address
- A parsed
@brain[/target]address.brainis a hub brain reference — the brain’s ULID id (works for any caller, including cross-party on a public brain) or a slug (which a hub resolves only against the caller’s own brains; slugs are unique per owner, not globally). - Agent
Signing Key - A loaded agent signing key: the PKCS#8 secret plus its derived public multikey. Debug never prints key material.
- Generated
Agent Key - What
dbmd key generatereturns: the public identity to register plus where the secret landed. - Head
- One observation of a brain’s feed head.
- HubConfig
- The resolved client configuration for one invocation.
- HubResponse
- One hub response: the status plus the parsed JSON body when there was one.
- Mirror
Report - What
dbmd mirrormaterialized. - Pull
Report - What a pull materialized.
- Rotation
Report - What
dbmd key rotatereturns.
Enums§
- Address
Target - What the part after
@brain/names. - Capability
- The two capabilities a v0 hub enforces.
- Link
Error - Everything that can go wrong on the wire or at its edges. Each variant maps onto one stable CLI error code; messages are single-line and never echo the credential.
Constants§
- AGENT_
KEY_ FILE_ ENV - Environment variable naming the PATH of an agent signing key file
(link.md §8
LinkMD-Sigproof of possession). When set, authenticated requests are signed per-request with the agent’s Ed25519 key instead of carrying a bearer: the signature binds method + path + body + a ±60s window, so nothing reusable ever crosses the wire or lands in a log or an agent transcript. The file holds the base64url PKCS#8 key minted bydbmd key generate; the path is not a secret, the file is (mode 0600). - BRAIN_
KEY_ FILE_ ENV - Environment variable naming the PATH of a self-custodied BRAIN key file
(link.md §2.4). When set,
sync --pushsigns each feed entry locally and ships it through the pack flow — the hub verifies and stores the exact client bytes and can never sign for the brain. Same file format as agent keys (dbmd key generate). - CONFIG_
REL_ PATH - The store-local config file, relative to the store root. Holds non-secret
toolkit state (
hub = <URL>); hidden, so every store walk skips it. - HUB_
KEY_ ENV - Environment variable carrying the hub bearer credential. The bearer credential source — see the module docs for why it is never store-based.
- HUB_
URL_ ENV - Environment variable naming the hub base URL (e.g.
https://hub.example.com). - MAX_
PROPOSE_ BYTES - The hub’s inbox cap on one
proposesubmission body, mirrored client-side so an oversized body fails before the upload, not after (the same fail-before-upload contract as the push caps). Public so the CLI can pre-check a--body-filefrom file metadata without reading it. - MIRROR_
REL_ DIR - The mirror state directory, relative to the mirror root.
Functions§
- collect_
push_ files - Collect the files a push sends: the store’s owned text —
DB.md,assets.jsonlwhen present, and every content.mdunderrecords/andsources/(the store walk, which already excludes hidden dirs like.dbmd/, thelog/archive, and derivedindex.*catalogs; the hub derives its own index, and local history stays local). Returns(store-relative path, content)pairs, path-sorted. - feed_
entry_ hash - SHA-256 hex of one feed entry’s stored bytes (
exact JSON + "\n") — the entry hash every consumer recomputes (SPEC §5.3). - generate_
agent_ key - Mint a fresh Ed25519 agent keypair. The secret is written to
out(base64url PKCS#8, one line, 0600, refusing to overwrite); only public identity is returned. The private key never enters a store and never travels — requests carry per-request signatures instead (link.md §8). - grant_
issue - Issue (or refresh) a grant on
braintograntee— a hub principal named by email in v0 (the protocol’s near-term simplification; key-named grantees arrive with the signing layer).scopeis a store-path prefix (the hub’s enforcement unit);untilan ISO 8601 expiry, absent = until revoked. - grant_
list - List the active grants (and pending invites) on
brain. Owner-side. - grant_
revoke - Revoke a grant (or cancel a pending invite) by id. Owner-side; revocation is soft on the hub (the audit trail survives).
- head
- Read and locally verify the brain’s current signed feed head.
subscribepolls this as movement detection; the caller re-pulls or re-queries after an advance. - hub_
config - Resolve the client configuration:
flag_hubbeatsHUB_URL_ENVbeats thehub =line in<dir>/.dbmd/config; no fallback default exists. The credential comes fromHUB_KEY_ENValone and is validated as a clean header token (never echoed on failure). - is_
valid_ handle - A published-site handle (the
proposetarget). Same lexical shape as a slug. - load_
signing_ key - Load and validate a signing-key file (agent or brain — same format):
one base64url line of PKCS#8. Public so
dbmd key rotatecan load the old key explicitly. - mirror
- Replicate a brain with full verification (link.md §5.4 over the WHOLE
chain, not just the head): every entry’s signature, hash, sequence
contiguity, and prev-hash linkage are checked before its exact bytes are
stored under
.dbmd/mirror/feed/<seq>.json; the identity is pinned in.dbmd/config(trust-on-first-use — a later mirror against a different identity refuses); the store files are pulled beside it. feed + files = the provable full copy, re-servable bydbmd serve— signatures survive re-hosting, which is what makes the export an export. - propose
- Submit
bodyto the published sitehandle, addressed to its app pageapp(a page that declares thewrite-inboxcapability). Deliberately unauthenticated — this is the cross-party door; the submission lands as evidence in the owner’ssources/inbox/, never as truth, and the owner’s curator accepts or rejects it. Returns the hub’s{id, path}receipt. - resolve
- resolve_
registry - Resolve a bare
@handlethrough the federation registry (link.md §7.1, E5): look the handle up in the hub’s registry, fetch the brain card from the returned HOME node, and PIN — the card’s identity fingerprint must equal the registry’s, or resolution fails. Returns the card enriched with the resolvedhome, orOk(None)when the registry has no such handle (so the caller can fall back to a direct lookup). - rotate_
brain_ key - Rotate a self-custodied brain’s key: mint a fresh keypair, build the
§9.1 statement — the new key, signed by the OLD key, normative
serialization — send it to the hub, and only after the hub accepts write
the new secret to
out(0600, refusing overwrite). The old key file is left untouched for the owner to retire. - safe_
store_ rel_ path - True when
pis a store-relative path this client will read from or write to disk: relative, no.., no empty or dot-leading segment (which shields.dbmd/and.git/), and only the hub-portable character set. Applied to every path an export hands us (the hub is not trusted with local layout) and to every path a push sends (mirroring the hub’s own gate). - sync_
pull - Pull the granted slice of
braintoout(default:./<slug>). Every exported path is safety-gated before it touches disk; files are written atomically; nothing local is ever deleted (locals the export lacks are reported inextra_localinstead). Returns the report; rebuilding the local index catalog afterwards is the caller’s (cheap, optional) step. - sync_
push - Push
filestobrainas a whole-store snapshot — the hub’s push semantics: the hosted copy becomes exactly this set (pull first if the hosted side may have records the local copy lacks). Client-side caps mirror the hub’s JSON-path limits so an oversized push fails before the upload.
Type Aliases§
- Link
Result - Result alias for link.md client operations.