Skip to content

Releases: Ad-Astra-Computing/ink

v0.4.0

10 Jun 19:40
v0.4.0
63d78e1

Choose a tag to compare

v0.4.0 Pre-release
Pre-release

This release tightens signature verification and input validation and adds
several verification helpers. It is published on the next dist-tag.

Potentially breaking validation tightenings

These reject inputs that 0.3.0 accepted. Legitimate signer and receiver
traffic is unaffected; the rejected inputs are malformed, malicious, or outside
the documented profile.

  • Ed25519 signatures are now verified in strict RFC 8032 mode at every
    verification site. Small-order public keys and non-canonical point encodings
    are rejected.
  • Signed JSON numbers are constrained to the forms every canonicalizer
    serializes identically: non-finite values, negative zero, and values whose
    shortest form uses exponential notation are rejected at signing and
    verification.
  • The agent card, audit, handshake, and discovery schemas now enforce maximum
    field lengths and array sizes.
  • The Authorization: INK-Ed25519 header is matched against single literal
    spaces; a tab, carriage return, or line feed in the separator is rejected.

Additions

  • verifyCheckpoint(signed, witnessPublicKey, expectedOrigin) verifies a signed
    C2SP checkpoint: the witness Ed25519 signature over the checkpoint body and the
    log origin. A checkpoint used for the inclusion-receipt cross-check must be
    verified this way first.
  • verifyReceipt({ receipt, senderPublicKey, expected }) binds a delivery
    receipt to the exact message it acknowledges: issuer key, from/to/
    messageId, the recomputed message hash, and an optional disposition.
  • verifyInclusionReceipt accepts an event option that recomputes the leaf
    hash and binds it to receipt.eventId. The legacy eventHash is retained but
    does not provide that binding.
  • verifyInkAuth returns a prefix-independent principal alongside the raw
    sender id; per-sender security state (blocks, rate limits) should key on
    principal. canonicalAgentPrincipal(agentId) is exported for the same use.

Per the pre-1.0 policy this release publishes under the next dist-tag; latest
is unchanged.

v0.3.0

09 Jun 20:50
v0.3.0
fa8e7a2

Choose a tag to compare

v0.3.0 Pre-release
Pre-release

extractPublicKeyFromAgentId now accepts either the canonical tulpa: prefix or the ink: alias introduced in ink/0.4. Both carry the identical multibase Ed25519 key, so the bootstrap verification key is byte-identical and a signature made with that key verifies regardless of which accepted prefix carried it. The prefix is identity syntax, not signing authority.

Emission is unchanged: deriveAgentId still returns tulpa: (accept both, emit one). The new AGENT_ID_KEY_PREFIXES export is frozen so a consumer cannot widen the accepted set at runtime. The change is additive and backward compatible. Existing tulpa: inputs behave exactly as before, and every previously rejected prefix other than ink: is still rejected. The wire protocol version is unchanged.

A receiver that keys per-sender security state (blocks, rate limits, duplicate-payload checks, cached verification keys, connection identity) MUST collapse the two spellings to one prefix-independent principal so a sender cannot switch prefix to dodge a block or split a rate-limit window. See Identity.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.2.0

03 Jun 04:44
v0.2.0
7300406

Choose a tag to compare

v0.2.0 Pre-release
Pre-release

Version-keyed body-signature domain. The body message signature is now domain-separated by protocol version. ink/0.1 messages, and any object with no explicit ink/0.2 protocol, keep the legacy tulpa/sign domain so every signature produced to date still verifies. ink/0.2 messages are signed and verified under the neutral ink/sign domain. The verifier selects exactly one domain from the signed protocol field and never tries an alternate, so a signature made under one version's domain cannot be replayed under another.

This change is receiver-first and backward compatible. Verifiers accept both versions and MessageEnvelopeSchema now accepts ink/0.1 and ink/0.2 as a strict enum, rejecting any unknown version. Senders still emit ink/0.1 by default. The HTTP transport-auth signature is unchanged.

New vectors in test-vectors/body-signature.json pin the version-keyed domain including the cross-version and tamper cases. The standalone Python interop client verifies them identically.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.1.7

