Internet-Draft Agent Handoff Context October 2026
Srivastava Expires 29 April 2027 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-srivastava-agentproto-handoff-context-00
Published:
Intended Status:
Informational
Expires:
Author:
K. Srivastava
Quantum Learning Machines

Signed Handoff Context for Agentic Dialogs

Abstract

When one agent hands a task to another, the receiving agent often needs to know who handed it over, on whose behalf, through which earlier agents, and which prior context the work depends on. It also needs to know that the handoff is fresh and meant for it, and the sender needs a clear answer back. This document describes a small, transport-neutral handoff context: a signed offer, a signed status reply, and the chain of earlier offers that led to the current one, defined in CDDL for JSON and CBOR, with a lifecycle that maps to Agent2Agent task states. Each offer names the one before it by hash, so that a dropped or reordered intermediate hop can be detected when the chain is carried. Prior context is named by digest only; any log or transparency service behind it is opaque. Appendices show how a SCITT receipt or a Learnlog signed head can be referenced. The document is offered as input to the agentproto working group's use cases and dialog-context work.

Discussion Venues

This note is to be removed before publishing as an RFC.

Discussion of this document takes place on the Agent Communication Protocols (agentproto) Working Group mailing list (agentproto@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/agentproto/.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 29 April 2027.

▲

Table of Contents

1. Introduction

Agent systems hand work across agents, vendors, and trust boundaries. A planner agent asks a coding agent to write a patch; the coding agent asks a test agent to run it. Each hop raises the same questions for the agent that receives work:

The sender, in turn, needs a clear answer: accepted, rejected and why, completed, or failed.

The individual draft "Agentic AI Use Cases and Requirements" [I-D.agentic-ai-usecases-requirements] states several of these needs as requirements. For example, its B3-6 asks for a verifiable provenance record of a request and its response across a delegation chain, such that removal of a hop is detectable; B3-7 asks that a receiver can detect and reject a delegation chain that contains a cycle; and B3-9 asks that dialog context propagate across each hop. The same document places accountability and auditing out of its own scope.

This document describes one way to meet part of those per-hop needs with a small element that existing agent protocols can carry, without defining an audit log. It links the offers that hand work along a chain. It does not cover responses or attribute transformations to hops. Section 7 lists each requirement it touches and says what is and is not met.

1.1. Why a Token Is Not Enough

An authorization token answers one question: may this agent act, and within what limits. A handoff raises questions that a token does not carry. Which agent handed this work over, to which agent, in which dialog, and when? Which earlier handoffs led here? Which prior context does the work depend on? Did the receiver take the work, and how did it end? OAuth 2.0 Token Exchange [RFC8693] can record a history of actors inside a token, but the token is issued by an authorization server, not by the agent handing over, and it says nothing about the dialog or about the answer back. The element defined here is signed by the agents themselves, at each hop, and is small enough to travel beside whatever token the host protocol carries.

1.2. Scope

This document defines:

  • a handoff offer, a handoff status message, and the handoff object that carries an offer with its chain, in CDDL [RFC8610], for JSON [RFC8259] and CBOR [RFC8949] (Section 2);
  • how they are signed with JWS [RFC7515] or COSE [RFC9052] (Section 3);
  • a lifecycle and its mapping to A2A task states (Section 4);
  • rules for freshness, replay, audience, chain linkage, cycles, and equivocation (Section 5);
  • how to carry the element in A2A and MCP (Section 6).

The following are out of scope:

  • Audit data structures, logs, and their storage or query. The agentproto charter [AGENTPROTO-CHARTER] lists "Audit data structures and their production, validation, or consumption" as out of scope. This document names prior context only by digest and treats whatever stores it as opaque.
  • Authorization. The element does not grant authority. [I-D.agentic-ai-usecases-requirements] expects delegated authorization to be addressed in the OAuth and WIMSE working groups, and the charter lists both for coordination (Section 5.5).
  • Key distribution. This document does not define how a receiver learns which keys speak for which agent (Section 3.4).
  • Agent internals. The charter excludes implementation details of AI agents, including the definition of AI models, and the standardization of agent decision-making or planning semantics. It also states that dialog context does not include the content exchanged with AI models, such as prompts.

1.3. Relationship to the agentproto Charter

The charter says the dialog context "consists of the identifiers and lifecycle state needed to correlate and maintain an agentic dialog", and that dialog context "may need to be propagated and remain coherent across multiple intermediaries". It says the mechanisms it calls for need to ensure, among other things, "delegated authorization across AI agent chains". It also says dialog identifiers "may be used in auditing".

The handoff context is intended to sit inside that boundary. It is consumed at handoff time, to decide whether to accept work and to correlate hops. It is not a record kept for later review. Whether the working group sees the chain and reference members as dialog context or as audit data is the working group's call; see Section 11.

1.4. Conventions and Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

Delegator
The agent that hands work to another agent and signs an offer.
Delegate
The agent that receives an offer and signs status replies.
Hop
One handoff from one delegator to one delegate, named by a hop identifier.
Signed handoff
An offer or status message in signed form (Section 3), as octets.
Handoff digest
The SHA-256 digest of a signed handoff's octets (Section 3.3).
Chain
The ordered list of earlier signed offers that led to the current offer, oldest first. It travels beside the current offer, not inside it (Section 2.1).
Host protocol
The agent protocol that carries the element, such as A2A [A2A] or MCP [MCP], or a future agentproto dialog management protocol.

2. Data Model

Member names are short text strings so that one definition serves JSON and CBOR. Except in Digest, which is closed, a receiver MUST ignore members it does not understand and a forwarder MUST NOT remove them, since they are covered by the signature.

HandoffOffer = {
  v: 1,
  type: "offer",
  hop: HopId,
  dialog: text,
  ? task: text,
  iss: AgentId,
  aud: AgentId,
  iat: Time,
  exp: Time,
  ? obo: Principal,
  ? grant: Digest,
  ? prev: Digest,
  ? refs: [+ ContextRef],
  * text => any
}
v
Version. This document defines version 1.
hop
A hop identifier: at least 128 bits from a cryptographically secure random source, encoded in base64url [RFC4648] without padding. It serves as the nonce for replay detection.
dialog
The dialog identifier of the host protocol in which the offer is sent, for example an A2A contextId. When agentproto defines a dialog identifier, that identifier is intended to go here.
task
An optional task identifier from the host protocol.
iss, aud
The delegator and the intended delegate. An AgentId is a string, RECOMMENDED to be a URI, that the receiver's trust configuration maps to keys (Section 3.4).
iat, exp
Issue time, and the end of the window in which the offer can be accepted (Section 5.2). exp bounds acceptance, not the work: how long the work may take is the host protocol's business, tracked in its task state.
obo
The principal on whose behalf the root of the chain acted (Section 5.5).
grant
The digest of the authorization credential that the delegator expects the delegate to present or receive with this hop (Section 5.5). The digest is computed over the credential's octets exactly as presented, for example the ASCII octets of a bearer token. Never the credential itself.
prev
The handoff digest of the offer that the delegator itself received and is now passing on. Absent when the delegator starts the chain.
refs
References to prior context (Section 2.2).
HandoffStatus = {
  v: 1,
  type: "status",
  hop: HopId,
  offer: Digest,
  iss: AgentId,
  aud: AgentId,
  iat: Time,
  state: State,
  ? reason: Reason,
  ? detail: text,
  ? refs: [+ ContextRef],
  * text => any
}

State = "accepted" / "rejected" / "completed" /
        "failed" / "canceled"

Reason = "bad-signature" / "untrusted-key" / "wrong-audience" /
         "stale" / "replay" / "equivocation" / "broken-chain" /
         "cycle" / "too-deep" / "unverifiable-ref" /
         "ref-mismatch" / "policy" / text
offer
The handoff digest of the offer this status answers.
iss, aud
The sender and receiver of this status. For "canceled", the sender is the delegator; for every other state, the sender is the delegate.
state
See Section 4.
reason, detail
Why an offer was rejected or work failed. Reason values other than those listed are permitted but SHOULD be avoided until a registry exists (Section 11). Detail is free text for people and MUST NOT be relied on by software.
refs
For "completed", references to the result, so the delegator can check that what it later receives is what the delegate reported.
HopId = text .regexp "[A-Za-z0-9_-]{22,64}"
AgentId = text
Time = uint

Principal = {
  sub: text,
  ? iss: text,
  * text => any
}

Digest = {
  alg: "sha-256" / text,
  val: B64u
}

B64u = text .regexp "[A-Za-z0-9_-]+"

ContextRef = {
  kind: "digest" / "salted-digest" / "scitt-receipt" /
        "learnlog-head" / text,
  dig: Digest,
  ? loc: text,
  ? proof: any,
  * text => any
}

; In JSON, a chain element is SignedHandoffJson.
; In CBOR, a chain element is SignedHandoffCbor.
SignedHandoff = SignedHandoffJson / SignedHandoffCbor
SignedHandoffJson = JwsCompact / B64u
SignedHandoffCbor = JwsCompact / bstr
JwsCompact = text .regexp
  "[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+"

Time is seconds since 1970-01-01T00:00:00Z, ignoring leap seconds, as an integer.

Digest is a closed map: it has exactly the two members shown. Its alg names the hash function, and its val is the full hash output in base64url without padding. This document defines one value, "sha-256", meaning SHA-256, which implementations MUST support. Other values are left to future specifications, which MUST NOT define a hash whose output is shorter than 256 bits. A receiver that does not implement the alg of a Digest MUST treat a check that depends on it as failed for prev and grant, and as unverifiable for refs.

2.1. The Handoff Object

What the host protocol carries is a Handoff: the signed offer together with its chain.

Handoff = {
  offer: SignedHandoff,
  ? chain: [+ SignedHandoff],
  * text => any
}
offer
The signed current offer.
chain
Earlier signed offers, oldest first, ending with the one that the current offer's prev names. Optional; see Section 9 for the trade-off.

The chain is outside the signature on purpose. Each offer already names its predecessor by digest, and each predecessor names its own, so the prev links fix the chain's membership and order without a second signature over them. Were the chain inside each signed offer, every offer would carry the chains of all its predecessors, and the size would double at each hop. Kept outside, the chain grows by one offer per hop. A chain that does not connect to the offer fails Section 5.3; a chain that was removed is simply absent, which the receiver's policy treats as it would any missing chain.

A status is carried on its own, as a SignedHandoff.

2.2. Context References

A ContextRef names prior context by digest. It says "the sender asserts that this work depends on the object with this digest". It does not say what the object means.

kind
"digest" means dig is the digest of octets the delegate is expected to receive with the task or fetch from loc. "salted-digest" means dig is the digest of a salt followed by those octets, where the salt is at least 16 octets from a cryptographically secure random source and is delivered with the octets, never in the element. "scitt-receipt" and "learnlog-head" are defined in Appendix A and Appendix B; support for them is OPTIONAL. Any other kind MUST be an absolute URI naming its definition.
loc
An optional URI where the object can be fetched.
proof
Kind-specific material, such as a receipt or a signed head.

A receiver that checks a reference reports one of four outcomes: verified (digest matched and any proof checked against a key it trusts), mismatch, unverifiable (it could not obtain or check the object), or not checked. A receiver MUST NOT report a reference as verified unless it performed the check. These outcomes follow the distinction drawn in [I-D.he-agentproto-verifier-evidence] and [I-D.konda-agentproto-evaluation-state] between a negative result and a result that could not be established.

2.3. Example

In this example, an assistant agent has handed a task to a planner, and the planner now hands part of it to a coder. The planner's offer payload, before signing, is:

{
  "v": 1,
  "type": "offer",
  "hop": "q3Zl0v8bVfQmJm2c4bq1Ww",
  "dialog": "ctx-7c1e",
  "task": "task-42",
  "iss": "spiffe://a.example/agent/planner",
  "aud": "spiffe://b.example/agent/coder",
  "iat": 1793000000,
  "exp": 1793000120,
  "obo": {
    "sub": "u-8f2a",
    "iss": "https://idp.u.example"
  },
  "grant": {
    "alg": "sha-256",
    "val": "SKLjsfET5xtZoO5hzIiZFigz2JoYZLmW8Cg8GuYh4o4"
  },
  "prev": {
    "alg": "sha-256",
    "val": "M-OyKnHLAGKpiZKw7sNqAsNKmtfRQ7DUFhtKAL3Slmg"
  },
  "refs": [
    {
      "kind": "digest",
      "dig": {
        "alg": "sha-256",
        "val": "V_WPM8F9ztg6WxBxj1ZIGnzRbM1Xyp5GVdpEYmwbvuQ"
      },
      "loc": "https://a.example/ctx/9"
    }
  ]
}

The Handoff that the planner sends to the coder holds that offer, signed with ES256, and a chain of one element: the assistant's signed offer to the planner. Long lines are folded using the single backslash strategy of [RFC8792].

NOTE: '\' line wrapping per RFC 8792

{
  "offer": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImxXR0ZBQzhDcGM5Zm5lcVhaM2I0\
  YUNqdGJiN3ZCb1Q4UmJ2SnhYNjEta1EiLCJ0eXAiOiJhZ2VudC1oYW5kb2ZmK2p3dC\
  J9.eyJ2IjoxLCJ0eXBlIjoib2ZmZXIiLCJob3AiOiJxM1psMHY4YlZmUW1KbTJjNGJ\
  xMVd3IiwiZGlhbG9nIjoiY3R4LTdjMWUiLCJ0YXNrIjoidGFzay00MiIsImlzcyI6I\
  nNwaWZmZTovL2EuZXhhbXBsZS9hZ2VudC9wbGFubmVyIiwiYXVkIjoic3BpZmZlOi8\
  vYi5leGFtcGxlL2FnZW50L2NvZGVyIiwiaWF0IjoxNzkzMDAwMDAwLCJleHAiOjE3O\
  TMwMDAxMjAsIm9ibyI6eyJzdWIiOiJ1LThmMmEiLCJpc3MiOiJodHRwczovL2lkcC5\
  1LmV4YW1wbGUifSwiZ3JhbnQiOnsiYWxnIjoic2hhLTI1NiIsInZhbCI6IlNLTGpzZ\
  kVUNXh0Wm9PNWh6SWlaRmlnejJKb1laTG1XOENnOEd1WWg0bzQifSwicHJldiI6eyJ\
  hbGciOiJzaGEtMjU2IiwidmFsIjoiTS1PeUtuSExBR0twaVpLdzdzTnFBc05LbXRmU\
  lE3RFVGaHRLQUwzU2xtZyJ9LCJyZWZzIjpbeyJraW5kIjoiZGlnZXN0IiwiZGlnIjp\
  7ImFsZyI6InNoYS0yNTYiLCJ2YWwiOiJWX1dQTThGOXp0ZzZXeEJ4ajFaSUduelJiT\
  TFYeXA1R1ZkcEVZbXdidnVRIn0sImxvYyI6Imh0dHBzOi8vYS5leGFtcGxlL2N0eC8\
  5In1dfQ.aHq9TQ3_SI_kM1xDVzxVluQRhWctEMDt0ATd0Tmf8KjWj6IscdZnav9rhZ\
  zBNNTrvrD1chtHaSsv0y6uRAuVSA",
  "chain": [
    "eyJhbGciOiJFUzI1NiIsImtpZCI6IktLT2JfVVJsZFBNRThYWFhiV3ZYODhFWHB\
  JNlRPaEtINHJ3dEhwcXRJYjgiLCJ0eXAiOiJhZ2VudC1oYW5kb2ZmK2p3dCJ9.eyJ2\
  IjoxLCJ0eXBlIjoib2ZmZXIiLCJob3AiOiJWYjNrUXg5WnRSMm1OOHBMNHdZYzFBIi\
  wiZGlhbG9nIjoiY3R4LTdjMWUiLCJpc3MiOiJzcGlmZmU6Ly91LmV4YW1wbGUvYWdl\
  bnQvYXNzaXN0YW50IiwiYXVkIjoic3BpZmZlOi8vYS5leGFtcGxlL2FnZW50L3BsYW\
  5uZXIiLCJpYXQiOjE3OTI5OTk5OTAsImV4cCI6MTc5MzAwMDExMCwib2JvIjp7InN1\
  YiI6InUtOGYyYSIsImlzcyI6Imh0dHBzOi8vaWRwLnUuZXhhbXBsZSJ9fQ.3BHyncw\
  224yirlOxWsl3gELq1MWlwBKVvkrVVV12qycHGyaByn019Beegv-lms_OFqseMOgf5\
  Xs_kJHaynMcwg"
  ]
}

The chain element's protected header decodes to the following (line breaks added for display):

{"alg":"ES256","kid":"KKOb_URldPME8XXXbWvX88EXpI6TOhKH4rwtHpqtIb8",
 "typ":"agent-handoff+jwt"}

Its payload decodes to the following (line breaks added for display):

{"v":1,"type":"offer","hop":"Vb3kQx9ZtR2mN8pL4wYc1A",
 "dialog":"ctx-7c1e","iss":"spiffe://u.example/agent/assistant",
 "aud":"spiffe://a.example/agent/planner","iat":1792999990,
 "exp":1793000110,
 "obo":{"sub":"u-8f2a","iss":"https://idp.u.example"}}

The two signatures verify with the following public keys, whose JWK Thumbprints [RFC7638] are the kid values in the two headers. Both key pairs are for this example only.

{"crv":"P-256","kty":"EC",
 "x":"G6ZXm5RqUggIPXdM3WR_kg2acGXtkaYFhoM51p-2_iA",
 "y":"8Gv0K14KLtbFeBUSjRTW0CYXr-t_WTYrtbHOFasEL6s"}
{"crv":"P-256","kty":"EC",
 "x":"WnRSpcn3Krie0WFNKoxLb14dgx8uBHCiO0bf7S36cx8",
 "y":"9t5Dm2PQpoSAckALLAGKhvYc4HccNnkPhGEBz3v2HUg"}

The first key is the assistant's and signed the chain element. The second is the planner's and signed the offer. The other values are computed as follows.

  • prev is the handoff digest of the chain element: SHA-256 over its 538 ASCII octets, unfolded.
  • grant is SHA-256 over the 61 ASCII octets of the following example credential string, shown on its own line:
example access token issued to spiffe://b.example/agent/coder
  • The reference's dig is SHA-256 over the following 65 octets of JSON, which the coder is expected to fetch from loc:
{"repo":"https://git.a.example/app","commit":"9fceb02","issue":9}

The coder accepts the work and replies with this status payload, which it signs with its own key. Its offer member is the handoff digest of the planner's signed offer: SHA-256 over its 942 ASCII octets, unfolded.

{
  "v": 1,
  "type": "status",
  "hop": "q3Zl0v8bVfQmJm2c4bq1Ww",
  "offer": {
    "alg": "sha-256",
    "val": "kJIcudVNmFFwbYKTXNO3mqC3e9dQSWVXDNbamGeoP18"
  },
  "iss": "spiffe://b.example/agent/coder",
  "aud": "spiffe://a.example/agent/planner",
  "iat": 1793000003,
  "state": "accepted"
}

3. Signing

Every offer and status MUST be signed by its iss. An unsigned element MUST be treated as absent.

3.1. JWS

The payload is the JSON form of the element. The signed handoff is the JWS Compact Serialization [RFC7515].

  • The protected header MUST contain alg, kid, and typ, with typ set to "agent-handoff+jwt", the short form of the media type application/agent-handoff+jwt (Section 10). It MUST NOT contain crit. The payload uses the JWT [RFC7519] claim names iss, aud, iat, and exp with their JWT meanings, so the explicit type keeps a signed handoff from being taken for another kind of JWT, as recommended in Section 3.11 of [RFC8725].
  • alg MUST name an asymmetric signature algorithm. "none" and MAC algorithms MUST NOT be used. Implementations MUST support ES256 [RFC7518].
  • kid SHOULD be the JWK Thumbprint [RFC7638] of the public key, using SHA-256, base64url without padding.

3.2. COSE

The payload is the CBOR form of the element. The signed handoff is a COSE_Sign1 message [RFC9052] with tag 18.

  • The protected header MUST contain alg and content type (label 3), with content type set to "application/agent-handoff+cbor". It SHOULD contain kid.
  • Implementations MUST support ES256 (alg -7) [RFC9053].

In a JSON chain, a COSE signed handoff is carried as base64url text, which never contains a period and so cannot be confused with a JWS. In a CBOR chain, a JWS is carried as text and a COSE message as a byte string.

3.3. Handoff Digest

The handoff digest is SHA-256 over the signed handoff's octets exactly as sent: the ASCII octets of the JWS Compact Serialization, or the encoded tagged COSE_Sign1 message. Hashing what was signed, as sent, avoids any need for canonical JSON. A party that forwards a signed handoff in a chain MUST forward these octets unchanged.

3.4. Learning Keys

This document does not define how a receiver learns that a key speaks for an AgentId. A receiver MUST use a key only if its own trust configuration binds that key to the iss of the message, for example through workload identity credentials of the kind WIMSE is chartered to define, X.509 certificates chaining to a configured anchor, or keys configured out of band. A key carried inside the message itself, without such a binding, shows nothing about who signed. A receiver MUST accept each trusted key with exactly one algorithm (Section 3.1 of [RFC8725]).

The agentproto charter asks for a reference architecture describing related protocol building blocks that the dialog management protocol can reuse, including identity and authentication. This element is meant to use whatever that architecture names.

4. Lifecycle

Each hop has its own lifecycle, held separately by the delegator and the delegate.

              offer (delegator)
                    |
                    v
               +---------+  rejected (delegate)
               | offered |---------------------> [rejected]
               +---------+
                 |     |  canceled (delegator)
     accepted    |     +-----------------------> [canceled]
    (delegate)   v
               +----------+  canceled (delegator)
               | accepted |--------------------> [canceled]
               +----------+
                 |      |
      completed  |      |  failed (delegate)
     (delegate)  v      v
          [completed]  [failed]

   Brackets mark terminal states.  Not drawn: "completed" or
   "failed" sent directly from "offered" (accepted is implied),
   and the local terminal state "expired".
Figure 1

The host protocol keeps its own task state. The table shows the nearest A2A TaskState [A2A] for each state. A2A states with no entry, such as TASK_STATE_INPUT_REQUIRED and TASK_STATE_AUTH_REQUIRED, stay in the host protocol; they do not change the hop's state.

Table 1: Mapping to A2A task states
Handoff state Nearest A2A TaskState
offered TASK_STATE_SUBMITTED
accepted TASK_STATE_WORKING
rejected TASK_STATE_REJECTED
completed TASK_STATE_COMPLETED
failed TASK_STATE_FAILED
canceled TASK_STATE_CANCELED

5. Processing Rules

5.1. Receiving an Offer

A delegate that receives an offer performs these checks. The first failure ends processing. Except where a check says otherwise, the delegate SHOULD send a "rejected" status with the reason shown, unless doing so would itself leak information its policy protects.

  1. Check the signed form (Section 3): the JWS typ or the COSE content type, and v equal to 1 and type equal to "offer" in the payload. Then verify the signature with a key that its trust configuration binds to iss (Section 3.4). Reasons: bad-signature, untrusted-key.
  2. Check that aud equals its own AgentId. Reason: wrong-audience.
  3. Check freshness (Section 5.2). Reason: stale.
  4. Check that (iss, hop) has not been seen before (Section 5.2). A replay gets no status; the earlier answer stands. Equivocation is handled as in Section 5.4.
  5. If the host protocol message carries a dialog identifier, check that dialog equals it. Reason: policy.
  6. If the Handoff carries a chain, check it (Section 5.3). Reasons: broken-chain, cycle, too-deep. If local policy requires a full, verified chain and the chain is absent, partial, or unverifiable, reject. Reason: policy.
  7. Check any references that local policy requires (Section 2.2). Reasons: unverifiable-ref, ref-mismatch.

If all checks pass and the delegate takes the work, it sends "accepted".

5.2. Freshness and Replay

  • A receiver MUST reject an offer whose exp is not later than its iat, whose exp is not later than the current time, or whose iat is later than the current time plus a configured skew. A skew of no more than 60 seconds is RECOMMENDED.
  • A receiver MUST reject an offer whose exp minus iat exceeds its configured maximum lifetime. A maximum of 300 seconds is RECOMMENDED for interactive use.
  • A receiver MUST remember each (iss, hop) pair that passed steps 1 through 3 of Section 5.1, with the handoff digest, at least until exp plus the skew. A second offer with the same pair and the same digest is a replay; with a different digest, it is equivocation (Section 5.4). Neither is accepted.
  • The aud and dialog members bind the offer to one receiver and one dialog. An offer copied to another agent fails step 2.

Expiry of the outer offer is checked. Earlier offers in a chain are history and are expected to have expired; Section 5.3 checks only that each was live when the next was issued.

5.3. Checking a Chain

Let C[0..n-1] be the decoded chain, oldest first, and O the current offer. For uniformity, let C[n] denote O.

  1. Check each C[i] as in step 1 of Section 5.1: its signed form, v and type, and its signature. A receiver that does not trust a key for some C[i].iss MUST treat the chain as unverifiable from that point back; its policy for a partial chain then applies (step 6 of Section 5.1).
  2. Check that for each i from 1 to n, C[i].prev equals the handoff digest of C[i-1].
  3. Check continuity: for each i from 1 to n, C[i-1].aud equals C[i].iss.
  4. Check timing: for each i from 1 to n, C[i-1].iat is not later than C[i].iat, and C[i].iat is not later than C[i-1].exp plus the skew. An agent passes on only an offer that is still live.
  5. If C[0] has a prev member, the chain is partial: it does not reach the start.
  6. If any AgentId appears as iss of more than one of C[0..n], or the receiver's own AgentId appears as iss or aud of any C[i] with i less than n, the chain contains a cycle, and the receiver SHOULD reject with reason "cycle" (B3-7 in [I-D.agentic-ai-usecases-requirements]). This document departs from B3-7 in one respect: local policy MAY admit a known re-entry, such as a callback to the original requester.
  7. A receiver MUST enforce a maximum chain length. A limit of 16 is RECOMMENDED. Reason: too-deep.

Failures of checks 2 through 4 use reason "broken-chain".

A verified chain shows that each listed agent signed an offer to the next, in that order, while the earlier offer was live. Removing or reordering an intermediate hop breaks check 2 or 3. It does not show that the agents were authorized, or that what they said was true (Section 8.2). It also does not show that an earlier offer had not been rejected or canceled when the next was issued.

5.4. Forks, Concurrency, and Equivocation

  • Fan-out is allowed. A delegator MAY issue several offers with the same prev, each with its own hop, to run subtasks in parallel.
  • A delegator that retransmits an offer MUST resend the identical octets. It MUST NOT sign the same hop a second time, since ES256 and most signature algorithms produce different octets each time, and the result would look like equivocation.
  • Two signed offers with the same iss and hop but different octets are equivocation. A receiver that sees the second MUST NOT accept it and sends no status for it. If it has not yet answered the first, it SHOULD send "rejected" for the first with reason "equivocation". If it already accepted the first, it SHOULD stop the work and send "failed" for the first with reason "equivocation". In both cases status.offer names the first offer, the hop gets one answer, and the receiver SHOULD flag the conflict to its operator. Only a party that sees both offers can detect this. Two offers with the same (iss, hop) sent to different audiences each look valid to their own receiver; the chains that grow from them diverge, and the divergence shows only to a party that later sees both.
  • The receiver of a status checks its signed form, with type equal to "status", and verifies its signature with a key that its trust configuration binds to status.iss. It then checks that status.iss equals offer.aud (offer.iss for "canceled"), that status.aud equals the other party of the hop, and that status.offer equals the handoff digest of the offer.
  • If a delegate sends conflicting statuses for one hop, such as both "completed" and "failed", the receiver MUST treat the first one it verified as the hop's state and SHOULD flag the conflict to its operator.
  • "canceled" and "completed" can cross in flight. Each party keeps the first terminal state it verified. This document does not resolve such races; it makes them visible to both sides.

5.5. On Behalf Of

The obo member names the principal for whom the root of the chain acted, such as a user. Prior delegators appear in chain. OAuth 2.0 Token Exchange [RFC8693] records a similar actor history with nested "act" claims, where the outermost actor is current and nested actors are earlier ones. As with nested act claims in Section 4.1 of [RFC8693], the prior delegators in chain are informational. Unlike a token's sub claim, obo is not an authorization claim. A receiver MUST NOT make an access control decision based on obo or chain alone.

Authority comes from credentials that the host protocol carries, issued under OAuth, WIMSE, or a similar framework. The grant member lets the delegator bind the hop to one such credential by digest. A receiver that is given a credential with the hop can check that it is the one the delegator named. Whether the credential's authority exceeds what the previous hop held (B3-8 in [I-D.agentic-ai-usecases-requirements]) is for that framework to decide, not this element.

Section 8.1 states, for each security-relevant claim this element makes, who carries it, who verifies it, and how it fails.

6. Carrying the Element

The handoff context is meant to travel inside the host protocol's own messages. This document defines no new transport and no HTTP header.

A2A
A2A extensions place custom attributes in the metadata map of core data structures [A2A]. By the convention of this document, the signed offer is placed in Message.metadata under a key equal to the extension URI "https://quantumlearningmachines.com/a2a/ext/agent-handoff/v1", and that URI is listed in Message.extensions. The value is the Handoff object of Section 2.1. The URI is an identifier; nothing needs to be fetched from it. A client also lists the URI in the A2A-Extensions service parameter of the request. A status is placed under the same key in the metadata of the Message that carries the reply, or of the status message (TaskStatus.message) of the returned Task. A delegator's "canceled" status is placed under the same key in the metadata of its Cancel Task request. If the working group takes up this work, the URI would move to one it chooses.
MCP
When one agent delegates through an MCP tool call, the Handoff object is placed under the key "quantumlearningmachines.com/agent-handoff" in the _meta object of the request params, which MCP's base request type allows [MCP]. A status is placed under the same key in the CallToolResult's _meta object. A delegator's "canceled" status is placed under the same key in the _meta object of the params of its notifications/cancelled notification, which MCP's base notification type allows. The key follows MCP's rules for _meta key prefixes, and its prefix is not one that MCP reserves.
agentproto
If the working group defines an extensible dialog context, the handoff context is intended to become one of its extensions, so that a mediator that translates between protocols (B5-3 in [I-D.agentic-ai-usecases-requirements]) can carry it unchanged. One check does not survive translation today: the dialog member holds the host protocol's identifier, and a mediator that maps one protocol's identifier to another's leaves step 5 of Section 5.1 to fail unless the receiver's policy knows the mapping. A dialog identifier defined by agentproto, carried unchanged through mediators, would close that gap.

7. Requirements Coverage

The table lists each requirement of [I-D.agentic-ai-usecases-requirements] that this element touches, what the element provides toward it, and what it leaves to other mechanisms.

Table 2: Requirements touched by this element
Requirement Provided Not provided
B3-6, verifiable per-hop provenance with removal detectable Signed offers linked by digest; removing or reordering an intermediate hop is detected when the chain is carried (Section 5.3) Responses and transformations are not attributed; the start of a chain can be dropped (Section 8.3)
B3-7, cycle detection Check 6 of Section 5.3 Cycles through hops not in the carried chain
B3-8, authority not exceeding the previous hop's grant binds the hop to one credential by digest (Section 5.5) The comparison itself, which belongs to the credential's framework
B3-9, dialog context propagated per hop The dialog member and carriage inside the host message (Section 6) The dialog context itself; this is one element of it
B1-7, checking a resuming party Nothing Resumption is a host protocol matter
CMN-10, revocation propagated down a chain "canceled" follows prev from hop to hop (Section 4) Revoking authority; the element grants none
B5-3, a mediator between protocols The Handoff is opaque octets a mediator can copy (Section 6) The dialog check across a translated identifier (see above)

8. Security Considerations

8.1. Security-Relevant Claims

[I-D.bu-agentproto-security-principal-binding] asks a protocol to state, for each security-relevant claim, its carrier, its verifier, what binds it, what keeps it fresh, and how it fails. For this element:

Table 3: Security-relevant claims
Claim Carrier Verifier Binding Freshness Failure
The offer comes from iss Signature over the offer Delegate A key its trust configuration binds to iss (Section 3.4) iat, exp, and hop (Section 5.2) "rejected": bad-signature or untrusted-key
The offer is for this receiver in this dialog aud and dialog, under the signature Delegate aud equals its AgentId; dialog equals the host identifier As above "rejected": wrong-audience or policy
The offer follows these earlier offers in order prev; the chain Delegate Handoff digests (Section 3.3); continuity and timing (Section 5.3) Check 4 of Section 5.3 "rejected": broken-chain, cycle, or too-deep; or unverifiable where a key is untrusted
The work depends on this prior context refs Delegate, when policy requires The object's digest and any kind-specific proof (Section 2.2) None in the element "rejected": unverifiable-ref or ref-mismatch; or not checked
The delegate answered as stated Signature over the status Delegator A key bound to status.iss; status.offer equals the offer's digest (Section 5.4) The first verified status stands Status discarded; conflict flagged to the operator

8.2. What a Signature Shows

A valid signature shows that the holder of a trusted key signed the offer. It does not show that the signer had authority to delegate, that the referenced context is correct, or that the work was done as reported. A hash link shows order and consistency, not authorship; authorship comes only from signatures checked against keys the receiver trusts. [I-D.wadkins-agentproto-action-determinability] discusses the gap between evidence of authorization and evidence of enforcement; this element addresses neither.

8.3. Truncated Chains

A delegator can omit prev and the chain and present itself as the start. The offer is still valid. A receiver that needs to know the origin MUST require a full chain whose first element is signed by an origin it trusts. Without the chain, a receiver also cannot tell whether the delegator passed on an offer that had expired, been rejected, or been canceled.

8.4. Replay and Freshness

Replay protection depends on the receiver keeping its (iss, hop) cache and on loosely synchronized clocks. A receiver that loses its cache, for example after a restart, SHOULD reject offers with iat before the restart until the maximum lifetime has passed.

8.5. Key Compromise

A stolen delegator key lets an attacker issue offers in that delegator's name until the key is withdrawn from trust. Short lifetimes limit how long a captured offer is useful but not what a stolen key can sign. Revocation of keys is left to the key distribution mechanism (Section 3.4).

8.6. Cross-Protocol Confusion

The typ and content type values make a signed handoff distinct from other JWS or COSE objects signed with the same key. Handoff receivers MUST check them (Section 5.1). This protects a handoff receiver from accepting another kind of object as an offer. It does not protect other verifiers that do not check a type, such as a verifier of Learnlog signed heads [I-D.srivastava-learnlog], which does not require a typ; using separate keys for separate purposes avoids the question.

8.7. Active Content

The media types registered in Section 10 do not contain active content.

8.8. Resource Use

Chains and references can be large, and loc invites fetches. A chain grows by one signed offer per hop (Section 2.1). Receivers MUST bound chain length and element size, and SHOULD NOT fetch loc URIs from untrusted senders without the safeguards they apply to any untrusted URL.

8.9. Secrets

The element MUST NOT contain secrets: no access tokens, API keys, tool credentials, passwords, or private keys. Credentials appear only as digests in grant.

9. Privacy Considerations

The considerations of [RFC6973] apply.

10. IANA Considerations

This document requests two media type registrations in the "Media Types" registry [RFC6838]. The first names a complete JWS signed handoff, for the typ header (Section 3). The second names the CBOR payload of a COSE signed handoff, for its content type header. No other registry is requested.

RFC Editor: please replace "RFC XXXX" below with the number of this document and remove this note.

10.1. application/agent-handoff+jwt

Type name
application
Subtype name
agent-handoff+jwt
Required parameters
N/A
Optional parameters
N/A
Encoding considerations
binary; a value is a JWS Compact Serialization: base64url-encoded parts separated by period characters.
Security considerations
See Section 8 of RFC XXXX. This media type does not contain active content.
Interoperability considerations
N/A
Published specification
RFC XXXX
Applications that use this media type
Agent communication protocols that carry handoff context.
Fragment identifier considerations
N/A
Additional information
Deprecated alias names for this type: N/A; Magic number(s): N/A; File extension(s): N/A; Macintosh file type code(s): N/A
Person and email address to contact for further information
Kumar Srivastava, kumar@quantumlearningmachines.com
Intended usage
COMMON
Restrictions on usage
none
Author
Kumar Srivastava
Change controller
IETF
Provisional registration? (standards tree only)
No

10.2. application/agent-handoff+cbor

This type labels the CBOR payload carried inside a COSE_Sign1 signed handoff (Section 3).

Type name
application
Subtype name
agent-handoff+cbor
Required parameters
N/A
Optional parameters
N/A
Encoding considerations
binary (CBOR)
Security considerations
See Section 8 of RFC XXXX. This media type does not contain active content.
Interoperability considerations
N/A
Published specification
RFC XXXX
Applications that use this media type
Agent communication protocols that carry handoff context.
Fragment identifier considerations
N/A
Additional information
Deprecated alias names for this type: N/A; Magic number(s): N/A; File extension(s): N/A; Macintosh file type code(s): N/A
Person and email address to contact for further information
Kumar Srivastava, kumar@quantumlearningmachines.com
Intended usage
COMMON
Restrictions on usage
none
Author
Kumar Srivastava
Change controller
IETF
Provisional registration? (standards tree only)
No

11. Open Issues

12. References

12.1. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC4648]
Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, , <https://www.rfc-editor.org/info/rfc4648>.
[RFC6838]
Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, DOI 10.17487/RFC6838, , <https://www.rfc-editor.org/info/rfc6838>.
[RFC7515]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, , <https://www.rfc-editor.org/info/rfc7515>.
[RFC7518]
Jones, M., "JSON Web Algorithms (JWA)", RFC 7518, DOI 10.17487/RFC7518, , <https://www.rfc-editor.org/info/rfc7518>.
[RFC7638]
Jones, M. and N. Sakimura, "JSON Web Key (JWK) Thumbprint", RFC 7638, DOI 10.17487/RFC7638, , <https://www.rfc-editor.org/info/rfc7638>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259]
Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/info/rfc8259>.
[RFC8610]
Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, , <https://www.rfc-editor.org/info/rfc8610>.
[RFC8949]
Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", STD 94, RFC 8949, DOI 10.17487/RFC8949, , <https://www.rfc-editor.org/info/rfc8949>.
[RFC9052]
Schaad, J., "CBOR Object Signing and Encryption (COSE): Structures and Process", STD 96, RFC 9052, DOI 10.17487/RFC9052, , <https://www.rfc-editor.org/info/rfc9052>.
[RFC9053]
Schaad, J., "CBOR Object Signing and Encryption (COSE): Initial Algorithms", RFC 9053, DOI 10.17487/RFC9053, , <https://www.rfc-editor.org/info/rfc9053>.

