@atrib/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +216 -0
- package/README.md +525 -0
- package/dist/attest.d.ts +106 -0
- package/dist/attest.d.ts.map +1 -0
- package/dist/attest.js +64 -0
- package/dist/attest.js.map +1 -0
- package/dist/attribution.d.ts +81 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +133 -0
- package/dist/attribution.js.map +1 -0
- package/dist/client.d.ts +18 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +244 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +113 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +91 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon.d.ts +32 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +175 -0
- package/dist/daemon.js.map +1 -0
- package/dist/evidence-envelope.d.ts +98 -0
- package/dist/evidence-envelope.d.ts.map +1 -0
- package/dist/evidence-envelope.js +108 -0
- package/dist/evidence-envelope.js.map +1 -0
- package/dist/evidence.d.ts +76 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +20 -0
- package/dist/evidence.js.map +1 -0
- package/dist/hashes.d.ts +26 -0
- package/dist/hashes.d.ts.map +1 -0
- package/dist/hashes.js +33 -0
- package/dist/hashes.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/recall.d.ts +122 -0
- package/dist/recall.d.ts.map +1 -0
- package/dist/recall.js +29 -0
- package/dist/recall.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
# @atrib/sdk
|
|
2
|
+
|
|
3
|
+
Consolidated atrib client SDK: two verbs over the substrate — **`attest()`**
|
|
4
|
+
(write) and **`recall()`** (read) — plus the complete [§1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#1-attribution-record-format) record layer
|
|
5
|
+
re-exported from `@atrib/mcp` so application code needs exactly one import.
|
|
6
|
+
|
|
7
|
+
This package is a consolidation, not a greenfield: it adds **no new
|
|
8
|
+
canonicalization, hashing, or signing implementation**. Every write
|
|
9
|
+
terminates in `@atrib/emit`'s `handleEmit` pipeline (records are
|
|
10
|
+
byte-identical to wrapper-signed and primitive-signed records), and every
|
|
11
|
+
cryptographic primitive is the existing `@atrib/mcp` one.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @atrib/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Version 0.1.0 is first-published manually. Later releases use npm Trusted
|
|
20
|
+
Publisher through `release.yml`. `@atrib/recall`, `@atrib/verify`, and
|
|
21
|
+
`@atrib/verify-mcp` are optional peers — install them alongside for the
|
|
22
|
+
in-process recall and verify fallbacks; without them those paths degrade to
|
|
23
|
+
a typed unavailable outcome per the degradation contract below.
|
|
24
|
+
|
|
25
|
+
Verify a local build with `pnpm --filter @atrib/sdk test`.
|
|
26
|
+
|
|
27
|
+
## Topology: daemon-first
|
|
28
|
+
|
|
29
|
+
Per [D120](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d120-local-substrate-coordinator-keeps-startup-spawn-sidecars-wrapper-owned) and the redesign upgrade path, the local primitives runtime is the
|
|
30
|
+
default peer. The SDK talks MCP Streamable HTTP to it
|
|
31
|
+
(`$ATRIB_PRIMITIVES_HTTP_ENDPOINT`, default `http://127.0.0.1:8796/mcp`)
|
|
32
|
+
and falls back to in-process engines when no daemon is reachable:
|
|
33
|
+
|
|
34
|
+
| Verb | Daemon path | In-process fallback |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `attest()` | `emit` tool (daemon-owned key) | `emitInProcess()` from `@atrib/emit` (caller-owned key) |
|
|
37
|
+
| `recall({shape: 'history'})` | `recall_my_attribution_history` | `recall()` from `@atrib/recall` (optional peer) |
|
|
38
|
+
| `recall({shape: 'verify'})` | `atrib-verify` | `handleAtribVerify()` from `@atrib/verify-mcp` (optional peer) |
|
|
39
|
+
| other recall shapes | matching runtime tool | degraded warning outcome (v0) |
|
|
40
|
+
|
|
41
|
+
`@atrib/recall` and `@atrib/verify-mcp` are **optional peer dependencies**
|
|
42
|
+
loaded lazily (the P047 pattern): without them installed, those two
|
|
43
|
+
in-process fallbacks degrade to a typed unavailable outcome with a
|
|
44
|
+
warning instead of an import failure. `@atrib/emit` stays a hard
|
|
45
|
+
dependency so the write path always works.
|
|
46
|
+
|
|
47
|
+
The SDK is **semantically stateless** (stateless-MCP-native posture):
|
|
48
|
+
`context_id` and chain tokens are explicit per-request values; nothing
|
|
49
|
+
rides on the MCP protocol session, which remains a transport detail of the
|
|
50
|
+
current runtime until the 2026-07-28 stateless transport ships.
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createAtribClient } from '@atrib/sdk'
|
|
56
|
+
|
|
57
|
+
const client = createAtribClient()
|
|
58
|
+
|
|
59
|
+
// Write: observation (default), or annotate/revise via ref.kind
|
|
60
|
+
const result = await client.attest({
|
|
61
|
+
content: { what: 'chose sqlite over postgres', why_noted: 'deployment constraint' },
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
await client.attest({
|
|
65
|
+
content: { summary: 'supersedes the sqlite decision', reason: 'scale changed' },
|
|
66
|
+
ref: { kind: 'revises', record_hash: result.record_hash! },
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// Read: one verb, shape-discriminated
|
|
70
|
+
const history = await client.recall({ shape: 'history', limit: 10 })
|
|
71
|
+
const walk = await client.recall({ shape: 'walk', from_record_hash: result.record_hash! })
|
|
72
|
+
|
|
73
|
+
await client.close()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`summarize` is deliberately **not** a recall shape: synthesis belongs to
|
|
77
|
+
the calling harness/model; the SDK returns verified raw material.
|
|
78
|
+
|
|
79
|
+
## Degradation contract ([§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract))
|
|
80
|
+
|
|
81
|
+
Operational failures never throw and never block: daemon unreachable →
|
|
82
|
+
fallback; no signing key → pass-through result with a warning; log
|
|
83
|
+
submission is non-blocking with bounded retry (via the existing
|
|
84
|
+
`@atrib/mcp` submission queue). The only throw paths are contradictory
|
|
85
|
+
inputs (programmer error), e.g. `ref.kind: 'revises'` with
|
|
86
|
+
`event_type: 'annotation'`.
|
|
87
|
+
|
|
88
|
+
## Anchors ([D138](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d138-anchor-plurality-as-the-default-trust-posture), [§2.11.7-§2.11.13](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2117-anchors-generalizing-the-replication-target))
|
|
89
|
+
|
|
90
|
+
`anchors` config takes a **set** of anchor descriptors — bare strings
|
|
91
|
+
(atrib-log [§2.6.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#261-submit-entry)
|
|
92
|
+
endpoints) or `{ url | endpoint, anchor_type?, ... }` objects covering
|
|
93
|
+
the [§2.11.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2118-anchor-type-registry)
|
|
94
|
+
registry (`atrib-log`, `sigstore-rekor`, `rfc3161-tsa`,
|
|
95
|
+
`opentimestamps`). In-process attests fan out to **every** configured
|
|
96
|
+
anchor through `@atrib/mcp`'s `createAnchorFanout` (fire-and-forget per
|
|
97
|
+
[§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission));
|
|
98
|
+
no anchor config at all resolves to `BUILT_IN_DEFAULT_ANCHOR_SET` (two
|
|
99
|
+
independent anchors, [§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture)
|
|
100
|
+
rule 1). A sub-plurality set (< 2 anchors) warns and writes the
|
|
101
|
+
`_local.anchor_config` sidecar degradation marker unless
|
|
102
|
+
`allowSingleAnchor: true` states it is deliberate. The resolved posture
|
|
103
|
+
surfaces as `anchor_posture` on `AttestResult`; `flushAnchors()` gives a
|
|
104
|
+
bounded wait on pending legs. Anchoring never touches signed bytes and
|
|
105
|
+
never blocks the write.
|
|
106
|
+
|
|
107
|
+
## Extension receipts (opt-in)
|
|
108
|
+
|
|
109
|
+
With `attributionReceipts: true`, the daemon client parses
|
|
110
|
+
`dev.atrib/attribution` attestation receipts from tool results' `_meta`
|
|
111
|
+
([D141](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d141-devatribattribution-first-class-mcp-extension-sep-2133),
|
|
112
|
+
extension v0.1): the propagation token, a receipt naming the record the
|
|
113
|
+
server already signed (`log_submission` is a queue status, never an
|
|
114
|
+
awaited proof), and optionally the full signed record for immediate
|
|
115
|
+
Tier-3 re-verification. Each parsed block is run through `@atrib/mcp`'s
|
|
116
|
+
`verifyAttributionReceipt` (extension spec [§6.2](https://github.com/creatornader/atrib/blob/main/docs/extensions/dev.atrib-attribution/v0.1.md#62-receipt-block) integrity check) and
|
|
117
|
+
surfaces as `attribution_receipt: { block, verification }` on
|
|
118
|
+
attest/recall results. Receipts are advisory — trust derives from
|
|
119
|
+
verifying signed records, never from the receipt.
|
|
120
|
+
|
|
121
|
+
## Evidence envelopes ([D137](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d137-universal-evidence-envelope-as-the-single-protocol-level-attachment-model), [§5.5.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#557-universal-evidence-envelope))
|
|
122
|
+
|
|
123
|
+
The universal envelope (profile type URI, four-tier ladder `declared →
|
|
124
|
+
shape → attested → verified`, payload commitment, verifier facts) is the
|
|
125
|
+
single attachment model for external evidence; the legacy `protocol`
|
|
126
|
+
string set is frozen. The SDK ships the structural types/helpers plus
|
|
127
|
+
production and validation: `buildEvidenceEnvelope` computes the payload
|
|
128
|
+
commitment (JCS or raw hash rule) and `validateEvidenceEnvelope` applies
|
|
129
|
+
the normative shape rules — both delegate to the optional peer
|
|
130
|
+
`@atrib/verify` and degrade with a warning when it is not installed.
|
|
131
|
+
Envelopes live outside signed bytes (mirror sidecar, archive evidence
|
|
132
|
+
projection, verifier results, host-owned packets).
|
|
133
|
+
|
|
134
|
+
## API reference
|
|
135
|
+
|
|
136
|
+
Everything below is exported from the package root (`import { … } from
|
|
137
|
+
'@atrib/sdk'`). The surface splits into the SDK layer (the two verbs, the
|
|
138
|
+
config, the daemon transport, the hash helpers, the evidence and receipt
|
|
139
|
+
types) and the record layer re-exported verbatim from `@atrib/mcp` and
|
|
140
|
+
`@atrib/emit`.
|
|
141
|
+
|
|
142
|
+
### `createAtribClient(config?)` → `AtribClient`
|
|
143
|
+
|
|
144
|
+
Builds a client from an [`AtribClientConfig`](#atribclientconfig)
|
|
145
|
+
(default `{}`). Construction is cheap and never throws on operational
|
|
146
|
+
problems: the daemon connection is lazy (first call), the in-process
|
|
147
|
+
signing key resolves lazily on the first attest that needs it, and anchor
|
|
148
|
+
normalization collects warnings instead of erroring.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
interface AtribClient {
|
|
152
|
+
attest(input: AttestInput): Promise<AttestResult>
|
|
153
|
+
recall<T = unknown>(query: RecallQuery): Promise<RecallOutcome<T>>
|
|
154
|
+
flushAnchors(): Promise<void> // bounded wait on pending anchor legs; never throws
|
|
155
|
+
close(): Promise<void>
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Throw vs degrade.** Both verbs follow the
|
|
160
|
+
[§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract)
|
|
161
|
+
degradation contract: operational failures (daemon unreachable, tool
|
|
162
|
+
error, missing key, missing optional peer, log unreachable) never throw —
|
|
163
|
+
they degrade into `warnings` on the result, with `via: 'none'` when
|
|
164
|
+
nothing could serve the call. The only throw paths are contradictory or
|
|
165
|
+
malformed **inputs** (programmer error): a `ref.kind` that contradicts an
|
|
166
|
+
explicit `event_type`, an unknown `ref.kind`, an unknown recall `shape`,
|
|
167
|
+
or an input shape that fails `emitInProcess`'s schema validation.
|
|
168
|
+
|
|
169
|
+
**`attest(input)` semantics.** Maps `AttestInput` to the shared
|
|
170
|
+
`EmitInput` argument shape via `buildEmitArgs` (exported; throws
|
|
171
|
+
`TypeError` on contradictory input — the write verb's only throw path),
|
|
172
|
+
then tries paths in order:
|
|
173
|
+
|
|
174
|
+
1. **Daemon** (`daemon.mode` `'prefer'` or `'require'`): calls the `emit`
|
|
175
|
+
tool on the primitives runtime. The daemon owns the signing key. A
|
|
176
|
+
structurally-garbage daemon result (no `record_hash` string) counts as
|
|
177
|
+
a daemon failure, not a silent all-null success.
|
|
178
|
+
2. **In-process** (`'prefer'` after a daemon failure, or `'off'`): resolves
|
|
179
|
+
the caller-owned key (see `key` in
|
|
180
|
+
[`AtribClientConfig`](#atribclientconfig)) and calls `emitInProcess`
|
|
181
|
+
from `@atrib/emit` with the configured `producer` and the primary
|
|
182
|
+
atrib-log anchor as `logEndpoint`, then reads the freshly signed
|
|
183
|
+
record back from the mirror tail and fans it out to every configured
|
|
184
|
+
anchor via `createAnchorFanout`
|
|
185
|
+
([D138](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d138-anchor-plurality-as-the-default-trust-posture);
|
|
186
|
+
fire-and-forget per [§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission)
|
|
187
|
+
— the primary log receiving the record twice is idempotent-safe per
|
|
188
|
+
[§2.6.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#261-submit-entry)
|
|
189
|
+
step 6), stamping the resolved `anchor_posture` on the result. No key
|
|
190
|
+
→ pass-through result (`via: 'none'`, `record_hash: null`) with a
|
|
191
|
+
warning, per
|
|
192
|
+
[§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract)
|
|
193
|
+
rule 5. The daemon path never consults the client's fan-out: the
|
|
194
|
+
daemon owns its own anchors.
|
|
195
|
+
|
|
196
|
+
Under `daemon.mode: 'require'`, a daemon failure returns the degraded
|
|
197
|
+
`via: 'none'` result directly — it never falls back and never throws.
|
|
198
|
+
|
|
199
|
+
**`recall(query)` semantics.** Resolves the shape (`query.shape`, default
|
|
200
|
+
`'history'`), maps it to the physical tool name via `SHAPE_TO_TOOL`
|
|
201
|
+
(exported), strips the SDK-only `shape` discriminator and `undefined`
|
|
202
|
+
values, and injects the client's default `context_id` for the
|
|
203
|
+
`session_chain` and `orphans` shapes when the query omits it. Then:
|
|
204
|
+
daemon first; on failure, the in-process fallback for the two shapes
|
|
205
|
+
whose engines are exported as libraries today (`history`, `verify`);
|
|
206
|
+
every other shape degrades to `via: 'none'` with a warning naming the
|
|
207
|
+
runtime tool to use instead. See the
|
|
208
|
+
[shape table](#recallquery-shapes) for the full routing.
|
|
209
|
+
|
|
210
|
+
**`close()`** closes the daemon transport if one was opened. Best-effort;
|
|
211
|
+
never throws. Safe to call when `daemon.mode` was `'off'`.
|
|
212
|
+
|
|
213
|
+
### `AttestInput` / `AttestRef`
|
|
214
|
+
|
|
215
|
+
One write shape collapsing emit / annotate / revise. `ref` is the
|
|
216
|
+
discriminator:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
interface AttestRef {
|
|
220
|
+
kind: 'annotates' | 'revises'
|
|
221
|
+
record_hash: string // sha256:<64-hex>
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
| Field | Type | Required | Meaning |
|
|
226
|
+
| --- | --- | --- | --- |
|
|
227
|
+
| `content` | `Record<string, unknown>` | yes | The content being attested. Committed via default `args_hash` = `sha256(JCS(content))` per [D099](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d099-explicit-emit-records-commit-local-content-through-default-args_hash); full content stays in the local mirror sidecar. |
|
|
228
|
+
| `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`. |
|
|
229
|
+
| `ref` | `AttestRef` | no | Collapsed annotate/revise reference; sets the record's `annotates` or `revises` field. |
|
|
230
|
+
| `informed_by` | `string[]` | no | `sha256:<64-hex>` refs of records this one was informed by ([§1.2.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#125-informed_by)). |
|
|
231
|
+
| `allow_unresolved_informed_by` | `boolean` | no | Keep deliberately dangling `informed_by` refs ([D113](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d113-unvalidated-informed_by-refs-are-omitted-by-default) opt-in). |
|
|
232
|
+
| `context_id` | `string` | no | Explicit context (32 lowercase hex). Default: the client's `contextId`, else `resolveEnvContextId()` ([D078](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d078-mcp-servers-honor-atrib_context_id-env-as-context_id-default)/[D083](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d083-harness-session-id-discovery-extends-d078-for-cognitive-primitive-mcp-servers)). |
|
|
233
|
+
| `chain_root` | `string` | no | Explicit chain_root override (requires a context_id). Default: [`resolveChainRoot`](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#1231-multi-producer-chain-composition) precedence in the emit pipeline. |
|
|
234
|
+
| `provenance_token` | `string` | no | [§1.2.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#126-provenance_token) cross-session anchor (genesis-only, 22-char base64url). |
|
|
235
|
+
| `tool_name` | `string` | no | [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture) tool-name disclosure. |
|
|
236
|
+
| `args_hash` | `string` | no | Explicit [§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) args commitment (overrides the [D099](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d099-explicit-emit-records-commit-local-content-through-default-args_hash) default). |
|
|
237
|
+
| `result_hash` | `string` | no | Explicit [§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) result commitment. |
|
|
238
|
+
|
|
239
|
+
### `AttestResult`
|
|
240
|
+
|
|
241
|
+
| Field | Type | Meaning |
|
|
242
|
+
| --- | --- | --- |
|
|
243
|
+
| `record_hash` | `string \| null` | `sha256:<64-hex>` of the signed record, or `null` when nothing was signed (degraded). |
|
|
244
|
+
| `context_id` | `string \| null` | Context the record landed in. |
|
|
245
|
+
| `log_index` | `number \| null` | Public-log index when submission already confirmed; `null` while in flight or disabled. |
|
|
246
|
+
| `inclusion_proof` | `ProofBundle['inclusion_proof'] \| null` | RFC 6962 inclusion proof when already available (cached by record hash per [§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission)). |
|
|
247
|
+
| `receipt_id` | `string?` | Present when the emit pipeline issued a receipt id. |
|
|
248
|
+
| `via` | `'daemon' \| 'in-process' \| 'none'` | Which path produced the record. `'none'` = degraded; see `warnings`. |
|
|
249
|
+
| `warnings` | `string[]` | `atrib:`-prefixed operational warnings (anchor skips, fallbacks, pass-through, flush deadline). |
|
|
250
|
+
| `anchor_posture` | `AttestAnchorPosture?` | `{ effective_anchor_count, used_default_set, warned }` — the resolved [§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture) posture; present on in-process attests that reached the anchor fan-out. |
|
|
251
|
+
| `attribution_receipt` | `VerifiedAttributionReceipt?` | `{ block, verification }` — the parsed `dev.atrib/attribution` receipt plus its `verifyAttributionReceipt` outcome; only when `attributionReceipts: true` and the daemon emitted one. Advisory. |
|
|
252
|
+
|
|
253
|
+
### `RecallQuery` shapes
|
|
254
|
+
|
|
255
|
+
`RecallQuery` is the union of ten query interfaces discriminated by
|
|
256
|
+
`shape` (omitted `shape` means `'history'`). `SHAPE_TO_TOOL` maps each
|
|
257
|
+
shape to its physical tool name on the primitives runtime; the fallback
|
|
258
|
+
column says what serves the shape when no daemon is reachable.
|
|
259
|
+
|
|
260
|
+
| Shape | Daemon tool | In-process fallback | Args (beyond `shape`) |
|
|
261
|
+
| --- | --- | --- | --- |
|
|
262
|
+
| `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?` |
|
|
263
|
+
| `walk` (`WalkQuery`) | `recall_walk` | none (degrades) | `from_record_hash` (required), `edge_types?` (`'CHAIN_PRECEDES' \| 'INFORMED_BY' \| 'ANNOTATES' \| 'REVISES'`), `depth?` |
|
|
264
|
+
| `annotations` (`AnnotationsQuery`) | `recall_annotations` | none (degrades) | `record_hash` (required) |
|
|
265
|
+
| `revisions` (`RevisionsQuery`) | `recall_revisions` | none (degrades) | `record_hash` (required) |
|
|
266
|
+
| `by_content` (`ByContentQuery`) | `recall_by_content` | none (degrades) | `query` (required), `k?`, `max_records?`, `evidence_mode?` (`'bounded' \| 'require_complete'`) |
|
|
267
|
+
| `session_chain` (`SessionChainQuery`) | `recall_session_chain` | none (degrades) | `context_id?` (defaulted from the client), `limit?`, `include_content?` |
|
|
268
|
+
| `orphans` (`OrphansQuery`) | `recall_orphans` | none (degrades) | `context_id?` (defaulted from the client), `event_type?`, `creator_key?`, `limit?` |
|
|
269
|
+
| `by_signer` (`BySignerQuery`) | `recall_by_signer` | none (degrades) | `min_records?` |
|
|
270
|
+
| `trace` / `trace_forward` (`TraceQuery`) | `trace` / `trace_forward` | none (degrades) | `record_hash` (required), `context_id?`, `depth?`, `max_nodes?`, `compact?`, `include_content?` |
|
|
271
|
+
| `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?` |
|
|
272
|
+
|
|
273
|
+
`verify` is Pattern 3 handoff-claim verification
|
|
274
|
+
([D105](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d105-pattern-3-handoff-claims-use-verifier-side-claim-acceptance)/[D106](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d106-verify-is-promoted-to-cognitive-primitive-7)).
|
|
275
|
+
"None (degrades)" shapes return `via: 'none'`, `data: null`, and a
|
|
276
|
+
warning naming the runtime tool — honestly, rather than via a divergent
|
|
277
|
+
reimplementation. When a peer-backed fallback engine itself throws, that
|
|
278
|
+
too is caught and degraded.
|
|
279
|
+
|
|
280
|
+
### `RecallOutcome<T>`
|
|
281
|
+
|
|
282
|
+
| Field | Type | Meaning |
|
|
283
|
+
| --- | --- | --- |
|
|
284
|
+
| `shape` | `RecallShape` | Echo of the resolved shape. |
|
|
285
|
+
| `via` | `'daemon' \| 'in-process' \| 'none'` | Which path served the read. `'none'` = degraded; see `warnings`. |
|
|
286
|
+
| `data` | `T \| null` | The tool/engine result (parsed JSON when the daemon returned the single-JSON-text-block convention), or `null` when degraded. |
|
|
287
|
+
| `warnings` | `string[]` | `atrib:`-prefixed operational warnings. |
|
|
288
|
+
| `attribution_receipt` | `VerifiedAttributionReceipt?` | As on `AttestResult`; opt-in, advisory. |
|
|
289
|
+
|
|
290
|
+
### `AtribClientConfig`
|
|
291
|
+
|
|
292
|
+
| Field | Type | Default | Meaning |
|
|
293
|
+
| --- | --- | --- | --- |
|
|
294
|
+
| `daemon` | `DaemonConfig` | see below | Daemon endpoint/mode/timeouts. |
|
|
295
|
+
| `anchors` | `AnchorSpec[]` | `BUILT_IN_DEFAULT_ANCHOR_SET` (two anchors; the atrib-log member honors `$ATRIB_LOG_ENDPOINT`) | [D138](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d138-anchor-plurality-as-the-default-trust-posture) anchor set; in-process attests fan out to every member. Hostile entries and unregistered `anchor_type` values warn-and-skip. |
|
|
296
|
+
| `allowSingleAnchor` | `boolean` | `false` | [§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture) rule 3: states a < 2-anchor set is deliberate, silencing the sub-plurality warning and the sidecar degradation marker. |
|
|
297
|
+
| `attributionReceipts` | `boolean` | `false` | Opt-in parsing + verification of `dev.atrib/attribution` receipts from daemon `_meta` ([D141](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d141-devatribattribution-first-class-mcp-extension-sep-2133)). |
|
|
298
|
+
| `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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract) rule 5). Note: *any* explicitly-set `key` property opts out of the `resolveKey()` ladder. |
|
|
299
|
+
| `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). |
|
|
300
|
+
| `producer` | `string` | `'atrib-sdk'` (`DEFAULT_PRODUCER`) | `_local.producer` mirror-sidecar label ([§5.9](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#59-local-mirror-conventions)); in-process path only. |
|
|
301
|
+
|
|
302
|
+
### `DaemonConfig` / `DaemonMode`
|
|
303
|
+
|
|
304
|
+
| Field | Type | Default | Meaning |
|
|
305
|
+
| --- | --- | --- | --- |
|
|
306
|
+
| `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. |
|
|
307
|
+
| `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). |
|
|
308
|
+
| `connectTimeoutMs` | `number` | `1500` | Daemon connect timeout. |
|
|
309
|
+
| `callTimeoutMs` | `number` | `10000` | Per-`tools/call` timeout. |
|
|
310
|
+
| `retryCooldownMs` | `number` | `30000` | Cooldown before re-probing an unreachable daemon; within the window, calls skip straight to the fallback. |
|
|
311
|
+
|
|
312
|
+
`resolveDaemonEndpoint(config?)` applies exactly that endpoint
|
|
313
|
+
precedence and is exported for hosts that want to probe the runtime
|
|
314
|
+
themselves.
|
|
315
|
+
|
|
316
|
+
### `AnchorSpec` / `resolveAnchorSet(anchors, allowSingleAnchor?)` → `ResolvedAnchorSet`
|
|
317
|
+
|
|
318
|
+
An anchor is either a bare string (an atrib-log
|
|
319
|
+
[§2.6.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#261-submit-entry)
|
|
320
|
+
endpoint, shorthand for `{ url }`) or an `AnchorDescriptor`
|
|
321
|
+
(`{ anchor_type?, anchor_id?, url?, endpoint?, ... }` — `url` wins over
|
|
322
|
+
`endpoint`; an absent `anchor_type` means `'atrib-log'`; registered
|
|
323
|
+
non-atrib-log types like `'opentimestamps'` need no URL).
|
|
324
|
+
|
|
325
|
+
`resolveAnchorSet` normalizes the caller's specs into the canonical
|
|
326
|
+
[§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture)
|
|
327
|
+
`AnchorSetConfig` that `createAnchorFanout` / `resolveAnchorPosture`
|
|
328
|
+
consume, and never throws: hostile entries (non-string/non-object,
|
|
329
|
+
missing/invalid endpoint where one is required) and `anchor_type` values
|
|
330
|
+
outside the [§2.11.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2118-anchor-type-registry)
|
|
331
|
+
registry warn-and-skip — skipped entries are **excluded** from the
|
|
332
|
+
config, so they never count toward the plurality posture. `undefined`
|
|
333
|
+
input returns an empty config (the built-in default set applies
|
|
334
|
+
downstream). Returns `{ config: AnchorSetConfig, primaryLogEndpoint:
|
|
335
|
+
string | undefined, warnings: string[] }`; `primaryLogEndpoint` (the
|
|
336
|
+
first usable atrib-log anchor) doubles as the in-process emit pipeline's
|
|
337
|
+
`logEndpoint`.
|
|
338
|
+
|
|
339
|
+
### `DaemonClient` / `DaemonCallOutcome`
|
|
340
|
+
|
|
341
|
+
The MCP Streamable HTTP transport to the primitives runtime, exported
|
|
342
|
+
for hosts that want raw tool access with the same degradation posture.
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
new DaemonClient(config?: DaemonConfig, options?: { attributionReceipts?: boolean })
|
|
346
|
+
|
|
347
|
+
type DaemonCallOutcome =
|
|
348
|
+
| { ok: true; value: unknown; attribution?: AttributionReceiptBlock }
|
|
349
|
+
| { ok: false; reason: string }
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
- `callTool(name, args)` → `Promise<DaemonCallOutcome>`. Never throws.
|
|
353
|
+
Tool results carrying a single JSON text block (the atrib primitive
|
|
354
|
+
convention) are parsed; non-JSON text is returned as the string; other
|
|
355
|
+
result shapes are returned raw. A result with `isError: true` is a
|
|
356
|
+
failure outcome.
|
|
357
|
+
- Connection is lazy and cached; a failed call closes the transport and
|
|
358
|
+
starts the `retryCooldownMs` window, during which `callTool` returns
|
|
359
|
+
`{ ok: false }` immediately without re-probing.
|
|
360
|
+
- `close()` — best-effort transport close; never throws.
|
|
361
|
+
- The client is semantically stateless: `context_id` and chain tokens
|
|
362
|
+
travel as explicit tool arguments on every call; the MCP protocol
|
|
363
|
+
session (initialize handshake + `Mcp-Session-Id`) is a transport
|
|
364
|
+
detail managed by the official `@modelcontextprotocol/sdk` client.
|
|
365
|
+
|
|
366
|
+
### Hash helpers
|
|
367
|
+
|
|
368
|
+
Compositions of `@atrib/mcp` primitives — no new hashing implementation.
|
|
369
|
+
|
|
370
|
+
| Export | Returns | Meaning |
|
|
371
|
+
| --- | --- | --- |
|
|
372
|
+
| `recordHashHex(record)` | bare 64-char lowercase hex | SHA-256 over the JCS-canonical COMPLETE signed record, including `signature` ([§1.2.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#123-chain_root-for-genesis-records)). |
|
|
373
|
+
| `recordHashRef(record)` | `sha256:<64-hex>` | The reference form used by `chain_root`, `informed_by`, `annotates`, `revises`. |
|
|
374
|
+
| `deriveProvenanceToken(upstream)` | 22-char base64url | [§1.2.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#126-provenance_token) token for a downstream genesis record: base64url (no padding) of the first 16 bytes of the upstream record hash. |
|
|
375
|
+
|
|
376
|
+
### Evidence envelope family ([D137](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d137-universal-evidence-envelope-as-the-single-protocol-level-attachment-model), [§5.5.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#557-universal-evidence-envelope))
|
|
377
|
+
|
|
378
|
+
Structural types/helpers are SDK-local; envelope **production and
|
|
379
|
+
validation** delegate to the optional peer `@atrib/verify` (lazy import;
|
|
380
|
+
missing peer degrades to a `null` envelope with a warning naming the
|
|
381
|
+
peer — [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract)).
|
|
382
|
+
Envelopes live outside signed bytes (mirror sidecar, archive evidence
|
|
383
|
+
projection, verifier results, host-owned packets).
|
|
384
|
+
|
|
385
|
+
| Export | Kind | Meaning |
|
|
386
|
+
| --- | --- | --- |
|
|
387
|
+
| `EvidenceTier` | type | `'declared' \| 'shape' \| 'attested' \| 'verified'` — what the verifier party actually did. |
|
|
388
|
+
| `EvidencePayloadRefKind` | type | `'inline' \| 'mirror' \| 'archive' \| 'external' \| 'withheld'`. |
|
|
389
|
+
| `EvidencePayloadRef` | type | `{ kind, uri?, record_hash? }` (`uri` / `record_hash` are string-or-null) — `uri` for archive/external locations; `record_hash` when the payload is itself a signed atrib record. |
|
|
390
|
+
| `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`. |
|
|
391
|
+
| `EvidenceConstraint` | type | `{ type, status: 'passed' \| 'failed' \| 'unresolved' \| 'not_checked', expected?, actual? }`. |
|
|
392
|
+
| `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`. |
|
|
393
|
+
| `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. |
|
|
394
|
+
| `evidenceTierRank(tier)` | function | Numeric rank, `0` (declared) … `3` (verified); unknown tiers rank `-1`. |
|
|
395
|
+
| `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). |
|
|
396
|
+
| `validateEvidenceEnvelope(envelope)` | async function | Runs the peer's normative [§5.5.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#557-universal-evidence-envelope) shape validation. Returns `{ validation, warnings }`; `validation: null` when the peer is missing. |
|
|
397
|
+
|
|
398
|
+
### Attribution receipt family ([D141](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d141-devatribattribution-first-class-mcp-extension-sep-2133), `dev.atrib/attribution` v0.1)
|
|
399
|
+
|
|
400
|
+
Receipts are advisory extension data: trust derives only from verifying
|
|
401
|
+
signed records and inclusion proofs, never from the receipt. See the
|
|
402
|
+
extension document under `docs/extensions/dev.atrib-attribution/`.
|
|
403
|
+
|
|
404
|
+
| Export | Kind | Meaning |
|
|
405
|
+
| --- | --- | --- |
|
|
406
|
+
| `ATTRIBUTION_EXTENSION_KEY` | const | `'dev.atrib/attribution'` — the `_meta` key. Aliases `@atrib/mcp`'s `ATTRIBUTION_EXTENSION_ID` (also re-exported). |
|
|
407
|
+
| `ATTRIBUTION_LOG_SUBMISSION_STATUSES` | const | The four known statuses, re-exported from `@atrib/mcp`. |
|
|
408
|
+
| `AttributionLogSubmissionStatus` | type | `'queued' \| 'submitted' \| 'disabled' \| 'failed'`; unknown future values pass through as strings. A queue status, never an awaited proof ([§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission)). |
|
|
409
|
+
| `AttributionReceipt` | type | `{ record_hash?, creator_key?, context_id?, event_type?, chain_root?, log_submission? }` — all optional strings. |
|
|
410
|
+
| `AttributionReceiptBlock` | type | `{ token?, receipt?, record? }` — the [§1.5.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#152-http-transport-tracestate) propagation token, the receipt, and optionally the full signed record for immediate Tier-3 re-verification. |
|
|
411
|
+
| `VerifiedAttributionReceipt` | type | `{ block, verification }` — what the daemon client attaches to attest/recall results: the parsed block plus the [§6.2](https://github.com/creatornader/atrib/blob/main/docs/extensions/dev.atrib-attribution/v0.1.md#62-receipt-block) integrity outcome. |
|
|
412
|
+
| `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. |
|
|
413
|
+
| `verifyAttributionReceipt(block)` | function | Re-exported from `@atrib/mcp`: the extension-spec [§6.2](https://github.com/creatornader/atrib/blob/main/docs/extensions/dev.atrib-attribution/v0.1.md#62-receipt-block) consumer check over the RAW result block — structural well-formedness plus token ↔ receipt ↔ (optional) record internal consistency. Returns `AttributionReceiptVerification` `{ valid, mismatched }` (`['malformed']` for non-blocks). Internal consistency only; not a proof. |
|
|
414
|
+
| `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). |
|
|
415
|
+
|
|
416
|
+
### Record-layer re-exports
|
|
417
|
+
|
|
418
|
+
The complete [§1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#1-attribution-record-format)
|
|
419
|
+
record layer, re-exported verbatim from `@atrib/mcp` (grouped as in
|
|
420
|
+
`src/index.ts`):
|
|
421
|
+
|
|
422
|
+
**Types + event vocabulary.**
|
|
423
|
+
|
|
424
|
+
- `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.
|
|
425
|
+
- `EVENT_TYPE_SHORT_NAMES` — the six short aliases accepted by agent-facing tools.
|
|
426
|
+
- `EVENT_TYPE_SHORT_TO_URI` — short alias → canonical URI map.
|
|
427
|
+
- `isNormativeEventTypeUri(uri)` — membership in the normative set (informational).
|
|
428
|
+
- `isValidEventTypeUri(value)` — [§1.4.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#145-event_type-uri-validation) syntactic URI validation (extension URIs pass).
|
|
429
|
+
- `normalizeEventType(value)` — short alias / known typo path → canonical URI; unknown values pass through.
|
|
430
|
+
|
|
431
|
+
**Canonicalization ([§1.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#13-canonical-serialization)).**
|
|
432
|
+
|
|
433
|
+
- `canonicalRecord(record)` — JCS bytes of the complete signed record (the record-hash preimage).
|
|
434
|
+
- `canonicalSigningInput(record)` — JCS bytes with `signature` removed (the signing input).
|
|
435
|
+
- `canonicalCrossAttestationInput(record)` — [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records) bytes with `signers: []` and no top-level `signature`.
|
|
436
|
+
|
|
437
|
+
**Signing + verification ([§1.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#14-signing-and-verification)).**
|
|
438
|
+
|
|
439
|
+
- `getPublicKey(privateKey)` — raw 32-byte Ed25519 public key for a 32-byte seed.
|
|
440
|
+
- `signRecord(record, privateKey)` — [§1.4.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#142-signing-procedure) signing; returns the record with `signature` set.
|
|
441
|
+
- `signTransactionRecord(record, privateKey, counterpartySigners?)` — signs the cross-attestation bytes; creator's signer entry first.
|
|
442
|
+
- `signTransactionAttestation(record, privateKey)` — one counterparty `SignerEntry` over an existing transaction record's bytes.
|
|
443
|
+
- `verifyRecord(record)` — [§1.4.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#143-verification-procedure) verification, all steps.
|
|
444
|
+
|
|
445
|
+
**Hashing + encoding.**
|
|
446
|
+
|
|
447
|
+
- `sha256(bytes)` — SHA-256 digest.
|
|
448
|
+
- `base64urlEncode` / `base64urlDecode` — base64url, no padding.
|
|
449
|
+
- `hexEncode` / `hexDecode` — lowercase hex.
|
|
450
|
+
|
|
451
|
+
**Chain composition ([§1.2.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#123-chain_root-for-genesis-records) / [§1.2.3.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#1231-multi-producer-chain-composition)).**
|
|
452
|
+
|
|
453
|
+
- `genesisChainRoot(contextId)` — `"sha256:" + hex(SHA-256(UTF-8(context_id)))`.
|
|
454
|
+
- `chainRoot(parentRecord)` — chain_root for a non-genesis record.
|
|
455
|
+
- `resolveChainRoot(opts)` — the [D067](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d067-multi-producer-chain-composition-precedence-contract) precedence contract (token > autoChain tail > env var > mirror tail > synthetic genesis). Never reimplement chain selection.
|
|
456
|
+
|
|
457
|
+
**Propagation ([§1.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#15-context-propagation)).**
|
|
458
|
+
|
|
459
|
+
- `encodeToken(record)` / `decodeToken(token)` — the [§1.5.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#152-http-transport-tracestate) propagation token (`base64url(record_hash) + "." + base64url(creator_key)`; lenient decode returns `null`).
|
|
460
|
+
- `extractTraceId(traceparent)` — trace-id from a W3C `traceparent` header.
|
|
461
|
+
- `mergeTracestate(atribEntry, existing)` / `parseTracestateAtrib(tracestate)` — atrib member handling in W3C `tracestate`.
|
|
462
|
+
- `mergeBaggageAtribSession(sessionToken, existing)` / `parseBaggageAtribSession(baggage)` — session token in W3C `baggage`.
|
|
463
|
+
- `readInboundContext(params)` / `writeOutboundContext(...)` — MCP `params._meta` context reading/writing ([§1.5.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#154-mcp-transport-params_meta)).
|
|
464
|
+
|
|
465
|
+
**Content identity ([§1.2.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#122-content_id-derivation)).**
|
|
466
|
+
|
|
467
|
+
- `computeContentId(serverUrl, toolName)` — `"sha256:" + hex(SHA-256(normalized + ":" + tool))`.
|
|
468
|
+
- `normalizeServerUrl(url)` — WHATWG-semantics URL normalization feeding `content_id`.
|
|
469
|
+
|
|
470
|
+
**Log entry serialization ([§2.3.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#231-entry-serialization)).**
|
|
471
|
+
|
|
472
|
+
- `serializeEntry(input)` — the 90-byte fixed log entry.
|
|
473
|
+
- `eventTypeUriToByte(uri)` — event_type byte mapping (extensions → `0xFF`).
|
|
474
|
+
|
|
475
|
+
**Submission-side validation ([§2.6.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#261-submit-entry) client parity).**
|
|
476
|
+
|
|
477
|
+
- `validateSubmission(record)` — client-side mirror of the log's submission validation; returns `ValidationResult`.
|
|
478
|
+
|
|
479
|
+
**Mirror conventions ([§5.9](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#59-local-mirror-conventions)).**
|
|
480
|
+
|
|
481
|
+
- `readMirrorTail(...)` — newest record on a mirror file.
|
|
482
|
+
- `inheritChainContext(...)` — mirror-based chain inheritance for new producers.
|
|
483
|
+
- `recordHashExistsInMirror(...)` — presence check by record hash.
|
|
484
|
+
|
|
485
|
+
**Context identity ([D078](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d078-mcp-servers-honor-atrib_context_id-env-as-context_id-default)/[D083](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d083-harness-session-id-discovery-extends-d078-for-cognitive-primitive-mcp-servers)).**
|
|
486
|
+
|
|
487
|
+
- `resolveEnvContextId(env?)` — `ATRIB_CONTEXT_ID`, then the harness discovery registry (Claude Code, Codex, file fallbacks).
|
|
488
|
+
|
|
489
|
+
**Submission queue ([§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission)).**
|
|
490
|
+
|
|
491
|
+
- `createSubmissionQueue(...)` — the non-blocking, bounded-retry log submitter with per-record-hash proof caching.
|
|
492
|
+
|
|
493
|
+
**Type re-exports.** `AtribRecord`, `UnsignedAtribRecord`, `SignerEntry`,
|
|
494
|
+
`ChainContext`, `DecodedToken`, `EntryInput`, `ProofBundle`,
|
|
495
|
+
`SubmissionQueue`, `ValidationResult`.
|
|
496
|
+
|
|
497
|
+
**Anchor plurality ([D138](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d138-anchor-plurality-as-the-default-trust-posture), [§2.11.7-§2.11.13](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2117-anchors-generalizing-the-replication-target)), re-exported from `@atrib/mcp`.**
|
|
498
|
+
|
|
499
|
+
- `ANCHOR_TYPES` — the [§2.11.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2118-anchor-type-registry) v1 registry (`atrib-log`, `sigstore-rekor`, `rfc3161-tsa`, `opentimestamps`).
|
|
500
|
+
- `BUILT_IN_DEFAULT_ANCHOR_SET` — the two-anchor zero-config default ([§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture) rule 1).
|
|
501
|
+
- `resolveAnchorPosture(config)` / `resolveEffectiveAnchors(config)` — the pure [§2.11.12](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#21112-producer-side-anchor-posture) posture/effective-set resolution.
|
|
502
|
+
- `createAnchorFanout(options)` / `submitToAnchors(...)` — the per-anchor transport fan-out the client uses on in-process attests; exported for hosts that anchor records themselves.
|
|
503
|
+
- Types `AnchorType`, `AnchorDescriptor`, `AnchorSetConfig`, `AnchorPostureResolution`, `AnchorConfigSidecarMarker`, `AnchorFanout`, `AnchorFanoutTicket`, `AnchorSubmissionOutcome`, `AnchorSubmissionStatus`.
|
|
504
|
+
|
|
505
|
+
**Key handling ([§5.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#56-key-management)), re-exported from `@atrib/emit`.**
|
|
506
|
+
|
|
507
|
+
- `resolveKey()` — the async key ladder: `ATRIB_PRIVATE_KEY` env → `ATRIB_KEY_FILE` → macOS Keychain → 1Password; `null` (pass-through) when nothing resolves.
|
|
508
|
+
- `emitInProcess(input, options?)` — the in-process write engine the SDK's fallback path uses; exported for hosts that want it directly.
|
|
509
|
+
- Types `EmitOutput`, `ResolvedKey`.
|
|
510
|
+
|
|
511
|
+
## Conformance
|
|
512
|
+
|
|
513
|
+
`test/` runs the shared corpora — `spec/conformance/1.4/` (signing +
|
|
514
|
+
adversarial), `1.2.6/` (provenance_token), `1.2.3/multi-producer/`
|
|
515
|
+
(chain-root precedence), `2.6.1/` (submission validation, client-side),
|
|
516
|
+
`evidence-envelope/` ([D137](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d137-universal-evidence-envelope-as-the-single-protocol-level-attachment-model) shape/build/validate), and the
|
|
517
|
+
`mcp-extension/` receipt cases ([D141](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d141-devatribattribution-first-class-mcp-extension-sep-2133) `verifyAttributionReceipt` +
|
|
518
|
+
consistency semantics) — against this package's exported surface. The
|
|
519
|
+
corpora are fixtures, not inspiration: any failure is a spec-bug
|
|
520
|
+
discovery, not something to route around.
|
|
521
|
+
|
|
522
|
+
## Status
|
|
523
|
+
|
|
524
|
+
v0.1.0, unpublished (first-publish pending; see
|
|
525
|
+
`docs/publishing-new-npm-package.md` and the Changesets ignore list).
|
package/dist/attest.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* attest(): the SDK's single write verb.
|
|
3
|
+
*
|
|
4
|
+
* Collapses emit / annotate / revise under one input shape with an
|
|
5
|
+
* optional `ref` discriminator (redesign upgrade-path step 6). All three
|
|
6
|
+
* routes produce records byte-identical to the existing producers because
|
|
7
|
+
* every path terminates in the same `handleEmit` pipeline:
|
|
8
|
+
*
|
|
9
|
+
* daemon path → tools/call 'emit' on the primitives runtime
|
|
10
|
+
* (the mounted @atrib/emit server; daemon-owned key)
|
|
11
|
+
* in-process path → emitInProcess() from @atrib/emit (caller-owned key)
|
|
12
|
+
*
|
|
13
|
+
* There is deliberately no third signing implementation.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProofBundle } from '@atrib/mcp';
|
|
16
|
+
import type { VerifiedAttributionReceipt } from './attribution.js';
|
|
17
|
+
/**
|
|
18
|
+
* The client's resolved D138 anchor posture (§2.11.12), surfaced on
|
|
19
|
+
* in-process attest results. `warned` is true exactly when the config is
|
|
20
|
+
* sub-plurality without `allowSingleAnchor` (rule 4) — the case where the
|
|
21
|
+
* fan-out also produced the §5.9.3 sidecar degradation marker.
|
|
22
|
+
*/
|
|
23
|
+
export interface AttestAnchorPosture {
|
|
24
|
+
effective_anchor_count: number;
|
|
25
|
+
used_default_set: boolean;
|
|
26
|
+
warned: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Reference discriminator collapsing the annotate/revise write kinds. */
|
|
29
|
+
export interface AttestRef {
|
|
30
|
+
kind: 'annotates' | 'revises';
|
|
31
|
+
record_hash: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AttestInput {
|
|
34
|
+
/**
|
|
35
|
+
* The content being attested. Committed via default args_hash
|
|
36
|
+
* (sha256 of JCS(content)) per D099; full content stays in the local
|
|
37
|
+
* mirror sidecar.
|
|
38
|
+
*/
|
|
39
|
+
content: Record<string, unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Event type short name ('observation', 'annotation', …) or absolute
|
|
42
|
+
* URI. Default 'observation', or derived from `ref.kind` when a ref is
|
|
43
|
+
* present ('annotates' → annotation, 'revises' → revision).
|
|
44
|
+
*/
|
|
45
|
+
event_type?: string;
|
|
46
|
+
/** Collapsed annotate/revise reference (sets annotates/revises field). */
|
|
47
|
+
ref?: AttestRef;
|
|
48
|
+
/** sha256:<64-hex> refs of records this one was informed by. */
|
|
49
|
+
informed_by?: string[];
|
|
50
|
+
/** Keep deliberately dangling informed_by refs (D113 opt-in). */
|
|
51
|
+
allow_unresolved_informed_by?: boolean;
|
|
52
|
+
/** Explicit context_id (32 lowercase hex). */
|
|
53
|
+
context_id?: string;
|
|
54
|
+
/** Explicit chain_root override (requires context_id). */
|
|
55
|
+
chain_root?: string;
|
|
56
|
+
/** §1.2.6 cross-session anchor (genesis-only, 22-char base64url). */
|
|
57
|
+
provenance_token?: string;
|
|
58
|
+
/** §8.2 tool-name disclosure. */
|
|
59
|
+
tool_name?: string;
|
|
60
|
+
/** Explicit §8.3 args commitment (overrides the D099 default). */
|
|
61
|
+
args_hash?: string;
|
|
62
|
+
/** Explicit §8.3 result commitment. */
|
|
63
|
+
result_hash?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface AttestResult {
|
|
66
|
+
/** `sha256:<64-hex>` of the signed record, or null when nothing signed. */
|
|
67
|
+
record_hash: string | null;
|
|
68
|
+
context_id: string | null;
|
|
69
|
+
log_index: number | null;
|
|
70
|
+
inclusion_proof: ProofBundle['inclusion_proof'] | null;
|
|
71
|
+
receipt_id?: string;
|
|
72
|
+
/** Which path produced the record. 'none' = degraded, see warnings. */
|
|
73
|
+
via: 'daemon' | 'in-process' | 'none';
|
|
74
|
+
warnings: string[];
|
|
75
|
+
/**
|
|
76
|
+
* `dev.atrib/attribution` receipt from the daemon result's `_meta`,
|
|
77
|
+
* present only when `attributionReceipts` is enabled and the daemon
|
|
78
|
+
* emitted one (D141): the parsed block plus its
|
|
79
|
+
* `verifyAttributionReceipt` outcome. Advisory; trust derives from
|
|
80
|
+
* verifying signed records.
|
|
81
|
+
*/
|
|
82
|
+
attribution_receipt?: VerifiedAttributionReceipt;
|
|
83
|
+
/**
|
|
84
|
+
* D138 anchor posture of the client's fan-out (§2.11.12), present on
|
|
85
|
+
* in-process results after anchor fan-out was consulted. The daemon
|
|
86
|
+
* path never carries it: the daemon owns its own anchors.
|
|
87
|
+
*/
|
|
88
|
+
anchor_posture?: AttestAnchorPosture;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Map AttestInput to the EmitInput argument shape shared by the daemon's
|
|
92
|
+
* `emit` tool and `emitInProcess`. Throws TypeError on contradictory input
|
|
93
|
+
* (the only throw path of the write verb — operational failures degrade).
|
|
94
|
+
*/
|
|
95
|
+
export declare function buildEmitArgs(input: AttestInput, defaultContextId?: string): Record<string, unknown>;
|
|
96
|
+
/** Shape of the daemon `emit` tool's JSON result (EmitOutput). */
|
|
97
|
+
export interface EmitOutputLike {
|
|
98
|
+
record_hash?: unknown;
|
|
99
|
+
log_index?: unknown;
|
|
100
|
+
inclusion_proof?: unknown;
|
|
101
|
+
context_id?: unknown;
|
|
102
|
+
receipt_id?: unknown;
|
|
103
|
+
warnings?: unknown;
|
|
104
|
+
}
|
|
105
|
+
export declare function attestResultFromEmitOutput(output: EmitOutputLike, via: 'daemon' | 'in-process', extraWarnings: string[]): AttestResult;
|
|
106
|
+
//# sourceMappingURL=attest.d.ts.map
|