@adastracomputing/ink 0.1.0-alpha.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/CODE_OF_CONDUCT.md +42 -0
  3. package/LICENSE-APACHE +201 -0
  4. package/LICENSE-MIT +21 -0
  5. package/README.md +133 -0
  6. package/SECURITY.md +57 -0
  7. package/docs/key-rotation-rule.md +108 -0
  8. package/docs/logo.svg +8 -0
  9. package/docs/maturity.md +81 -0
  10. package/docs/threat-model.md +150 -0
  11. package/package.json +72 -0
  12. package/specs/ink-agent-containment-and-governance-extension-spec.md +508 -0
  13. package/specs/ink-auditability.md +652 -0
  14. package/specs/ink-authorization-chain.md +242 -0
  15. package/specs/ink-compatibility-policy.md +263 -0
  16. package/specs/ink-compliance-checklist.md +309 -0
  17. package/specs/ink-containment-phase1-implementation-spec.md +593 -0
  18. package/specs/ink-introduction-receipts-extension.md +501 -0
  19. package/specs/ink-key-rotation-spec.md +535 -0
  20. package/src/crypto/ink.ts +902 -0
  21. package/src/crypto/keys.ts +211 -0
  22. package/src/crypto/multi-key-verify.ts +170 -0
  23. package/src/crypto/sign.ts +155 -0
  24. package/src/crypto/verify.ts +1 -0
  25. package/src/discovery/agent-card.ts +508 -0
  26. package/src/index.ts +59 -0
  27. package/src/ink/checkpoint.ts +75 -0
  28. package/src/ink/discovery-gating.ts +147 -0
  29. package/src/ink/handshake-budget.ts +413 -0
  30. package/src/ink/receipts.ts +114 -0
  31. package/src/ink/transport-auth.ts +96 -0
  32. package/src/middleware/ink-auth.ts +263 -0
  33. package/src/models/agent-card.ts +63 -0
  34. package/src/models/ink-audit.ts +205 -0
  35. package/src/models/ink-handshake.ts +123 -0
  36. package/src/models/intent.ts +201 -0
  37. package/src/models/key-entry.ts +52 -0
  38. package/src/models/profile.ts +31 -0
  39. package/test-vectors/README.md +129 -0
  40. package/test-vectors/encryption.json +90 -0
  41. package/test-vectors/handshake.json +482 -0
  42. package/test-vectors/jcs.json +30 -0
  43. package/test-vectors/key-rotation.json +101 -0
  44. package/test-vectors/keys.json +32 -0
  45. package/test-vectors/receipts-and-audit.json +142 -0
  46. package/test-vectors/replay.json +88 -0
  47. package/test-vectors/signing.json +61 -0
  48. package/test-vectors/witness.json +394 -0