12.2. Informative References

[A2A]
A2A Project, "Agent2Agent (A2A) Protocol Specification, Version 1.0.0", <https://a2a-protocol.org/latest/specification/>.
[AGENTPROTO-CHARTER]
IETF, "Agent Communication Protocols (agentproto) Charter, Revision 01", , <https://datatracker.ietf.org/doc/charter-ietf-agentproto/>.
[I-D.agentic-ai-usecases-requirements]
Reddy.K, T., Sarker, Z., and K. Yao, "Agentic AI Use Cases and Requirements", Work in Progress, Internet-Draft, draft-agentic-ai-usecases-requirements-04, , <https://datatracker.ietf.org/doc/html/draft-agentic-ai-usecases-requirements-04>.
[I-D.bu-agentproto-security-principal-binding]
Bu, S., "Security Principal and Verifier Binding for Agent Communication Protocols", Work in Progress, Internet-Draft, draft-bu-agentproto-security-principal-binding-08, , <https://datatracker.ietf.org/doc/html/draft-bu-agentproto-security-principal-binding-08>.
[I-D.he-agentproto-verifier-evidence]
He, J. S., "Exercise and Completeness Evidence for Agent Protocol Verifier Results", Work in Progress, Internet-Draft, draft-he-agentproto-verifier-evidence-01, , <https://datatracker.ietf.org/doc/html/draft-he-agentproto-verifier-evidence-01>.
[I-D.konda-agentproto-evaluation-state]
Konda, G., "Preserving Evaluation State in Agent Protocol Decisions", Work in Progress, Internet-Draft, draft-konda-agentproto-evaluation-state-02, , <https://datatracker.ietf.org/doc/html/draft-konda-agentproto-evaluation-state-02>.
[I-D.srivastava-learnlog]
Srivastava, K., "Learnlog Assistance Capture Profile and Optional Event File Representation", Work in Progress, Internet-Draft, draft-srivastava-learnlog-03, , <https://datatracker.ietf.org/doc/html/draft-srivastava-learnlog-03>.
[I-D.wadkins-agentproto-action-determinability]
Wadkins, D. L., "Independent Determinability of Agent Actions", Work in Progress, Internet-Draft, draft-wadkins-agentproto-action-determinability-00, , <https://datatracker.ietf.org/doc/html/draft-wadkins-agentproto-action-determinability-00>.
[MCP]
Model Context Protocol Project, "Model Context Protocol Specification, Version 2025-06-18", , <https://modelcontextprotocol.io/specification/2025-06-18>.
[RFC6973]
Cooper, A., Tschofenig, H., Aboba, B., Peterson, J., Morris, J., Hansen, M., and R. Smith, "Privacy Considerations for Internet Protocols", RFC 6973, DOI 10.17487/RFC6973, , <https://www.rfc-editor.org/info/rfc6973>.
[RFC7519]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, , <https://www.rfc-editor.org/info/rfc7519>.
[RFC8693]
Jones, M., Nadalin, A., Campbell, B., Ed., Bradley, J., and C. Mortimore, "OAuth 2.0 Token Exchange", RFC 8693, DOI 10.17487/RFC8693, , <https://www.rfc-editor.org/info/rfc8693>.
[RFC8725]
Sheffer, Y., Hardt, D., and M. Jones, "JSON Web Token Best Current Practices", BCP 225, RFC 8725, DOI 10.17487/RFC8725, , <https://www.rfc-editor.org/info/rfc8725>.
[RFC8785]
Rundgren, A., Jordan, B., and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, DOI 10.17487/RFC8785, , <https://www.rfc-editor.org/info/rfc8785>.
[RFC8792]
Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, "Handling Long Lines in Content of Internet-Drafts and RFCs", RFC 8792, DOI 10.17487/RFC8792, , <https://www.rfc-editor.org/info/rfc8792>.
[RFC9596]
Jones, M.B. and O. Steele, "CBOR Object Signing and Encryption (COSE) "typ" (type) Header Parameter", RFC 9596, DOI 10.17487/RFC9596, , <https://www.rfc-editor.org/info/rfc9596>.
[RFC9942]
Steele, O., Birkholz, H., Delignat-Lavaud, A., and C. Fournet, "CBOR Object Signing and Encryption (COSE) Receipts", RFC 9942, DOI 10.17487/RFC9942, , <https://www.rfc-editor.org/info/rfc9942>.
[RFC9943]
Birkholz, H., Delignat-Lavaud, A., Fournet, C., Deshpande, Y., and S. Lasker, "An Architecture for Trustworthy and Transparent Digital Supply Chains", RFC 9943, DOI 10.17487/RFC9943, , <https://www.rfc-editor.org/info/rfc9943>.

Appendix A. Referencing a SCITT Receipt

A delegator may want to show that some prior context was registered with a transparency service, so a delegate can check it without trusting the delegator's own storage. The SCITT architecture [RFC9943] defines Signed Statements as COSE_Sign1 messages, and Receipts [RFC9942] as signed proofs that a statement is included in a verifiable data structure.

For kind "scitt-receipt":

A verified receipt shows that the statement was registered. It says nothing about whether the statement is true.

Appendix B. Referencing a Learnlog Signed Head

Learnlog [I-D.srivastava-learnlog] is a hash-chained record format. It defines a record as "A header and the entries about one subject, written by one producer", and its subject is a learner. It suits hops where the delegator is the producer of a Learnlog record about a learner, for example a tutoring agent that hands part of a session to another agent.

Learnlog defines signed heads. A head names the latest entry of a record (record_hash, seq, entry_hash, and time) and is signed with a JWS whose kid is the signing key's JWK Thumbprint; ES256 is mandatory to implement. A ContextRef of kind "learnlog-head" is one way to pass a head along a handoff:

Limits:

Author's Address

Kumar Srivastava
Quantum Learning Machines