@adastracomputing/ink 0.2.0 → 0.3.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/README.md +6 -4
- package/dist/crypto/keys.d.ts +14 -1
- package/dist/crypto/keys.js +16 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/docs/maturity.md +10 -6
- package/package.json +5 -5
- package/specs/ink-agent-containment-and-governance-extension-spec.md +3 -2
- package/specs/ink-auditability.md +1 -1
- package/specs/ink-authorization-chain.md +1 -1
- package/specs/ink-compatibility-policy.md +15 -3
- package/specs/ink-compliance-checklist.md +3 -2
- package/specs/ink-containment-phase1-implementation-spec.md +3 -2
- package/specs/ink-introduction-receipts-extension.md +3 -5
- package/specs/ink-key-rotation-spec.md +3 -2
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
An open protocol for AI agents that need to send each other typed, signed messages on the public web. Built for scheduling, introductions, receipts, and other coordination flows where a user delegates an agent to act on their behalf.
|
|
6
6
|
|
|
7
|
-
**Status:
|
|
7
|
+
**Status: experimental; current defined wire version `ink/0.2`.** Wire formats, trust semantics, and APIs may change without backward-compatible migration before v1.0. On npm, `latest` is `0.1.2` and `0.2.0` is published on the `next` tag; senders still emit `ink/0.1` by default unless explicitly configured.
|
|
8
|
+
|
|
9
|
+
`ink/0.2` is the recommended target for new receiver implementations. It is a backward-compatible minor over `ink/0.1`, changing only the body-signature domain: the neutral `ink/sign` in place of the legacy `tulpa/sign`, selected from the signed `protocol` field. `ink/0.1` remains fully supported: both are major version 0, and conformant major-0 receivers accept either. There is no plan to drop `ink/0.1` within major 0; any future version sunset follows the [compatibility policy](specs/ink-compatibility-policy.md).
|
|
8
10
|
|
|
9
11
|
| | |
|
|
10
12
|
|---|---|
|
|
@@ -23,7 +25,7 @@ An open protocol for AI agents that need to send each other typed, signed messag
|
|
|
23
25
|
- [Agent-assisted implementation](#agent-assisted-implementation)
|
|
24
26
|
- [Tests](#tests)
|
|
25
27
|
- [Layout](#layout)
|
|
26
|
-
- [What's stable
|
|
28
|
+
- [What's stable](#whats-stable)
|
|
27
29
|
- [Naming](#naming)
|
|
28
30
|
- [Relationship to Tulpa](#relationship-to-tulpa)
|
|
29
31
|
- [Interoperability](#interoperability)
|
|
@@ -130,9 +132,9 @@ test/ vitest unit + integration tests
|
|
|
130
132
|
|
|
131
133
|
The library runs on any runtime providing standard Web Crypto and `fetch`: Node 24+, Deno, Bun, Cloudflare Workers, browsers. The timestamp freshness window is enforced inside `verifyInkAuth`; nonce single-use is enforced when a `NonceStore` is passed (otherwise `checkReplay` must be called separately). Nonce backing storage and its TTL policy are the integrator's choice.
|
|
132
134
|
|
|
133
|
-
## What's stable
|
|
135
|
+
## What's stable
|
|
134
136
|
|
|
135
|
-
Reliable to depend on:
|
|
137
|
+
These hold across major version 0 (both `ink/0.1` and `ink/0.2`). Reliable to depend on:
|
|
136
138
|
|
|
137
139
|
- Envelope structure and signing base
|
|
138
140
|
- Authorization: signed intent plus Agent Card key set
|
package/dist/crypto/keys.d.ts
CHANGED
|
@@ -30,13 +30,26 @@ export declare function decodePublicKeyMultibase(multibase: string): Uint8Array;
|
|
|
30
30
|
* Returns the raw 32-byte public key.
|
|
31
31
|
*/
|
|
32
32
|
export declare function decodeEncryptionKeyMultibase(multibase: string): Uint8Array;
|
|
33
|
+
/**
|
|
34
|
+
* agentId method prefixes that carry the same key-derived identity. Both encode
|
|
35
|
+
* the identical multibase public key, so they denote the same actor. `tulpa:`
|
|
36
|
+
* is canonical for emission (see deriveAgentId); `ink:` is an accepted inbound
|
|
37
|
+
* alias introduced in ink/0.4. Accept both, emit one.
|
|
38
|
+
*/
|
|
39
|
+
export declare const AGENT_ID_KEY_PREFIXES: readonly ["tulpa:", "ink:"];
|
|
33
40
|
/**
|
|
34
41
|
* Derive agent ID from a public key.
|
|
35
|
-
* Format: tulpa:<multibase-encoded-public-key>
|
|
42
|
+
* Format: tulpa:<multibase-encoded-public-key> (canonical emission).
|
|
36
43
|
*/
|
|
37
44
|
export declare function deriveAgentId(publicKey: Uint8Array): string;
|
|
38
45
|
/**
|
|
39
46
|
* Extract the public key from an agent ID.
|
|
40
47
|
* Only used for initial key exchange — after that, always resolve via identity store.
|
|
48
|
+
*
|
|
49
|
+
* Accepts either the canonical `tulpa:` prefix or the `ink:` alias (ink/0.4):
|
|
50
|
+
* both carry the identical multibase key, so a signature made with that key
|
|
51
|
+
* verifies regardless of which accepted prefix carried it. The prefix is
|
|
52
|
+
* identity syntax, not signing authority. The multibase tail is decoded the
|
|
53
|
+
* same way for both, so a malformed tail is rejected identically.
|
|
41
54
|
*/
|
|
42
55
|
export declare function extractPublicKeyFromAgentId(agentId: string): Uint8Array;
|
package/dist/crypto/keys.js
CHANGED
|
@@ -156,9 +156,16 @@ export function decodeEncryptionKeyMultibase(multibase) {
|
|
|
156
156
|
}
|
|
157
157
|
return key;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* agentId method prefixes that carry the same key-derived identity. Both encode
|
|
161
|
+
* the identical multibase public key, so they denote the same actor. `tulpa:`
|
|
162
|
+
* is canonical for emission (see deriveAgentId); `ink:` is an accepted inbound
|
|
163
|
+
* alias introduced in ink/0.4. Accept both, emit one.
|
|
164
|
+
*/
|
|
165
|
+
export const AGENT_ID_KEY_PREFIXES = Object.freeze(["tulpa:", "ink:"]);
|
|
159
166
|
/**
|
|
160
167
|
* Derive agent ID from a public key.
|
|
161
|
-
* Format: tulpa:<multibase-encoded-public-key>
|
|
168
|
+
* Format: tulpa:<multibase-encoded-public-key> (canonical emission).
|
|
162
169
|
*/
|
|
163
170
|
export function deriveAgentId(publicKey) {
|
|
164
171
|
return `tulpa:${encodePublicKeyMultibase(publicKey)}`;
|
|
@@ -166,13 +173,19 @@ export function deriveAgentId(publicKey) {
|
|
|
166
173
|
/**
|
|
167
174
|
* Extract the public key from an agent ID.
|
|
168
175
|
* Only used for initial key exchange — after that, always resolve via identity store.
|
|
176
|
+
*
|
|
177
|
+
* Accepts either the canonical `tulpa:` prefix or the `ink:` alias (ink/0.4):
|
|
178
|
+
* both carry the identical multibase key, so a signature made with that key
|
|
179
|
+
* verifies regardless of which accepted prefix carried it. The prefix is
|
|
180
|
+
* identity syntax, not signing authority. The multibase tail is decoded the
|
|
181
|
+
* same way for both, so a malformed tail is rejected identically.
|
|
169
182
|
*/
|
|
170
183
|
export function extractPublicKeyFromAgentId(agentId) {
|
|
171
184
|
if (typeof agentId !== "string" || agentId.length === 0 || agentId.length > 512) {
|
|
172
185
|
throw new Error("Invalid agent ID");
|
|
173
186
|
}
|
|
174
|
-
const prefix =
|
|
175
|
-
if (!
|
|
187
|
+
const prefix = AGENT_ID_KEY_PREFIXES.find((p) => agentId.startsWith(p));
|
|
188
|
+
if (!prefix) {
|
|
176
189
|
throw new Error("Invalid agent ID format");
|
|
177
190
|
}
|
|
178
191
|
return decodePublicKeyMultibase(agentId.slice(prefix.length));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { signInkMessage, verifyInkSignature, buildSignatureBase, buildAuthHeader, computeMessageHash, computeEventHash, computeAuditMerkleLeafHash, signAuditEvent, verifyAuditEventSignature, signAuditResponse, verifyAuditResponseSignature, verifyAuditEventChain, signAuditQueryResponse, verifyAuditQueryResponseSignature, encryptInkPayload, decryptInkPayload, checkReplay, base64urlEncode, base64urlDecode, hexToBytes, bytesToHex, jcsCanonicalize, MAX_TIMESTAMP_AGE_MS, MAX_FUTURE_TIMESTAMP_MS, } from "./crypto/ink.js";
|
|
2
2
|
export { signMessage, verifyMessage } from "./crypto/sign.js";
|
|
3
3
|
export { verifyInkSignatureWithKeys } from "./crypto/multi-key-verify.js";
|
|
4
|
-
export { generateKeypair, generateEncryptionKeypair, deriveAgentId, encodePublicKeyMultibase, encodeEncryptionKeyMultibase, decodePublicKeyMultibase, decodeEncryptionKeyMultibase, extractPublicKeyFromAgentId, } from "./crypto/keys.js";
|
|
4
|
+
export { generateKeypair, generateEncryptionKeypair, deriveAgentId, encodePublicKeyMultibase, encodeEncryptionKeyMultibase, decodePublicKeyMultibase, decodeEncryptionKeyMultibase, extractPublicKeyFromAgentId, AGENT_ID_KEY_PREFIXES, } from "./crypto/keys.js";
|
|
5
5
|
export { fetchAgentCard, extractCandidateKeys, resolveBaseUrl, } from "./discovery/agent-card.js";
|
|
6
6
|
export { verifyInkAuth, type NonceStore } from "./middleware/ink-auth.js";
|
|
7
7
|
export { verifyInclusionReceipt, verifyAuditQueryResponse, type InclusionReceipt, type InclusionReceiptVerifyResult, type AuditQueryResponse, type AuditQueryResponseVerifyResult, type VerifyStep, } from "./audit/inclusion-receipt.js";
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export { signInkMessage, verifyInkSignature, buildSignatureBase, buildAuthHeader, computeMessageHash, computeEventHash, computeAuditMerkleLeafHash, signAuditEvent, verifyAuditEventSignature, signAuditResponse, verifyAuditResponseSignature, verifyAuditEventChain, signAuditQueryResponse, verifyAuditQueryResponseSignature, encryptInkPayload, decryptInkPayload, checkReplay, base64urlEncode, base64urlDecode, hexToBytes, bytesToHex, jcsCanonicalize, MAX_TIMESTAMP_AGE_MS, MAX_FUTURE_TIMESTAMP_MS, } from "./crypto/ink.js";
|
|
5
5
|
export { signMessage, verifyMessage } from "./crypto/sign.js";
|
|
6
6
|
export { verifyInkSignatureWithKeys } from "./crypto/multi-key-verify.js";
|
|
7
|
-
export { generateKeypair, generateEncryptionKeypair, deriveAgentId, encodePublicKeyMultibase, encodeEncryptionKeyMultibase, decodePublicKeyMultibase, decodeEncryptionKeyMultibase, extractPublicKeyFromAgentId, } from "./crypto/keys.js";
|
|
7
|
+
export { generateKeypair, generateEncryptionKeypair, deriveAgentId, encodePublicKeyMultibase, encodeEncryptionKeyMultibase, decodePublicKeyMultibase, decodeEncryptionKeyMultibase, extractPublicKeyFromAgentId, AGENT_ID_KEY_PREFIXES, } from "./crypto/keys.js";
|
|
8
8
|
// Discovery: Agent Card fetch + candidate-key extraction
|
|
9
9
|
export { fetchAgentCard, extractCandidateKeys, resolveBaseUrl, } from "./discovery/agent-card.js";
|
|
10
10
|
// Middleware: transport-level INK auth
|
package/docs/maturity.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Maturity Notice
|
|
2
2
|
|
|
3
|
-
> INK
|
|
4
|
-
>
|
|
5
|
-
>
|
|
3
|
+
> INK is **experimental**. The current defined wire version is `ink/0.2`, a
|
|
4
|
+
> backward-compatible minor over `ink/0.1` (both major version 0). Wire formats,
|
|
5
|
+
> trust semantics and APIs may change without backward-compatible migration
|
|
6
|
+
> before v1.0. Do not use for load-bearing production traffic without your own
|
|
7
|
+
> review.
|
|
6
8
|
|
|
7
9
|
## What "experimental" means here
|
|
8
10
|
|
|
@@ -12,8 +14,8 @@
|
|
|
12
14
|
agent-card fetch, and DoS-amplification surfaces. Internal review is
|
|
13
15
|
not a substitute for a third-party audit, treat the security
|
|
14
16
|
posture accordingly.
|
|
15
|
-
- Interop vectors (`../test-vectors/`) are authoritative for
|
|
16
|
-
be added to or revised between
|
|
17
|
+
- Interop vectors (`../test-vectors/`) are authoritative for the current wire
|
|
18
|
+
version but may be added to or revised between patch releases. Mismatched
|
|
17
19
|
implementations should report discrepancies as issues.
|
|
18
20
|
- The protocol is in use by one production integrator (Tulpa). That is
|
|
19
21
|
one data point, not a guarantee of robustness at scale.
|
|
@@ -22,7 +24,9 @@
|
|
|
22
24
|
Bun, and edge runtimes. Browser use is feasible but not exercised by
|
|
23
25
|
the maintainers.
|
|
24
26
|
|
|
25
|
-
## What is stable
|
|
27
|
+
## What is stable
|
|
28
|
+
|
|
29
|
+
These hold across major version 0 (`ink/0.1` and `ink/0.2`):
|
|
26
30
|
|
|
27
31
|
- Envelope structure (fields, canonicalization with JCS / RFC 8785)
|
|
28
32
|
- Ed25519 signing base: `ink/0.1\nMETHOD\nPATH\nrecipientDid\nJCS(body)\ntimestamp`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adastracomputing/ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Library and specification for the INK (Inter-agent Networking Kernel) protocol",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"author": "Ad Astra Computing Inc.",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"zod": "^4.4.3"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@cloudflare/workers-types": "^4.
|
|
64
|
+
"@cloudflare/workers-types": "^4.20260604.1",
|
|
65
65
|
"@types/node": "^24.12.4",
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^8.60.
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
67
67
|
"@typescript-eslint/parser": "^8.60.0",
|
|
68
|
-
"eslint": "^10.4.
|
|
69
|
-
"tsx": "^4.22.
|
|
68
|
+
"eslint": "^10.4.1",
|
|
69
|
+
"tsx": "^4.22.4",
|
|
70
70
|
"typescript": "^6.0.3",
|
|
71
71
|
"vitest": "^4.1.7"
|
|
72
72
|
},
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# INK Compatibility and Versioning Policy
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
**Status:** Draft, v1 stabilization
|
|
4
|
+
**Authors:** Ad Astra Computing
|
|
5
|
+
**Last updated:** 2026-05-24
|
|
5
6
|
|
|
6
7
|
## Purpose
|
|
7
8
|
|
|
@@ -15,7 +16,7 @@ This is the normative compatibility contract. Any change to the INK wire format
|
|
|
15
16
|
|
|
16
17
|
INK uses a single protocol version string in every message envelope, receipt, audit event and handshake message.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Defined versions: `ink/0.1` (default) and `ink/0.2` (negotiated). See [§1.4](#14-defined-wire-versions).
|
|
19
20
|
|
|
20
21
|
The version string appears in the `protocol` field of every top-level INK object and in the first line of every signature base.
|
|
21
22
|
|
|
@@ -48,6 +49,17 @@ prefix (e.g. `network.ink.*`) and define a transition policy. Until then,
|
|
|
48
49
|
conforming implementations MUST emit and accept `network.tulpa.*` types as
|
|
49
50
|
specified.
|
|
50
51
|
|
|
52
|
+
### 1.4 Defined wire versions
|
|
53
|
+
|
|
54
|
+
Two wire versions are defined:
|
|
55
|
+
|
|
56
|
+
- `ink/0.1`, the original version. A sender emits it by default unless it has positively negotiated otherwise.
|
|
57
|
+
- `ink/0.2`, a backward-compatible minor that changes only the body-signature domain separator, from the legacy `tulpa/sign\n` to the neutral `ink/sign\n`. Everything else, the transport-auth signature base, the envelope shape, the encryption and audit sub-protocols and every `network.tulpa.*` type, is identical to `ink/0.1`.
|
|
58
|
+
|
|
59
|
+
`ink/0.2` is receiver-first. A receiver advertises the versions it verifies in its Agent Card `supportedProtocolVersions` array; when that field is absent a sender MUST assume `ink/0.1` only, and a sender MUST NOT emit `ink/0.2` to a receiver that has not advertised it. The negotiation is what keeps the change compatible: an `ink/0.1`-only receiver never receives `ink/0.2` traffic, so it is never asked to verify a domain it does not implement. An `ink/0.2` receiver selects the body-signature domain from the signed `protocol` field and verifies both versions, and because `protocol` is inside the signed body a relabelled message fails verification.
|
|
60
|
+
|
|
61
|
+
This satisfies §1.1. The minor bump adds a capability without breaking deployed `ink/0.1` implementations, because the body-signature domain is negotiated rather than assumed.
|
|
62
|
+
|
|
51
63
|
---
|
|
52
64
|
|
|
53
65
|
## 2. Compatibility Rules
|