Internet-Draft ACP November 2026
Liu Expires 6 May 2027 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-liu-agentproto-acp-00
Published:
Intended Status:
Standards Track
Expires:
Author:
D. Liu
Alibaba

The Agent Communication Protocol (ACP)

Abstract

An agentic dialog can run for hours or days, go quiet for long stretches, move between hosts, and survive the loss of whatever connection was carrying it. The Agent Communication Protocol (ACP) architecture names Agentic Dialog Management as a building block and requires an identifier that correlates every message of a dialog and outlives the transport, but leaves the wire format out of scope. This document specifies one such wire format.

ACP is an application-level session protocol in the style of SIP: every message is a start line, a block of text header fields, a blank line, and an optional body. A dialog is named by an Agentic Dialog Identifier (ADID) and its durable state is an append-only log of entries, each digesting the one before it into a hash chain. The chain lets two endpoints that have been apart establish in one exchange which entries they still share, replay only what is missing, and detect divergence. Periodic checkpoints bound the log, so aligning a dialog does not cost more as it ages.

ACP carries control and log state only. Real-time media flows beside it on its own channels and enters the log as a metadata entry or as a content-addressed reference, never as bytes the chain must digest. The semantics are transport-independent; this version binds them to Media over QUIC Transport (MoQ) and to WebTransport over HTTP/3, both of which multiplex the channels ACP needs and migrate across network paths without disturbing the dialog.

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 6 May 2027.

▲

Table of Contents

1. Introduction

A task handed to an agent is rarely one request and one answer. It runs for hours, produces output long after the request that caused it, goes quiet while a human sleeps, and resumes from a different device. The connection carrying it will be replaced several times over that life. Nothing in the connection survives, so the dialog needs a name and a state of its own.

The ACP architecture [I-D.manyfolks-agentproto-arch] names that state Agentic Dialog Management and requires an identifier that correlates every message of a dialog and survives the loss or replacement of the transport. It does not say what the messages look like. This document supplies a wire format for that building block, and adds the one thing a dialog that spans days cannot do without: a way for two endpoints that have been apart to agree on what they both remember.

The problem is not reliability. QUIC already delivers a stream without gaps. The problem is the interval between connections. An agent may finish work while its principal is offline; a principal may accept an entry whose acknowledgement never arrived; a server may recover from a crash having lost its last few entries. Each side holds a plausible history and there is no shared clock or shared connection to arbitrate them. ACP answers this with a hash chain: every log entry digests its predecessor, so a history is a sequence of digests that can be compared from the tail backwards, and the first position where two histories differ is exactly the position where they diverged (Section 6.6).

The encoding follows SIP [RFC3261] rather than a structured data format, for two reasons. A text start line and text header fields can be read by a human in a log, generated by a shell script, and extended by adding a field without a schema change. And because the body is carried as raw octets with no field ordering to normalize, the digest of an entry is the digest of a byte string both endpoints already hold verbatim. A format whose in-memory representation is serialized differently by different implementations cannot offer that, and a chain that disagrees about its own digests is worse than no chain at all.

The rest of this document is organized as follows. Section 2 defines the terms used throughout; Section 3 gives the layering, the traffic classes, the participants and their identity, and the mapping onto transports; Section 4 gives the dialog and transport state machines; Section 5 defines the message format, the header fields, the methods, transactions, and status codes; Section 6 defines the log, its event boundaries, the entry digest, asset references, checkpoints, and the alignment procedure that lets a dialog survive its transport; and Section 7 maps ACP onto MoQ and WebTransport.

This is a first revision and is deliberately narrow. How a client learns the https URI of the agent service it wants is not specified here; ACP assumes the client already has one. Delegation between dialogs, per-entry signatures, concurrent access from several devices, and the media negotiation body are likewise identified but not specified.

1.1. Conventions and Definitions

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.

The syntax uses the Augmented Backus-Naur Form of [RFC5234]. The terms "octet", "byte", and the character names CR, LF, and SP are used as in that specification.

2. Terminology

The terms below follow the ACP architecture [I-D.manyfolks-agentproto-arch] where it defines them.

Agent

A software process that acts on a task over an extended period, holds state between exchanges, and produces output that is not a direct function of a single request. An agent is the server side of a dialog in this document, but an agent may also be the principal of another dialog.

Principal

The entity on whose behalf a dialog is conducted: a human user, or an agent acting for one.

Agentic dialog (dialog)

A long-lived session between two participants, named by an ADID. A dialog is a protocol object with state of its own; it is not a connection, and it does not end when one is lost.

ADID

The Agentic Dialog Identifier: an opaque, unguessable identifier for a dialog (Section 3.3).

Client, server

The participant that sends INITIATE is the client; the participant that answers it is the server. The roles name who offered the dialog, not which side runs the model.

Ordering authority

The participant that assigns the authoritative Sequence numbers of a dialog's log. In this version the server is always the ordering authority (Section 6.1).

Log

The ordered, append-only sequence of entries that constitutes a dialog's durable state (Section 6). Each participant holds a replica; the ordering authority's replica is authoritative.

Entry

One unit of the log, occupying exactly one Sequence number and carrying one digest (Section 6.3).

Event boundary

A point at which an application's execution has completed a whole unit of work: a turn, a tool call and its result, an accepted utterance. Every entry closes exactly one event boundary (Section 6.2).

Dialog context

The protocol state of a dialog: its ADID, its participants, its capability and lifetime parameters, and its log.

Model context

The inference state an agent's runtime keeps for a dialog: token windows, scratch memory, tool bindings. Model context belongs to the application. ACP neither carries nor reconstructs it, and losing it is not an ACP failure.

Alignment

The process by which two replicas of a log establish their last common entry and bring the lagging one up to date (Section 6.6).

Checkpoint

An entry of Entry-Type system that commits to a prefix of the log, after which entries in that prefix may be discarded (Section 6.5).

Control plane, log plane

The two planes on which ACP carries traffic that must be delivered reliably. The control plane is requests and responses, matched by CSeq. The log plane is committed entries. They are separated because their durability requirements differ: the log must also be recoverable after a connection is replaced. A third class, progress traffic, rides neither plane and is never logged (Section 3.2).

3. Protocol Layering and Transport Mapping

ACP sits between the application that owns the dialog and the transport that carries it. It is layered so that neither knows the other: the application issues methods and appends entries, the transport adapter decides which channel each byte takes, and the session layer owns the log that makes the two independent of any particular connection (Table 1).

Table 1: ACP layering
Layer Responsibilities
ACP application layer dialog management, identity and delegation, authorization
ACP session and synchronization layer log, entry digest, alignment, checkpoints
ACP transport adapter channel mapping, connection migration, resumption
underlying transport WebTransport over HTTP/3 or MoQ; further bindings TBD

The layering matters for one reason above the others. A dialog's lifetime is not a connection's lifetime, and the difference can be days. Everything ACP defines is therefore keyed to the ADID and to log position, never to a connection, a stream, or a socket. A transport connection may be established, migrated, and lost any number of times while the dialog stays in one state, and when a connection is replaced the dialog does not restart: it aligns (Section 6.6).

3.1. Protocol Overview

Two parties take part in a dialog: the client, which acts for a principal, and the server, which acts for an agent and is the ordering authority for the log. Figure 1 walks one dialog through establishment, steady state, an interruption, and recovery.

    Client                                        Server
(for a principal)                             (for an agent)
       |                                             |
  (1)  | INITIATE                                    |
       |   ADID, From, To, Supported-Modalities      |
       |-------------------------------------------->|
  (2)  | 200                                         |
       |   ADID, Session-TTL, Tail-Seq: 0            |
       |<--------------------------------------------|
       |               dialog ACTIVE                 |
       |                                             |
  (3)  | APPEND  Sequence: 1, Entry-Type: input      |
       |-------------------------------------------->|
  (4)  | 200  Sequence: 1, Entry-Hash                |
       |<--------------------------------------------|
  (5)  | APPEND  Sequence: 2, Entry-Type: output     |
       |<--------------------------------------------|
  (6)  | 200  Sequence: 2                            |
       |-------------------------------------------->|
       |                                             |
  (7)  | media and progress, on their own channels   |
       |<- - - - - - - - - - - - - - - - - - - - - ->|
       | no ACP header, no Sequence, no digest       |
       |                                             |
  (8)  | the connection dies                         |
       |                      X                      |
       |             both go SUSPENDED               |
       |                                             |
  (9)  | RESUME  Tail-Seq: 2, Tail-Hash: H2          |
       |-------------------------------------------->|
 (10)  | 206  Action: replay, Replay-From: 3         |
       |<--------------------------------------------|
 (11)  | the entries the client missed               |
       |<============================================|
       |             both ACTIVE again               |
Figure 1: The life of a dialog

Steps 1 and 2 establish the dialog. The client generates the ADID and offers what it supports; the server records the dialog durably, grants a lifetime, and answers with an empty log position. Three fields are the whole handshake, because everything else is either implied by the channel or negotiated later.

Steps 3 to 6 are the steady state, and they are the same exchange in both directions. Each entry is proposed by its author with the next Sequence and the digest of the entry before it, and is committed when the peer accepts it. The response is not an acknowledgement in the transport sense; it is the commit, and until it arrives the entry is pending (Section 6.1.1).

