Skip to main content

Module linkmd

Module linkmd 

Source
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:

verbbinding
resolveGET /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
grantGET / POST /api/hub/brains/<brain>/grants, DELETE /api/hub/brains/<brain>/grants/<id>
proposePOST /api/hub/sites/<handle>/inbox — evidence in, without trust (unauthenticated by design)
subscribeGET /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:

  1. the --hub <URL> flag,
  2. the DBMD_HUB_URL environment variable,
  3. the hub = <URL> line in the store-local .dbmd/config file (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. brain is 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).
AgentSigningKey
A loaded agent signing key: the PKCS#8 secret plus its derived public multikey. Debug never prints key material.
GeneratedAgentKey
What dbmd key generate returns: 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.
MirrorReport
What dbmd mirror materialized.
PullReport
What a pull materialized.
RotationReport
What dbmd key rotate returns.

Enums§

AddressTarget
What the part after @brain/ names.
Capability
The two capabilities a v0 hub enforces.
LinkError
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-Sig proof 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 by dbmd 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 --push signs 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 propose submission 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-file from 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.jsonl when present, and every content .md under records/ and sources/ (the store walk, which already excludes hidden dirs like .dbmd/, the log/ archive, and derived index.* 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 brain to grantee — a hub principal named by email in v0 (the protocol’s near-term simplification; key-named grantees arrive with the signing layer). scope is a store-path prefix (the hub’s enforcement unit); until an 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. subscribe polls this as movement detection; the caller re-pulls or re-queries after an advance.
hub_config
Resolve the client configuration: flag_hub beats HUB_URL_ENV beats the hub = line in <dir>/.dbmd/config; no fallback default exists. The credential comes from HUB_KEY_ENV alone and is validated as a clean header token (never echoed on failure).
is_valid_handle
A published-site handle (the propose target). 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 rotate can 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 by dbmd serve — signatures survive re-hosting, which is what makes the export an export.
propose
Submit body to the published site handle, addressed to its app page app (a page that declares the write-inbox capability). Deliberately unauthenticated — this is the cross-party door; the submission lands as evidence in the owner’s sources/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 @handle through 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 resolved home, or Ok(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 p is 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 brain to out (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 in extra_local instead). Returns the report; rebuilding the local index catalog afterwards is the caller’s (cheap, optional) step.
sync_push
Push files to brain as 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§

LinkResult
Result alias for link.md client operations.