<?xml version="1.0" encoding="UTF-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="info" docName="draft-srivastava-agentproto-handoff-context-01" ipr="trust200902" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3" xml:lang="en"><front><title abbrev="Agent Handoff Context">Signed Handoff Context for Agentic Dialogs</title><seriesInfo name="Internet-Draft" value="draft-srivastava-agentproto-handoff-context-01"/><author initials="K." surname="Srivastava" fullname="Kumar Srivastava"><organization>Quantum Learning Machines</organization><address><email>kumar@quantumlearningmachines.com</email></address></author><date/><area>ART</area><keyword>agent</keyword><keyword>delegation</keyword><keyword>handoff</keyword><keyword>dialog context</keyword><keyword>JWS</keyword><keyword>COSE</keyword><abstract><t>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.</t></abstract><note removeInRFC="true"><name>Discussion Venues</name><t>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/.</t></note></front><middle><section anchor="introduction"><name>Introduction</name><t>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:</t><ul><li>Who is handing this to me, and is it meant for me?</li><li>On whose behalf, and through which earlier agents?</li><li>Is this a fresh request, or a replay of an old one?</li><li>What prior context does the sender say this depends on, and can I check that I have the same context?</li></ul><t>The sender, in turn, needs a clear answer: accepted, rejected and why, completed, or failed.</t><t>The individual draft "Agentic AI Use Cases and Requirements" <xref target="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.</t><t>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.  <xref target="reqs"/> lists each requirement it touches and says what is and is not met.</t><section anchor="why"><name>Why a Token Is Not Enough</name><t>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 <xref target="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.</t></section><section anchor="scope"><name>Scope</name><t>This document defines:</t><ul><li>a handoff offer, a handoff status message, and the handoff object that carries an offer with its chain, in CDDL <xref target="RFC8610"/>, for JSON <xref target="RFC8259"/> and CBOR <xref target="RFC8949"/> (<xref target="data"/>);</li><li>how they are signed with JWS <xref target="RFC7515"/> or COSE <xref target="RFC9052"/> (<xref target="signing"/>);</li><li>a lifecycle and its mapping to A2A task states (<xref target="lifecycle"/>);</li><li>rules for freshness, replay, audience, chain linkage, cycles, and equivocation (<xref target="processing"/>);</li><li>how to carry the element in A2A and MCP (<xref target="carriage"/>).</li></ul><t>The following are out of scope:</t><ul><li>Audit data structures, logs, and their storage or query.  The agentproto charter <xref target="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.</li><li>Authorization.  The element does not grant authority. <xref target="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 (<xref target="obo"/>).</li><li>Key distribution.  This document does not define how a receiver learns which keys speak for which agent (<xref target="keys"/>).</li><li>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.</li></ul></section><section anchor="relationship-to-the-agentproto-charter"><name>Relationship to the agentproto Charter</name><t>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".</t><t>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.  A delegate keeps some state for each hop so that it can answer a delegator that asks again (<xref target="freshness"/>); that state serves the dialog while it runs.</t><t>This document uses one test to place each member: a member is dialog context if the next participant decides on it.  Section 5.3 of <xref target="I-D.konda-agentproto-evaluation-state"/> draws a similar distinction for evaluation state: passing it to the next hop helps when the next participant can act on it, and recording it locally suits details that are too sensitive to pass on, not needed by the next hop, or useful only for incident review.  By that test:</t><ul><li>The signed offer, including its chain, is dialog context.  The delegate checks it before it accepts the work (<xref target="receiving"/>).</li><li>The status is dialog context.  The delegator relies on it to know the state of the hop (<xref target="asking-again"/>).</li><li>A reference is dialog context when local policy requires the delegate to check it before accepting (step 7 of <xref target="receiving"/>).  The object or log behind the reference is audit data.  The element names it by digest and keeps it opaque (<xref target="refs"/>).</li></ul><t>Whether the working group accepts this placement is its call (<xref target="open-issues"/>).</t></section><section anchor="conventions-and-terminology"><name>Conventions and Terminology</name><t>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&#160;14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t><dl newline="true"><dt>Delegator</dt><dd>The agent that hands work to another agent and signs an offer.</dd><dt>Delegate</dt><dd>The agent that receives an offer and signs status replies.</dd><dt>Hop</dt><dd>One handoff from one delegator to one delegate, named by a hop identifier.</dd><dt>Signed handoff</dt><dd>An offer or status message in signed form (<xref target="signing"/>), as octets.</dd><dt>Handoff digest</dt><dd>The SHA-256 digest of a signed handoff's octets (<xref target="digest"/>).</dd><dt>Chain</dt><dd>The ordered list of earlier signed offers that led to the current offer, oldest first.  It travels beside the current offer, not inside it (<xref target="handoff"/>).</dd><dt>Host protocol</dt><dd>The agent protocol that carries the element, such as A2A <xref target="A2A"/> or MCP <xref target="MCP"/>, or a future agentproto dialog management protocol.</dd></dl></section></section><section anchor="data"><name>Data Model</name><t>Member names are short text strings so that one definition serves JSON and CBOR.  Except in Digest, which is closed, a receiver <bcp14>MUST</bcp14> ignore members it does not understand and a forwarder <bcp14>MUST NOT</bcp14> remove them from a signed offer or status, since they are covered by the signature.  Members of the Handoff object itself (<xref target="handoff"/>) are not signed.</t><sourcecode type="cddl"><![CDATA[
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
}
]]></sourcecode><dl newline="true"><dt>v</dt><dd>Version.  This document defines version 1.</dd><dt>hop</dt><dd>A hop identifier: at least 128 bits from a cryptographically secure random source, encoded in base64url <xref target="RFC4648"/> without padding.  It serves as the nonce for replay detection.</dd><dt>dialog</dt><dd>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.</dd><dt>task</dt><dd>An optional task identifier from the host protocol.</dd><dt>iss, aud</dt><dd>The delegator and the intended delegate.  An AgentId is a string, <bcp14>RECOMMENDED</bcp14> to be a URI, that the receiver's trust configuration maps to keys (<xref target="keys"/>).</dd><dt>iat, exp</dt><dd>Issue time, and the end of the window in which the offer can be accepted (<xref target="freshness"/>).  exp bounds acceptance, not the work: how long the work may take is the host protocol's business, tracked in its task state.</dd><dt>obo</dt><dd>The principal on whose behalf the root of the chain acted (<xref target="obo"/>).</dd><dt>grant</dt><dd>The digest of the authorization credential that the delegator expects the delegate to present or receive with this hop (<xref target="obo"/>).  The digest is computed over the credential's octets exactly as presented, for example the ASCII octets of a bearer token.  grant <bcp14>MUST NOT</bcp14> contain the credential itself.</dd><dt>prev</dt><dd>The handoff digest of the offer that the delegator itself received and is now passing on.  Absent when the delegator starts the chain.</dd><dt>refs</dt><dd>References to prior context (<xref target="refs"/>).</dd></dl><sourcecode type="cddl"><![CDATA[
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
]]></sourcecode><dl newline="true"><dt>offer</dt><dd>The handoff digest of the offer this status answers.</dd><dt>iss, aud</dt><dd>The sender and receiver of this status.  For "canceled", the sender is the delegator; for every other state, the sender is the delegate.</dd><dt>state</dt><dd>See <xref target="lifecycle"/>.</dd><dt>reason, detail</dt><dd>Why an offer was rejected or work failed.  Reason values other than those listed are permitted but <bcp14>SHOULD</bcp14> be avoided until a registry exists (<xref target="open-issues"/>).  Detail is free text for people and <bcp14>MUST NOT</bcp14> be relied on by software.</dd><dt>refs</dt><dd>For "completed", references to the result, so the delegator can check that what it later receives is what the delegate reported.  For "failed", references to any part of the work that took effect (<xref target="outcome"/>).</dd></dl><sourcecode type="cddl"><![CDATA[
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_-]+"
]]></sourcecode><t>In Principal, sub identifies the principal, and iss, when present, names the issuer in whose namespace sub is unique.</t><t>Time is seconds since 1970-01-01T00:00:00Z, ignoring leap seconds, as an integer.</t><t>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 <xref target="RFC6234"/>, which implementations <bcp14>MUST</bcp14> support.  Other values are left to future specifications, which <bcp14>MUST NOT</bcp14> define a hash whose output is shorter than 256 bits.  A receiver that does not implement the alg of a Digest <bcp14>MUST</bcp14> treat a check that depends on it as failed for prev and grant, and as unverifiable for refs.</t><section anchor="handoff"><name>The Handoff Object</name><t>What the host protocol carries is a Handoff: the signed offer together with its chain.</t><sourcecode type="cddl"><![CDATA[
Handoff = {
  offer: SignedHandoff,
  ? chain: [+ SignedHandoff],
  * text => any
}
]]></sourcecode><dl newline="true"><dt>offer</dt><dd>The signed current offer.</dd><dt>chain</dt><dd>Earlier signed offers, oldest first, ending with the one that the current offer's prev names.  Optional; see <xref target="privacy"/> for the trade-off.</dd></dl><t>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 <xref target="chain"/>; a chain that was removed is simply absent, which the receiver's policy treats as it would any missing chain.</t><t>A status is carried on its own, as a SignedHandoff.</t></section><section anchor="refs"><name>Context References</name><t>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.</t><dl newline="true"><dt>kind</dt><dd>"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.  The salt <bcp14>MUST NOT</bcp14> appear in the element.  "scitt-receipt" and "learnlog-head" are defined in <xref target="scitt"/> and <xref target="learnlog"/>; support for them is <bcp14>OPTIONAL</bcp14>.  Any other kind <bcp14>MUST</bcp14> be an absolute URI <xref target="RFC3986"/> naming its definition.</dd><dt>loc</dt><dd>An optional URI where the object can be fetched.</dd><dt>proof</dt><dd>Kind-specific material, such as a receipt or a signed head.</dd></dl><t>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 <bcp14>MUST NOT</bcp14> report a reference as verified unless it performed the check.  These outcomes follow the distinction drawn in <xref target="I-D.he-agentproto-verifier-evidence"/> and <xref target="I-D.konda-agentproto-evaluation-state"/> between a negative result and a result that could not be established.</t></section><section anchor="example"><name>Example</name><t>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:</t><sourcecode type="json"><![CDATA[
{
  "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"
    }
  ]
}
]]></sourcecode><t>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 <xref target="RFC8792"/>.</t><sourcecode type="json"><![CDATA[
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"
  ]
}
]]></sourcecode><t>The chain element's protected header decodes to the following (line breaks added for display):</t><sourcecode type="json"><![CDATA[
{"alg":"ES256","kid":"KKOb_URldPME8XXXbWvX88EXpI6TOhKH4rwtHpqtIb8",
 "typ":"agent-handoff+jwt"}
]]></sourcecode><t>Its payload decodes to the following (line breaks added for display):</t><sourcecode type="json"><![CDATA[
{"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"}}
]]></sourcecode><t>The two signatures verify with the following public keys, whose JWK Thumbprints <xref target="RFC7638"/> are the kid values in the two headers.  Both key pairs are for this example only.</t><sourcecode type="json"><![CDATA[
{"crv":"P-256","kty":"EC",
 "x":"G6ZXm5RqUggIPXdM3WR_kg2acGXtkaYFhoM51p-2_iA",
 "y":"8Gv0K14KLtbFeBUSjRTW0CYXr-t_WTYrtbHOFasEL6s"}
]]></sourcecode><sourcecode type="json"><![CDATA[
{"crv":"P-256","kty":"EC",
 "x":"WnRSpcn3Krie0WFNKoxLb14dgx8uBHCiO0bf7S36cx8",
 "y":"9t5Dm2PQpoSAckALLAGKhvYc4HccNnkPhGEBz3v2HUg"}
]]></sourcecode><t>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.</t><ul><li>prev is the handoff digest of the chain element: SHA-256 over its 538 ASCII octets, unfolded.</li><li>grant is SHA-256 over the 61 ASCII octets of the following example credential string, shown on its own line:</li></ul><sourcecode><![CDATA[
example access token issued to spiffe://b.example/agent/coder
]]></sourcecode><ul><li>The reference's dig is SHA-256 over the following 65 octets of JSON, which the coder is expected to fetch from loc:</li></ul><sourcecode type="json"><![CDATA[
{"repo":"https://git.a.example/app","commit":"9fceb02","issue":9}
]]></sourcecode><t>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.</t><sourcecode type="json"><![CDATA[
{
  "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"
}
]]></sourcecode></section></section><section anchor="signing"><name>Signing</name><t>Every offer and status <bcp14>MUST</bcp14> be signed by its iss.  An unsigned element <bcp14>MUST</bcp14> be treated as absent.</t><section anchor="jws"><name>JWS</name><t>The payload is the JSON form of the element.  The signed handoff is the JWS Compact Serialization <xref target="RFC7515"/>.</t><ul><li>The protected header <bcp14>MUST</bcp14> contain alg, kid, and typ, with typ set to "agent-handoff+jwt", the short form of the media type application/agent-handoff+jwt (<xref target="iana"/>).  It <bcp14>MUST NOT</bcp14> contain crit. The payload uses the JWT <xref target="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 <xref target="RFC8725" section="3.11" sectionFormat="of"/>.</li><li>alg <bcp14>MUST</bcp14> name an asymmetric signature algorithm.  "none" and MAC algorithms <bcp14>MUST NOT</bcp14> be used.  Implementations <bcp14>MUST</bcp14> support ES256 <xref target="RFC7518"/>.</li><li>kid <bcp14>SHOULD</bcp14> be the JWK Thumbprint <xref target="RFC7638"/> of the public key, using SHA-256, base64url without padding.</li></ul></section><section anchor="cose"><name>COSE</name><t>The payload is the CBOR form of the element.  The signed handoff is a COSE_Sign1 message <xref target="RFC9052"/> with tag 18.</t><ul><li>The protected header <bcp14>MUST</bcp14> contain alg and content type (label 3), with content type set to "application/agent-handoff+cbor".  It <bcp14>SHOULD</bcp14> contain kid.</li><li>Implementations <bcp14>MUST</bcp14> support ES256 (alg -7) <xref target="RFC9053"/>.</li></ul><t>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.</t></section><section anchor="digest"><name>Handoff Digest</name><t>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 <bcp14>MUST</bcp14> forward these octets unchanged.</t></section><section anchor="keys"><name>Learning Keys</name><t>This document does not define how a receiver learns that a key speaks for an AgentId.  A receiver <bcp14>MUST</bcp14> 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 <bcp14>MUST</bcp14> accept each trusted key with exactly one algorithm (<xref target="RFC8725" section="3.1" sectionFormat="of"/>).</t><t>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.</t></section></section><section anchor="lifecycle"><name>Lifecycle</name><t>Each hop has its own lifecycle, held separately by the delegator and the delegate.</t><figure><artwork type="ascii-art"><![CDATA[
              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, provisional state "expired".  A "rejected"
   with reason "stale" or "replay" is not terminal (Section 5.3).
]]></artwork></figure><ul><li>Except for nonterminal "rejected" statuses with reason "stale" or "replay", a delegate <bcp14>MUST</bcp14> send at most one of "accepted" and "rejected" for a hop, and at most one of "completed" and "failed".  It <bcp14>MUST NOT</bcp14> send "rejected" for a hop it has taken, except with reason "stale" or "replay" for a hop it no longer remembers.  Such a rejection says only that the delegate does not remember the offer.  It may follow a status the delegate has since forgotten, and it never sets the hop's state (<xref target="asking-again"/>).</li><li>A delegate <bcp14>MUST NOT</bcp14> send "completed" or "failed" while it does not know whether the work took effect.  Until it knows, the hop stays "accepted" (<xref target="outcome"/>).  "failed" with no refs tells the delegator that the work took no effect.</li><li>A delegate <bcp14>MAY</bcp14> send "completed" or "failed" without first sending "accepted".  The delegator then treats "accepted" as implied.</li><li>An offer that reaches exp at the delegator with no status is expired there.  Expiry is local and provisional: no message is sent, and a status for the hop that arrives later and passes the checks in <xref target="forks"/> still counts and replaces "expired".  A status can be lost, so an expired offer may have been accepted.  <xref target="asking-again"/> says when the delegator may issue a new offer for the same work.</li><li>"canceled" from the delegator is a revocation of the hop.  A delegate that receives a valid "canceled" <bcp14>SHOULD</bcp14> send "canceled" for each offer it issued whose prev equals this hop's offer digest. Each receiver of such a cancel does the same, so the cancel follows the hops down.  This relates to CMN-10 in <xref target="I-D.agentic-ai-usecases-requirements"/>, which asks that revocation propagate across a delegation chain; the element itself revokes no authority.  A "canceled" does not show that the work took no effect: the delegate may have done the work before the cancel arrived, and some host protocols suppress the reply to a canceled request (<xref target="carriage"/>).  <xref target="asking-again"/> applies to any new offer for the same work.</li></ul><t>The host protocol keeps its own task state.  The table shows the nearest A2A TaskState <xref target="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.</t><table><name>Mapping to A2A task states</name><thead><tr><th>Handoff state</th><th>Nearest A2A TaskState</th></tr></thead><tbody><tr><td>offered</td><td>TASK_STATE_SUBMITTED</td></tr><tr><td>accepted</td><td>TASK_STATE_WORKING</td></tr><tr><td>rejected</td><td>TASK_STATE_REJECTED</td></tr><tr><td>completed</td><td>TASK_STATE_COMPLETED</td></tr><tr><td>failed</td><td>TASK_STATE_FAILED</td></tr><tr><td>canceled</td><td>TASK_STATE_CANCELED</td></tr></tbody></table></section><section anchor="processing"><name>Processing Rules</name><section anchor="receiving"><name>Receiving an Offer</name><t>A delegate that receives an offer performs these checks.  The first failure ends processing.  Except where a check says otherwise, the delegate <bcp14>SHOULD</bcp14> send a "rejected" status with the reason shown, unless doing so would itself leak information its policy protects.</t><ol><li>Check the signed form (<xref target="signing"/>): 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 (<xref target="keys"/>).  Reasons: bad-signature, untrusted-key.</li><li>Check that aud equals its own AgentId.  Reason: wrong-audience.</li><li>Check freshness (<xref target="freshness"/>).  Reason: stale.  An offer whose (iss, hop) pair the delegate remembers skips this check and goes to step 4, so that a retransmission sent after exp is still answered and an equivocating offer is still treated as equivocation.</li><li>Check that (iss, hop) has not been seen before (<xref target="freshness"/>).  An offer with a remembered pair and the same handoff digest is a retransmission: it is not processed again, and it is answered as in <xref target="asking-again"/>.  An offer with a remembered pair and a different digest is equivocation, handled as in <xref target="forks"/>.</li><li>If the host protocol message carries a dialog identifier, check that dialog equals it.  Reason: policy.</li><li>If the Handoff carries a chain, check it (<xref target="chain"/>).  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.</li><li>Check any references that local policy requires (<xref target="refs"/>). Reasons: unverifiable-ref, ref-mismatch.</li></ol><t>If all checks pass and the delegate takes the work, it sends "accepted".</t></section><section anchor="freshness"><name>Freshness and Replay</name><ul><li>A receiver <bcp14>MUST</bcp14> reject an offer whose exp is not later than its iat, or whose iat is later than the current time plus a configured skew.  It <bcp14>MUST</bcp14> also reject an offer whose exp is not later than the current time, unless it remembers the offer's (iss, hop) pair (step 3 of <xref target="receiving"/>).  A skew of no more than 60 seconds is <bcp14>RECOMMENDED</bcp14>.</li><li>A receiver <bcp14>MUST</bcp14> reject an offer whose exp minus iat exceeds its configured maximum lifetime.  A maximum of 300 seconds is <bcp14>RECOMMENDED</bcp14> for interactive use.</li><li>A receiver <bcp14>MUST</bcp14> remember each (iss, hop) pair that passed steps 1 through 3 of <xref target="receiving"/>, with the handoff digest, at least until exp plus the skew.  A delegate that has answered an offer or taken the work for a hop <bcp14>SHOULD</bcp14> also keep the pair, the digest, and the last status it sent, in storage that survives a restart.  It keeps them until it has sent "rejected", "completed", or "failed", and then for a further retention period, set by local policy and made known to its delegators, in which a delegator may still ask again.  A hop that stays "accepted" because its outcome is unknown is kept until its operator resolves it (<xref target="outcome"/>).  A delegate that loses them handles later offers as in <xref target="replay-and-freshness"/>.  A second offer with the same pair and the same digest is an exact copy, whether retransmitted or replayed, and is answered as in <xref target="asking-again"/>; with a different digest, it is equivocation (<xref target="forks"/>).  Neither is accepted a second time.</li><li>The aud and dialog members bind the offer to one receiver and one dialog.  An offer copied to another agent fails step 2.</li></ul><t>Expiry of the outer offer is checked.  Earlier offers in a chain are history and are expected to have expired; <xref target="chain"/> checks only that each was live when the next was issued.</t></section><section anchor="asking-again"><name>Asking Again</name><t>Messages can be lost in either direction.  A delegator that has not received a status it expects learns the state of the hop by asking again, never by guessing.  This follows Section 4.2.1 of <xref target="I-D.agentic-ai-usecases-requirements"/>: before resending an operation, the delegating agent checks its outcome, and an outcome that cannot be determined stays unresolved.</t><ul><li>A delegator that has not received a status it expects <bcp14>MAY</bcp14> retransmit the offer, as the identical octets (<xref target="forks"/>).  How long it waits and how often it asks are local policy.  It <bcp14>SHOULD</bcp14> wait longer after each attempt, and <bcp14>SHOULD</bcp14> make its first retransmission before exp, while a delegate that never received the offer can still process it.</li><li>A delegate that receives a retransmission <bcp14>MUST NOT</bcp14> process the offer again or do the work again.  If it has sent a status for the hop, it <bcp14>SHOULD</bcp14> resend the last status it sent, as the identical octets, subject to <xref target="replay-and-freshness"/>.  If it has sent none and has taken the work, it <bcp14>SHOULD</bcp14> send "accepted".  If it has sent none and has not yet decided, it sends nothing for now.  Where the host protocol requires a reply to every request, as an MCP tool call does, that reply carries a status only when one of these rules provides one.</li><li>A delegator <bcp14>MUST NOT</bcp14> treat a missing status as "failed".</li><li>A hop is resolved for the delegator once it holds, for that hop, a verified "completed" or "failed", or a verified "rejected" with a reason other than "stale" or "replay".  A "failed" with refs says what part of the work took effect, and the delegator takes that into account before any new attempt.  A hop is also resolved once the delegator has an authoritative observation that the work did not take effect.  Every other hop is unresolved.  That includes a hop that expired, a hop rejected as "stale" or "replay", and a hop the delegator canceled: in each case the delegate may have done the work.</li><li>While a hop is unresolved, the delegator <bcp14>MUST NOT</bcp14> issue a new offer for the same work, unless it knows the work is safe to do twice.  A delegator that stops asking while a hop is unresolved <bcp14>SHOULD</bcp14> flag the hop to its operator.</li><li>A delegate that does not remember an offer cannot say whether it never received the offer or has forgotten it.  A hop whose offer may never have arrived therefore stays unresolved unless the delegator can observe the outcome another way.  Retransmitting before exp avoids most such cases.</li><li>Where a new attempt is allowed, it is a new offer with a new hop.  It is checked afresh, as any offer is.  A delegator never re-signs the old hop (<xref target="forks"/>).</li></ul></section><section anchor="outcome"><name>Knowing the Outcome</name><t>"completed" and "failed" are claims about what happened.  A delegate makes them only when it knows, including after a crash or after losing an acknowledgement from its own storage.</t><ul><li>For work whose effect is in the delegate's own store, a delegate <bcp14>SHOULD</bcp14> record the pair (iss, hop) and the handoff digest of the offer in that store, in the same atomic step that makes the work take effect.  The record then answers whether the work took effect.</li><li>An outcome that could not be established is not a failure.  Section 5.3 of <xref target="I-D.konda-agentproto-evaluation-state"/> states the same rule for evaluation state: a hop does not treat an input that was not established as negative.</li><li>A record written in the same atomic step as the effect shows, by being present, that the effect took place.  Its absence shows that the effect did not take place only once the delegate knows that the step cannot still complete, for example because its store reported an abort or has finished its own recovery.  An absent record found by a lookup that timed out, or made while the step may still be running, shows nothing.</li><li>Where the effect is outside the delegate's own store, such as a message sent or a call to another system, no record the delegate keeps can be atomic with it, and its own record does not show the outcome.  The outcome is then known only from an authoritative observation of that same attempt, for example the other system's record of the request, found by an identifier the delegate gave it and derived from (iss, hop).  A delegate that cannot make such an observation keeps the hop "accepted" (see below).</li><li>While the outcome is unknown, the hop stays "accepted".  The delegate answers a retransmission as in <xref target="asking-again"/> and keeps looking.</li><li>If part of the work took effect and the rest did not, a delegate that sends "failed" <bcp14>MUST</bcp14> list in refs what took effect, so that the delegator does not assume nothing changed.  Each such ref names, by digest, a record of one effect, such as the other system's record of a request.</li><li>If the record is lost and the outcome cannot be learned, the delegate <bcp14>MUST NOT</bcp14> guess.  It keeps the hop "accepted" and <bcp14>SHOULD</bcp14> flag the hop to its operator.  The hop stays unresolved for the delegator (<xref target="asking-again"/>).</li></ul><t>How the outcome is recorded is the delegate's business.  This document only requires that "completed" and "failed" be true when sent.</t></section><section anchor="chain"><name>Checking a Chain</name><t>Let C[0..n-1] be the decoded chain, oldest first, and O the current offer.  For uniformity, let C[n] denote O.</t><ol><li>Check each C[i] as in step 1 of <xref target="receiving"/>: its signed form, v and type, and its signature.  A receiver that does not trust a key for some C[i].iss <bcp14>MUST</bcp14> treat the chain as unverifiable from that point back; its policy for a partial chain then applies (step 6 of <xref target="receiving"/>).</li><li>Check that for each i from 1 to n, C[i].prev equals the handoff digest of C[i-1].</li><li>Check continuity: for each i from 1 to n, C[i-1].aud equals C[i].iss.</li><li>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.</li><li>If C[0] has a prev member, the chain is partial: it does not reach the start.</li><li>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 <bcp14>SHOULD</bcp14> reject with reason "cycle" (B3-7 in <xref target="I-D.agentic-ai-usecases-requirements"/>).  This document departs from B3-7 in one respect: local policy <bcp14>MAY</bcp14> admit a known re-entry, such as a callback to the original requester.</li><li>A receiver <bcp14>MUST</bcp14> enforce a maximum chain length.  A limit of 16 is <bcp14>RECOMMENDED</bcp14>.  Reason: too-deep.</li></ol><t>Failures of checks 2 through 4 use reason "broken-chain".</t><t>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 (<xref target="sec-authority"/>).  It also does not show that an earlier offer had not been rejected or canceled when the next was issued.</t></section><section anchor="forks"><name>Forks, Concurrency, and Equivocation</name><ul><li>Fan-out is allowed.  A delegator <bcp14>MAY</bcp14> issue several offers with the same prev, each with its own hop, to run subtasks in parallel.</li><li>A delegator that retransmits an offer <bcp14>MUST</bcp14> resend the identical octets.  It <bcp14>MUST NOT</bcp14> 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.</li><li>Two signed offers with the same iss and hop but different octets are equivocation.  A receiver that sees the second <bcp14>MUST NOT</bcp14> accept it and <bcp14>MUST NOT</bcp14> send a status for it, whether or not it has expired (step 3 of <xref target="receiving"/>).  If the receiver has neither taken the work nor answered the first, it <bcp14>SHOULD</bcp14> send "rejected" for the first with reason "equivocation".  If it has taken the work but sent no terminal status, it <bcp14>SHOULD</bcp14> stop the work if it can.  Once it knows the outcome (<xref target="outcome"/>), it <bcp14>SHOULD</bcp14> send "completed" if the work took full effect, and otherwise "failed" with reason "equivocation", listing in refs any part of the work that took effect.  If it has already rejected the first or sent a terminal status, it <bcp14>MUST NOT</bcp14> send another status for the first.  In each case status.offer names the first offer, and the receiver <bcp14>SHOULD</bcp14> 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.</li><li>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.</li><li>If a delegate sends conflicting statuses for one hop, such as both "completed" and "failed", the receiver <bcp14>MUST</bcp14> treat the first one it verified as the hop's state and <bcp14>SHOULD</bcp14> flag the conflict to its operator.  A "rejected" with reason "stale" or "replay" is never such a conflict and never sets the hop's state, whichever order it arrives in; it shows only that the delegate does not remember the hop (<xref target="lifecycle"/>).  A verified status that arrives after it still counts.</li><li>"canceled" and "completed" can cross in flight.  Each party keeps the first terminal state it verified.  For the delegator, a verified "completed" or "failed" that arrives after its own "canceled" still resolves the hop (<xref target="asking-again"/>).  This document does not resolve such races; it makes them visible to both sides.</li></ul></section><section anchor="obo"><name>On Behalf Of</name><t>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 <xref target="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 <xref target="RFC8693" section="4.1" sectionFormat="of"/>, the prior delegators in chain are informational.  Unlike a token's sub claim, obo is not an authorization claim.  A receiver <bcp14>MUST NOT</bcp14> make an access control decision based on obo or chain alone.</t><t>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 <xref target="I-D.agentic-ai-usecases-requirements"/>) is for that framework to decide, not this element.</t><t><xref target="claims"/> states, for each security-relevant claim this element makes, who carries it, who verifies it, and how it fails.</t></section></section><section anchor="carriage"><name>Carrying the Element</name><t>The handoff context is meant to travel inside the host protocol's own messages.  This document defines no new transport and no HTTP header.</t><dl newline="true"><dt>A2A</dt><dd>A2A extensions place custom attributes in the metadata map of core data structures <xref target="A2A-EXT"/>.  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 <xref target="handoff"/>.  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.</dd><dt>MCP</dt><dd>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 <xref target="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.  MCP asks the receiver of a cancellation to stop and not to send a response, and the sender to ignore a response that arrives afterward, so a delegator that cancels over MCP may never see the delegate's last status; the hop is then unresolved (<xref target="asking-again"/>).  A tool call gets one reply, so a delegator that delegates over MCP learns of any later status for the hop by retransmitting (<xref target="asking-again"/>).  The key follows MCP's rules for _meta key prefixes, and its prefix is not one that MCP reserves.</dd><dt>agentproto</dt><dd>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 <xref target="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 <xref target="receiving"/> to fail unless the receiver's policy knows the mapping.  A dialog identifier defined by agentproto, carried unchanged through mediators, would close that gap.</dd></dl></section><section anchor="reqs"><name>Requirements Coverage</name><t>The table lists each requirement of <xref target="I-D.agentic-ai-usecases-requirements"/> that this element touches, what the element provides toward it, and what it leaves to other mechanisms.</t><table><name>Requirements touched by this element</name><thead><tr><th>Requirement</th><th>Provided</th><th>Not provided</th></tr></thead><tbody><tr><td>B3-6, verifiable per-hop provenance with removal detectable</td><td>Signed offers linked by digest; removing or reordering an intermediate hop is detected when the chain is carried (<xref target="chain"/>)</td><td>Responses and transformations are not attributed; the start of a chain can be dropped (<xref target="truncated"/>)</td></tr><tr><td>B3-7, cycle detection</td><td>Check 6 of <xref target="chain"/></td><td>Cycles through hops not in the carried chain</td></tr><tr><td>B3-8, authority not exceeding the previous hop's</td><td>grant binds the hop to one credential by digest (<xref target="obo"/>)</td><td>The comparison itself, which belongs to the credential's framework</td></tr><tr><td>B3-9, dialog context propagated per hop</td><td>The dialog member and carriage inside the host message (<xref target="carriage"/>)</td><td>The dialog context itself; this is one element of it</td></tr><tr><td>B1-7, checking a resuming party</td><td>Nothing</td><td>Resumption is a host protocol matter</td></tr><tr><td>B2-4, a response timeout after which the request is unresolved</td><td>A delegator that times out asks again and treats the hop as unresolved, not failed; a delegate answers only with what it knows (<xref target="asking-again"/>, <xref target="outcome"/>)</td><td>The timeout value and halting the subtask, which belong to the host protocol</td></tr><tr><td>CMN-10, revocation propagated down a chain</td><td>"canceled" follows prev from hop to hop (<xref target="lifecycle"/>)</td><td>Revoking authority; the element grants none</td></tr><tr><td>B5-3, a mediator between protocols</td><td>The Handoff is opaque octets a mediator can copy (<xref target="carriage"/>)</td><td>The dialog check across a translated identifier (<xref target="carriage"/>)</td></tr></tbody></table></section><section anchor="security"><name>Security Considerations</name><section anchor="claims"><name>Security-Relevant Claims</name><t><xref target="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:</t><table><name>Security-relevant claims</name><thead><tr><th>Claim</th><th>Carrier</th><th>Verifier</th><th>Binding</th><th>Freshness</th><th>Failure</th></tr></thead><tbody><tr><td>The offer comes from iss</td><td>Signature over the offer</td><td>Delegate</td><td>A key its trust configuration binds to iss (<xref target="keys"/>)</td><td>iat, exp, and hop (<xref target="freshness"/>)</td><td>"rejected": bad-signature or untrusted-key; stale for freshness</td></tr><tr><td>The offer is for this receiver in this dialog</td><td>aud and dialog, under the signature</td><td>Delegate</td><td>aud equals its AgentId; dialog equals the host identifier</td><td>As above</td><td>"rejected": wrong-audience or policy</td></tr><tr><td>The offer follows these earlier offers in order</td><td>prev; the chain</td><td>Delegate</td><td>Handoff digests (<xref target="digest"/>); continuity and timing (<xref target="chain"/>)</td><td>Check 4 of <xref target="chain"/></td><td>"rejected": broken-chain, cycle, or too-deep; or unverifiable where a key is untrusted</td></tr><tr><td>The work depends on this prior context</td><td>refs</td><td>Delegate, when policy requires</td><td>The object's digest and any kind-specific proof (<xref target="refs"/>)</td><td>None in the element</td><td>"rejected": unverifiable-ref or ref-mismatch; or not checked</td></tr><tr><td>The delegate answered as stated</td><td>Signature over the status</td><td>Delegator; the delegate, for "canceled"</td><td>A key bound to status.iss; status.offer equals the offer's digest (<xref target="forks"/>)</td><td>The first verified status stands, except a "stale" or "replay" rejection (<xref target="forks"/>)</td><td>Status discarded; conflict flagged to the operator</td></tr></tbody></table></section><section anchor="sec-authority"><name>What a Signature Shows</name><t>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.  <xref target="I-D.wadkins-agentproto-action-determinability"/> discusses the gap between evidence of authorization and evidence of enforcement; this element addresses neither.</t></section><section anchor="truncated"><name>Truncated Chains</name><t>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 <bcp14>MUST</bcp14> 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.</t></section><section anchor="replay-and-freshness"><name>Replay and Freshness</name><t>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, <bcp14>SHOULD</bcp14> reject offers with iat before the restart until the maximum lifetime has passed, with reason "replay", since it cannot tell whether it has already seen them.  That rule does not apply to hops whose records it still keeps (<xref target="freshness"/>); it answers those as in <xref target="asking-again"/>.  A delegate that keeps the records of <xref target="freshness"/> in storage that survives the restart has not lost them, and the rule does not apply to it.  The delegator treats a "replay" rejection as it treats "stale" (<xref target="asking-again"/>).  Once a delegate drops a hop's records, a new offer that reuses the hop identifier passes every check.  <xref target="forks"/> forbids signing a hop twice, but such a delegate cannot detect it.</t><t>A delegate answers a retransmission by resending a status it already signed (<xref target="asking-again"/>).  Anyone who can replay the offer to the delegate can therefore cause that status to be sent again.  The status is addressed to the delegator and reveals the hop's state, its reason, and any refs.  Where the host protocol returns a reply to whoever sent the request, as A2A and MCP responses do, the status goes to the party that sent the retransmission.  A delegate <bcp14>SHOULD</bcp14> resend a status only when the host protocol has authenticated that party as offer.iss, for example by the credential the request carries, and otherwise <bcp14>SHOULD NOT</bcp14> resend it.</t></section><section anchor="key-compromise"><name>Key Compromise</name><t>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 (<xref target="keys"/>).</t></section><section anchor="cross-protocol-confusion"><name>Cross-Protocol Confusion</name><t>The typ and content type values make a signed handoff distinct from other JWS or COSE objects signed with the same key.  Handoff receivers <bcp14>MUST</bcp14> check them (<xref target="receiving"/>).  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 <xref target="I-D.srivastava-learnlog"/>, which does not require a typ; using separate keys for separate purposes avoids the question.</t></section><section anchor="active-content"><name>Active Content</name><t>The media types registered in <xref target="iana"/> do not contain active content.</t></section><section anchor="resource-use"><name>Resource Use</name><t>Chains and references can be large, and loc invites fetches.  A chain grows by one signed offer per hop (<xref target="handoff"/>).  Receivers <bcp14>MUST</bcp14> bound chain length and element size, and <bcp14>SHOULD NOT</bcp14> fetch loc URIs from untrusted senders without the safeguards they apply to any untrusted URL.</t></section><section anchor="secrets"><name>Secrets</name><t>The element <bcp14>MUST NOT</bcp14> contain secrets: no access tokens, API keys, tool credentials, passwords, or private keys.  Credentials appear only as digests in grant.</t></section></section><section anchor="privacy"><name>Privacy Considerations</name><t>The considerations of <xref target="RFC6973"/> apply.</t><ul><li>Linkability.  The dialog, hop, and AgentId values let anyone who sees several messages link them.  The charter asks the working group to analyze privacy risks and specify mitigations.</li><li>Chain disclosure.  A chain reveals every prior agent, and obo reveals the principal, to every later hop.  A delegator <bcp14>SHOULD</bcp14> include chain only when the next hop needs it, and <bcp14>SHOULD</bcp14> use a pairwise or pseudonymous sub in obo where the deployment allows. Omitting the chain trades verifiability for privacy; prev still lets a party that holds the earlier offer check the link.  A delegator that received no chain can pass on only what it holds, so the chain it sends is partial.</li><li>Guessable digests.  A digest of low-entropy content, such as a short prompt, an instruction template, or a yes/no answer, can be reversed by hashing guesses.  Prompts and other sensitive content <bcp14>MUST</bcp14> be named by digest only, never included, and <bcp14>SHOULD</bcp14> be named with kind "salted-digest" (<xref target="refs"/>).</li><li>Detail text.  The detail member can leak internal state.  It <bcp14>SHOULD</bcp14> be omitted when the status crosses a trust boundary.</li><li>Resent statuses.  A resent status repeats the hop's state, reason, and refs.  <xref target="replay-and-freshness"/> limits who receives it.</li><li>Kept records.  The records a delegate keeps to answer retransmissions (<xref target="freshness"/>) link the delegator, the hop, and its outcome.  A delegate <bcp14>SHOULD</bcp14> keep them no longer than its retention period (<xref target="freshness"/>), except for a hop whose outcome is still unknown.</li></ul></section><section anchor="iana"><name>IANA Considerations</name><t>This document requests two media type registrations in the "Media Types" registry <xref target="RFC6838"/>.  The first names a complete JWS signed handoff, for the typ header (<xref target="signing"/>).  The second names the CBOR payload of a COSE signed handoff, for its content type header. No other registry is requested.</t><t>RFC Editor: please replace "RFC XXXX" below with the number of this document and remove this note.</t><section anchor="application-agent-handoff-jwt"><name>application/agent-handoff+jwt</name><dl newline="true"><dt>Type name</dt><dd>application</dd><dt>Subtype name</dt><dd>agent-handoff+jwt</dd><dt>Required parameters</dt><dd>N/A</dd><dt>Optional parameters</dt><dd>N/A</dd><dt>Encoding considerations</dt><dd>8bit; a value is a JWS Compact Serialization: base64url-encoded parts separated by period characters.</dd><dt>Security considerations</dt><dd>See <xref target="security"/> of RFC XXXX.  This media type does not contain active content.</dd><dt>Interoperability considerations</dt><dd>N/A</dd><dt>Published specification</dt><dd>RFC XXXX</dd><dt>Applications that use this media type</dt><dd>Agent communication protocols that carry handoff context.</dd><dt>Fragment identifier considerations</dt><dd>N/A</dd><dt>Additional information</dt><dd>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</dd><dt>Person and email address to contact for further information</dt><dd>Kumar Srivastava, kumar@quantumlearningmachines.com</dd><dt>Intended usage</dt><dd>COMMON</dd><dt>Restrictions on usage</dt><dd>none</dd><dt>Author</dt><dd>Kumar Srivastava</dd><dt>Change controller</dt><dd>IETF</dd><dt>Provisional registration? (standards tree only)</dt><dd>No</dd></dl></section><section anchor="application-agent-handoff-cbor"><name>application/agent-handoff+cbor</name><t>This type labels the CBOR payload carried inside a COSE_Sign1 signed handoff (<xref target="signing"/>).</t><dl newline="true"><dt>Type name</dt><dd>application</dd><dt>Subtype name</dt><dd>agent-handoff+cbor</dd><dt>Required parameters</dt><dd>N/A</dd><dt>Optional parameters</dt><dd>N/A</dd><dt>Encoding considerations</dt><dd>binary (CBOR)</dd><dt>Security considerations</dt><dd>See <xref target="security"/> of RFC XXXX.  This media type does not contain active content.</dd><dt>Interoperability considerations</dt><dd>N/A</dd><dt>Published specification</dt><dd>RFC XXXX</dd><dt>Applications that use this media type</dt><dd>Agent communication protocols that carry handoff context.</dd><dt>Fragment identifier considerations</dt><dd>N/A</dd><dt>Additional information</dt><dd>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</dd><dt>Person and email address to contact for further information</dt><dd>Kumar Srivastava, kumar@quantumlearningmachines.com</dd><dt>Intended usage</dt><dd>COMMON</dd><dt>Restrictions on usage</dt><dd>none</dd><dt>Author</dt><dd>Kumar Srivastava</dd><dt>Change controller</dt><dd>IETF</dd><dt>Provisional registration? (standards tree only)</dt><dd>No</dd></dl></section></section><section anchor="open-issues"><name>Open Issues</name><ul><li>Scope fit.  <xref target="relationship-to-the-agentproto-charter"/> places the offer, its chain, the status, and the refs a delegate checks inside dialog context, and the objects behind refs in audit data.  Does the working group agree?  If not, the per-hop requirements here may be better contributed to the use cases document alone.</li><li>Whether reason values need a registry, or a fixed list is enough.</li><li>Whether CBOR should use integer map keys for size.</li><li>Whether the dialog check should admit a mapping across mediators, or wait for an agentproto dialog identifier (<xref target="carriage"/>).</li><li>Whether the COSE form should also carry the typ header parameter (label 16) defined in <xref target="RFC9596"/>.</li><li>Whether the hop identifier should merge with an agentproto dialog or message identifier once one exists.</li><li>Whether "canceled" should propagate down the chain as a <bcp14>MUST</bcp14>.</li><li>Whether a delegator needs a status query that is lighter than retransmitting the whole offer (<xref target="asking-again"/>).</li><li>Whether status refs, and the records a delegate keeps to answer retransmissions, fall on the dialog-context side of the line drawn in <xref target="relationship-to-the-agentproto-charter"/>, and whether ContextRef is the right way to say what took effect in a "failed" status (<xref target="outcome"/>).</li><li>Whether a delegate needs a way to say that it never received an offer, so that a hop whose offer was lost can be resolved (<xref target="asking-again"/>).</li></ul></section></middle><back><references><name>References</name><references><name>Normative References</name><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml"/><reference anchor="RFC3986" target="https://www.rfc-editor.org/info/rfc3986"><front><title>Uniform Resource Identifier (URI): Generic Syntax</title><author initials="T." surname="Berners-Lee" fullname="T. Berners-Lee"/><author initials="R." surname="Fielding" fullname="R. Fielding"/><author initials="L." surname="Masinter" fullname="L. Masinter"/><date year="2005" month="January"/></front><seriesInfo name="STD" value="66"/><seriesInfo name="RFC" value="3986"/><seriesInfo name="DOI" value="10.17487/RFC3986"/></reference><reference anchor="RFC6234" target="https://www.rfc-editor.org/info/rfc6234"><front><title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title><author initials="D." surname="Eastlake 3rd" fullname="D. Eastlake 3rd"/><author initials="T." surname="Hansen" fullname="T. Hansen"/><date year="2011" month="May"/></front><seriesInfo name="RFC" value="6234"/><seriesInfo name="DOI" value="10.17487/RFC6234"/></reference><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6838.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7518.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7638.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8610.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8949.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9052.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9053.xml"/></references><references><name>Informative References</name><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6973.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7519.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8693.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8725.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8785.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8792.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9596.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9942.xml"/><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9943.xml"/><reference anchor="I-D.srivastava-learnlog" target="https://datatracker.ietf.org/doc/html/draft-srivastava-learnlog-03">
  <front>
    <title>Learnlog Assistance Capture Profile and Optional Event File Representation</title>
    <author fullname="Kumar Srivastava" initials="K." surname="Srivastava">
      <organization>Quantum Learning Machines</organization>
    </author>
    <date day="20" month="October" year="2026"/>
    <abstract>
      <t>This document proposes Learnlog as an assistance capture profile for measuring AI scaffolding, with xAPI and Caliper bindings. Its motivation is Quantum Learning Machines' work on QLM Measure. The profile defines what assistance was requested, offered, generated, transmitted, displayed, or accepted; what an instrument captured; which facts remain unknown; and which assertions were observed, self- reported, or inferred. Existing logging ecosystems can carry these definitions. Their reviewed base specifications do not, by themselves, require this particular combined agreement on assistance, achieved capture, unavailable information, and mapping provenance. Existing AI and tutoring profiles already cover important parts of the domain. For discussion, the document also proposes event families beyond assistance, among them prediction, revision, recall after a delay, stated confidence, and agency. The document retains the existing Learnlog event file representation, hash chains, optional signed heads, and verifiable redaction as an optional carrier. An implementation can use the assistance profile without producing that file representation. Experimental companion software constructs importer-observation records in xAPI and Caliper while preserving source assistance assertions separately. The implementation does not establish independent interoperability, truthful or complete capture, independent learning, or scientific equivalence across products. The core file format is unchanged in this revision.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-srivastava-learnlog-03"/>