Step 7 is the traffic ACP deliberately does not carry. Real-time media and progress indications flow on their own channels with no header, no position, and no digest, and are recorded in the log only as the event that opened or closed them (Section 6.2). This is what keeps the chain cheap enough for a dialog that runs for days.

Steps 8 to 11 are the reason the chain exists. The connection dies and both participants suspend without exchanging anything. When the client returns, possibly days later and on a different host, it names the last entry it holds and its digest; the server compares, and answers with either agreement or the position to replay from. One round trip establishes what the two have in common, and the entries that follow are verified as they arrive rather than trusted (Section 6.6).

3.2. Traffic Classes

ACP distinguishes traffic by what has to survive.

Control traffic

Requests and responses on the control plane: INITIATE, SUSPEND, RESUME, PROBE, CHECKPOINT, TERMINATE, and CANCEL. It must be delivered reliably and in order within a connection, and it is small. It is matched by CSeq (Section 5.3).

Log traffic

Committed entries, each an indivisible octet string that has already been digested by its author. It must be delivered reliably and in order, it may be large, and it must be recoverable after a connection is replaced, because a peer that reconnects needs the entries it missed rather than the ones it has.

Progress traffic

Ephemeral indications that something is happening: generation is underway, a tool call started, a partial transcript. It is time-bounded and superseded by the next indication. It MUST be carried unreliably, it is never part of the log, and no ACP state may depend on receiving it.

Keeping these apart is what allows ACP to be both light and durable. Real-time media takes the third path: it flows on its own channels, and the log records only that it flowed and how to find it (Section 6.4). A dialog can therefore carry hours of voice and video while its log stays small enough to align in one exchange.

3.3. The Agentic Dialog Identifier

Every dialog has an Agentic Dialog Identifier (ADID), a version 4 UUID [RFC9562]: 122 bits from a cryptographically secure random source [RFC4086], written in the canonical textual form of 36 lowercase hexadecimal digits in five hyphen-separated groups so that it can be compared verbatim. The client generates it and sends it in the INITIATE; the server echoes it in the final response and from then on it names the dialog for both participants. It MUST NOT be chosen or influenced by a peer of the generator, and MUST NOT be reused, including for an INITIATE that went unanswered.

The ADID identifies the dialog, not the connection carrying it, so a dialog that moves to a new connection keeps its ADID and its log position. Because it carries 122 bits of randomness, collisions are negligible and no registration is needed. It is also not a credential: it is opaque, non-self-certifying, and reveals nothing about the dialog. Knowledge of an ADID is not authority to use it (Section 8.1).

3.4. Participants

A dialog has exactly two participants, both named when it is initiated: the client, acting for a principal, and the server, acting for an agent. Each is named by a SPIFFE ID [SPIFFE], which is what the architecture uses for a participant and what a workload identity carries ([I-D.ietf-wimse-workload-creds]), for example spiffe://example.org/ns/agent/travel.

A SPIFFE ID names a participant, not a place to send a message. The request target of INITIATE is an https URI (Section 5.1) naming the agent service: it says where to send the offer, while the From, To, and Author fields say who is in the dialog. A client that does not yet know which workload will serve it addresses the service and learns the participant from the To of the server's final response, which from then on is the name the log uses.

3.5. Workload Identity and Attribution

ACP is neither an identity mechanism nor an authorization mechanism, and it introduces no new cryptographic construction. It takes the model the architecture specifies [I-D.manyfolks-agentproto-arch] and states where it rides.

Each participant holds a WIMSE workload identity [I-D.ietf-wimse-workload-creds], expressed as a SPIFFE ID [SPIFFE] and carried as the sub claim of a Workload Identity Token (WIT) that binds a public key in cnf.jwk:

{ "iss": "https://aim.example.org",
  "sub": "spiffe://example.org/ns/agent/travel",
  "aud": "https://agent.example.com",
  "cnf": { "jwk": { "kty": "EC", "crv": "P-256",
                    "x": "...", "y": "..." } },
  "exp": 1793316000 }
Figure 2: The identity a participant presents

The same identity serves twice. At the transport layer the participant presents it as a workload identity credential over a channel that mutually authenticates both ends, which is what makes the channel requirement of Section 8 satisfiable. At the application layer it presents a token derived from that credential, in an Authorization field, in the messages where the peer has to check authority rather than merely connectivity: INITIATE and RESUME. The WIT is the input to that derivation and is not itself what is sent: a workload identity says who a participant is, while authorizing one request also needs the transaction context that Section 8.2 describes.

Attribution then needs no signature of ACP's own, and two rules are the whole of the mechanism. A recipient MUST check that the Author of an APPEND, and the From of any other request, equal the workload identity the channel authenticated, and MUST reject the message with 403 if they do not. And a participant MUST NOT accept dialog traffic on a channel that does not authenticate its sender, because without an authenticated channel there is nothing to attribute a message to and the ADID by itself asserts nothing.

The private key corresponding to cnf.jwk is also the key with which the participant signs the tokens it obtains, so one identity serves for channel authentication, for the authority it presents, and for the name that appears in the log. ACP adds no second identity and no second key. Note what this does and does not buy: it proves who sent a message on the connection that carried it, and it does not survive the connection. An entry committed to the log is attributed by an Author string inside a digest, which anyone able to write to the authoritative replica can set.

3.6. Transport Mapping

The three traffic classes of Section 3.2 have different delivery requirements, and the adapter's only job is to satisfy each of them on whatever transport is available. Table 2 summarizes the mapping; Section 7 specifies it.

Table 2: Channel requirements and how each binding meets them
Channel Requires MoQ WebTransport
control reliable, ordered, bidirectional one bidirectional stream one bidirectional stream
log reliable, ordered, recoverable after a reconnect published track, one group per entry bidirectional stream, replayed by the server
asset reliable, content-addressed, must not block the log a track per asset unidirectional streams
progress, live media low latency, unreliable is acceptable datagrams or media objects datagrams

Two properties of the underlying transport do work that ACP would otherwise have to do itself. Connection migration lets a dialog change network path without changing state (Section 4.2), and per-stream flow control lets a large asset move without holding up an entry that is a few hundred octets. A binding that cannot provide either is still conformant, but the dialog will suspend more often and its log will stall behind its media.

4. Dialog and Transport State

A participant in a dialog tracks two independent variables. Its dialog state is a property of the ADID and survives any number of connections. Its transport state is a property of the connection the binding gives it and survives nothing. Conflating them is the mistake that makes a session protocol fragile, so ACP keeps them apart and defines exactly how the second drives the first (Section 4.2).

4.1. Dialog State

ACP keeps one dialog state per participant. The states are the same for both, except that only the server enters ALIGNING: the client stays in SUSPENDED until alignment completes, because it is the server that arbitrates and only the server needs a state in which it has accepted a resumption but not yet settled it.

   IDLE
   |
   | INITIATE
   v
   INITIATING --4xx / 5xx / T1--> TERMINATED
   |
   | 200
   v
   ACTIVE <--------------------------+
   |                                 |
   | transport loss, or SUSPEND      | alignment complete
   v                                 | (200, or 206 after replay)
   SUSPENDED ---+                    |
   |            |                    |
   |            +--> ALIGNING -------+
   |                 (server only)
   |
   | TTL expiry, or TERMINATE
   v
   TERMINATED
Figure 3: Dialog states
IDLE

No dialog state exists for this ADID.

INITIATING

An INITIATE has been sent or received and no final response has settled it. The client has chosen an ADID that is not yet in use.

ACTIVE

The dialog is established, a transport channel carries it, and the two replicas are aligned. Entries may be appended and work may be requested. On the server this is also the state in which it holds runtime resources for the dialog; it is not required to hold model context, and losing it is not a protocol failure.

SUSPENDED

The dialog exists and its log is durably held, but no channel carries it. The server releases whatever runtime resources it was holding. This state may last for the whole Session-TTL, which is measured from the moment the dialog was suspended and not from the moment it was created.

ALIGNING

The server has accepted a RESUME and is comparing replicas. It does not accept APPEND in this state, because an append would move the tail it is trying to agree on.

TERMINATED

The dialog is finished. State MAY be purged, and the ADID MUST NOT be reused. A RESUME for a terminated dialog receives 404.

CANCEL does not change dialog state. It stops work associated with an entry already in the log and adds an entry recording that it did (Section 5.4.3), after which the dialog is ACTIVE and accepts the next transaction.

4.2. Transport State and Transitions

Transport state is whatever the binding reports: connected, migrating, or gone. It is not an ACP state machine and ACP defines no polling for it, because QUIC reports path loss directly [RFC9000]. What ACP defines is the mapping from transport events to dialog transitions, in Table 3.