02 Jun 02:27
v0.1.7
76697ab

Choose a tag to compare

v0.1.7 Pre-release
Pre-release

Pure additive release. Re-exports every per-intent Zod payload schema (ScheduleMeetingPayloadSchema, IntroRequestPayloadSchema, OpportunityPayloadSchema, ConnectionRequestPayloadSchema, FollowUpPayloadSchema, AskPayloadSchema, PingPayloadSchema, RetractPayloadSchema, ContextSharePayloadSchema, MultiPartySyncPayloadSchema, plus the matching *ResponsePayloadSchema variants) and the getPayloadSchema(intent) resolver from the package root. Adopters writing intent-aware receivers / handlers can now type their dispatch surface directly against the canonical payload shapes.

No wire-level changes. No behavior changes inside the existing functions. Receivers on 0.1.6 work unchanged on 0.1.7.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.1.6

02 Jun 02:10
v0.1.6
5f77ad1

Choose a tag to compare

v0.1.6 Pre-release
Pre-release

Pure additive release. Two surface expansions and one backward-compatible schema addition:

  • Intent surface — re-exports IntentTypeSchema constant and IntentType type from the package root. Adopters writing payload-aware receivers can now type their intent dispatch off the canonical Zod enum without reaching into a deep path.
  • Key-entry surface — re-exports KeyStatusSchema, KeyRoleSchema, KeyEntrySchema constants and KeyStatus, KeyRole, KeyEntry, StoredKey types. Adopters wiring their own key-set storage and rotation can now type the persistence shapes without reaching into a deep path. CandidateKey was already root-exported.
  • InkAuditInclusionSchema — adds an optional inclusionProof: z.array(z.string()).optional() field. Third-party auditor clients that verify Merkle inclusion proofs use this field; receivers that only check signatures can ignore it. Backward-compatible because the field is optional — receivers on 0.1.5 work unchanged on 0.1.6.

No wire-level changes. No behavior changes inside the existing functions.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.1.5

02 Jun 01:49
v0.1.5
f0c8b71

Choose a tag to compare

v0.1.5 Pre-release
Pre-release

Pure additive release. Re-exports the InkChallenge, InkRejection, InkResolution, InkTransport types and the InkTransportSchema constant from the package root. Adopters writing handshake-aware receivers can now type their state-machine without reaching into a deep path. No wire-level changes. No behavior changes inside the existing functions. Receivers on 0.1.4 work unchanged on 0.1.5.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.1.4

02 Jun 01:36
v0.1.4
d607557

Choose a tag to compare

v0.1.4 Pre-release
Pre-release

Pure additive release. The implementation files have shipped in earlier releases under deep paths; this release brings them to the package root so adopters writing receivers, builders, or auditor clients can import everything they need from @adastracomputing/ink directly.

New root-level exports:

  • Receipts (./ink/receipts): buildReceipt, shouldSendReceipt, sendReceiptFireAndForget. The canonical INK delivery-receipt builders, signing helpers and fire-and-forget transport. A receiver that wants to ack inbound envelopes per Auditability §6 can drop these in without rolling its own.
  • Transport-auth (./ink/transport-auth): resolveEffectiveTransports, checkTransportAllowed. The token-level transport allowlist enforcement, including the "field absent vs empty array" semantics. Required for any extension token issuer.
  • Discovery-gating (./ink/discovery-gating): buildRedactedCard, shouldRedactOnGet, AgentCardQuerySchema. Visibility-aware Agent Card responses (public, network_only, capability_gated, private).
  • Checkpoint parsing (./ink/checkpoint): parseCheckpoint, formatCheckpoint, CheckpointData. For consumers of transparency-log signed checkpoints.
  • Audit event schemas + types (./models/ink-audit): InkAuditEventTypeSchema, InkAuditEventSchema, InkAuditInclusionSchema, InkReceiptSchema, InkAuditQuerySchema, InkIntroductionReceiptSchema, plus matching types InkAuditEventType, InkAuditEvent, InkAuditInclusion, InkReceipt, InkAuditQuery, InkAuditResponse, InkIntroductionReceiptStatus.
  • Handshake message schemas (./models/ink-handshake): InkChallengeSchema, InkRejectionSchema, InkResolutionSchema, type AgentCardVisibility.
  • Agent Card schema (./models/agent-card): AgentCardSchema (the type was already exported).
  • Encryption key encoder (./crypto/keys): encodeEncryptionKeyMultibase (the encoder companion to the already-exported decodeEncryptionKeyMultibase from 0.1.3).