</reference><reference anchor="I-D.agentic-ai-usecases-requirements" target="https://datatracker.ietf.org/doc/html/draft-agentic-ai-usecases-requirements-05">
  <front>
    <title>Agentic AI Use Cases and Requirements</title>
    <author fullname="Tirumaleswar Reddy.K" initials="T." surname="Reddy.K">
      <organization>Nokia</organization>
    </author>
    <author fullname="Zaheduzzaman Sarker" initials="Z." surname="Sarker">
      <organization>Nokia</organization>
    </author>
    <author fullname="Kehan Yao" initials="K." surname="Yao">
      <organization>China Mobile</organization>
    </author>
    <date day="27" month="October" year="2026"/>
    <abstract>
      <t>This document describes use cases for agentic AI communication systems and derives protocol requirements from those use cases. The requirements are intended to guide IETF standardization work on protocols in the context of agent-to-agent communication, agent-to- tool communication, with focus on dialog management, transport, multimodal communication, communication security, agent identity and authentication.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-agentic-ai-usecases-requirements-05"/>
</reference><reference anchor="I-D.bu-agentproto-security-principal-binding" target="https://datatracker.ietf.org/doc/html/draft-bu-agentproto-security-principal-binding-08">
  <front>
    <title>Security Principal and Verifier Binding for Agent Communication Protocols</title>
    <author fullname="Songbo Bu" initials="S." surname="Bu"/>
    <date day="13" month="October" year="2026"/>
    <abstract>
      <t>Agent communication protocols often carry claims about user authority, agent instance identity, tool or external-resource identity, delegation state, session continuity, and action evidence. These claims have different verifiers, freshness requirements, failure modes, and security consequences. If they are collapsed into a single token, identity label, session identifier, or audit record, protocol text can accidentally imply more authority or accountability than the receiver can actually verify. This document defines a verifier-facing model for separating those claims. It provides a reusable matrix format that protocol authors can use to state, for each security-relevant claim, which field carries it, which party verifies it, what binding or freshness rule applies, what failure behavior is required when the claim is absent, stale, inconsistent, or not verifiable, and what constrained result an application may consume after successful verification. It also separates specification status, implementation status, and evidence type so that reviewers can distinguish current protocol text, implementation evidence, inherited mechanisms, and architectural assumptions. The document is protocol-neutral. It is intended to help compare candidate agent communication drafts and to provide security-considerations and requirements text for agent session and delegation binding. The document also defines row-outcome semantics and dependency- closure rules for composed mappings. These rules prevent a composite result from becoming stronger than its verified inputs, distinguish failed checks, unsupported verifier capabilities, checks skipped after a failed prerequisite, and unavailable or ambiguous inputs, propagate transitive dependency failures, and make cyclic, stale, downgraded, or revision-incoherent dependencies visible to reviewers.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-bu-agentproto-security-principal-binding-08"/>