Table 3: Dialog state transitions
Who From Event To
client IDLE sends INITIATE INITIATING
client INITIATING receives 200 ACTIVE
client INITIATING 4xx, 5xx, or T1 expiry TERMINATED
server IDLE receives INITIATE INITIATING
server INITIATING log initialized, sends 200 ACTIVE
server INITIATING rejects, sends 4xx or 5xx TERMINATED
both ACTIVE path changes; migration completes within T1 ACTIVE
both ACTIVE transport gone, and no migration within T1 SUSPENDED
both ACTIVE SUSPEND settled by 200 SUSPENDED
server SUSPENDED receives RESUME ALIGNING
server ALIGNING replicas agree; 200, or 206 and replay complete ACTIVE
server ALIGNING digests differ, sends 409; or tail below Min-Seq, sends 412 ALIGNING
server ALIGNING T2 expiry, or client abandons SUSPENDED
client SUSPENDED alignment complete ACTIVE
client SUSPENDED receives 404, or Session-TTL expires TERMINATED
both any TERMINATE settled, or Session-TTL expires TERMINATED

The row that matters most is the one that changes nothing. Where the binding supports connection migration, as QUIC does, a participant moving from one network path to another stays ACTIVE and sends no ACP message at all: the dialog is keyed to the ADID and to log position, never to a socket (Section 3). It moves to SUSPENDED only when the connection is gone and no migration has completed within T1. This is why a dialog can survive a walk from a wireless network to a cellular one without either participant noticing, and why the resumption path is reserved for separations long enough that the connection really did die.

5. Wire Format and Signaling

Everything on the control plane and the log plane has one shape: a start line naming a method or a status, a block of text header fields, a blank line, and an optional body. This section defines that shape, the fields, the methods, and the transactions that match a request to its response. Section 5.4 gives each method in full, and Section 5.5 the response codes.

5.1. Message Format

An ACP message is a start line, zero or more header fields, a blank line, and an optional body:

ACP-message   = request / response

request       = Request-Line *( header-field CRLF ) CRLF [ body ]
response      = Status-Line  *( header-field CRLF ) CRLF [ body ]

Request-Line  = method SP request-uri SP "ACP/1.0" CRLF
Status-Line   = "ACP/1.0" SP status-code SP reason-phrase CRLF

method        = "INITIATE" / "APPEND" / "CANCEL" / "SUSPEND"
                / "RESUME" / "PROBE" / "CHECKPOINT" / "TERMINATE"
                / token

status-code   = 3DIGIT
reason-phrase = 1*( unreserved / SP )

header-field  = field-name ":" OWS field-value OWS
field-name    = token
field-value   = *( HTAB / SP / VCHAR )

request-uri   = "https:" "//" authority [ path-abempty ]

body          = *OCTET

OWS           = *( SP / HTAB )
token         = 1*tchar
tchar         = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+"
                / "-" / "." / "^" / "_" / "`" / "|" / "~"
                / DIGIT / ALPHA

3DIGIT        = DIGIT DIGIT DIGIT
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
authority     = <authority, Section 3.2 of [RFC3986]>
path-abempty  = <path-abempty, Section 3.3 of [RFC3986]>
Figure 4: ACP message syntax

OWS, token, and 3DIGIT match the definitions of the same names in [RFC9110], and unreserved matches [RFC3986], Section 2.3; all four are repeated here so that the grammar is self-contained. authority and path-abempty are used by reference to [RFC3986], Sections 3.2 and 3.3.

The request-uri is an https URI naming the agent service, and is the same in every request of a dialog. It is a locator, not the name of a participant (Section 3.4); its userinfo, query, and fragment components MUST NOT be used. That the scheme is https does not mean ACP runs inside HTTP: how the URI is reached is a property of the binding (Section 7).

Three properties of this syntax are normative because the entry digest of Section 6.3 depends on them. First, a field-value cannot contain CR or LF, since it is built from VCHAR, SP, and HTAB only; that is what makes a sequence of field values separable without length prefixes. Second, the blank line that ends the header block is exactly CRLF following the CRLF of the last header field, with no other form permitted. Third, the body is an opaque octet string whose extent is given by Content-Length; no transfer encoding, and in particular no chunked encoding, is defined.

A sender MUST NOT send a header field it does not understand the syntax of, and a recipient MUST ignore a header field it does not recognize unless Section 5.2 marks it as required for the method in question. This is what allows a field to be added without a version change. A recipient that receives a message whose start line it cannot parse MUST respond 400; one whose method it does not support MUST respond 501.

Content-Length is REQUIRED on every message sent on a channel that carries more than one message, and on every message with a body. On a channel that carries exactly one entry body and is then closed by the transport, the end of the stream delimits the body and Content-Length MAY be omitted (Section 7).

5.2. Header Fields

Table 4 lists the fields this version defines. Field names are case-insensitive. A field MUST NOT appear more than once unless its definition says otherwise.

Table 4: ACP header fields
Field Value Where it appears
ADID The dialog identifier (Section 3.3) Every message, including an INITIATE request, where it is the client-generated value
CSeq seq SP method, per transaction Every request; echoed by its response
From, To Participant URIs (Section 3.4) INITIATE request and its final response
Sequence Log position of an entry APPEND; a response that assigns one
Prev-Hash Entry-Hash of Sequence minus one APPEND
Entry-Hash Digest of this entry (Section 6.3) APPEND
Entry-Type input, output, meta, abort, system APPEND
Author Participant URI of the entry's creator, which MUST equal the identity the channel authenticated (Section 3.5) APPEND
Timestamp Seconds since the Unix epoch APPEND, CHECKPOINT
Event-Cursor A token naming the runtime boundary the entry closes (Section 6.2); optional APPEND, CANCEL
Tail-Seq, Tail-Hash Position and digest of the sender's last committed entry RESUME, PROBE, and responses that report position
Min-Seq Oldest Sequence still retained RESUME and its responses
CP-Seq, CP-Hash Latest checkpoint entry and its digest (Section 6.5) CHECKPOINT, RESUME responses
Replay-From First Sequence the responder will replay 206 response to RESUME
Action replay, resync, or probe Responses to RESUME
Proof One seq=hash-value pair; repeatable PROBE request and response
Session-TTL delta-seconds; requested in a request, granted in a response INITIATE, SUSPEND, RESUME
Supported-Modalities Comma-separated media type ranges INITIATE request
Target-Seq Sequence whose processing is to stop CANCEL
Reason Machine-readable token CANCEL, TERMINATE
Authorization Credentials of the sender, syntax as in [RFC9110]; carries the token obtained as Section 8.2 describes INITIATE, RESUME
Content-Type Media type of the body [RFC2046] Any message with a body
Content-Length Body length in octets See Section 5.1

The values of the fields that carry a digest or a position use this syntax:

seq          = 1*15DIGIT

hash-value   = hash-alg "-" b64
hash-alg     = "sha256"
b64          = 43*unreserved   ; RFC 4648, Section 5, unpadded

Proof        = seq "=" hash-value

action       = "replay" / "resync" / "probe"
Figure 5: Position and digest value syntax

Tail-Seq and Tail-Hash MUST appear together and describe the same entry. Min-Seq defaults to 1 when absent. Proof is the only field in this document that MAY appear more than once; the set it denotes is the union of its occurrences, and a seq MUST NOT be repeated across them.

Digest values are written as the algorithm name, a hyphen, and the base64url encoding of the digest without padding ([RFC4648], Section 5), which for SHA-256 is 43 characters. Hexadecimal is not used because a 64-character digest cannot share a line with a field name inside the formatting width this document observes, and folding a digest across lines would put its textual form at the mercy of each implementation's folder. The algorithm prefix is not decorative: a recipient MUST check it and MUST reject a value naming an algorithm it does not support with 400.

Header field order is not significant. A sender MAY emit fields in any order, and a recipient MUST NOT infer meaning from their arrangement. The digest of Section 6.3 uses a fixed order of values that has nothing to do with the order they appear in.

5.3. Transactions, Ordering, and Timers

A transaction is one request and the responses to it. The CSeq field carries a sequence number and the method name, separated by a single space. Each participant keeps one CSeq counter per dialog, starting at 1 and increasing by at least one for each request it sends; the counter is independent of log Sequence numbers, because a dialog may see many transactions that add no entry. A response echoes the CSeq of its request verbatim. A recipient that sees a CSeq it has already answered on this dialog MUST discard the request, which makes requests safe to repeat after a connection is replaced.

A participant MUST NOT have more than one outstanding APPEND per dialog, so that its pending entries have a total order. It MAY have one outstanding APPEND and one outstanding control request at the same time. Responses may arrive in a different order from requests only where this paragraph allows it, so a recipient matches them by CSeq and never by arrival order.

Because every channel ACP uses is reliable and ordered within a connection (Section 7), ACP defines no retransmission timer and no hop-by-hop acknowledgement. It does define two timers, because a request can still go unanswered when a connection dies:

Table 5: ACP timers
Timer Default Meaning
T1 5 s Bound on waiting for a final response. On expiry the transaction fails locally; the outcome is unknown and the participant MUST align before relying on it (Section 6.1.1).
T2 60 s Bound on completing a replay announced by 206. On expiry the alignment attempt fails and MAY be retried.

A dialog also has a lifetime, Session-TTL, expressed in delta-seconds. A request carries the value the sender wants; the response carries the value granted, which MAY be shorter. The default is 259200 (72 hours). Time starts again on each successful APPEND, RESUME, or CHECKPOINT. When it expires the dialog moves to the terminated state and its state MAY be purged; a later RESUME then fails with 404.

5.4. Methods

ACP defines eight methods, summarized in Table 6. The subsections that follow define each one in full: what it requires, what a successful response commits both participants to, and how it fails. The examples use one dialog throughout, with the digests that follow from it, so they can be checked against the construction of Section 6.3.

