@atrib/sdk
v7.1.3
Published
Consolidated client SDK for atrib's verifiable action layer. Provides attest() and recall() verbs with a daemon-first runtime and in-process fallback.
Maintainers
Readme
@atrib/sdk
Consolidated atrib client SDK. Two cognitive verbs over the substrate:
attest() (write) and recall() (read), plus an explicit
action() helper for application-owned execution boundaries. The complete
§1
record layer is re-exported from @atrib/mcp, so application code needs one
import.
This package is a consolidation, not a greenfield: it adds no new
canonicalization, hashing, or signing implementation. Every write
terminates in @atrib/emit's handleEmit pipeline (records are
byte-identical to wrapper-signed and primitive-signed records), and every
cryptographic primitive is the existing @atrib/mcp one.
Install
pnpm add @atrib/sdkReleases publish through npm Trusted Publisher via release.yml. @atrib/recall, @atrib/verify, and
@atrib/verify-mcp are optional peers. Install them alongside for the
in-process recall and verify fallbacks. Without them, those paths degrade to
a typed unavailable outcome per the degradation contract below.
Verify a local build with pnpm --filter @atrib/sdk test.
Topology: daemon-first
Per D120 and the redesign upgrade path, the local primitives runtime is the
default peer. The SDK talks MCP Streamable HTTP to it
($ATRIB_PRIMITIVES_HTTP_ENDPOINT, default http://127.0.0.1:8796/mcp)
and falls back to in-process engines when no daemon is reachable:
| Verb | Daemon path | In-process fallback |
| ---------------------------- | ------------------------------- | -------------------------------------------------------------- |
| attest() | emit tool (daemon-owned key) | emitInProcess() from @atrib/emit (caller-owned key) |
| action() | Two linked attest() calls | Same shared write path as attest() |
| recall({shape: 'history'}) | recall_my_attribution_history | recall() from @atrib/recall (optional peer) |
| recall({shape: 'state'}) | modern recall tool | state projector from @atrib/recall (optional peer) |
| recall({shape: 'verify'}) | atrib-verify | handleAtribVerify() from @atrib/verify-mcp (optional peer) |
| other recall shapes | matching runtime tool | degraded warning outcome (v0) |
@atrib/recall and @atrib/verify-mcp are optional peer dependencies
loaded lazily (the P047 pattern): without them installed, the peer-backed
fallback families degrade to a typed unavailable outcome with a
warning instead of an import failure. @atrib/emit stays a hard
dependency so the write path always works.
The SDK is semantically stateless: context_id and chain tokens are
explicit per-request values. Its v2 MCP client negotiates the 2026-07-28
protocol with a compatible daemon and falls back to the legacy handshake for
an older runtime.
For a retryable write, pass one caller-generated key and reuse it only for the same intended action:
const result = await client.attest({
content: { what: 'accepted deployment plan' },
context_id: '0123456789abcdef0123456789abcdef',
idempotency_key: 'deploy-plan-019fac220001',
})The daemon binds the key to the context, tool, and complete arguments. A completed retry returns the original result. Changed arguments are rejected. If the daemon outcome is uncertain, the SDK suppresses in-process fallback and asks the caller to retry the same key.
Usage
import { createAtribClient } from '@atrib/sdk'
const client = createAtribClient()
// Write: observation (default), or annotate/revise via ref.kind
const result = await client.attest({
content: { what: 'chose sqlite over postgres', why_noted: 'deployment constraint' },
})
await client.attest({
content: { summary: 'supersedes the sqlite decision', reason: 'scale changed' },
ref: { kind: 'revises', record_hash: result.record_hash! },
})
// Read: one verb, shape-discriminated
const history = await client.recall({ shape: 'history', limit: 10 })
const walk = await client.recall({ shape: 'walk', from_record_hash: result.record_hash! })
const state = await client.recall({
shape: 'state',
trusted_creator_keys: ['<base64url Ed25519 key>'],
include_content: true,
head_limit: 100,
})
// Application action: sign request, execute, then sign the terminal outcome.
const action = await client.action({
name: 'write_invoice',
args: { invoice_id: 'inv-7', cents: 1200 },
execute: async ({ request }) => {
return writeInvoice({ invoice_id: 'inv-7', cents: 1200 }, request.record_hash)
},
})
await client.close()summarize is deliberately not a recall shape: synthesis belongs to
the calling harness/model; the SDK returns verified raw material.
Explicit action path
action() is for application code that owns the actual execution boundary and
cannot mount automatic MCP middleware. It is not a synonym for attest().
The helper:
- hashes the action name;
- makes a fresh salted JCS commitment to the arguments;
- signs the request before execution;
- runs the caller's
executefunction even if attribution degraded; and - signs a linked success or failure outcome with a fresh salted result commitment.
const result = await client.action({
name: 'payments.transfer',
args: { cents: 500, currency: 'USD' },
execute: () => payments.transfer({ cents: 500, currency: 'USD' }),
})
if (!result.ok) {
// result.error is the original application error.
throw result.error
}
console.log(result.request.record_hash, result.outcome.record_hash)The result is an explicit success/failure union. The helper does not claim
automatic coverage outside the supplied execute function. A caller that
bypasses this function is outside its capture boundary. Automatic MCP or
framework middleware remains the preferred path when the host exposes one.
Matching a disclosed result to result_hash proves consistency with the
signer's commitment. It does not prove that the result is true. Use tool-side
or counterparty evidence when a verifier needs independent corroboration.
Degradation contract (§5.8)
Operational failures never throw and never block. If the daemon is
unreachable, the SDK falls back to in-process engines. If there is no
signing key, it returns a pass-through result with a warning. Log
submission is non-blocking with bounded retry, through the existing
@atrib/mcp submission queue. The only throw paths are contradictory
inputs (programmer error), such as ref.kind: 'revises' with
event_type: 'annotation'.
Anchors (D138, §2.11.7-§2.11.13)
anchors config takes a set of anchor descriptors: bare strings
(atrib-log §2.6.1
endpoints) or { url | endpoint, anchor_type?, ... } objects covering
the §2.11.8
registry (atrib-log, sigstore-rekor, rfc3161-tsa,
opentimestamps). In-process attests fan out to every configured
anchor through @atrib/mcp's createAnchorFanout (fire-and-forget per
§5.3.5).
No anchor config at all resolves to BUILT_IN_DEFAULT_ANCHOR_SET (two
independent anchors, §2.11.12
rule 1). A sub-plurality set (fewer than two anchors) warns and writes the
_local.anchor_config sidecar degradation marker unless
allowSingleAnchor: true states it is deliberate. The resolved posture
surfaces as descriptor-based anchor_posture on AttestResult.
flushAnchors() gives a bounded wait and returns reports that separate
configured, attempted, accepted, and proof-ready legs. A pending or
confirmed outcome counts as an accepted submission. Only confirmed
counts as proof-ready.
Independent plurality remains a verifier decision over proof bytes, trust
roots, and operator groups. Anchoring never touches signed bytes and never
blocks the write.
Stateless request carriage and extension receipts
The daemon client declares dev.atrib/attribution on every request, carries
the resolved context_id in the extension block, emits W3C trace context, and
keeps the legacy atrib token carriers for compatibility. It preserves custom
metadata and other client capabilities. A valid receipt token automatically
becomes the propagation token on the next request.
Receipt parsing is on by default. The daemon client parses
dev.atrib/attribution attestation receipts from tool results' _meta
(D141,
extension v0.1): the propagation token, a receipt naming the record the
server already signed (log_submission is a queue status, never an
awaited proof), and optionally the full signed record for immediate
Tier-3 re-verification. Each parsed block is run through @atrib/mcp's
verifyAttributionReceipt (extension spec §6.2 integrity check) and
surfaces as attribution_receipt: { block, verification } on
attest/recall results. Receipts are advisory. Trust derives from
verifying signed records, never from the receipt. Set
attributionReceipts: false only for compatibility diagnosis.
Evidence envelopes (D137, §5.5.7)
The universal envelope (profile type URI, four-tier ladder declared →
shape → attested → verified, payload commitment, verifier facts) is the
single attachment model for external evidence; the legacy protocol
string set is frozen. The SDK ships the structural types/helpers plus
production and validation: buildEvidenceEnvelope computes the payload
commitment (JCS or raw hash rule) and validateEvidenceEnvelope applies
the normative shape rules. Both delegate to the optional peer
@atrib/verify and degrade with a warning when it is not installed.
Envelopes live outside signed bytes (mirror sidecar, archive evidence
projection, verifier results, host-owned packets).
API reference
Everything below is exported from the package root (import { … } from
'@atrib/sdk'). The surface splits into the SDK layer (the two verbs, the
config, the daemon transport, the hash helpers, the evidence and receipt
types) and the record layer re-exported verbatim from @atrib/mcp and
@atrib/emit.
createAtribClient(config?) → AtribClient
Builds a client from an AtribClientConfig
(default {}). Construction is cheap and never throws on operational
problems: the daemon connection is lazy (first call), the in-process
signing key resolves lazily on the first attest that needs it, and anchor
normalization collects warnings instead of erroring.
interface AtribClient {
attest(input: AttestInput): Promise<AttestResult>
action<TArgs extends JsonObject, TResult extends JsonValue>(
input: ActionInput<TArgs, TResult>,
): Promise<ActionResult<TResult>>
recall<T = unknown>(query: RecallQuery): Promise<RecallOutcome<T>>
flushAnchors(): Promise<AnchorSubmissionReport[]> // settled leg accounting; never throws
close(): Promise<void>
}Throw vs degrade. Both cognitive verbs and the action evidence path follow the
§5.8
degradation contract: operational failures (daemon unreachable, tool
error, missing key, missing optional peer, log unreachable) never throw.
They degrade into warnings on the result, with via: 'none' when
nothing could serve the call. The only throw paths are contradictory or
malformed inputs (programmer error): a ref.kind that contradicts an
explicit event_type, an unknown ref.kind, an unknown recall shape,
or an input shape that fails emitInProcess's schema validation.
attest(input) semantics. Maps AttestInput to the shared
EmitInput argument shape via buildEmitArgs (exported; throws
TypeError on contradictory input, the write verb's only throw path),
then tries paths in order:
- Daemon (
daemon.mode'prefer'or'require'): calls theemittool on the primitives runtime. The daemon owns the signing key. A structurally-garbage daemon result (norecord_hashstring) counts as a daemon failure, not a silent all-null success. - In-process (
'prefer'after a daemon failure, or'off'): resolves the caller-owned key (seekeyinAtribClientConfig) and callsemitInProcessfrom@atrib/emitwith the configuredproducer,mirrorPath,autochainSource, and primary atrib-log anchor aslogEndpoint. It then reads the freshly signed record back from that same explicit mirror path and fans it out to every configured anchor viacreateAnchorFanout(D138; fire-and-forget per §5.3.5; the primary log receiving the record twice is idempotent-safe per §2.6.1 step 6), stamping the resolvedanchor_postureon the result. Without a key, the SDK returns a pass-through result (via: 'none',record_hash: null) with a warning, per §5.8 rule 5. The daemon path never consults the client's fan-out: the daemon owns its own anchors.
Under daemon.mode: 'require', a daemon failure returns the degraded
via: 'none' result directly. It never falls back and never throws.
When AttestInput.idempotency_key is set, the daemon path is also required for
that call. The SDK never signs through the in-process fallback after a timeout
or transport failure because that path cannot see the daemon's reservation.
action(input) semantics. Calls attest() for the request and terminal
outcome. The action name uses the hashed-name posture. Arguments and results
use independent 16-byte salted JCS commitments. A successful execution returns
{ ok: true, result, request, outcome }. A thrown application error returns
{ ok: false, error, request, outcome } after signing the failure envelope.
Signing degradation does not suppress execution.
recall(query) semantics. Resolves the shape (query.shape, default
'history'), maps it to the physical tool name via SHAPE_TO_TOOL
(exported), strips the SDK-only shape discriminator and undefined
values, and injects the client's default context_id for the
session_chain and orphans shapes when the query omits it. Then:
daemon first; on failure, the in-process fallback for the two shapes
whose engines are exported as libraries today (history, verify);
every other shape degrades to via: 'none' with a warning naming the
runtime tool to use instead. See the
shape table for the full routing.
close() closes the daemon transport if one was opened. Best-effort;
never throws. Safe to call when daemon.mode was 'off'.
AttestInput / AttestRef
One write shape collapsing emit / annotate / revise. ref is the
discriminator:
interface AttestRef {
kind: 'annotates' | 'revises'
record_hash: string // sha256:<64-hex>
}| Field | Type | Required | Meaning |
| ------------------------------ | ------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| content | Record<string, unknown> | yes | The content being attested. Committed via default args_hash = sha256(JCS(content)) per D099; full content stays in the local mirror sidecar. |
| event_type | string | no | Short name ('observation', 'annotation', …) or absolute URI. Default 'observation', or derived from ref.kind ('annotates' → annotation, 'revises' → revision). An explicit value that contradicts ref.kind throws TypeError. |
| ref | AttestRef | no | Collapsed annotate/revise reference; sets the record's annotates or revises field. |
| informed_by | string[] | no | sha256:<64-hex> refs of records this one was informed by (§1.2.5). |
| allow_unresolved_informed_by | boolean | no | Keep deliberately dangling informed_by refs (D113 opt-in). |
| context_id | string | no | Explicit context (32 lowercase hex). Default: the client's contextId, else resolveEnvContextId() (D078/D083). |
| chain_root | string | no | Explicit chain_root override (requires a context_id). Default: resolveChainRoot precedence in the emit pipeline. |
| provenance_token | string | no | §1.2.6 cross-session anchor (genesis-only, 22-char base64url). |
| tool_name | string | no | §8.2 tool-name disclosure. |
| args_hash | string | no | Explicit §8.3 args commitment (overrides the D099 default). |
| args_salt | string | no | Canonical base64url 16-byte salt paired with an explicit args_hash. A salt without the hash is rejected. |
| result_hash | string | no | Explicit §8.3 result commitment. |
| result_salt | string | no | Canonical base64url 16-byte salt paired with an explicit result_hash. A salt without the hash is rejected. |
AttestResult
| Field | Type | Meaning |
| --------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| record_hash | string \| null | sha256:<64-hex> of the signed record, or null when nothing was signed (degraded). |
| context_id | string \| null | Context the record landed in. |
| log_index | number \| null | Public-log index when submission already confirmed; null while in flight or disabled. |
| inclusion_proof | ProofBundle['inclusion_proof'] \| null | RFC 6962 inclusion proof when already available (cached by record hash per §5.3.5). |
| receipt_id | string? | Present when the emit pipeline issued a receipt id. |
| via | 'daemon' \| 'in-process' \| 'none' | Which path produced the record. 'none' = degraded; see warnings. |
| warnings | string[] | atrib:-prefixed operational warnings (anchor skips, fallbacks, pass-through, flush deadline). |
| anchor_posture | AttestAnchorPosture? | { effective_anchor_count, used_default_set, warned, basis: 'configured_descriptors', plurality_met: null }: the resolved §2.11.12. Descriptor count is not proof success. |
| attribution_receipt | VerifiedAttributionReceipt? | { block, verification }: the parsed negotiated receipt plus its integrity result. Advisory. |
| transport | DaemonTransportInfo? | Negotiated protocol version and era, discover result, server identity when present, and validated attribution declaration. |
RecallQuery shapes
RecallQuery is the union of eleven query interfaces discriminated by
shape (omitted shape means 'history'). SHAPE_TO_TOOL maps each
shape to its physical tool name on the primitives runtime; the fallback
column says what serves the shape when no daemon is reachable.
| Shape | Daemon tool | In-process fallback | Args (beyond shape) |
| ---------------------------------------- | ------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| history (HistoryQuery) | recall_my_attribution_history | recall() from @atrib/recall (optional peer) | context_id?, context_scope? ('all' \| 'env'), creator_key?, event_type?, content_id?, tool_name?, args_hash?, min_importance? ('critical' \| 'high' \| 'medium' \| 'low' \| 'noise'), topic_tags?, include_revised?, min_signers?, rank_by? ('timestamp' \| 'relevance' \| 'causal_distance'), rank_anchor?, toc?, limit?, offset?, compact?, include_unverified? |
| walk (WalkQuery) | recall_walk | none (degrades) | from_record_hash (required), edge_types? ('CHAIN_PRECEDES' \| 'INFORMED_BY' \| 'ANNOTATES' \| 'REVISES'), depth? |
| annotations (AnnotationsQuery) | recall_annotations | none (degrades) | record_hash (required) |
| revisions (RevisionsQuery) | recall_revisions | none (degrades) | record_hash (required) |
| by_content (ByContentQuery) | recall_by_content | none (degrades) | query (required), k?, max_records?, evidence_mode? ('bounded' \| 'require_complete') |
| session_chain (SessionChainQuery) | recall_session_chain | none (degrades) | context_id? (defaulted from the client), limit?, include_content? |
| orphans (OrphansQuery) | recall_orphans | none (degrades) | context_id? (defaulted from the client), event_type?, creator_key?, limit? |
| by_signer (BySignerQuery) | recall_by_signer | none (degrades) | min_records? |
| trace / trace_forward (TraceQuery) | trace / trace_forward | none (degrades) | record_hash (required), context_id?, depth?, max_nodes?, compact?, include_content? |
| state (StateQuery) | modern recall | state projector from @atrib/recall (optional peer) | root_record_hashes?, trusted_creator_keys?, allowed_context_ids?, include_content?, limit?, head_limit? |
| verify (VerifyQuery) | atrib-verify | handleAtribVerify() from @atrib/verify-mcp (optional peer) | packet?, records?, claims?, required_record_hashes?, trusted_creator_keys?, allowed_context_ids?, require_body?, require_body_commitment?, require_log_inclusion?, log_public_key_b64?, now_ms?, max_age_ms? |
verify is Pattern 3 handoff-claim verification
(D105/D106).
"None (degrades)" shapes return via: 'none', data: null, and a
warning naming the runtime tool to use instead, rather than a divergent
reimplementation. When a peer-backed fallback engine itself throws, that
too is caught and degraded.
RecallOutcome<T>
| Field | Type | Meaning |
| --------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| shape | RecallShape | Echo of the resolved shape. |
| via | 'daemon' \| 'in-process' \| 'none' | Which path served the read. 'none' = degraded; see warnings. |
| data | T \| null | The tool/engine result (parsed JSON when the daemon returned the single-JSON-text-block convention), or null when degraded. |
| warnings | string[] | atrib:-prefixed operational warnings. |
| attribution_receipt | VerifiedAttributionReceipt? | As on AttestResult; present when the daemon returned a valid negotiated receipt. Advisory. |
| transport | DaemonTransportInfo? | Negotiated protocol version and era, discover result, server identity when present, and validated attribution declaration. |
AtribClientConfig
| Field | Type | Default | Meaning |
| --------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| daemon | DaemonConfig | see below | Daemon endpoint/mode/timeouts. |
| anchors | AnchorSpec[] | BUILT_IN_DEFAULT_ANCHOR_SET (two anchors; the atrib-log member honors $ATRIB_LOG_ENDPOINT) | D138 anchor set; in-process attests fan out to every member. Hostile entries and unregistered anchor_type values warn-and-skip. |
| allowSingleAnchor | boolean | false | §2.11.12 rule 3: states a < 2-anchor set is deliberate, silencing the sub-plurality warning and the sidecar degradation marker. |
| attributionReceipts | boolean | true | Parsing + verification of negotiated dev.atrib/attribution receipts. Set false only for compatibility diagnosis. |
| attributionAccept | ('token' \| 'record')[] | ['token'] | Receipt forms requested in the per-request extension declaration. |
| key | ResolvedKey \| null | resolveKey() ladder from @atrib/emit (ATRIB_PRIVATE_KEY env → ATRIB_KEY_FILE → macOS Keychain → 1Password) | Pre-resolved in-process signing key. null disables in-process signing (pass-through per §5.8 rule 5). Note: any explicitly-set key property opts out of the resolveKey() ladder. |
| contextId | string | resolveEnvContextId() at call time | Per-client default context (32 lowercase hex). Context identity stays an explicit per-request value (stateless-MCP-native posture). |
| producer | string | 'atrib-sdk' (DEFAULT_PRODUCER) | _local.producer mirror-sidecar label (§5.9); in-process path only. |
| mirrorPath | string | $ATRIB_MIRROR_FILE, then the per-agent default | Explicit in-process mirror write path for this client. Anchor fan-out reads the same path. Use this for multiple clients in one process. |
| autochainSource | string | mirrorPath, then $ATRIB_AUTOCHAIN_SOURCE, then the legacy mirror fallback | Explicit in-process mirror source for chain inheritance. Set it separately when a client writes to one mirror but inherits an existing chain from another. |
DaemonConfig / DaemonMode
| Field | Type | Default | Meaning |
| ------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| endpoint | string | $ATRIB_PRIMITIVES_HTTP_ENDPOINT, then http://127.0.0.1:8796/mcp (DEFAULT_DAEMON_ENDPOINT) | MCP Streamable HTTP endpoint of the local primitives runtime. |
| mode | 'prefer' \| 'require' \| 'off' | 'prefer' | 'prefer': try daemon, fall back in-process. 'require': daemon only; failure degrades to a warning result (never a throw). 'off': in-process only (no DaemonClient is constructed). |
| connectTimeoutMs | number | 1500 | Daemon connect timeout. |
| callTimeoutMs | number | 10000 | Per-tools/call timeout. |
| retryCooldownMs | number | 30000 | Cooldown before re-probing an unreachable daemon; within the window, calls skip straight to the fallback. |
| requestMeta | Record<string, unknown> | {} | Custom metadata merged into every request. atrib-owned fields resolve after this object; unrelated keys survive. |
| clientCapabilities | Record<string, unknown> | {} | Additional client capabilities merged with the attribution extension declaration. |
| sessionToken | string | none | Cross-trace atrib session token carried in W3C baggage. |
resolveDaemonEndpoint(config?) applies exactly that endpoint
precedence and is exported for hosts that want to probe the runtime
themselves.
AnchorSpec / resolveAnchorSet(anchors, allowSingleAnchor?) → ResolvedAnchorSet
An anchor is either a bare string (an atrib-log
§2.6.1
endpoint, shorthand for { url }) or an AnchorDescriptor
({ anchor_type?, anchor_id?, url?, endpoint?, ... }: url wins over
endpoint; an absent anchor_type means 'atrib-log'; registered
non-atrib-log types like 'opentimestamps' need no URL).
resolveAnchorSet normalizes the caller's specs into the canonical
§2.11.12
AnchorSetConfig that createAnchorFanout / resolveAnchorPosture
consume, and never throws: hostile entries (non-string/non-object,
missing/invalid endpoint where one is required) and anchor_type values
outside the §2.11.8
registry warn-and-skip. Skipped entries are excluded from the
config, so they never count toward the plurality posture. undefined
input returns an empty config (the built-in default set applies
downstream). Returns { config: AnchorSetConfig, primaryLogEndpoint:
string | undefined, warnings: string[] }; primaryLogEndpoint (the
first usable atrib-log anchor) doubles as the in-process emit pipeline's
logEndpoint.
DaemonClient / DaemonCallOutcome
The MCP Streamable HTTP transport to the primitives runtime, exported for hosts that want raw tool access with the same degradation posture.
new DaemonClient(config?: DaemonConfig, options?: {
attributionReceipts?: boolean
attributionAccept?: readonly ('token' | 'record')[]
})
type DaemonCallOutcome =
| {
ok: true
value: unknown
transport: DaemonTransportInfo
attribution?: AttributionReceiptBlock
}
| { ok: false; reason: string }callTool(name, args)→Promise<DaemonCallOutcome>. Never throws. Tool results carrying a single JSON text block (the atrib primitive convention) are parsed; non-JSON text is returned as the string; other result shapes are returned raw. A result withisError: trueis a failure outcome.connect()probes negotiation without sendingtools/calland returns transport facts or an unavailable outcome.- Connection is lazy and cached; a failed call closes the transport and
starts the
retryCooldownMswindow, during whichcallToolreturns{ ok: false }immediately without re-probing. close(): best-effort transport close; never throws.- The client negotiates MCP 2026-07-28 through
server/discover. Every modern request carries protocol version, client identity, capabilities, explicit atrib context, and trace metadata. There is no initialize handshake orMcp-Session-Idon the modern path. - Daemon writes fail before
tools/callwhen no explicit context can be resolved. Selectdaemon.mode: 'off'only when the in-process fresh-orphan compatibility behavior is intentional.
Hash helpers
Compositions of @atrib/mcp primitives, with no hashing implementation of their own.
| Export | Returns | Meaning |
| --------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| recordHashHex(record) | bare 64-char lowercase hex | SHA-256 over the JCS-canonical COMPLETE signed record, including signature (§1.2.3). |
| recordHashRef(record) | sha256:<64-hex> | The reference form used by chain_root, informed_by, annotates, revises. |
| deriveProvenanceToken(upstream) | 22-char base64url | §1.2.6 token for a downstream genesis record: base64url (no padding) of the first 16 bytes of the upstream record hash. |
Evidence envelope family (D137, §5.5.7)
Structural types/helpers are SDK-local; envelope production and
validation delegate to the optional peer @atrib/verify (lazy import;
missing peer degrades to a null envelope with a warning naming the
peer, per §5.8).
Envelopes live outside signed bytes (mirror sidecar, archive evidence
projection, verifier results, host-owned packets).
| Export | Kind | Meaning |
| ------------------------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| EvidenceTier | type | 'declared' \| 'shape' \| 'attested' \| 'verified': what the verifier party actually did. |
| EvidencePayloadRefKind | type | 'inline' \| 'mirror' \| 'archive' \| 'external' \| 'withheld'. |
| EvidencePayloadRef | type | { kind, uri?, record_hash? } (uri and record_hash are string-or-null). uri for archive/external locations; record_hash when the payload is itself a signed atrib record. |
| EvidencePayload | type | { hash, media_type?, ref?, inline? }: hash is a "sha256:" + hex commitment to the raw evidence material; inline only when ref.kind === 'inline', never public. The type is lenient; normative validation requires ref. |
| EvidenceConstraint | type | { type, status: 'passed' \| 'failed' \| 'unresolved' \| 'not_checked', expected?, actual? }. |
| EvidenceEnvelope | type | { envelope: 1, profile, profile_version, tier, payload, facts?, result?, verifier? }: one envelope schema, N profiles identified by absolute HTTPS type URI. Normative validation requires result. |
| evidenceEnvelopeKey(envelope) | function | Dedup identity: `${profile} ${payload.hash}`. Multiple instances per key are permitted; consumers order by tier desc, then checked_at_ms desc, then verifier name. |
| evidenceTierRank(tier) | function | Numeric rank, 0 (declared) … 3 (verified); unknown tiers rank -1. |
| buildEvidenceEnvelope(input) | async function | Producer-side builder: computes payload.hash from payload.material (JCS rule) or hash_rule: 'raw' (UTF-8 rule), fills the default result, and validates via the peer. Returns { envelope, validation, warnings } with envelope: null on rejection or missing peer; throws TypeError only on contradictory input (hash AND material, hash_rule without material, neither). |
| validateEvidenceEnvelope(envelope) | async function | Runs the peer's normative §5.5.7 shape validation. Returns { validation, warnings }; validation: null when the peer is missing. |
Attribution receipt family (D141, dev.atrib/attribution v0.1)
Receipts are advisory extension data: trust derives only from verifying
signed records and inclusion proofs, never from the receipt. See the
extension document under docs/extensions/dev.atrib-attribution/.
| Export | Kind | Meaning |
| ---------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| ATTRIBUTION_EXTENSION_KEY | const | 'dev.atrib/attribution': the _meta key. Aliases @atrib/mcp's ATTRIBUTION_EXTENSION_ID (also re-exported). |
| ATTRIBUTION_LOG_SUBMISSION_STATUSES | const | The four known statuses, re-exported from @atrib/mcp. |
| AttributionLogSubmissionStatus | type | 'queued' \| 'submitted' \| 'disabled' \| 'failed'; unknown future values pass through as strings. A queue status, never an awaited proof (§5.3.5). |
| AttributionReceipt | type | { record_hash?, creator_key?, context_id?, event_type?, chain_root?, log_submission? }: all optional strings. |
| AttributionReceiptBlock | type | { token?, receipt?, record? }: the §1.5.2 propagation token, the receipt, and optionally the full signed record for immediate Tier-3 re-verification. |
| VerifiedAttributionReceipt | type | { block, verification }: what the daemon client attaches to attest/recall results: the parsed block plus the §6.2 integrity outcome. |
| parseAttributionReceiptBlock(meta) | function | Lenient extraction from a tool result's _meta: anything malformed yields null, never a throw; wrong-typed fields are dropped; an all-dropped receipt counts as absent. |
| verifyAttributionReceipt(block) | function | Re-exported from @atrib/mcp: the extension-spec §6.2 consumer check over the RAW result block: structural well-formedness plus internal consistency across token, receipt, and the optional record. Returns AttributionReceiptVerification { valid, mismatched } (['malformed'] for non-blocks). Internal consistency only; not a proof. |
| checkAttributionReceiptConsistency(block, record?) | function | Record-side consistency: checks a parsed block's claims against the signed record they name (attached or caller-retrieved). No record at all → { receipt_valid: false, mismatched_fields: ['record'] } (conservative, nothing to check against). |
Record-layer re-exports
The complete §1
record layer, re-exported verbatim from @atrib/mcp (grouped as in
src/index.ts):
Types + event vocabulary.
EVENT_TYPE_TOOL_CALL_URI,EVENT_TYPE_TRANSACTION_URI,EVENT_TYPE_OBSERVATION_URI,EVENT_TYPE_DIRECTORY_ANCHOR_URI,EVENT_TYPE_ANNOTATION_URI,EVENT_TYPE_REVISION_URI: the six normative event-type URIs.EVENT_TYPE_SHORT_NAMES: the six short aliases accepted by agent-facing tools.EVENT_TYPE_SHORT_TO_URI: short alias → canonical URI map.isNormativeEventTypeUri(uri): membership in the normative set (informational).isValidEventTypeUri(value): §1.4.5 syntactic URI validation (extension URIs pass).normalizeEventType(value): short alias / known typo path → canonical URI; unknown values pass through.
Canonicalization (§1.3).
canonicalRecord(record): JCS bytes of the complete signed record (the record-hash preimage).canonicalSigningInput(record): JCS bytes withsignatureremoved (the signing input).canonicalCrossAttestationInput(record): §1.7.6 bytes withsigners: []and no top-levelsignature.
Signing + verification (§1.4).
getPublicKey(privateKey): raw 32-byte Ed25519 public key for a 32-byte seed.signRecord(record, privateKey): §1.4.2 signing; returns the record withsignatureset.signTransactionRecord(record, privateKey, counterpartySigners?): signs the cross-attestation bytes; creator's signer entry first.signTransactionAttestation(record, privateKey): one counterpartySignerEntryover an existing transaction record's bytes.verifyRecord(record): §1.4.3 verification, all steps.
Hashing + encoding.
sha256(bytes): SHA-256 digest.base64urlEncode/base64urlDecode: base64url, no padding.hexEncode/hexDecode: lowercase hex.
Chain composition (§1.2.3 / §1.2.3.1).
genesisChainRoot(contextId):"sha256:" + hex(SHA-256(UTF-8(context_id))).- `
