Title: Agent Context Compression Protocol (ACCP)
Version: 1.0
Status: Proposed Standard
Authors: Russell Benzing
Date: April 2026
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.
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:
- Message encoding format (Section 3)
- Intent and operation codes (Section 4)
- Context state management (Section 5)
- Schema registry interface (Section 6)
- Codec API (Section 7)
ACCP does NOT define:
- Transport mechanisms (defer to MCP/A2A/HTTP)
- Agent discovery or routing (defer to A2A/ANP)
- LLM API specifics
- Authentication or authorization (defer to transport layer)
| 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 |
Keywords: MUST, MUST NOT, SHOULD, SHOULD NOT, MAY follow RFC 2119 semantics.
Agent A Agent B
│ │
├── compose message (NL/struct) │
│ │ │
│ ┌────▼─────┐ │
│ │ ACCP │ │
│ │ Encoder │ │
│ └────┬─────┘ │
│ │ (ACCP Frame) │
│ ┌────▼─────┐ ┌─────┴─────┐
│ │Transport │ ───────► │ Transport │
│ │(MCP/A2A) │ │ (MCP/A2A) │
│ └──────────┘ └─────┬─────┘
│ │
│ ┌─────▼─────┐
│ │ ACCP │
│ │ Decoder │
│ └─────┬─────┘
│ │
│ inject into LLM context
- Sending agent composes a message (natural language or structured)
- ACCP Encoder compresses it into a Frame
- Frame is transmitted via the existing transport layer
- ACCP Decoder at receiving end reconstructs the semantic content
- Decoded content is injected into the receiving agent's LLM context
An ACCP Frame is a single-line UTF-8 string defined by the following ABNF grammar (RFC 5234):
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:
- No whitespace — Frames MUST NOT contain spaces, tabs, or newlines.
- Abbreviated keys — Use shortest unambiguous key names (see Section 4.2).
- Symbolic values — Prefer symbols over words:
+,-,%,>,<. - Reference over inline — If a value exceeds 50 characters, store in state and reference via
$key. - Omit defaults — Do not encode values that match the schema default.
- Coalesce arrays — Use comma separation within brackets, no spaces.
| 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:
- Idempotency: Decoders MUST maintain a set of seen
msg_idvalues per session. Frames with a previously seenmsg_idMUST be rejected with errorE3002 DUPLICATE. - Ordering: Frames MUST be processed in ascending
seqorder. A gap in sequence numbers MUST trigger errorE3003 SEQUENCE_GAP. - Retries: Frames with retryable error codes MAY be retransmitted with the same
correlation_idand a newmsg_idandseq. - Cancellation: A
cancelintent frame referencing acorrelation_idMUST stop all processing for that request chain. - TTL enforcement: Frames received after their TTL has elapsed MUST be rejected silently (no error response, to prevent timing attacks).
| 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:
Tier 1: HOT STATE (in-context)
- Current frame + immediate parent frames
- Active task parameters
- Max budget: 500 tokens
Tier 2: WARM STATE (compressed summaries)
- Checkpoint summaries from completed phases
- Key-fact extractions
- Referenced via $warm.key
- Max budget: 200 tokens per checkpoint
Tier 3: COLD STATE (external store)
- Full conversation history
- Raw tool outputs
- Referenced via $cold.key
- Zero token budget (not injected into context)
A checkpoint MUST be triggered when ANY of the following conditions are met:
- An agent completes a task (
doneintent) - Accumulated hot state exceeds 400 tokens
- A handoff between agents occurs (
escintent) - The harness signals a phase boundary
- An agent explicitly requests compression (
compintent)
1. Freeze current hot state
2. Extract key facts (entity, value, relationship triples)
3. Generate compressed summary (≤ 100 tokens)
4. Move summary to warm state with checkpoint ID
5. Move raw data to cold state
6. Reset hot state with checkpoint reference
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.
public interface IAccpCodec
{
/// Encode a structured message into an ACCP Frame
AccpFrame Encode(AgentMessage message, AccpSession session);
/// Decode an ACCP Frame back into a structured message
AgentMessage Decode(AccpFrame frame, AccpSession session);
/// Trigger a compression checkpoint
CheckpointResult Checkpoint(AccpSession session);
/// Get current token budget usage
TokenBudget GetBudget(AccpSession session);
/// Register a custom schema
void RegisterSchema(string name, AccpSchema schema);
}
public record AccpFrame(
string AgentId,
AccpIntent Intent,
string Operation,
Dictionary<string, object> Payload,
Dictionary<string, string>? Metadata = null
);
public record AccpSession(
string SessionId,
StateStore HotState,
StateStore WarmState,
IExternalStore ColdState,
SchemaRegistry Registry,
int CurrentCheckpointVersion
);
public record TokenBudget(
int HotUsed,
int HotMax,
int WarmUsed,
int WarmMax,
int TotalUsed,
int TotalMax
);Input (AgentMessage)
│
├─1─ Schema resolution (expand or compact via registry)
├─2─ Key abbreviation (full keys → abbreviated keys)
├─3─ Value compression (inline values → references if large)
├─4─ Default omission (remove fields matching schema defaults)
├─5─ Token estimation (count via BPE tokenizer)
├─6─ Budget check (within frame limits?)
│ ├─ YES → emit single frame
│ └─ NO → split into frame sequence or externalize to state
└─7─ Emit ACCP Frame string
Input (ACCP Frame string)
│
├─1─ Parse grammar (header, body, metadata)
├─2─ Resolve references ($warm.key, $cold.key, schema codes)
├─3─ Expand abbreviations (abbreviated keys → full keys)
├─4─ Apply schema defaults (fill omitted fields)
├─5─ Reconstruct AgentMessage
└─6─ Return structured message for LLM context injection
An implementation MUST support:
- Frame encoding/decoding (Section 3)
- Core intents (Section 4.1)
- Basic key abbreviations (Section 4.2)
An implementation MUST additionally support:
- Context state management (Section 5)
- Compression checkpoints (Section 5.2)
- Schema registry (Section 6)
An implementation MUST additionally support:
- Delta encoding (Section 5.4)
- Registry negotiation (Section 6.4)
- Token budget enforcement (Section 7.1)
- Streaming frames (Section 4.1,
stream/endintents)
- Opacity risk: Compact formats are harder for humans to audit. Implementations SHOULD provide a "debug mode" that logs decoded human-readable equivalents.
- Injection: Frame parsing MUST validate grammar strictly. Malformed frames MUST be rejected, not partially parsed.
- State store access: Cold state references MUST be scoped to the current session. Cross-session state access requires explicit authorization.
- Registry tampering: Schema registries SHOULD be integrity-checked via hash (Section 6.4).
- Parser DoS Protection: Decoders MUST implement strict limits on array nesting depth (recommended maximum: 5 levels) and limit payload parsing complexity to prevent resource exhaustion attacks.
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
Typical frame sequence:
@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
Typical frame sequence:
@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:
transaction_idMUST be stable across retries (idempotency key).amountMUST be serialized as decimal (not string) to avoid precision loss.currencySHOULD follow ISO 4217.- Retries MUST use the same
transaction_idwith a newmsg_id.
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.
- Method:
POST /accp/v1/frames - Content-Type:
application/accp - Body: One ACCP frame string per request (UTF-8)
- Response:
200 OKwith response ACCP frame, or400with ER-schema error frame body - Streaming: use
Transfer-Encoding: chunkedwith one ST-schema frame per chunk
- Frame type:
text - One ACCP frame string per WebSocket message
- Session established by the first
sync:registryframe from the initiator - Heartbeat:
ping/pongintent frames every 30 seconds
- ACCP frames are carried as MCP
resourcecontent with MIME typeapplication/accp - Tool calls use the TC profile; results are returned as MCP tool responses containing the TC-schema
done:toolframe - Registry sync occurs at MCP session initialization via a
sync:registryframe in the system prompt
- ACCP frames are embedded as A2A message
partswith content typeapplication/accp - A2A task creation maps to ACCP
reqintent; task completion maps todone - A2A streaming artifact parts map 1:1 to ST-schema stream frames
- ACCP-over-A2A: Formal binding of ACCP frames as A2A message parts.
- ACCP-over-MCP: Integration as an MCP resource type for tool-output compression.
- Model-specific tokenizer profiles: Optimize encoding per model's BPE vocabulary.
- Adaptive compression: ML-based encoder that learns optimal compression per domain.
| 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.
- Anthropic, "Model Context Protocol," 2024
- Google, "Agent2Agent (A2A) Protocol Specification," 2025
- IBM, "Agent Communication Protocol (ACP)," 2025
- TOON, "Token-Oriented Object Notation," 2025
- Claw Compactor, "6-layer deterministic context compression," 2026
- Janea Systems, "JSPLIT: Taxonomy-driven MCP selection," 2025
End of Specification