| Internet-Draft | ACCP | April 2026 |
| Benzing | Expires 9 October 2026 | [Page] |
This document specifies the Agent Context Compression Protocol (ACCP), a semantic encoding and context management protocol for communication between AI agents within agentic harnesses. ACCP defines a compact message format, intent ontology, state compression strategy, and codec interface that collectively reduce token consumption by 60-90% compared to natural language or standard JSON messaging. ACCP is designed to complement existing protocols (MCP, A2A) and is transport-agnostic.¶
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 3 October 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The operational cost of multi-agent AI systems is dominated by token consumption at the LLM inference layer. Existing agent communication protocols optimize for interoperability, discovery, and routing but transmit messages in verbose formats (natural language, pretty-printed JSON) that are highly wasteful from a token-cost perspective.¶
ACCP addresses this by introducing a protocol layer between the orchestration harness and the LLM API that encodes agent communication into a compact, semantically-faithful format.¶
ACCP defines:¶
ACCP does NOT define:¶
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 capitalized, as shown here.¶
| Term | Definition |
|---|---|
| Agent | An autonomous LLM-backed process within a harness |
| Harness | The orchestration framework managing agents |
| Codec | The ACCP encoder/decoder library |
| Frame | A single ACCP-encoded message unit |
| Session | A bounded sequence of frames comprising one workflow |
| Checkpoint | A state compression boundary |
| Intent | A standardized operation code |
Agent A Agent B | | +-- compose message (NL/struct) | | | | | +----v-----+ | | | ACCP | | | | Encoder | | | +----+-----+ | | | (ACCP Frame) | | +----v-----+ +-----+-----+ | |Transport | -------> | Transport | | |(MCP/A2A) | | (MCP/A2A) | | +----------+ +-----+-----+ | | | +-----v-----+ | | ACCP | | | Decoder | | +-----+-----+ | | | inject into LLM context
An ACCP Frame is a single-line UTF-8 string defined by the following ABNF grammar ([RFC5234]):¶
frame = header body [metadata]
header = "@" agent-id ">" intent
body = ":" operation "{" [payload] "}"
metadata = "[" meta-pairs "]"
payload = param *( "|" param )
param = key ":" value
value = typed-literal / array / map / ref / null
typed-literal = boolean / integer / decimal / string
boolean = "true" / "false"
integer = ["-"] 1*DIGIT
decimal = ["-"] 1*DIGIT "." 1*DIGIT
string = 1*( safe-char / escaped-char )
safe-char = VCHAR except delimiter
escaped-char = "\" delimiter
delimiter = "@" / ">" / ":" / "{" / "}" / "[" / "]"
/ "|" / "$" / "," / "~" / "\"
null = "~"
array = "[" [ value *( "," value ) ] "]"
map = "{" [ key ":" value *( "," key ":" value ) ] "}"
ref = "$" ref-key
meta-pairs = param *( "," param )
agent-id = 1*( ALPHA / DIGIT / "-" / "_" )
intent = 1*( ALPHA )
operation = 1*( ALPHA / DIGIT / "_" )
key = 1*( ALPHA / DIGIT / "_" )
ref-key = 1*( ALPHA / DIGIT / "_" / "." )
¶
| Type | Wire Format | Example |
|---|---|---|
| String | Raw printable ASCII; delimiters escaped with \ | hello, a\:b |
| Integer | Decimal, no leading zeros | 42, -7 |
| Decimal | Canonical 6dp, trailing zeros stripped | 3.14, -0.5 |
| Boolean | true or false | true |
| Null | ~ | ~ |
| Array | [v1,v2,v3] | [1,2,3] |
| Map | {k1:v1,k2:v2} -- keys sorted ascending | {a:1,b:2} |
| Ref | $tier.key | $warm.ckpt_1.status |
Decimal values MUST be serialized with up to 6 decimal places, trailing zeros stripped. Encoders MUST NOT use scientific notation.¶
Task completion with findings:¶
@research>done:analyze{d:q3_sales|f:[rev:-12%QoQ,ent_seg:decline,
churn:+3.2%]|nx:@strategy:plan}
¶
Request with parameters:¶
@planner>req:schedule{who:@dev_team|when:sprint_14|
task:impl_auth_module|pri:high}
¶
Query with context reference:¶
@analyst>qry:lookup{src:$ctx.sales_db|q:revenue_by_region|fmt:summary}
¶
State sync:¶
@orchestrator>sync:state{v:7|delta:{task_3:done,task_4:wip,
budget:$42.30}}
¶
Error with escalation:¶
@data_agent>fail:fetch{src:api.crm|err:timeout_30s|retry:3|
esc:@supervisor}
¶
Encoders MUST follow these rules to minimize token count:¶
| Component | Max Tokens (soft) | Max Tokens (hard) |
|---|---|---|
| Header | 5 | 10 |
| Body | 50 | 200 |
| Metadata | 10 | 30 |
| Total Frame | 65 | 240 |
Frames exceeding the hard limit SHOULD be split into a frame sequence or reference external state.¶
Every ACCP frame MUST include the following envelope fields in its metadata block:¶
| Field | Abbrev | Type | Required | Description |
|---|---|---|---|---|
| msg_id | mid | string(12) | MUST | Unique message identifier (hex, 12 chars) |
| sequence | seq | integer | MUST | Monotonically increasing per session |
| timestamp | ts | integer | MUST | Unix epoch seconds |
| correlation_id | cid | string | SHOULD | Links request to response |
| causation_id | aid | string | MAY | Links to the message that caused this one |
| session_id | sid | string | SHOULD | ACCP session identifier |
| ttl | ttl | integer | MAY | Seconds until frame expires; 0 = no expiry |
Example metadata block:¶
[mid:49679033e07c,seq:3,ts:1714000000,cid:corr123,sid:abc-session]¶
Decoders MUST reject frames with expired TTL. Frames missing "mid" or "seq" MUST be rejected.¶
Standard error frames use intent "fail", operation "error", and schema "ER".¶
Error code taxonomy:¶
| Range | Category |
|---|---|
| E1xxx | Parse / grammar errors |
| E2xxx | State store errors |
| E3xxx | Transport / delivery errors |
| E4xxx | Tool / MCP errors |
| E5xxx | Policy / authorization errors |
| E9xxx | Internal / unknown errors |
Standard error codes:¶
| Code | Name | Retryable |
|---|---|---|
| E1001 | PARSE_ERROR | No |
| E1002 | INVALID_INTENT | No |
| E1003 | UNKNOWN_SCHEMA | No |
| E1004 | INVALID_TYPE | No |
| E2001 | REF_NOT_FOUND | No |
| E2002 | REF_EXPIRED | No |
| E2003 | BUDGET_EXCEEDED | No |
| E3001 | TIMEOUT | Yes |
| E3002 | DUPLICATE | No |
| E3003 | SEQUENCE_GAP | Yes |
| E4001 | TOOL_NOT_FOUND | No |
| E4002 | TOOL_EXEC_FAILED | Yes |
| E4003 | TOOL_SCHEMA_MISMATCH | No |
| E5001 | POLICY_DENIED | No |
| E5002 | UNAUTHORIZED_REF | No |
| E9999 | INTERNAL_ERROR | Yes |
Error frame example:¶
@agent>fail:error{code:E3001|msg:connection_timed_out|retry:true|
schema:ER}[mid:abc,seq:4,ts:1714000001]
¶
Implementations MUST enforce the following delivery guarantees:¶
| Code | Meaning | Description |
|---|---|---|
| req | Request | Request another agent to perform an action |
| done | Complete | Report task completion with results |
| fail | Failure | Report task failure with error details |
| wait | Waiting | Awaiting external input or dependency |
| esc | Escalate | Delegate to a higher-authority agent |
| comp | Compress | Trigger context compression checkpoint |
| sync | Synchronize | Share or request state synchronization |
| qry | Query | Request information lookup |
| ack | Acknowledge | Confirm receipt of a frame |
| cancel | Cancel | Abort an in-progress task |
| stream | Stream | Begin streaming incremental results |
| end | End stream | Close a streaming sequence |
| Abbreviation | Full Meaning |
|---|---|
| d | data / dataset |
| f | findings / fields |
| nx | next action |
| src | source |
| dst | destination |
| q | query |
| fmt | format |
| pri | priority |
| err | error |
| v | version |
| ts | timestamp |
| ttl | time-to-live |
| ctx | context reference |
| who | target agent/entity |
| when | temporal constraint |
| why | rationale code |
Operations are domain-specific verbs registered in the Schema Registry (Section 6). Core operations:¶
analyze, plan, execute, review, approve, reject, fetch, transform, summarize, classify, generate, validate, schedule, notify, merge, split, route, cache, purge¶
Harnesses MAY register custom operations via the registry extension mechanism.¶
ACCP defines a three-tier state model:¶
A checkpoint MUST be triggered when ANY of the following conditions are met:¶
After checkpoint N, subsequent frames SHOULD transmit only deltas:¶
@agent>sync:state{v:N+1|delta:{changed_key:new_val,removed_key:null}}
¶
The decoder reconstructs full state by applying deltas to the last checkpoint.¶
The schema registry allows agents to reference pre-defined data structures by compact codes rather than re-describing them in every message. This eliminates the need to re-inject tool definitions and response schemas into the context window.¶
{
"schemas": {
"sales_report": {
"code": "SR",
"version": 1,
"fields": ["period", "revenue", "growth_pct",
"segments", "notes"],
"defaults": { "period": "quarterly", "segments": [] }
},
"task_assignment": {
"code": "TA",
"version": 2,
"fields": ["assignee", "task", "priority",
"deadline", "deps"],
"defaults": { "priority": "medium", "deps": [] }
}
}
}
¶
@planner>req:execute{schema:TA|assignee:@dev|task:auth_module|
deadline:sprint_14}
¶
The decoder expands "schema:TA" into the full field set, populating defaults for omitted fields.¶
At session start, agents MUST exchange registry versions:¶
@orchestrator>sync:registry{v:3|hash:a7f2c1}
¶
If hashes match, no further exchange is needed. On mismatch, the full registry delta is transmitted once and cached.¶
The codec interface defines the following operations that conforming implementations MUST provide:¶
An implementation MUST support:¶
An implementation MUST additionally support:¶
An implementation MUST additionally support:¶
A Domain Profile is a named combination of schema codes, intent sequences, and operational patterns optimised for a specific use case. Profiles are additive -- a harness may activate multiple profiles simultaneously.¶
Schema: CH -- fields: role, content, turn, lang, reply_to. Defaults: role=assistant, lang=en.¶
@user>req:chat{content:What_are_Q3_findings?|role:user|turn:1|
schema:CH}[mid:...,seq:1]
@assistant>done:chat{content:Revenue_declined_12%.|turn:2|
schema:CH}[mid:...,seq:2,cid:...]
¶
Schema: TC -- fields: tool_name, arguments, result, status, error_code. Defaults: status=ok.¶
@orchestrator>req:tool{tool:web_search|args:{q:ACCP,max:5}|
schema:TC}[mid:m1,seq:1]
@tool_agent>done:tool{tool:web_search|res:{hits:[...]}|stat:ok|
schema:TC}[mid:m2,seq:2,cid:m1]
¶
Tool calls MUST include "correlation_id" in the response to link result to request. Tool errors MUST use schema "ER" with code E4002 TOOL_EXEC_FAILED.¶
Schema: TX -- fields: transaction_id, amount, currency, account, reference, status, retryable. Defaults: currency=USD, status=pending, retryable=false.¶
@payments>req:transaction{txn:txn_001|amt:142.5|acc:acct_9876|
schema:TX}[mid:...,seq:5]
@payments>done:transaction{txn:txn_001|stat:settled|
schema:TX}[mid:...,seq:6,cid:...]
¶
Transaction safety requirements:¶
Schema: ST -- fields: chunk_index, total_chunks, data, is_final. Defaults: is_final=false.¶
@streamer>stream:infer{idx:0|tot:3|d:Hello|
schema:ST}[mid:m1,seq:1,cid:stream_abc]
@streamer>stream:infer{idx:1|tot:3|d:_world|
schema:ST}[mid:m2,seq:2,cid:stream_abc]
@streamer>stream:infer{idx:2|tot:3|d:!|done:true|
schema:ST}[mid:m3,seq:3,cid:stream_abc]
¶
All chunks in a stream MUST share the same "correlation_id". The final chunk MUST set "is_final=true". Consumers MUST buffer and reorder by "chunk_index" before processing.¶
Schema: TA -- fields: assignee, task, priority, deadline, deps. Defaults: priority=medium, deps=[].¶
@planner>req:schedule{asgn:@dev|task:impl_auth|dead:sprint_14|
pri:high|schema:TA}[mid:...,seq:8]
@dev>done:schedule{task:impl_auth|stat:complete|prog:100|
schema:TA}[mid:...,seq:9,cid:...]
¶
ACCP frames are transport-agnostic. The following bindings define how frames are carried over common transports.¶
This document requests IANA registration of the media type "application/accp" for ACCP frame payloads.¶
| Scenario | NL Tokens | JSON Tokens | ACCP Tokens | Reduction |
|---|---|---|---|---|
| Task completion + findings | 85 | 62 | 22 | 74% |
| Task request + params | 45 | 38 | 15 | 67% |
| Error + escalation | 60 | 48 | 18 | 70% |
| State sync (10 fields) | 120 | 95 | 35 | 71% |
| Full 5-agent pipeline | 8,500 | 6,200 | 1,800 | 79% |
Note: Benchmarks are based on empirical validation of Phase 1 implementation.¶
The author acknowledges the contributions of the broader AI agent protocol community, including the developers of [MCP], [A2A], and [ACP], whose work informed the design of ACCP.¶