</reference><reference anchor="I-D.konda-agentproto-evaluation-state" target="https://datatracker.ietf.org/doc/html/draft-konda-agentproto-evaluation-state-02">
  <front>
    <title>Preserving Evaluation State in Agent Protocol Decisions</title>
    <author fullname="Girish Konda" initials="G." surname="Konda"/>
    <date day="19" month="October" year="2026"/>
    <abstract>
      <t>Agent protocols often require a participant to establish a decision- time input before it acts: issuer standing, key availability, delegated authority, policy profile availability, consumption state, revocation status, or the outcome of a downstream operation. A participant that establishes an input and receives a negative answer has learned a different fact from a participant that cannot establish the input at all. Collapsing those facts into one denial or failure value changes retry behavior, alert routing, audit interpretation, incident ownership, and post-incident reconstruction. This document specifies requirements for preserving evaluation state across agent protocol boundaries: the value of an input, whether that value was established at decision time, the freshness of the source used to establish it, and whether the resulting policy decision was actually evaluated. The requirements are stated independently of encoding, so that policy, authorization, revocation, routing, and audit documents can satisfy them in their own formats. Test cases for the requirements are included, with a machine-readable form published separately.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-konda-agentproto-evaluation-state-02"/>
</reference><reference anchor="I-D.he-agentproto-verifier-evidence" target="https://datatracker.ietf.org/doc/html/draft-he-agentproto-verifier-evidence-01">
  <front>
    <title>Exercise and Completeness Evidence for Agent Protocol Verifier Results</title>
    <author fullname="James Siyuan He" initials="J. S." surname="He">
      <organization>Independent</organization>
    </author>
    <date day="18" month="October" year="2026"/>
    <abstract>
      <t>A verifier result reports what a check returned. It does not report whether the check could have returned anything else. A check that inspects too narrow a set of fields, and a check whose rejecting or unverifiable input has never occurred, both report the same accepting value as a check that distinguishes, and a conformance matrix does not tell them apart. This document defines requirements for reporting whether a check has been exercised into its declared rejecting and unverifiable outcomes, and requirements for results that claim completeness: that the records relied on were the whole of some stated set. Those are two separate obligations. A result must name the set it claims to have seen, and must not treat a party with an interest in the answer as the only thing looking. This document defines no wire format, encoding, token, claim vocabulary, test harness, or registry. It does require a record to identify certain facts, which is a constraint on what a record must be able to express rather than on how it is written down. A profile satisfying these requirements will need a place to put those facts.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-he-agentproto-verifier-evidence-01"/>