Table 6: ACP methods
Method Sent by Effect
INITIATE client Create a dialog and fix its ADID and participants
APPEND either Add one entry to the log
CANCEL either Stop work caused by an entry already in the log
SUSPEND either Release runtime resources, keep the dialog
RESUME client Align the log and reactivate the dialog
PROBE client Locate the common ancestor after a 409
CHECKPOINT either Commit to a log prefix and permit its truncation
TERMINATE either End the dialog and purge its state

5.4.1. INITIATE

INITIATE creates a dialog. The client generates the ADID (Section 3.3), names both participants, states the modalities it can handle, and asks for a lifetime. Required fields: ADID, CSeq, From, To. Optional: Supported-Modalities, Session-TTL.

INITIATE https://agent.example.com/travel ACP/1.0
CSeq: 1 INITIATE
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
From: spiffe://example.org/ns/agent/client-1
To: spiffe://example.com/ns/agent/travel
Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOi...
Supported-Modalities: text/plain, image/*, audio/opus
Session-TTL: 259200
Content-Length: 0


ACP/1.0 200 OK
CSeq: 1 INITIATE
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
From: spiffe://example.org/ns/agent/client-1
To: spiffe://example.com/ns/agent/travel
Session-TTL: 259200
Tail-Seq: 0
Tail-Hash: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Min-Seq: 1
Content-Length: 0
Figure 6: INITIATE and its acceptance

On 200 the server has durably recorded the dialog with an empty log and both participants are ACTIVE. The ADID in the response MUST equal the one requested; a server cannot substitute its own, since the client has already begun using it. Session-TTL in the response is the lifetime granted, which MAY be shorter than requested.

A server that cannot serve the modalities offered responds 488; one that is out of capacity responds 486; one that cannot durably record the dialog responds 500 and MUST NOT leave partial state. After any failure, and after a T1 expiry, the client MUST discard the ADID and generate a fresh one for any retry: a dialog whose establishment did not settle has no state to resume.

ACP does not define the format of a media negotiation body in this revision. Supported-Modalities is a list of media type ranges as in [RFC6838], and 488 is the only negotiation failure this version specifies. Offer and answer semantics, and how a modality is bound to a data channel, are deferred to a later revision.

5.4.2. APPEND

APPEND adds one entry to the log. Required fields: ADID, CSeq, Sequence, Entry-Type, Prev-Hash, Author, Timestamp, Entry-Hash. Optional: Event-Cursor (Section 6.2). The body is optional but its extent must be determinate, so Content-Length is required unless the binding delimits the body by closing a stream.

APPEND https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 502 APPEND
Sequence: 90
Entry-Type: input
Prev-Hash: sha256-_NrWKsIcH0PxTqjFxzYbg4w8ad2vogH1iWwLtcffWBQ
Author: spiffe://example.org/ns/agent/client-1
Timestamp: 1793312400
Event-Cursor: turn-complete
Content-Type: multipart/mixed; boundary=acp-9b1deb4d
Content-Length: 113
Entry-Hash: sha256-2qyCqGMY8i6F-zXfLQRYMkzVSHBqre6g0CkYq9mmziU

--acp-9b1deb4d
Content-Type: text/plain; charset=utf-8

Please review the flight schedule.
--acp-9b1deb4d--


ACP/1.0 200 OK
CSeq: 502 APPEND
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Sequence: 90
Entry-Hash: sha256-2qyCqGMY8i6F-zXfLQRYMkzVSHBqre6g0CkYq9mmziU
Content-Length: 0
Figure 7: An APPEND by the client, and its acceptance

An entry authored by the server is identical in form, with Entry-Type: output and the server's URI as Author, and travels in the other direction on the log plane. The response echoes Sequence and Entry-Hash and nothing else is needed: the echo is the commit, and after it the entry is part of the log and its author may use its digest as the next Prev-Hash.

A server rejects an APPEND with 409 if it does not extend its tail exactly (Section 6.1), with 422 if the received digest does not match the octets it got (Section 6.3), with 413 if the body is larger than it will accept, and with 415 if it cannot handle the media type. A rejected entry is not written and its Sequence is not consumed. Until a final response arrives the entry is pending and its author is bound by Section 6.1.1.

5.4.3. CANCEL

CANCEL asks the peer to stop work caused by an entry that is already in the log. It does not remove the entry and does not undo the dialog: an entry, once committed, is part of the history whether or not the work it caused was finished. Required fields: ADID, CSeq, Target-Seq. Optional: Reason, Event-Cursor.

CANCEL https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 503 CANCEL
Target-Seq: 90
Reason: user-interrupted
Content-Length: 0


ACP/1.0 200 OK
CSeq: 503 CANCEL
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Content-Length: 0
Figure 8: CANCEL and its acceptance

CANCEL is a request to stop, not a guarantee that nothing further was produced. The recipient SHOULD stop as soon as it can and MUST then append an entry of Entry-Type: abort recording the Target-Seq and the reason, so that both replicas agree on where the abandoned work ended. That entry, not the 200, is what settles the cancellation in the log; a partial output produced before the stop MAY be appended as an output entry below it, and an application that must know how much was produced reads the two together. This is not an exception to Section 6.2: the cancellation closes the event, so what was produced before it is complete in the only sense that matters, namely that no more is coming. Fragments still in flight when the stop arrives are not part of any entry and are discarded.

Because stopping work is often urgent and generation is often metered, a binding SHOULD give CANCEL the highest priority available and SHOULD NOT queue it behind log traffic (Section 7). A server that cannot identify the work referred to, because the entry is not in its log or the work already finished, responds 200 anyway: the requested end state holds. A server that is not authorized to be told to stop responds 403.

CANCEL does not change dialog state (Section 4).

5.4.4. SUSPEND

SUSPEND tells the peer that the sender is going away and asks it to release runtime resources while keeping the dialog. It is advisory about resources and normative about nothing else: a dialog that is never suspended behaves identically, since losing the transport has the same effect (Section 4). Sending it is nonetheless useful, because it lets the server release capacity immediately rather than at a timeout, and it lets the sender ask for a specific retention period. Required fields: ADID, CSeq. Optional: Session-TTL.

SUSPEND https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 601 SUSPEND
Session-TTL: 86400
Content-Length: 0


ACP/1.0 200 OK
CSeq: 601 SUSPEND
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Session-TTL: 86400
Tail-Seq: 90
Tail-Hash: sha256-2qyCqGMY8i6F-zXfLQRYMkzVSHBqre6g0CkYq9mmziU
Min-Seq: 1
Content-Length: 0
Figure 9: SUSPEND and its acceptance

The response reports the lifetime granted and the responder's tail, so the sender can tell before disconnecting whether it is about to strand an unacknowledged append. Session-TTL in the response MAY be shorter than requested; a server that will not retain the dialog at all responds 404 and terminates it. After a 200 the sender closes its channels and moves to SUSPENDED.

5.4.5. RESUME

RESUME re-opens a suspended dialog. It is the entry point to alignment, and its outcomes are specified in Section 6.6.1. Required fields: ADID, CSeq, Tail-Seq, Tail-Hash. Optional: Min-Seq, Session-TTL.

The example below is the ordinary recovery case, and it exercises the pending-entry rule. The client sent the APPEND of Figure 7 and lost the connection before the response arrived, so the entry stayed pending and its tail is still 89. The server received and committed it.

RESUME https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 701 RESUME
Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOi...
Tail-Seq: 89
Tail-Hash: sha256-_NrWKsIcH0PxTqjFxzYbg4w8ad2vogH1iWwLtcffWBQ
Min-Seq: 1
Session-TTL: 259200
Content-Length: 0


ACP/1.0 206 Partial Content
CSeq: 701 RESUME
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Tail-Seq: 90
Tail-Hash: sha256-2qyCqGMY8i6F-zXfLQRYMkzVSHBqre6g0CkYq9mmziU
Min-Seq: 1
Action: replay
Replay-From: 90
Content-Length: 0
Figure 10: RESUME answered with a replay

The server now replays entry 90 on the log plane. It is the entry of Figure 7, whose digest the client already holds as its pending entry, so the replay settles that entry as committed rather than duplicating it. Once the client has committed up to Tail-Seq 90 both participants are ACTIVE with no further exchange. Had the client instead sent new input while offline, it would renumber and resubmit it now (Section 6.1.1).

RESUME MUST be authenticated and authorized against the dialog. A server MUST NOT reveal whether an ADID exists to a sender it has not authenticated; to one it has authenticated but that is not a participant of the dialog it responds 403 rather than 404, and to an unauthenticated sender it responds 401 (Section 8.1).

5.4.6. PROBE

PROBE locates the last position at which two diverged replicas agree, after a 409. The procedure is specified in Section 6.6.2. Required fields: ADID, CSeq, and at least one Proof.

In the example, the client wrongly treated its entry 89 as committed while the server holds a different entry 89, produced after the hold expired and was extended. Both agree at 88.

RESUME https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 702 RESUME
Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOi...
Tail-Seq: 90
Tail-Hash: sha256-2qyCqGMY8i6F-zXfLQRYMkzVSHBqre6g0CkYq9mmziU
Min-Seq: 1
Content-Length: 0


ACP/1.0 409 Conflict
CSeq: 702 RESUME
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Tail-Seq: 90
Tail-Hash: sha256-0pNGg9pstIfSFkwGd466m1ObAHFrwyy2cp7nGHgrTIU
Min-Seq: 1
Action: probe
Content-Length: 0


PROBE https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 703 PROBE
Proof: 89=sha256-_NrWKsIcH0PxTqjFxzYbg4w8ad2vogH1iWwLtcffWBQ
Proof: 88=sha256-ej6bM05D6ILtYQ7s78oWlq87P_1UAdmlri_92oCZUcM
Content-Length: 0


ACP/1.0 200 OK
CSeq: 703 PROBE
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Proof: 88=sha256-ej6bM05D6ILtYQ7s78oWlq87P_1UAdmlri_92oCZUcM
Tail-Seq: 90
Tail-Hash: sha256-0pNGg9pstIfSFkwGd466m1ObAHFrwyy2cp7nGHgrTIU
Min-Seq: 1
Content-Length: 0
Figure 11: Divergence, and the PROBE that finds the ancestor

The highest position the server confirmed is 88, so that is the common ancestor. The client moves its entries 89 and 90 back to pending, accepts a replay of the server's 89 and 90, and then renumbers its own input to 91 against the tail it has just been given. Only two rungs were needed here; a search that has to go further adds 86, 82, 74, and so on, widening the step each time, and Section 6.6.2 bounds the whole ladder at sixteen proofs. The digests at 88, 89, and 90 are the ones the construction of Section 6.3 produces for the bodies shown in Section 5.4.2, so those rungs can be recomputed.

5.4.7. CHECKPOINT

CHECKPOINT commits a prefix of the log to one entry so that the prefix can be discarded. The construction is in Section 6.5. Required fields: ADID, CSeq, and a body carrying Lower and Upper. Either participant may propose one; the ordering authority appends the entry.

CHECKPOINT https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 801 CHECKPOINT
Content-Type: text/plain; charset=utf-8
Content-Length: 78

acp-checkpoint/1
88
90
sha256-eMqjKss9gHwczrgROqwJKOhAc04c0G30WVgbvF9AJ48


ACP/1.0 200 OK
CSeq: 801 CHECKPOINT
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CP-Seq: 91
CP-Hash: sha256-4eYccg4zhfuEkqtJWcZwf91PJUsFTps8TFd-fZk6Js8
Tail-Seq: 91
Tail-Hash: sha256-4eYccg4zhfuEkqtJWcZwf91PJUsFTps8TFd-fZk6Js8
Min-Seq: 91
Content-Length: 0
Figure 12: CHECKPOINT and its acceptance

The checkpoint occupies Sequence 91 and is an ordinary entry, so CP-Hash and Tail-Hash are the same value and the next entry above it links to it as to any predecessor. Both participants may now discard entries 88 to 90, and Min-Seq becomes 91. A recipient that cannot reproduce the accumulator responds 409 and discards nothing. A server MUST NOT accept a CHECKPOINT from a sender it has not authorized for the dialog, and a client MAY refuse one it did not propose.

5.4.8. TERMINATE

TERMINATE ends a dialog and permits both participants to purge its state. Required fields: ADID, CSeq. Optional: Reason.

TERMINATE https://agent.example.com/travel ACP/1.0
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
CSeq: 901 TERMINATE
Reason: task-completed
Content-Length: 0


ACP/1.0 200 OK
CSeq: 901 TERMINATE
ADID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Content-Length: 0
Figure 13: TERMINATE and its acceptance

After a 200 both participants are TERMINATED: the log MAY be erased, the ADID MUST NOT be reused, and a later RESUME receives 404. A participant MAY terminate unilaterally, and a server MAY terminate on Session-TTL expiry without asking; the other participant learns of it on its next RESUME. Termination is therefore not a negotiation, and an application that needs both sides to agree before discarding history must arrange that above ACP.

Purging is OPTIONAL and is a matter of local policy. A participant subject to a retention obligation MAY keep its replica after termination; doing so does not keep the dialog alive.

5.5. Status Codes

A status code is three digits and a reason phrase. The reason phrase is descriptive only and a recipient MUST NOT parse it. ACP status codes occupy the same numeric space as HTTP [RFC9110] and SIP [RFC3261] and several deliberately echo them, but ACP defines its own code space and the meaning of a code is the one given here. In particular 206 and 412 are not HTTP's byte-range responses: they report the outcome of an alignment attempt.

Class 1xx is reserved for provisional responses. This version defines none, but a recipient MUST accept and ignore one. A recipient that receives a code it does not recognize MUST treat it as the default for its class: 2xx as success, 3xx as a redirection it cannot follow, 4xx as a permanent failure of the request, and 5xx as a failure of the recipient that MAY succeed later.

Table 7: ACP status codes
Code Meaning
200 The request succeeded.
206 Resumption accepted; the responder is ahead and will replay from Replay-From (Section 6.6.1).
400 The message could not be parsed, a required field is missing, or a digest names an unsupported algorithm.
401 The sender is not authenticated.
403 The sender is authenticated but is not a participant of this dialog, or is not permitted this operation.
404 No dialog with this ADID, or it has terminated or its Session-TTL expired.
408 The request was not completed in time.
409 The replicas disagree: an APPEND does not extend the authoritative tail, a digest did not verify on replay, or a checkpoint accumulator could not be reproduced. For RESUME, proceed with PROBE (Section 6.6.2).
412 The sender's position is below the responder's Min-Seq; align from the checkpoint instead (Section 6.6.3).
413 The body is larger than the recipient accepts.
415 The media type is not supported for this dialog.
422 The message is well formed but the received Entry-Hash does not match the octets received (Section 6.3).
486 The agent has no capacity for another dialog now; the request MAY succeed later.
488 The offered modalities cannot be served (Section 5.4.1).
500 The recipient failed internally.
501 The method is not implemented.
503 The recipient is unavailable; the request MAY succeed later.

Class 3xx is undefined in this version. Redirecting a dialog is not a simple matter of following a pointer, because the log lives where the dialog lives; a mechanism for it is deferred to a later revision.

6. The Log

A dialog's durable state is its log: an ordered sequence of entries, each occupying one Sequence number, each carrying a digest of itself and of the entry before it. Both participants hold a replica. The log is append-only: an entry that has been committed is never edited, and a committed Sequence number is never reused. What changes history is not editing but truncation from the front (Section 6.5), which is itself a committed act.

The log holds protocol state, not conversation. An entry may carry a message body, but nothing in ACP interprets it: the body is opaque, and an application is free to put a transcript, a tool call, or a capability description in it. What ACP requires is that the body be an octet string both participants can digest identically. Media is handled by reference rather than by inclusion (Section 6.4).

6.1. Entries and Sequencing

Sequence is a positive integer. The first entry of a dialog is 1 and each subsequent entry is one greater, with no gaps in the authoritative log. The ordering authority for a dialog is its server: its replica defines what the log is, and a client replica that differs from it is wrong and is repaired (Section 6.6).

A participant that authors an entry proposes the next Sequence and its Prev-Hash. The ordering authority accepts the entry only if it extends its own tail exactly, that is, only if the proposed Sequence is one greater than its current tail and the proposed Prev-Hash equals that tail's Entry-Hash. If it does, the entry is committed at that position and the response echoes both. If it does not, the entry is rejected with 409 and nothing is written; the author must align, then renumber its entry against the tail it learns, recompute the digest, and resubmit. Rejecting rather than silently renumbering keeps the digest of a committed entry stable: an entry is committed once, at one position, with one digest, and that digest is what the next entry's Prev-Hash refers to.

 +------+    +------+    +------+    +------+
 | e.88 |===>| e.89 |===>| e.90 |===>| e.91 |
 +------+    +------+    +------+    +------+
  Prev=H87    Prev=H88    Prev=H89    Prev=H90
  Hash=H88    Hash=H89    Hash=H90    Hash=H91
Figure 14: The log as a hash chain; e.N is the entry at Sequence N

6.1.1. Pending Entries

An APPEND that has been sent but not finally answered leaves its entry pending. A pending entry is not committed. Its author:

  • MUST NOT report it as its tail in Tail-Seq and Tail-Hash;

  • MUST NOT use its Entry-Hash as the Prev-Hash of a later entry;

  • MUST retain it, with its digest, until alignment settles whether the ordering authority committed it; and

  • MUST NOT present it to its application as part of the dialog history without marking it unconfirmed.

Pending entries are the ordinary source of divergence. A client whose APPEND timed out at T1 cannot know whether the entry was committed before the connection died, and a server that crashed may have committed it without answering. This is why alignment compares digests rather than counts (Section 6.6.1): a count says the two replicas are the same length, which is not the same statement as that they are the same log.

Once alignment establishes the ordering authority's tail, each pending entry is settled by comparison. If the authority holds an entry at that Sequence with that Entry-Hash, the pending entry was committed and becomes part of the replica. If the authority's entry at that Sequence differs, or there is none, the pending entry was not committed: its author renumbers it against the tail, recomputes its digest, and resubmits it. Nothing is lost and nothing is duplicated, which is the property that makes an unacknowledged append safe to retry.

6.2. Event Boundaries

A log entry is the unit of commitment, and ACP requires that it also be a unit of meaning: an entry closes exactly one complete event of the application that produced it, and an incomplete event is never committed. One turn of conversation, one tool invocation together with its result, one accepted user utterance, one cancellation are each a complete event. Half of a turn is not an event and MUST NOT become an entry.

This rule is what makes the chain usable under streaming. An agent generating a long answer emits it as fragments on a data channel; the fragments carry no ACP header, no Sequence, and no digest (Section 3.2). Nothing is hashed while they flow. When generation ends, the author gathers the completed event into one body and appends one entry, so the cost of the chain is one digest per event rather than one per fragment. A connection that dies in the middle of generation therefore loses fragments that were never part of any entry: the chain is untouched, both tails still point at the last committed entry, and alignment has nothing to reconcile (Section 6.6). The alternative, digesting fragments as they arrive, would put a hash computation in the per-token path and would leave a truncated fragment committed in a chain that both peers then have to agree to forget.

Two interruption cases look alike on the wire and are worth separating. If the connection dies while the author is still gathering the event, no APPEND was sent, no entry exists on either side, and the fragments are simply dropped. If it dies after the author sent the APPEND but before the response arrived, the entry is pending (Section 6.1.1): the peer may or may not have committed it, and alignment settles which by comparing digests. In neither case is a partial event committed, and in neither case does a participant have to guess how many octets of an unfinished stream the other one received.

An author MAY record which boundary an entry closes by including Event-Cursor, whose value is a token [RFC9110] meaningful to the application, such as turn-complete or tool-result-3. ACP neither defines the token space, nor requires the field, nor interprets it. Its use is local and diagnostic: it tells an application which step of its own execution a given Sequence corresponds to, which is what it needs to re-run the right step after a rollback (Section 6.6.2) or to continue at the right point after an interruption.

Event-Cursor is deliberately not part of the digest input (Section 6.3). Alignment compares digests and sequence numbers; it never compares cursors. Two replicas holding identical bytes hold the same log whatever their cursors say, and a cursor inside the digest would let an application-level label cause a 422 on an otherwise valid entry. A CANCEL MAY carry the cursor of the boundary at which the sender wants work to stop; that is a hint about where to cut, not a position in the log, and the normative target of a cancellation remains Target-Seq (Section 5.4.3).

6.3. The Entry Digest

Each entry carries Entry-Hash, the digest of a fixed octet string built from six field values and the body. The construction is the whole basis of alignment, so it is stated once and precisely.

digest-input = ADID-value        LF
               Prev-Hash-value   LF
               Sequence-value    LF
               Entry-Type-value  LF
               Author-value      LF
               Timestamp-value   LF
               body-octets

Entry-Hash   = "sha256-" base64url( SHA-256( digest-input ) )
Figure 15: The digest input

Each -value is the corresponding header field value exactly as it appears in the message, after stripping leading and trailing OWS, and without the field name or the colon. body-octets is the body, exactly Content-Length octets, or the octets between the blank line and the end of the stream where Content-Length is omitted as Section 5.1 allows. An empty body contributes zero octets. The separator is LF (0x0A), not CRLF: the digest input is deliberately not a substring of any message, so that no part of a wire encoding can be mistaken for it. SHA-256 is as specified in [RFC6234] and base64url in [RFC4648], Section 5, without padding.

For the entry at Sequence 1 there is no predecessor. Its Prev-Hash is the constant GENESIS, defined as sha256- followed by 43 A characters, which is the base64url encoding of 32 zero octets. GENESIS is a constant and not a digest of anything; it MUST NOT be interpreted as an entry. A log with no entries is described in the position fields as Tail-Seq: 0 with Tail-Hash equal to GENESIS, which keeps the invariant that the entry at Sequence n carries the digest of n - 1 in its Prev-Hash true for n = 1 without a special case.

Why these six fields and not the whole message. A digest over the complete header block would depend on field order, on OWS, and on fields that legitimately differ between the original transmission of an entry and its replay, so two participants could hold the same entry and compute different digests. That is the failure this construction exists to avoid. Why these six and not the body alone. A digest over the body would leave the entry's position, its predecessor, its type, and its author uncommitted, so an entry could be relabelled, reordered, or moved to another dialog without changing its digest. Binding the ADID in particular is what stops an entry from one dialog being replayed into another at the same position. The six fields are exactly those whose meaning a verifier must be able to trust.

Fields not in the digest input are protected only by the channel. That is acceptable for CSeq, which is per transaction and differs when an entry is resubmitted, for Event-Cursor, which labels the boundary an entry closes rather than anything the entry asserts (Section 6.2), and for Content-Length, which the recipient can check against what it received. It is also acceptable for the message-level Content-Type, because a body that needs typed parts carries them as MIME parts [RFC2046] whose own Content-Type headers are inside the body and therefore covered. An implementation that needs the message-level media type to be committed SHOULD repeat it as the first body part header.

A recipient of an APPEND MUST recompute the digest and compare it with the received Entry-Hash before committing the entry. On mismatch it MUST NOT commit, MUST respond 422, and SHOULD treat the dialog as requiring alignment, since a mismatch means the two participants disagree about the octet string and not merely about a checksum.

The digest of an entry depends only on octets its author already held, so it can be computed once and verified anywhere, including by a participant that never saw the original transmission. It is not a signature. A digest proves that two replicas hold the same bytes; it does not prove who produced them, and a participant that can write to the authoritative log can rewrite history and produce consistent digests. Per-entry signatures are deferred to a later revision.

6.4. Media and Large Assets

A dialog that ran for hours of voice and video would have an unusable log if every entry digested its media. ACP therefore keeps media out of the chain, in two ways according to whether the media is stored or live.

Stored media is carried by reference. A MIME part MAY omit its content and carry instead an Asset-Ref parameter giving the hash-value of the asset's octets and an Asset-Size giving their length:

--acp-9b1deb4d
Content-Type: video/mp4
Asset-Ref: sha256-GIgdzwklKPw4gUd4U32RfGAuSrr5MEpdNK5NP3bMj78
Asset-Size: 104857600
Content-Location: https://agent.example.com/acp-asset/9b1deb4d/a3
Figure 16: A body part that references an asset

The reference is text inside the body, so the digest commits to it, and the asset's octets are transferred separately on an asset channel (Section 7) and never enter the digest input. A recipient that retrieves the asset MUST verify it against Asset-Ref. A consequence worth stating plainly: a log can be fully aligned and every digest verified while an asset is still missing, and an asset can be lost without invalidating the chain. That is intended. The chain records what the dialog said about its media, which is the part that has to survive days of separation; the media itself has its own storage and its own lifetime.

Live media is not an asset and is not referenced either. It flows on its own channels while the dialog is active, and the event that opens or closes a media session is recorded as a meta entry describing it (Section 6.2), for example:

Session-Type: realtime-voice
Media-Status: active
Active-Tracks: audio-01 (opus/48000/2)
Transport-Mapping: wt-session 0xef4a
Figure 17: A meta entry body

Such an entry is a few hundred octets, costs one digest, and is enough to re-establish the media path after an interruption. ACP does not define the fields of a meta body, does not transcribe speech, and does not summarize a conversation: those are application concerns, and an application that wants a transcript in the log appends an entry containing one. Keeping them out is what lets the signaling path stay short enough not to interfere with the media it is setting up.

6.5. Checkpoints and Truncation

A dialog may run for months. Its log must not grow without bound, so ACP allows a prefix of it to be committed to a single entry and then discarded. A checkpoint is itself an entry, of Entry-Type system, appended at the next Sequence like any other. Making it an entry rather than a side structure is deliberate: it keeps the chain continuous across truncation, it means a checkpoint has an Entry-Hash of exactly the same kind as any other entry, and it means a participant that has lost everything below a checkpoint can still resume by naming that one entry (Section 6.6.3).

The body of a checkpoint entry is four lines:

body         = "acp-checkpoint/1" CRLF Lower CRLF Upper CRLF
               accumulator CRLF

Lower        = seq          ; first Sequence covered, inclusive
Upper        = seq          ; last Sequence covered, inclusive
accumulator  = "sha256-" base64url( SHA-256( cp-input ) )

cp-input     = for i = Lower to Upper, in increasing order:
                 Entry-Hash-value(i) LF
Figure 18: Checkpoint entry body and accumulator

The body is ordinary message content, so its line endings are CRLF like the rest of a message. cp-input is not a wire format: it is the octet string the accumulator is computed over, and its separator is LF, as in Section 6.3.

where Entry-Hash-value(i) is the complete textual hash-value of the entry at Sequence i, and Lower is the proposer's current Min-Seq, which is 1 for a dialog that has never been checkpointed. Checkpoints therefore compose: a checkpoint whose Lower is an earlier checkpoint's Sequence is well defined, and a participant that has already truncated can still take part in a later one.

A CHECKPOINT transaction proposes Lower and Upper. The recipient recomputes accumulator from the entries it holds. If it matches, the ordering authority appends the checkpoint entry and responds 200 with CP-Seq set to that entry's Sequence and CP-Hash to its Entry-Hash. Both participants record the entry durably, and only then MAY either discard entries with Sequence below CP-Seq; Min-Seq becomes CP-Seq. If the recipient cannot recompute accumulator, because the digests disagree or because it has already discarded part of the range without holding a checkpoint that covers it, it MUST NOT discard anything and MUST respond 409, or 412 where Section 6.6.3 applies. Discarding before the peer has confirmed is not recoverable and MUST NOT be done.

Sequence numbers are never reset by a checkpoint, and the checkpoint entry is retained: the entry above it carries its Entry-Hash as Prev-Hash, so the chain above a checkpoint links to the chain below it through a single digest. A dialog checkpointed a hundred times still has one continuous numbering. A participant holding only the latest checkpoint and the entries above it can still verify every entry it holds, and a forged prefix would require inverting the checkpoint entry's digest.

6.6. Log Alignment

Alignment is what makes a dialog survive its transport. A participant that reconnects after an hour or after a week runs the same procedure, and the cost depends on how much it missed rather than on how long it was away. The procedure has three outcomes, decided by one exchange: the replicas agree, the client is behind, or they diverged. A fourth case, where the client is behind by more than the server retains, is handled by Section 6.6.3.

6.6.1. Tail Verification

The client sends RESUME with Tail-Seq and Tail-Hash giving its last committed entry, and with Min-Seq. It MUST NOT report a pending entry as its tail (Section 6.1.1). The server then applies the first rule that matches:

Table 8: RESUME outcomes
# Condition Response
1 ADID unknown, terminated, or TTL expired 404
2 Sender not authenticated or not authorized for this dialog 401 or 403
3 Client Tail-Seq is below server Min-Seq 412 with Action: resync
4 Server holds no entry at the client's Tail-Seq, or holds one with a different digest 409 with Action: probe
5 Tails equal 200
6 Server tail ahead of client tail 206 with Action: replay and Replay-From

The order matters. Rule 3 precedes rule 4 because a client below Min-Seq cannot be probed: the entries needed to find a common ancestor are gone. Rules 5 and 6 are reached only when the digests match, which is the point of comparing digests rather than lengths.

Every response to RESUME carries the server's Tail-Seq, Tail-Hash, and Min-Seq, and CP-Seq and CP-Hash where a checkpoint exists, so the client learns the authoritative position and any truncation in the same exchange.

On 206 the server replays entries from Replay-From, which is the client's Tail-Seq plus one, up to and including its own tail, in increasing Sequence order, on the log plane. The recipient verifies each entry's digest and that its Prev-Hash equals the Entry-Hash of the entry below it, and commits each as it arrives; replay is driven by the transport's ordering, not by per-entry acknowledgement. Alignment is complete when the entry at the Tail-Seq announced in the 206 is committed, so no further message is needed, the target having been announced in advance. If T2 expires first, the attempt fails and MAY be retried with a new RESUME.

On 200 or on completion of a replay, both participants are ACTIVE. The client then settles any pending entries as Section 6.1.1 describes, renumbering and resubmitting those the server did not commit.

6.6.2. Fork Detection and Resolution

A 409 means the two replicas held the same dialog and now disagree about it. The cause is usually benign: an APPEND whose acknowledgement was lost, a server that recovered from a crash behind its last flush, or a client that committed an entry it should have left pending. Resolution is to find the last position at which the two agree and rebuild above it.

The client sends PROBE carrying a ladder of Proof fields: one for each of the positions Tail-Seq - 1, Tail-Seq - 2, Tail-Seq - 4, and so on by powers of two down to its Min-Seq, one for Min-Seq itself, and at most 16 in total. The server responds 200 with Proof fields for exactly those positions whose digest it also holds, together with its own Tail-Seq, Tail-Hash, and Min-Seq. It MUST NOT assert a pair it does not hold, and it need not explain the absence of one.

The highest matching position is the common ancestor. The client moves every entry it holds above it back to pending, accepts a replay from the position above it, and then renumbers and resubmits its pending entries against the tail it has been given. Because a renumbered entry has a different Sequence and a different Prev-Hash, it has a different digest: the two versions of the same input are distinct entries, and only the one the ordering authority committed is in the log. No content is lost, and the chain above the ancestor is the server's alone.

A 16-pair ladder reaches 215 entries below the tail, so one PROBE settles almost every divergence. Where it does not, the client continues from the ancestor it found with a further PROBE. If no pair matches, the divergence is below everything the ladder reaches and the server responds 412 instead; Section 6.6.3 applies. A server MUST rate-limit PROBE per dialog, since each one is a read against durable storage and none of them makes forward progress.

6.6.3. Resynchronization Below a Checkpoint

A participant that has been away long enough to fall below the other's Min-Seq cannot be aligned entry by entry, because the entries are gone. A 412 carries Action: resync together with Min-Seq, CP-Seq, CP-Hash, Tail-Seq, and Tail-Hash. Because a checkpoint is an ordinary entry (Section 6.5), CP-Hash is the Entry-Hash of the entry at CP-Seq and can be adopted as a tail directly, with no second kind of digest value anywhere in the protocol.

The recipient first checks whether it holds the entry at CP-Seq. If it does and the digest matches, its own history is a prefix of the authoritative one and it simply discards what is below and continues. If it does not hold that entry, or the digest differs, its history below CP-Seq is unreconcilable: it MUST stop treating those entries as part of the dialog, SHOULD retain them in local storage if its own policy permits, since they may be the only record it has of what it was told, and then adopts the checkpoint as its base by setting Min-Seq and Tail-Seq to CP-Seq and Tail-Hash to CP-Hash. A second RESUME then proceeds normally and is answered 200 or 206.

A participant that adopts a checkpoint it could not verify is trusting the ordering authority. That is not a new trust: it already relies on that authority for every entry it was given. What the checkpoint changes is that the reliance can no longer be checked against the discarded prefix. A signed checkpoint would remove the reliance and is deferred to a later revision.

7. Transport Bindings

7.1. Binding Requirements

ACP is transport-independent, and a binding is the mapping of its channels onto one transport. A binding MUST provide:

  • a reliable, ordered, bidirectional channel for the control plane, on which many messages may follow one another;

  • a reliable, ordered channel for the log plane that does not share a head-of-line queue with the control plane, so that a large entry cannot delay a CANCEL;

  • a way to carry asset octets without blocking either of the above; and

  • a signal when the connection is lost, so that a participant can move to SUSPENDED (Section 4).

A binding SHOULD also provide an unreliable low-latency channel for progress traffic, and SHOULD support connection migration, which lets a dialog stay ACTIVE across a change of network path. A binding that provides neither is still conformant; progress is then carried on the log channel and simply not logged, and migration is then no better than a suspend and resume.

Every stream a binding opens for ACP begins with a preamble that says what the stream carries:

channel-preamble = "ACP/1.0" SP channel-name CRLF
channel-name     = "control" / "log" / "asset" / token
Figure 19: Stream preamble

A recipient MUST read the preamble before treating a stream as ACP and MUST reset a stream whose preamble it does not recognize. The preamble is what identifies a channel, and no binding may identify one by a stream number instead: transports assign stream identifiers, and an application cannot choose one. Messages on the control channel are delimited by Content-Length, which is REQUIRED there. On a log channel exactly one entry message is sent per stream and the end of the stream delimits it, so Content-Length MAY be omitted; the octets that follow the preamble are the entry exactly as its author digested it, and a recipient MUST NOT re-encode them before verifying the digest.

7.2. MoQ Binding

This binding carries the log plane on Media over QUIC Transport (MoQ) [I-D.ietf-moq-transport]. It is the binding to use where a dialog should be relayable and cacheable by infrastructure that understands MoQ, and where recovery of missed entries should be a subscription rather than an application-level replay.

A dialog occupies one track namespace:

{ authority, "acp", adid }
Figure 20: The track namespace of a dialog

where authority is the domain of the agent service that publishes the dialog and adid is the ADID, which uses only URI-unreserved characters and so needs no further encoding. The literal "acp" keeps these namespaces distinct from other uses of the same authority. Because the ADID is in the namespace, a relay forwards, caches, and correlates every track of a dialog without decrypting or interpreting a payload, and a peer that sees the same namespace on a new session can correlate it with the dialog it already knows.

Table 9: ACP mapped onto MoQ
ACP MoQ
Dialog Track namespace {authority, "acp", adid}
Authoritative log The track named log, published by the ordering authority
One committed entry One object on log, with Group equal to Sequence and Object 0
Control plane A bidirectional stream in the same session, carrying the control preamble
One asset or media track A track of its own in the namespace, named by the application
Replay after resumption SUBSCRIBE to log starting at Group Tail-Seq + 1

Two points in this mapping need stating, because both are places where an obvious alternative does not work.

A committed entry is carried as a single object rather than split across one object per MIME part. Splitting would require a recipient to reassemble parts before it could verify the digest, and any reassembly that is not byte-exact turns a verified entry into an unverified one. One object per entry means the object payload is the octet string the author digested, and verification is a single pass over what arrived. Bulk content is separated by the asset reference of Section 6.4, not by the object structure.

The control plane does not ride MoQ control messages. MoQ data tracks flow from publisher to subscribers, and putting ACP requests inside MoQ control messages would require an extension to MoQ that this document cannot define. Using a bidirectional stream in the same session needs no extension, keeps the preamble framing of Section 7.1, and lets both participants send requests. Whether a native MoQ control-message binding is worth defining is left open.

Only the ordering authority publishes log, and it publishes every committed entry including those a client authored. A single authoritative track is what makes recovery a subscription: the client subscribes from the group above its tail and receives exactly the entries it is missing, in order, from whatever cache can serve them. Relay caching is an optimization and not a store. The ordering authority MUST be able to serve the whole retained range itself, and a subscriber MUST NOT treat an object as committed until its digest verifies.

7.3. WebTransport Binding

This binding runs ACP over WebTransport [I-D.ietf-webtrans-http3], and therefore over HTTP/3 [RFC9114] and QUIC [RFC9000]. It is the binding to use where one endpoint is a browser or another environment that offers WebTransport but not a general QUIC stack.

The request target of Section 5.4.1 is already an https origin and path, so the client opens a WebTransport session to it directly with an extended CONNECT. The session is the dialog's transport for as long as it lives, and it may carry more than one dialog, since every stream is identified by its preamble and every message by its ADID.

Table 10: ACP mapped onto WebTransport
ACP WebTransport
Control plane The first bidirectional stream the client opens in the session, carrying the control preamble
One log entry One unidirectional stream opened by the entry's author, carrying the log preamble, closed when the entry is complete
One asset One unidirectional stream carrying the asset preamble, at lower priority than log
Progress traffic QUIC datagrams [RFC9297]
Connection loss Session closure or abort
Change of network path QUIC connection migration; the dialog stays ACTIVE

Because a log entry occupies its own stream, an entry carrying a large body cannot delay the control plane or another entry, and several entries and assets may be in flight at once. A sender SHOULD set stream priority so that control outranks log and log outranks asset.

Progress datagrams are limited in size by the path MTU and are neither delivered nor ordered. A binding MUST NOT put anything on them that the log or the state machine depends on, and a recipient MUST tolerate losing any of them. Where datagrams are unavailable, progress traffic MAY be sent on the control channel, in which case it MUST still be excluded from the log.

8. Security Considerations

ACP defines no key exchange, no authentication mechanism, and no confidentiality mechanism of its own. It is a session protocol that assumes it is given a channel with three properties: the peer is authenticated, the channel is confidential and integrity-protected, and messages are not delivered to anyone else. Every binding in Section 7 provides these through QUIC [RFC9000], which mandates TLS 1.3. ACP MUST NOT be used over a transport that does not provide them, and an implementation MUST NOT fall back to such a transport.

Who a participant is, and what it may do, are decided above and below ACP. Below it, the channel tells each endpoint who the peer is; a deployment identifying agents by workload uses a workload identity [I-D.ietf-wimse-workload-creds]. Above it, the ordering authority decides whether an authenticated peer may append to a given dialog. ACP assumes both decisions have been made correctly and does not re-make them.

8.1. Dialog Identifiers

An ADID is 128 bits drawn from a random source [RFC4086], so it cannot be guessed at any useful rate. That property is doing real work: several places in this document answer a request about a dialog the sender is not a participant of, and rely on the sender not having found the dialog by searching. An implementation MUST NOT generate ADIDs from a counter, a timestamp, or any other low-entropy source, and MUST NOT reuse one.

Knowledge of an ADID is nonetheless not authority to use it. A server MUST authorize every request against the dialog's participants independently of whether the request names the dialog correctly, and MUST NOT treat a correct ADID as proof that the sender belongs to the dialog. Because an ADID is a bearer string that appears in every message, it will end up in logs, proxies, and error reports; a deployment SHOULD treat a leaked ADID as a reason to terminate and re-initiate rather than as a harmless disclosure.

Section 5.4.5 has a server answer 403 to a sender it recognizes and 404 to one it does not, which reveals that the dialog exists. That is deliberate: a client recovering on a new device needs to know whether to resume or to start over. A server concerned about the disclosure MAY answer 404 to every sender it has not authorized, at the cost of making recovery from a lost credential indistinguishable from a lost dialog.

8.2. Authorizing Session Establishment

Establishing a dialog requires the client to obtain authorization, and ACP does that with existing OAuth mechanisms rather than defining one of its own. The token it obtains is carried in the Authorization field of Section 5.2.

Within a trust domain the client presents a Transaction Token [I-D.ietf-oauth-transaction-tokens], obtained from the workload identity it already holds. A Transaction Token carries the delegation context of one transaction, not the standing authority of a workload, which is what lets the ordering authority authorize a dialog against the principal the client acts for and not only against the workload that asked. Its narrow scope and short lifetime are also what make it safe to carry in a header field that will end up in logs.

Across trust domains there is no issuer both sides accept, so the client instead trades the credential it holds for one the remote domain accepts using OAuth 2.0 Token Exchange [RFC8693], naming the remote service as the audience.

Because the token in Authorization is not the credential the channel authenticated, the two must be tied together: the workload identity the channel authenticated, the From of the request, and the identity the token authorizes MUST all name the same participant (Section 3.5). A server that cannot establish that, or that cannot validate the token, answers 403. A token is minted per request, not per dialog: a transaction token is short-lived, and a RESUME days after its INITIATE is a new transaction carrying a new token.

9. IANA Considerations

This document requests that IANA create registries for the protocol's namespaces. The registries are listed here so that the namespace they govern is reserved; their registration procedures and initial contents will be specified in a later revision of this document.

9.1. ACP Registries

IANA is requested to create an "Agent Communication Protocol (ACP) Parameters" registry group containing the registries in Table 11.

Table 11: Requested ACP registries
Registry Governs Section
ACP Methods Request method tokens Section 5.4
ACP Status Codes Numeric response codes Section 5.5
ACP Header Fields Header field names Section 5.2
ACP Entry Types Entry-Type values Section 6
ACP Hash Algorithms hash-alg prefixes Section 6.3
ACP Channel Names Stream preamble channel names Section 7.1

10. References

10.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>.
[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>.
[RFC2046]
Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046, , <https://www.rfc-editor.org/info/rfc2046>.
[RFC3986]
Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/info/rfc3986>.
[RFC4086]
Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, , <https://www.rfc-editor.org/info/rfc4086>.
[RFC4648]
Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, , <https://www.rfc-editor.org/info/rfc4648>.
[RFC5234]
Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, , <https://www.rfc-editor.org/info/rfc5234>.
[RFC6234]
Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)", RFC 6234, DOI 10.17487/RFC6234, , <https://www.rfc-editor.org/info/rfc6234>.
[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>.
[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>.
[RFC9000]
Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, , <https://www.rfc-editor.org/info/rfc9000>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/info/rfc9110>.
[RFC9114]
Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114, , <https://www.rfc-editor.org/info/rfc9114>.
[RFC9297]
Schinazi, D. and L. Pardue, "HTTP Datagrams and the Capsule Protocol", RFC 9297, DOI 10.17487/RFC9297, , <https://www.rfc-editor.org/info/rfc9297>.
[RFC9562]
Davis, K., Peabody, B., and P. Leach, "Universally Unique IDentifiers (UUIDs)", RFC 9562, DOI 10.17487/RFC9562, , <https://www.rfc-editor.org/info/rfc9562>.
[I-D.ietf-webtrans-http3]
Frindell, A., Kinnear, E., and V. Vasiliev, "WebTransport over HTTP/3", Work in Progress, Internet-Draft, draft-ietf-webtrans-http3-16, , <https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3-16>.
[I-D.ietf-moq-transport]
Nandakumar, S., Vasiliev, V., Swett, I., and A. Frindell, "Media over QUIC Transport", Work in Progress, Internet-Draft, draft-ietf-moq-transport-22, , <https://datatracker.ietf.org/doc/html/draft-ietf-moq-transport-22>.
[I-D.ietf-wimse-workload-creds]
Campbell, B., Salowey, J. A., Schwenkschuster, A., Sheffer, Y., and Y. Rosomakho, "WIMSE Workload Credentials", Work in Progress, Internet-Draft, draft-ietf-wimse-workload-creds-02, , <https://datatracker.ietf.org/doc/html/draft-ietf-wimse-workload-creds-02>.
[I-D.ietf-oauth-transaction-tokens]
Tulshibagwale, A., Fletcher, G., and P. Kasselman, "Transaction Tokens", Work in Progress, Internet-Draft, draft-ietf-oauth-transaction-tokens-11, , <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-transaction-tokens-11>.
[SPIFFE]
CNCF SPIFFE Project, "Secure Production Identity Framework for Everyone (SPIFFE)", , <https://spiffe.io/>. Defines the workload identity form permitted for a participant identifier (Section 3.4).

10.2. Informative References

[RFC3261]
Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP: Session Initiation Protocol", RFC 3261, DOI 10.17487/RFC3261, , <https://www.rfc-editor.org/info/rfc3261>.
[I-D.manyfolks-agentproto-arch]
Rosenberg, J., Sarker, Z., Reddy.K, T., Yao, K., Liu, D., and S. Krishnan, "Architecture for AI Agent Communications on the Internet", Work in Progress, Internet-Draft, draft-manyfolks-agentproto-arch-00, , <https://datatracker.ietf.org/doc/html/draft-manyfolks-agentproto-arch-00>.

Acknowledgements

TBD.

Author's Address

Dapeng Liu
Alibaba