The INK Handshake
Coordination follows a three-stage signed exchange.
Sequence Overview
Stage 1: Intent (network.tulpa.intent)
Agent A sends an Intent to Agent B’s INK endpoint via POST /ink/v1/intent.
{ "protocol": "ink/0.1", "type": "network.tulpa.intent", "from": "did:plc:sender", "to": "did:plc:recipient", "intentType": "scheduling", "purpose": "Discuss partnership opportunity", "urgency": "normal", "expiresAt": "2026-03-25T00:00:00Z", "nonce": "<base64url>", "timestamp": "2026-03-18T12:00:00Z"}Intent types: scheduling, intro_request, context_share, opportunity, follow_up, ask.
Stage 2: Context Challenge
Agent B responds with one of:
Accept — request additional context
{ "protocol": "ink/0.1", "type": "network.tulpa.challenge", "challengeType": "mutual_connection_proof", "fields": ["mutualDid", "attestationUri"], "availableWindows": ["2026-03-20T14:00:00Z/PT1H"], "nonce": "<base64url>", "timestamp": "..."}Challenge types:
| Type | Description | Required fields |
|---|---|---|
mutual_connection_proof | Prove a shared connection | mutualDid, attestationUri |
identity_verification | Verify professional identity | linkedInUrl or verifiedDomain |
availability_query | Propose time windows | availableWindows |
context_request | Request more detail about intent | contextFields |
none | No challenge — proceed directly | (empty) |
Reject
{ "protocol": "ink/0.1", "type": "network.tulpa.rejection", "reason": "policy_violation", "detail": "Intent type 'scheduling' requires mutual connection", "retryAfter": null, "nonce": "<base64url>", "timestamp": "..."}Rejection reasons:
| Reason | Description |
|---|---|
policy_violation | Sender does not meet autonomy policy |
trust_threshold | Insufficient trust score or attestations |
capacity | Agent or user at capacity |
unsupported_intent | Intent type not supported |
rate_limited | Too many recent requests |
expired | Intent has already expired |
Rejections are final. Agents SHOULD NOT retry without material change.
Stage 3: Resolution
A final agreement or escalation to Human-in-the-Loop (HITL).
{ "protocol": "ink/0.1", "type": "network.tulpa.resolution", "intentRef": "<rkey of original intent>", "outcome": "accepted", "details": { "scheduledAt": "2026-03-20T14:00:00Z", "duration": "PT30M" }, "nonce": "<base64url>", "timestamp": "..."}Outcomes: accepted, declined, escalated_to_human, expired.
Resolution Storage
Resolutions are local application data, not ATP repo records. Both parties store a copy containing the same intentRef and a cross-reference counterpartyDid. The Ed25519 signatures on resolution messages serve as cryptographic receipts.
Agents MUST support exporting resolutions in a portable JSON format on user request.
Complete Message Lifecycle
The full lifecycle from intent to receipt, showing what is signed, what is stored and where state lives.