No wire-level changes. No behavior changes inside the existing functions. Receivers on 0.1.3 work unchanged on 0.1.4.

Per the pre-1.0 policy this release publishes under the next dist-tag.

v0.1.3

02 Jun 01:09
v0.1.3
193ea58

Choose a tag to compare

v0.1.3 Pre-release
Pre-release

Pure additive release that re-exports two helpers from the package root so adopters no longer have to import them through a deep internal path:

  • validateMessage(raw) runs the canonical MessageEnvelopeSchema parse plus the intent-specific payload schema. Receivers building from scratch were either re-implementing the schema check or pulling from @adastracomputing/ink/dist/models/intent.js, which is not a stable surface. The implementer-guide at https://ink.tulpa.network/guides/implementing-a-receiver/ documented this helper as if it were already exported; this release makes that documentation accurate.
  • decodeEncryptionKeyMultibase(multibase) is the companion to the already-exported decodePublicKeyMultibase. The former handles X25519 keys (the Agent Card encryption-key prefix); the latter handles Ed25519. The encrypted-intents guide tells adopters to decode an Agent Card's publicKeyMultibase for use with encryptInkPayload, which expects hex; without the X25519 decoder exported, adopters had to inline the multicodec strip themselves.

Also re-exports the MessageEnvelope type and the MessageEnvelopeSchema constant so adopters can type their parser surface against the canonical schema. No wire-level changes. No behavior changes inside the existing functions. Receivers on 0.1.2 work unchanged on 0.1.3.

This release publishes under the npm next dist-tag per the pre-1.0 policy.

v0.1.2

01 Jun 17:31
v0.1.2
091e846

Choose a tag to compare

v0.1.2 Pre-release
Pre-release

Maturity note. v0.1.x is wire-compatible across patches (ink/0.1 stays frozen) but the API surface and trust semantics remain alpha-quality. See docs/maturity.md. Starting with this release, pre-1.0 versions publish under npm's next dist-tag; latest only advances when a release is explicitly promoted. Adopters who want the current pre-1.0 line install with npm install @adastracomputing/ink@next; the bare npm install @adastracomputing/ink will resolve to the most recent release a maintainer has stamped adopter-grade.

Fixes the v0.1.1 erratum: the Python examples/interop-cli/ shipped in v0.1.1 emitted a phantom envelope shape (type, intentType, purpose, urgency at top level, no id, no correlationId, no createdAt, no body-level signature) that no conforming receiver could accept. v0.1.2 rewrites the CLI's envelope builder to emit the canonical MessageEnvelopeSchema shape:

  • id and correlationId are now generated as 26-char Crockford-base32 ULIDs.
  • createdAt is the canonical envelope creation timestamp (ISO-8601 UTC); the body also carries a separate timestamp field that verifyInkAuth() uses for HTTP §3.3 freshness, distinct from createdAt.
  • intent is the canonical enum value (intro_request for introductions); the legacy intentType/purpose flatten into payload: { target, reason, urgency } per IntroRequestPayloadSchema.
  • Body-level signature is now produced by the canonical domain-separated signer (Ed25519("tulpa/sign\n" + JCS(envelope-without-signature)), base64url, no padding) — matches src/crypto/sign.ts byte-for-byte.
  • provenance is omitted when absent (the field is .optional(); an explicit null would be rejected by Zod).
  • HTTP §3.3 fields (timestamp, nonce) ride alongside the canonical fields so verifyInkAuth() still reads them.