</reference><reference anchor="I-D.wadkins-agentproto-action-determinability" target="https://datatracker.ietf.org/doc/html/draft-wadkins-agentproto-action-determinability-00">
  <front>
    <title>Independent Determinability of Agent Actions</title>
    <author fullname="Douglas Wadkins" initials="D. L." surname="Wadkins">
      <organization>Strakewright</organization>
    </author>
    <date day="11" month="September" year="2026"/>
    <abstract>
      <t>Evidence that an agent was authorized to act does not establish that the authorization was enforced, that the action was executed, or that the intended effect occurred. These are distinct transitions. This document defines requirements for making a claimed agent transition independently determinable after the original interaction has ended. The requirements address binding the material action and governing conditions to the transition at decision time, identifying which revision of a mutable governing artifact was in force, preventing later substitution, and preserving enough information for an independent evaluator to establish the claimed transition after participants, sessions, credentials, keys, or agent instances are no longer available. This document defines no evidence format, token, action identifier, delegation protocol, audit system, registry, or transparency service.</t>
    </abstract>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-wadkins-agentproto-action-determinability-00"/>
</reference><reference anchor="AGENTPROTO-CHARTER" target="https://datatracker.ietf.org/doc/charter-ietf-agentproto/"><front><title>Agent Communication Protocols (agentproto) Charter, Revision 01</title><author><organization>IETF</organization></author><date year="2026" month="October" day="8"/></front></reference><reference anchor="A2A" target="https://a2a-protocol.org/v1.0.0/specification/"><front><title>Agent2Agent (A2A) Protocol Specification, Version 1.0.0</title><author><organization>A2A Project</organization></author><date/></front></reference><reference anchor="A2A-EXT" target="https://a2a-protocol.org/latest/topics/extensions/"><front><title>A2A Extensions</title><author><organization>A2A Project</organization></author><date/></front></reference><reference anchor="MCP" target="https://modelcontextprotocol.io/specification/2025-06-18"><front><title>Model Context Protocol Specification, Version 2025-06-18</title><author><organization>Model Context Protocol Project</organization></author><date year="2025" month="June" day="18"/></front></reference></references></references><section anchor="scitt"><name>Referencing a SCITT Receipt</name><t>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 <xref target="RFC9943"/> defines Signed Statements as COSE_Sign1 messages, and Receipts <xref target="RFC9942"/> as signed proofs that a statement is included in a verifiable data structure.</t><t>For kind "scitt-receipt":</t><ul><li>dig is the SHA-256 digest of the encoded, tagged COSE_Sign1 Signed Statement with its unprotected header set to the empty map.  This removes Receipts carried in the unprotected header (header parameter 394) and other unprotected parameters that could make digests of one statement differ.  <xref target="RFC9942"/> also allows Receipts in the protected header; those remain part of the digest.</li><li>proof is the Receipt, as a byte string in CBOR or base64url text in JSON.</li><li>The delegate needs the Signed Statement itself to check the Receipt. The statement is delivered with the task or fetched from loc.  If the delegate cannot obtain it, the reference is unverifiable.</li><li>The delegate checks dig against the statement, then verifies the Receipt for that statement with a transparency service key it trusts.</li></ul><t>A verified receipt shows that the statement was registered.  It says nothing about whether the statement is true.</t></section><section anchor="learnlog"><name>Referencing a Learnlog Signed Head</name><t>Learnlog <xref target="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.</t><t>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:</t><ul><li>proof is the SignedHead object.</li><li>dig is the SHA-256 digest of the UTF-8 octets of the JSON Canonicalization Scheme <xref target="RFC8785"/> form of that object, which is the canonical form Learnlog uses.</li><li>The delegate verifies the head's signature with a key it trusts for the record's producer.  It can then check a copy of the record against the head using Learnlog's own verification.</li></ul><t>Limits:</t><ul><li>The delegate does not append to the delegator's record.  A record has one producer.  If the delegate keeps its own Learnlog record, it is a separate record, linked to this hop only through the offer.</li><li>A verified head shows that the producer committed to the record up to that entry.  It does not show that the record is complete: a holder could remove a later head along with the entries it covers.</li><li>A Learnlog record about a learner is personal data.  Pass a head only to agents that are entitled to see that the record exists.</li></ul></section><section anchor="changes" removeInRFC="true"><name>Changes from -00</name><ul><li>An exact retransmission of an offer is answered by resending the delegate's last status, even after exp.  In -00 such an offer got no status.  An equivocating offer is treated as equivocation even after exp (<xref target="receiving"/>, <xref target="freshness"/>, <xref target="asking-again"/>, <xref target="forks"/>).</li><li>A delegate that has answered an offer or taken the work keeps the pair, the digest, and its last status, in storage that survives a restart, until it sends "rejected", "completed", or "failed" and for a retention period after (<xref target="freshness"/>).</li><li>New <xref target="asking-again"/>: how a delegator asks again after a lost status, and why it never treats silence as "failed".  It defines when a hop is resolved.  An expired hop, a hop rejected as "stale" or "replay", and a canceled hop are unresolved, and no new offer replaces an unresolved hop unless the work is safe to do twice.  A "canceled" does not show that the work took no effect (<xref target="lifecycle"/>).</li><li>New <xref target="outcome"/>: "completed" and "failed" are sent only when the delegate knows whether the work took effect; while it does not, the hop stays "accepted".  "failed" lists in refs any part of the work that took effect, and Section 2 says so for refs.  An outcome record shows the effect only when it is written in the delegate's own store atomically with it; an effect outside that store needs an authoritative observation of the same attempt.</li><li>"expired" is now local and provisional; a later verified status still counts.  A delegate does not send "rejected" for a hop it has taken, except "stale" or "replay" for a hop it no longer remembers, and such a rejection never sets the hop's state.  "failed" with no refs says the work took no effect.  The new rules in <xref target="lifecycle"/> use BCP 14 keywords.</li><li>The equivocation rule in <xref target="forks"/> now waits for a known outcome and then sends the status that is true.  A "stale" or "replay" rejection is never a conflict, and a late "completed" or "failed" still resolves a canceled hop.</li><li>Security: a receiver that lost its cache rejects with reason "replay", but still answers hops it records; a resent status is sent only to a party authenticated as offer.iss (a <bcp14>SHOULD</bcp14>); a forgotten hop identifier can be reused undetected (<xref target="replay-and-freshness"/>).  Privacy: resent statuses and kept records.</li><li>Carriage: MCP cancellation can suppress the reply, and an MCP delegator learns later statuses by retransmitting (<xref target="carriage"/>).  A reference for A2A extensions is added.</li><li>Appendix A: Receipts in the protected header remain part of the digest.</li><li>Normative references to RFC 3986 and RFC 6234 are added.  Section 2 says that members of the Handoff object are not signed, and the salt and grant rules use BCP 14 keywords.</li><li>Scope: <xref target="relationship-to-the-agentproto-charter"/> now states a test for what is dialog context and what is audit data, with a similar distinction from Section 5.3 of <xref target="I-D.konda-agentproto-evaluation-state"/>, and the scope open issue asks whether the working group agrees.</li><li>Sections 5.3 through 5.5 of -00 are now Sections <xref target="chain" format="counter"/> through <xref target="obo" format="counter"/>.</li><li>Requirements coverage: B2-4.  Open issues: a lighter status query; status refs and kept records against the audit line; offers that were never received.</li></ul></section><section anchor="acknowledgments" numbered="false"><name>Acknowledgments</name><t>Iman Schrock and Justin Kintzele worked three state-import cases against -00 with the author. Their cases found the lost-response gap that Sections <xref target="asking-again" format="counter"/> and <xref target="outcome" format="counter"/> address, and Iman's review sharpened the conditions in Sections <xref target="lifecycle" format="counter"/> and <xref target="outcome" format="counter"/>.</t></section></back></rfc>