@@ -0,0 +1,501 @@
1
+ # INK Introduction Receipts Extension v0.1
2
+
3
+ ## Status
4
+ Draft
5
+
6
+ ## Last Updated
7
+ 23 March 2026
8
+
9
+ ## Purpose
10
+
11
+ This specification defines a protocol-level extension for verifiable introductions in INK.
12
+
13
+ It introduces a signed introduction artifact that allows agents to prove that:
14
+ - an introduction workflow occurred
15
+ - a specific introducer participated
16
+ - the introduction reached a defined outcome
17
+ - the artifact is linked to the underlying INK exchange
18
+
19
+ This extension is intended to strengthen Tulpa's warm-path and introduction flows without requiring private relationship context to be published publicly.
20
+
21
+ ---
22
+
23
+ ## 1. Problem
24
+
25
+ The core INK handshake and the message receipt extension provide strong evidence that messages were sent, received, and acted upon.
26
+
27
+ They do not yet provide a first-class artifact for the distinct social action of an introduction.
28
+
29
+ This creates several gaps:
30
+
31
+ 1. A completed introduction is visible only as a series of lower-level intents, resolutions, and local UI actions.
32
+ 2. There is no portable proof that a specific introducer approved or forwarded an introduction.
33
+ 3. Trust-path explanations cannot rely on a standardized signed artifact.
34
+ 4. Implementations cannot exchange or export introduction provenance in an interoperable way.
35
+
36
+ ---
37
+
38
+ ## 2. Design Goals
39
+
40
+ This extension aims to provide:
41
+ - a signed, portable proof of introduction workflow outcomes
42
+ - linkage to the original INK exchange
43
+ - clear role semantics for requester, introducer, and introduced parties
44
+ - local-first storage with optional selective sharing
45
+ - compatibility with INK auditability and authorization chains
46
+
47
+ This extension does not aim to:
48
+ - publish private introduction context by default
49
+ - replace generic INK delivery/disposition receipts
50
+ - create a public reputation or ranking layer
51
+ - encode arbitrary social-graph claims without underlying workflow evidence
52
+
53
+ ---
54
+
55
+ ## 3. Core Model
56
+
57
+ An introduction receipt is a distinct INK message type.
58
+
59
+ It is not:
60
+ - an `intentType`
61
+ - a replacement for `network.tulpa.receipt`
62
+ - a public ATP record by default
63
+
64
+ It is a signed artifact that attests to the outcome of an introduction-related workflow.
65
+
66
+ ### 3.1 Roles
67
+
68
+ This specification uses the following roles:
69
+
70
+ - **requester**: the agent that asked for an introduction
71
+ - **introducer**: the agent representing the person deciding whether to bridge the parties
72
+ - **beneficiary**: the party the requester wants to meet
73
+ - **target**: the counterparty being introduced to the beneficiary
74
+
75
+ For the common case:
76
+ - requester = beneficiary
77
+ - target = person the beneficiary wants to meet
78
+
79
+ The model keeps these fields separate so future workflows can support assistant-mediated or delegated requests without changing the wire shape.
80
+
81
+ ### 3.2 Receipt Trigger
82
+
83
+ An introduction receipt SHOULD be issued when an introduction workflow reaches one of these terminal states:
84
+ - approved
85
+ - declined
86
+ - forwarded
87
+ - completed
88
+ - expired
89
+
90
+ An introduction receipt MUST NOT be emitted for every intermediate step.
91
+ It is an outcome artifact, not a transcript replacement.
92
+
93
+ ---
94
+
95
+ ## 4. Wire Format
96
+
97
+ ### 4.1 Message Type
98
+
99
+ This extension defines a new INK message type:
100
+
101
+ `network.tulpa.introduction_receipt`
102
+
103
+ ### 4.2 Envelope
104
+
105
+ ```json
106
+ {
107
+ "protocol": "ink/0.1",
108
+ "type": "network.tulpa.introduction_receipt",
109
+ "id": "01JQ....",
110
+ "correlationId": "01JQ....",
111
+ "from": "did:plc:introducer",
112
+ "to": "did:plc:requester",
113
+ "requesterDid": "did:plc:requester",
114
+ "introducerDid": "did:plc:introducer",
115
+ "beneficiaryDid": "did:plc:beneficiary",
116
+ "targetDid": "did:plc:target",
117
+ "status": "forwarded",
118
+ "purpose": "Warm introduction for hiring conversation",
119
+ "relatedIntentId": "01JQ....",
120
+ "relatedResolutionId": "01JQ....",
121
+ "contextHash": "a4c8...",
122
+ "nonce": "<base64url>",
123
+ "timestamp": "2026-03-23T12:00:00Z"
124
+ }
125
+ ```
126
+
127
+ ### 4.3 Required Fields
128
+
129
+ | Field | Description |
130
+ |------|-------------|
131
+ | `protocol` | MUST be `ink/0.1` |
132
+ | `type` | MUST be `network.tulpa.introduction_receipt` |
133
+ | `id` | Unique ULID or equivalent globally unique identifier |
134
+ | `correlationId` | Correlates the receipt to the introduction workflow |
135
+ | `from` | Sender of the receipt |
136
+ | `to` | Primary recipient of the receipt |
137
+ | `requesterDid` | DID of the requesting agent |
138
+ | `introducerDid` | DID of the introducing agent |
139
+ | `beneficiaryDid` | DID of the party seeking the introduction |
140
+ | `targetDid` | DID of the party being introduced |
141
+ | `status` | Outcome of the introduction workflow |
142
+ | `purpose` | Short human-meaningful statement of purpose |
143
+ | `nonce` | Replay protection nonce |
144
+ | `timestamp` | Receipt creation time |
145
+
146
+ ### 4.4 Optional Fields
147
+
148
+ | Field | Description |
149
+ |------|-------------|
150
+ | `relatedIntentId` | Stage 1 intent or application-layer intro request that triggered the workflow |
151
+ | `relatedResolutionId` | Final resolution identifier if one exists |
152
+ | `note` | Optional short note from the introducer or implementation |
153
+ | `contextHash` | SHA-256 hex digest of a locally stored private context bundle |
154
+ | `authorizationChainRef` | Reference to an authorization chain artifact if used |
155
+ | `expiresAt` | Optional expiry for the receipt's asserted relevance, not its validity |
156
+
157
+ ### 4.5 Status Values
158
+
159
+ The `status` field MUST be one of:
160
+
161
+ | Status | Meaning |
162
+ |--------|---------|
163
+ | `approved` | Introducer approved the introduction request but forwarding may not yet have happened |
164
+ | `declined` | Introducer declined to make the introduction |
165
+ | `forwarded` | Introducer forwarded the intro to the target or otherwise initiated the bridge |
166
+ | `completed` | The introduction was accepted and the bridge was established |
167
+ | `expired` | The intro workflow expired without completion |
168
+
169
+ Implementations SHOULD use:
170
+ - `approved` when the introducer has given consent but delivery to the target is not yet complete
171
+ - `forwarded` when the introducer has actually sent the bridge
172
+ - `completed` only when the introduction reached the intended counterparties successfully
173
+
174
+ ---
175
+
176
+ ## 5. Delivery and Recipients
177
+
178
+ ### 5.1 Delivery Path
179
+
180
+ Introduction receipts SHOULD be delivered over HTTP using a dedicated endpoint:
181
+
182
+ `POST /ink/v1/introduction-receipt`
183
+
184
+ This keeps them distinct from generic delivery/disposition receipts.
185
+
186
+ ### 5.2 Recipients
187
+
188
+ At minimum, the receipt MUST be sent to the requester.
189
+
190
+ The receipt MAY also be sent to:
191
+ - the beneficiary, if different from the requester
192
+ - the target, when the status is `forwarded` or `completed`
193
+
194
+ Implementations MUST NOT send the receipt to unrelated third parties.
195
+
196
+ ### 5.3 Loop Prevention
197
+
198
+ Receiving a `network.tulpa.introduction_receipt` MUST NOT trigger:
199
+ - a generic message receipt
200
+ - another introduction receipt
201
+
202
+ This follows the same loop-prevention principle as generic INK receipts.
203
+
204
+ ---
205
+
206
+ ## 6. Signature and Replay Protection
207
+
208
+ Introduction receipts are full INK messages.
209
+
210
+ They MUST:
211
+ - be signed using the standard INK Ed25519 request signing flow
212
+ - include a nonce
213
+ - include a timestamp
214
+ - be replay-checked under the same nonce window as other INK messages
215
+
216
+ The signature base SHOULD follow the same pattern as other INK endpoints:
217
+
218
+ ```text
219
+ ink/0.1
220
+ POST
221
+ /ink/v1/introduction-receipt
222
+ <recipientDid>
223
+ <JCS(body)>
224
+ <timestamp>
225
+ ```
226
+
227
+ If a receipt is sent to multiple recipients, each HTTP request MUST be signed for the specific recipient DID.
228
+
229
+ ---
230
+
231
+ ## 7. Privacy Model
232
+
233
+ ### 7.1 Local-First Storage
234
+
235
+ Introduction receipts MUST be treated as local application data by default.
236
+
237
+ They SHOULD be stored inside each relevant participant's local application state and SHOULD NOT be published to ATP by default.
238
+
239
+ ### 7.2 Minimal Disclosure
240
+
241
+ The receipt SHOULD contain only the minimum information needed to prove that the introduction workflow occurred.
242
+
243
+ Sensitive framing, notes, or relationship context SHOULD remain local and MAY be referenced indirectly through `contextHash`.
244
+
245
+ ### 7.3 Selective Sharing
246
+
247
+ Users MAY export or share introduction receipts selectively.
248
+
249
+ Any future ATP publication of introduction receipts MUST be:
250
+ - opt-in
251
+ - purpose-specific
252
+ - documented in a separate spec
253
+
254
+ ### 7.4 Trust Distance and Graph Use
255
+
256
+ Introduction receipts MAY be used to explain warm paths or trust distance inside Tulpa.
257
+
258
+ They MUST NOT be used as a generic public popularity score or implicit endorsement outside the introduction workflow context.
259
+
260
+ ---
261
+
262
+ ## 8. Relationship to Existing INK Artifacts
263
+
264
+ ### 8.1 Generic Message Receipts
265
+
266
+ `network.tulpa.receipt` answers:
267
+ "What happened to this message?"
268
+
269
+ `network.tulpa.introduction_receipt` answers:
270
+ "What happened to this introduction workflow?"
271
+
272
+ Implementations MUST keep these concepts separate.
273
+
274
+ ### 8.2 Resolutions
275
+
276
+ Introduction receipts complement, but do not replace, `network.tulpa.resolution`.
277
+
278
+ Resolutions capture the final handshake outcome.
279
+ Introduction receipts capture the social trust artifact of a completed or declined introduction path.
280
+
281
+ ### 8.3 Audit Events
282
+
283
+ Introduction receipt issuance SHOULD be mirrored into the audit chain with event types such as:
284
+ - `introduction.requested`
285
+ - `introduction.approved`
286
+ - `introduction.declined`
287
+ - `introduction.forwarded`
288
+ - `introduction.completed`
289
+ - `introduction.receipt_sent`
290
+ - `introduction.receipt_received`
291
+
292
+ These event types SHOULD be added in `specs/ink-auditability.md` if this extension is adopted.
293
+
294
+ ### 8.4 Authorization Chains
295
+
296
+ If the introduction depends on delegated authority or multi-hop approval, the receipt MAY reference an authorization chain artifact.
297
+
298
+ The receipt itself does not replace authorization chains.
299
+
300
+ ---
301
+
302
+ ## 9. Access Control
303
+
304
+ An agent receiving an introduction receipt MUST verify that it is an intended participant in the workflow.
305
+
306
+ An implementation MUST reject the receipt with `access_denied` if:
307
+ - the recipient is not the requester
308
+ - the recipient is not the beneficiary when explicitly addressed
309
+ - the recipient is not the target when explicitly addressed
310
+
311
+ The implementation SHOULD also verify:
312
+ - that the signer matches `from`
313
+ - that `introducerDid` is consistent with the signer when the introducer is the sender
314
+ - that the receipt references a known or expected correlation when available
315
+
316
+ ---
317
+
318
+ ## 10. Lexicon Shape
319
+
320
+ Recommended lexicon ID:
321
+
322
+ `network.tulpa.ink.introductionReceipt`
323
+
324
+ Recommended required properties:
325
+
326
+ ```ts
327
+ type InkIntroductionReceipt = {
328
+ protocol: "ink/0.1"
329
+ type: "network.tulpa.introduction_receipt"
330
+ id: string
331
+ correlationId: string
332
+ from: string
333
+ to: string
334
+ requesterDid: string
335
+ introducerDid: string
336
+ beneficiaryDid: string
337
+ targetDid: string
338
+ status: "approved" | "declined" | "forwarded" | "completed" | "expired"
339
+ purpose: string
340
+ nonce: string
341
+ timestamp: string
342
+ relatedIntentId?: string
343
+ relatedResolutionId?: string
344
+ note?: string
345
+ contextHash?: string
346
+ authorizationChainRef?: string
347
+ expiresAt?: string
348
+ }
349
+ ```
350
+
351
+ ---
352
+
353
+ ## 11. Example Flows
354
+
355
+ ### 11.1 Approved but Not Yet Forwarded
356
+
357
+ 1. Requester sends intro-related intent
358
+ 2. Introducer approves internally
359
+ 3. Introducer emits `network.tulpa.introduction_receipt` with `status = approved`
360
+ 4. Requester stores artifact and updates UI
361
+
362
+ ### 11.2 Forwarded
363
+
364
+ 1. Introducer sends the actual bridge message to target
365
+ 2. Introducer emits introduction receipt with `status = forwarded`
366
+ 3. Requester receives proof that the bridge was made
367
+
368
+ ### 11.3 Completed
369
+
370
+ 1. Target accepts or bridge is otherwise established
371
+ 2. Introducer or receiving implementation emits introduction receipt with `status = completed`
372
+ 3. Relevant parties store the final trust artifact
373
+
374
+ ### 11.4 Declined
375
+
376
+ 1. Introducer declines the request
377
+ 2. Introducer emits receipt with `status = declined`
378
+ 3. Requester receives a signed proof of decline and explanatory note if allowed
379
+
380
+ ---
381
+
382
+ ## 12. Storage and Export
383
+
384
+ Implementations SHOULD store introduction receipts in a dedicated local collection or table.
385
+
386
+ Suggested fields:
387
+ - receipt id
388
+ - correlation id
389
+ - participant DIDs
390
+ - status
391
+ - signed payload
392
+ - message hash
393
+ - created at
394
+ - received at
395
+
396
+ Implementations MUST support exporting introduction receipts in a portable JSON format on user request.
397
+
398
+ The export SHOULD include:
399
+ - the signed receipt payload
400
+ - transport metadata sufficient for verification
401
+ - any related resolution or authorization references that the user is allowed to export
402
+
403
+ ---
404
+
405
+ ## 13. UI / Product Requirements
406
+
407
+ Tulpa or other INK implementations adopting this extension SHOULD expose:
408
+ - a human-readable intro history
409
+ - clear explanation of who introduced whom
410
+ - the current intro status
411
+ - the reason or purpose statement
412
+ - the fact that the proof is signed and portable
413
+
414
+ The UI SHOULD avoid:
415
+ - gamified trust scores
416
+ - public leaderboards of introductions
417
+ - exposing hidden third-party context without consent
418
+
419
+ ---
420
+
421
+ ## 14. Error Handling
422
+
423
+ Implementations SHOULD use standard INK structured errors where possible.
424
+
425
+ Recommended error codes:
426
+ - `invalid_receipt`
427
+ - `access_denied`
428
+ - `unknown_correlation`
429
+ - `signature_failed`
430
+ - `replay_detected`
431
+ - `unsupported_extension`
432
+
433
+ If the receiver does not support this extension, it SHOULD return `unsupported_extension`.
434
+
435
+ ---
436
+
437
+ ## 15. Compatibility and Rollout
438
+
439
+ This extension is optional.
440
+
441
+ Agents SHOULD advertise support in Agent Card capabilities.
442
+
443
+ Recommended capability shape:
444
+
445
+ ```json
446
+ {
447
+ "capabilities": {
448
+ "introductionReceipts": {
449
+ "send": true,
450
+ "receive": true,
451
+ "statuses": ["approved", "declined", "forwarded", "completed", "expired"]
452
+ }
453
+ }
454
+ }
455
+ ```
456
+
457
+ Senders MUST NOT assume support unless capability discovery or prior negotiation indicates it.
458
+
459
+ If the recipient does not support introduction receipts, the sender MAY:
460
+ - fall back to local-only receipt generation
461
+ - rely on generic message receipts and audit events only
462
+
463
+ ---
464
+
465
+ ## 16. Test Vectors and Compliance
466
+
467
+ If adopted, this extension SHOULD add:
468
+ - signed receipt test vectors
469
+ - replay-protection test vectors
470
+ - multi-recipient delivery examples
471
+ - correlation-link validation cases
472
+
473
+ Compliance checks SHOULD verify that an implementation:
474
+ - validates required fields
475
+ - verifies signatures
476
+ - enforces participant access control
477
+ - prevents receipt loops
478
+ - exports receipts portably
479
+
480
+ ---
481
+
482
+ ## 17. Recommended Follow-On Implementation Work
483
+
484
+ The Tulpa codebase SHOULD next implement:
485
+
486
+ 1. a lexicon file for `network.tulpa.ink.introductionReceipt`
487
+ 2. receipt verification and persistence utilities
488
+ 3. a local store for introduction receipts
489
+ 4. owner API endpoints for intro history and proof export
490
+ 5. UI surfaces for warm-path trust explanation
491
+ 6. audit event additions for introduction lifecycle states
492
+
493
+ ---
494
+
495
+ ## 18. Open Questions
496
+
497
+ 1. Should `completed` be emitted only by the introducer, or may the beneficiary or target also finalize it?
498
+ 2. Should `approved` be optional if `forwarded` follows immediately?
499
+ 3. Should `contextHash` commit to a standardized canonical bundle shape?
500
+ 4. Should there be a compact participant visibility field for cases where the target should not receive the full receipt?
501
+ 5. Should future ATP publication support a redacted proof form derived from the local receipt?