CLI now builds connection_request envelopes. ink-interop send/build --intent-type connection_request (or the alias connection) constructs a ConnectionRequestPayloadSchema-conformant payload (method, context, profileSnapshot). This is the bootstrap intent for first contact between strangers: receivers that opt in to foreign senders verify the body signature against the inline key extracted from the sender's did:key (trust-on-first-use). Other intent types (intro_request, ask, follow_up) presume the sender is already a known contact and remain reserved for established relationships.

Verified end-to-end against https://api.tulpa.network/ink/v1/<agentId>/intent: a did:key: connection_request from ink-interop send lands as a pending action in the recipient's inbox (status: 200, accepted: true, pendingActionId: 01KT…). Coverage spans schema validation, body + transport signature verification, replay/freshness, identity resolution, routing, the foreign-DID policy gate, and shield risk-scoring. Tests pinned to the canonical shape (tests/test_envelope.py) prevent regression. The npm library itself is unchanged from v0.1.1.

Example-helper API break. examples/interop-cli/'s Python helper build_intent_envelope() now requires keypair, replaces intent_type/purpose/timestamp with canonical args (target, reason, created_at, etc.), and removes the extra= kwarg. Adopters who imported the old helper directly will need to update their calls — the previous signature emitted invalid wire data so no callable interop existed there to preserve. This is an example-only change; the npm library (@adastracomputing/ink) exports are unchanged.

v0.1.1

01 Jun 17:31
v0.1.1
a66faea

Choose a tag to compare

v0.1.1 Pre-release
Pre-release

Erratum, 2026-06-01: the bundled Python interop CLI at
examples/interop-cli/ shipped with this tag emits an envelope
shape that does not match the canonical MessageEnvelopeSchema
(id, correlationId, createdAt, intent enum, payload,
body-level signature). The npm library is unaffected. End-to-end
sends from the Python CLI to a conforming receiver fail with
invalid_envelope. Fixed in v0.1.2.

This release is wire-compatible with v0.1.0; the wire version stays ink/0.1. Every change below is additive and accepts the prior shape for the duration of the v0.1.x line — implementations that emit and consume v0.1.0 cards / service entries continue to interoperate. One observable library behavior changes: the runtime emit value of the redacted Agent Card type field flips from "tulpa.agent.card" to "ink.agent.card" (see below). Consumers that pinned to the literal must accept either string; the TypeScript union has been widened accordingly.

Service entry rename. The DID Document service entry for INK endpoints is now type: "INKAgentEndpoint". The legacy "TulpaAgentEndpoint" is still accepted by consumers during v0.1.x; new publishers SHOULD emit INKAgentEndpoint. When both are present, INKAgentEndpoint takes precedence. Removed at the next wire-version bump.

Service entry now points at the Agent Card URL. serviceEndpoint is the URL of the Agent Card, not the inbound message endpoint. Inbound URL stays on the Card itself in the endpoint field. Per the spec update, inboxEndpoint is also accepted as a synonym for endpoint.

Normative SSRF floor for discovery fetches. The Discovery spec now mandates HTTPS-only, refusal of private/link-local/loopback/cloud-metadata hosts, bounded redirects with host re-checking on each hop, response size and time caps, and honoring Cache-Control. Detailed hardening stays implementer responsibility but the normative floor lives in the spec.

Normative DID-binding of fetched cards. Consumers MUST bind the card's ownerDid (when present) to the DID under resolution, and bind the card's agentId to the agent identifier being sent to. A mismatch on either field is a hard reject. This closes the substitution attack where a host that legitimately publishes one DID claims to publish another.

Cache and refresh rules lifted into normative Discovery. Refresh on signature/keyId miss, on observed keySetVersion increase, never fall back to bootstrap keys after a valid card has been observed.

Redacted Agent Card type renamed. The type field on a redacted Agent Card is now "ink.agent.card". Consumers MUST also accept the legacy "tulpa.agent.card" during v0.1.x. The network.tulpa.* wire-message types are explicitly frozen for v0.x per the compatibility policy; rewriting them would break every deployed router.

Wire version is ink/0.1. All v0.1.x package releases emit protocol: "ink/0.1" on the wire. The next wire-version bump is ink/0.2.