<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-model href="urn:ietf:params:xml:ns:rfc7991" type="application/xml"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     docName="draft-benzing-accp-00"
     category="std"
     submissionType="IETF"
     consensus="true"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="ACCP">Agent Context Compression Protocol (ACCP)</title>

    <seriesInfo name="Internet-Draft" value="draft-benzing-accp-00"/>

    <author fullname="Russell Benzing" initials="RB" surname="Benzing">

      <address>
        <email>me@russellbenzing.com</email>
      </address>
    </author>

    <date year="2026" month="April"/>

    <area>Applications and Real-Time</area>
    <workgroup>Internet Engineering Task Force</workgroup>

    <keyword>AI agents</keyword>
    <keyword>context compression</keyword>
    <keyword>token optimization</keyword>
    <keyword>agent communication</keyword>

    <abstract>
      <t>
        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.
      </t>
    </abstract>
  </front>

  <middle>
    <!-- Section 1: Introduction -->
    <section anchor="introduction">
      <name>Introduction</name>

      <section anchor="motivation">
        <name>Motivation</name>
        <t>
          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.
        </t>
        <t>
          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.
        </t>
      </section>

      <section anchor="scope">
        <name>Scope</name>
        <t>ACCP defines:</t>
        <ul>
          <li>Message encoding format (<xref target="message-format"/>)</li>
          <li>Intent and operation codes (<xref target="intent-ontology"/>)</li>
          <li>Context state management (<xref target="state-management"/>)</li>
          <li>Schema registry interface (<xref target="schema-registry"/>)</li>
          <li>Codec API (<xref target="codec-api"/>)</li>
        </ul>
        <t>ACCP does NOT define:</t>
        <ul>
          <li>Transport mechanisms (defer to <xref target="MCP"/>/<xref target="A2A"/>/HTTP)</li>
          <li>Agent discovery or routing (defer to <xref target="A2A"/>/ANP)</li>
          <li>LLM API specifics</li>
          <li>Authentication or authorization (defer to transport layer)</li>
        </ul>
      </section>

      <section anchor="terminology">
        <name>Terminology</name>
        <t>
          The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
          "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
          "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
          "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
          "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
          "<bcp14>OPTIONAL</bcp14>" in this document are to be
          interpreted as described in BCP 14
          <xref target="RFC2119"/> <xref target="RFC8174"/>
          when, and only when, they appear in capitalized, as shown here.
        </t>
        <table>
          <thead>
            <tr><th>Term</th><th>Definition</th></tr>
          </thead>
          <tbody>
            <tr><td>Agent</td><td>An autonomous LLM-backed process within a harness</td></tr>
            <tr><td>Harness</td><td>The orchestration framework managing agents</td></tr>
            <tr><td>Codec</td><td>The ACCP encoder/decoder library</td></tr>
            <tr><td>Frame</td><td>A single ACCP-encoded message unit</td></tr>
            <tr><td>Session</td><td>A bounded sequence of frames comprising one workflow</td></tr>
            <tr><td>Checkpoint</td><td>A state compression boundary</td></tr>
            <tr><td>Intent</td><td>A standardized operation code</td></tr>
          </tbody>
        </table>
      </section>
    </section>

    <!-- Section 2: Protocol Overview -->
    <section anchor="protocol-overview">
      <name>Protocol Overview</name>

      <section anchor="architecture">
        <name>Architecture</name>
        <figure>
          <name>ACCP Architecture</name>
          <artwork type="ascii-art"><![CDATA[
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
]]></artwork>
        </figure>
      </section>

      <section anchor="frame-lifecycle">
        <name>Frame Lifecycle</name>
        <ol>
          <li>Sending agent composes a message (natural language or structured)</li>
          <li>ACCP Encoder compresses it into a Frame</li>
          <li>Frame is transmitted via the existing transport layer</li>
          <li>ACCP Decoder at receiving end reconstructs the semantic content</li>
          <li>Decoded content is injected into the receiving agent's LLM context</li>
        </ol>
      </section>
    </section>

    <!-- Section 3: Message Format -->
    <section anchor="message-format">
      <name>Message Format (ACCP-M)</name>

      <section anchor="frame-structure">
        <name>Frame Structure</name>
        <t>
          An ACCP Frame is a single-line UTF-8 string defined by the
          following ABNF grammar (<xref target="RFC5234"/>):
        </t>
        <sourcecode type="abnf"><![CDATA[
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 / "_" / "." )
]]></sourcecode>

        <section anchor="typed-value-rules">
          <name>Typed Value Canonical Rules</name>
          <table>
            <thead>
              <tr><th>Type</th><th>Wire Format</th><th>Example</th></tr>
            </thead>
            <tbody>
              <tr><td>String</td><td>Raw printable ASCII; delimiters escaped with \</td><td>hello, a\:b</td></tr>
              <tr><td>Integer</td><td>Decimal, no leading zeros</td><td>42, -7</td></tr>
              <tr><td>Decimal</td><td>Canonical 6dp, trailing zeros stripped</td><td>3.14, -0.5</td></tr>
              <tr><td>Boolean</td><td>true or false</td><td>true</td></tr>
              <tr><td>Null</td><td>~</td><td>~</td></tr>
              <tr><td>Array</td><td>[v1,v2,v3]</td><td>[1,2,3]</td></tr>
              <tr><td>Map</td><td>{k1:v1,k2:v2} -- keys sorted ascending</td><td>{a:1,b:2}</td></tr>
              <tr><td>Ref</td><td>$tier.key</td><td>$warm.ckpt_1.status</td></tr>
            </tbody>
          </table>
          <t>
            Decimal values <bcp14>MUST</bcp14> be serialized with up to
            6 decimal places, trailing zeros stripped.  Encoders
            <bcp14>MUST NOT</bcp14> use scientific notation.
          </t>
        </section>
      </section>

      <section anchor="frame-examples">
        <name>Frame Examples</name>
        <t>Task completion with findings:</t>
        <sourcecode type="accp"><![CDATA[
@research>done:analyze{d:q3_sales|f:[rev:-12%QoQ,ent_seg:decline,
  churn:+3.2%]|nx:@strategy:plan}
]]></sourcecode>
        <t>Request with parameters:</t>
        <sourcecode type="accp"><![CDATA[
@planner>req:schedule{who:@dev_team|when:sprint_14|
  task:impl_auth_module|pri:high}
]]></sourcecode>
        <t>Query with context reference:</t>
        <sourcecode type="accp"><![CDATA[
@analyst>qry:lookup{src:$ctx.sales_db|q:revenue_by_region|fmt:summary}
]]></sourcecode>
        <t>State sync:</t>
        <sourcecode type="accp"><![CDATA[
@orchestrator>sync:state{v:7|delta:{task_3:done,task_4:wip,
  budget:$42.30}}
]]></sourcecode>
        <t>Error with escalation:</t>
        <sourcecode type="accp"><![CDATA[
@data_agent>fail:fetch{src:api.crm|err:timeout_30s|retry:3|
  esc:@supervisor}
]]></sourcecode>
      </section>

      <section anchor="token-optimization">
        <name>Token Optimization Rules</name>
        <t>Encoders <bcp14>MUST</bcp14> follow these rules to minimize token count:</t>
        <ol>
          <li>No whitespace -- Frames <bcp14>MUST NOT</bcp14> contain spaces, tabs, or newlines.</li>
          <li>Abbreviated keys -- Use shortest unambiguous key names (see <xref target="key-abbreviations"/>).</li>
          <li>Symbolic values -- Prefer symbols over words: +, -, %, &gt;, &lt;.</li>
          <li>Reference over inline -- If a value exceeds 50 characters, store in state and reference via $key.</li>
          <li>Omit defaults -- Do not encode values that match the schema default.</li>
          <li>Coalesce arrays -- Use comma separation within brackets, no spaces.</li>
        </ol>
      </section>

      <section anchor="frame-size-limits">
        <name>Frame Size Limits</name>
        <table>
          <thead>
            <tr><th>Component</th><th>Max Tokens (soft)</th><th>Max Tokens (hard)</th></tr>
          </thead>
          <tbody>
            <tr><td>Header</td><td>5</td><td>10</td></tr>
            <tr><td>Body</td><td>50</td><td>200</td></tr>
            <tr><td>Metadata</td><td>10</td><td>30</td></tr>
            <tr><td>Total Frame</td><td>65</td><td>240</td></tr>
          </tbody>
        </table>
        <t>
          Frames exceeding the hard limit <bcp14>SHOULD</bcp14> be split
          into a frame sequence or reference external state.
        </t>
      </section>

      <section anchor="message-envelope">
        <name>Standard Message Envelope</name>
        <t>
          Every ACCP frame <bcp14>MUST</bcp14> include the following
          envelope fields in its metadata block:
        </t>
        <table>
          <thead>
            <tr><th>Field</th><th>Abbrev</th><th>Type</th><th>Required</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td>msg_id</td><td>mid</td><td>string(12)</td><td>MUST</td><td>Unique message identifier (hex, 12 chars)</td></tr>
            <tr><td>sequence</td><td>seq</td><td>integer</td><td>MUST</td><td>Monotonically increasing per session</td></tr>
            <tr><td>timestamp</td><td>ts</td><td>integer</td><td>MUST</td><td>Unix epoch seconds</td></tr>
            <tr><td>correlation_id</td><td>cid</td><td>string</td><td>SHOULD</td><td>Links request to response</td></tr>
            <tr><td>causation_id</td><td>aid</td><td>string</td><td>MAY</td><td>Links to the message that caused this one</td></tr>
            <tr><td>session_id</td><td>sid</td><td>string</td><td>SHOULD</td><td>ACCP session identifier</td></tr>
            <tr><td>ttl</td><td>ttl</td><td>integer</td><td>MAY</td><td>Seconds until frame expires; 0 = no expiry</td></tr>
          </tbody>
        </table>
        <t>Example metadata block:</t>
        <sourcecode type="accp"><![CDATA[
[mid:49679033e07c,seq:3,ts:1714000000,cid:corr123,sid:abc-session]
]]></sourcecode>
        <t>
          Decoders <bcp14>MUST</bcp14> reject frames with expired TTL.
          Frames missing "mid" or "seq" <bcp14>MUST</bcp14> be rejected.
        </t>
      </section>

      <section anchor="error-model">
        <name>Error Model</name>
        <t>
          Standard error frames use intent "fail", operation "error",
          and schema "ER".
        </t>
        <t>Error code taxonomy:</t>
        <table>
          <thead>
            <tr><th>Range</th><th>Category</th></tr>
          </thead>
          <tbody>
            <tr><td>E1xxx</td><td>Parse / grammar errors</td></tr>
            <tr><td>E2xxx</td><td>State store errors</td></tr>
            <tr><td>E3xxx</td><td>Transport / delivery errors</td></tr>
            <tr><td>E4xxx</td><td>Tool / MCP errors</td></tr>
            <tr><td>E5xxx</td><td>Policy / authorization errors</td></tr>
            <tr><td>E9xxx</td><td>Internal / unknown errors</td></tr>
          </tbody>
        </table>
        <t>Standard error codes:</t>
        <table>
          <thead>
            <tr><th>Code</th><th>Name</th><th>Retryable</th></tr>
          </thead>
          <tbody>
            <tr><td>E1001</td><td>PARSE_ERROR</td><td>No</td></tr>
            <tr><td>E1002</td><td>INVALID_INTENT</td><td>No</td></tr>
            <tr><td>E1003</td><td>UNKNOWN_SCHEMA</td><td>No</td></tr>
            <tr><td>E1004</td><td>INVALID_TYPE</td><td>No</td></tr>
            <tr><td>E2001</td><td>REF_NOT_FOUND</td><td>No</td></tr>
            <tr><td>E2002</td><td>REF_EXPIRED</td><td>No</td></tr>
            <tr><td>E2003</td><td>BUDGET_EXCEEDED</td><td>No</td></tr>
            <tr><td>E3001</td><td>TIMEOUT</td><td>Yes</td></tr>
            <tr><td>E3002</td><td>DUPLICATE</td><td>No</td></tr>
            <tr><td>E3003</td><td>SEQUENCE_GAP</td><td>Yes</td></tr>
            <tr><td>E4001</td><td>TOOL_NOT_FOUND</td><td>No</td></tr>
            <tr><td>E4002</td><td>TOOL_EXEC_FAILED</td><td>Yes</td></tr>
            <tr><td>E4003</td><td>TOOL_SCHEMA_MISMATCH</td><td>No</td></tr>
            <tr><td>E5001</td><td>POLICY_DENIED</td><td>No</td></tr>
            <tr><td>E5002</td><td>UNAUTHORIZED_REF</td><td>No</td></tr>
            <tr><td>E9999</td><td>INTERNAL_ERROR</td><td>Yes</td></tr>
          </tbody>
        </table>
        <t>Error frame example:</t>
        <sourcecode type="accp"><![CDATA[
@agent>fail:error{code:E3001|msg:connection_timed_out|retry:true|
  schema:ER}[mid:abc,seq:4,ts:1714000001]
]]></sourcecode>
      </section>

      <section anchor="delivery-semantics">
        <name>Delivery Semantics</name>
        <t>Implementations <bcp14>MUST</bcp14> enforce the following delivery guarantees:</t>
        <ol>
          <li>Idempotency: Decoders <bcp14>MUST</bcp14> maintain a set of seen "msg_id" values per session. Frames with a previously seen "msg_id" <bcp14>MUST</bcp14> be rejected with error E3002 DUPLICATE.</li>
          <li>Ordering: Frames <bcp14>MUST</bcp14> be processed in ascending "seq" order. A gap in sequence numbers <bcp14>MUST</bcp14> trigger error E3003 SEQUENCE_GAP.</li>
          <li>Retries: Frames with retryable error codes <bcp14>MAY</bcp14> be retransmitted with the same "correlation_id" and a new "msg_id" and "seq".</li>
          <li>Cancellation: A "cancel" intent frame referencing a "correlation_id" <bcp14>MUST</bcp14> stop all processing for that request chain.</li>
          <li>TTL enforcement: Frames received after their TTL has elapsed <bcp14>MUST</bcp14> be rejected silently (no error response, to prevent timing attacks).</li>
        </ol>
      </section>
    </section>

    <!-- Section 4: Intent & Operation Ontology -->
    <section anchor="intent-ontology">
      <name>Intent and Operation Ontology (ACCP-I)</name>

      <section anchor="core-intents">
        <name>Core Intents</name>
        <table>
          <thead>
            <tr><th>Code</th><th>Meaning</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td>req</td><td>Request</td><td>Request another agent to perform an action</td></tr>
            <tr><td>done</td><td>Complete</td><td>Report task completion with results</td></tr>
            <tr><td>fail</td><td>Failure</td><td>Report task failure with error details</td></tr>
            <tr><td>wait</td><td>Waiting</td><td>Awaiting external input or dependency</td></tr>
            <tr><td>esc</td><td>Escalate</td><td>Delegate to a higher-authority agent</td></tr>
            <tr><td>comp</td><td>Compress</td><td>Trigger context compression checkpoint</td></tr>
            <tr><td>sync</td><td>Synchronize</td><td>Share or request state synchronization</td></tr>
            <tr><td>qry</td><td>Query</td><td>Request information lookup</td></tr>
            <tr><td>ack</td><td>Acknowledge</td><td>Confirm receipt of a frame</td></tr>
            <tr><td>cancel</td><td>Cancel</td><td>Abort an in-progress task</td></tr>
            <tr><td>stream</td><td>Stream</td><td>Begin streaming incremental results</td></tr>
            <tr><td>end</td><td>End stream</td><td>Close a streaming sequence</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="key-abbreviations">
        <name>Standard Key Abbreviations</name>
        <table>
          <thead>
            <tr><th>Abbreviation</th><th>Full Meaning</th></tr>
          </thead>
          <tbody>
            <tr><td>d</td><td>data / dataset</td></tr>
            <tr><td>f</td><td>findings / fields</td></tr>
            <tr><td>nx</td><td>next action</td></tr>
            <tr><td>src</td><td>source</td></tr>
            <tr><td>dst</td><td>destination</td></tr>
            <tr><td>q</td><td>query</td></tr>
            <tr><td>fmt</td><td>format</td></tr>
            <tr><td>pri</td><td>priority</td></tr>
            <tr><td>err</td><td>error</td></tr>
            <tr><td>v</td><td>version</td></tr>
            <tr><td>ts</td><td>timestamp</td></tr>
            <tr><td>ttl</td><td>time-to-live</td></tr>
            <tr><td>ctx</td><td>context reference</td></tr>
            <tr><td>who</td><td>target agent/entity</td></tr>
            <tr><td>when</td><td>temporal constraint</td></tr>
            <tr><td>why</td><td>rationale code</td></tr>
          </tbody>
        </table>
      </section>

      <section anchor="operation-registry">
        <name>Operation Registry</name>
        <t>
          Operations are domain-specific verbs registered in the Schema
          Registry (<xref target="schema-registry"/>).  Core operations:
        </t>
        <t>
          analyze, plan, execute, review, approve, reject, fetch,
          transform, summarize, classify, generate, validate,
          schedule, notify, merge, split, route, cache, purge
        </t>
        <t>
          Harnesses <bcp14>MAY</bcp14> register custom operations via
          the registry extension mechanism.
        </t>
      </section>
    </section>

    <!-- Section 5: Context State Management -->
    <section anchor="state-management">
      <name>Context State Management (ACCP-S)</name>

      <section anchor="state-hierarchy">
        <name>State Hierarchy</name>
        <t>ACCP defines a three-tier state model:</t>
        <dl>
          <dt>Tier 1: HOT STATE (in-context)</dt>
          <dd>Current frame + immediate parent frames. Active task parameters. Max budget: 500 tokens.</dd>
          <dt>Tier 2: WARM STATE (compressed summaries)</dt>
          <dd>Checkpoint summaries from completed phases. Key-fact extractions. Referenced via $warm.key. Max budget: 200 tokens per checkpoint.</dd>
          <dt>Tier 3: COLD STATE (external store)</dt>
          <dd>Full conversation history. Raw tool outputs. Referenced via $cold.key. Zero token budget (not injected into context).</dd>
        </dl>
      </section>

      <section anchor="compression-checkpoints">
        <name>Compression Checkpoints</name>
        <t>
          A checkpoint <bcp14>MUST</bcp14> be triggered when ANY of the
          following conditions are met:
        </t>
        <ol>
          <li>An agent completes a task ("done" intent)</li>
          <li>Accumulated hot state exceeds 400 tokens</li>
          <li>A handoff between agents occurs ("esc" intent)</li>
          <li>The harness signals a phase boundary</li>
          <li>An agent explicitly requests compression ("comp" intent)</li>
        </ol>
      </section>

      <section anchor="checkpoint-process">
        <name>Checkpoint Process</name>
        <ol>
          <li>Freeze current hot state</li>
          <li>Extract key facts (entity, value, relationship triples)</li>
          <li>Generate compressed summary (less than or equal to 100 tokens)</li>
          <li>Move summary to warm state with checkpoint ID</li>
          <li>Move raw data to cold state</li>
          <li>Reset hot state with checkpoint reference</li>
        </ol>
      </section>

      <section anchor="delta-encoding">
        <name>Delta Encoding</name>
        <t>
          After checkpoint N, subsequent frames <bcp14>SHOULD</bcp14>
          transmit only deltas:
        </t>
        <sourcecode type="accp"><![CDATA[
@agent>sync:state{v:N+1|delta:{changed_key:new_val,removed_key:null}}
]]></sourcecode>
        <t>
          The decoder reconstructs full state by applying deltas to the
          last checkpoint.
        </t>
      </section>
    </section>

    <!-- Section 6: Schema Registry -->
    <section anchor="schema-registry">
      <name>Schema Registry (ACCP-R)</name>

      <section anchor="registry-purpose">
        <name>Purpose</name>
        <t>
          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.
        </t>
      </section>

      <section anchor="registry-structure">
        <name>Registry Structure</name>
        <sourcecode type="json"><![CDATA[
{
  "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": [] }
    }
  }
}
]]></sourcecode>
      </section>

      <section anchor="registry-usage">
        <name>Usage in Frames</name>
        <sourcecode type="accp"><![CDATA[
@planner>req:execute{schema:TA|assignee:@dev|task:auth_module|
  deadline:sprint_14}
]]></sourcecode>
        <t>
          The decoder expands "schema:TA" into the full field set,
          populating defaults for omitted fields.
        </t>
      </section>

      <section anchor="registry-negotiation">
        <name>Registry Negotiation</name>
        <t>
          At session start, agents <bcp14>MUST</bcp14> exchange registry
          versions:
        </t>
        <sourcecode type="accp"><![CDATA[
@orchestrator>sync:registry{v:3|hash:a7f2c1}
]]></sourcecode>
        <t>
          If hashes match, no further exchange is needed.  On mismatch,
          the full registry delta is transmitted once and cached.
        </t>
      </section>
    </section>

    <!-- Section 7: Codec API -->
    <section anchor="codec-api">
      <name>Codec API Specification</name>

      <section anchor="interface-definition">
        <name>Interface Definition</name>
        <t>
          The codec interface defines the following operations that
          conforming implementations <bcp14>MUST</bcp14> provide:
        </t>
        <dl>
          <dt>Encode(message, session) -&gt; Frame</dt>
          <dd>Encode a structured message into an ACCP Frame</dd>
          <dt>Decode(frame, session) -&gt; Message</dt>
          <dd>Decode an ACCP Frame back into a structured message</dd>
          <dt>Checkpoint(session) -&gt; CheckpointResult</dt>
          <dd>Trigger a compression checkpoint</dd>
          <dt>GetBudget(session) -&gt; TokenBudget</dt>
          <dd>Get current token budget usage</dd>
          <dt>RegisterSchema(name, schema)</dt>
          <dd>Register a custom schema</dd>
        </dl>
      </section>

      <section anchor="encoding-pipeline">
        <name>Encoding Pipeline</name>
        <ol>
          <li>Schema resolution (expand or compact via registry)</li>
          <li>Key abbreviation (full keys to abbreviated keys)</li>
          <li>Value compression (inline values to references if large)</li>
          <li>Default omission (remove fields matching schema defaults)</li>
          <li>Token estimation (count via BPE tokenizer)</li>
          <li>Budget check (within frame limits): if YES, emit single frame; if NO, split into frame sequence or externalize to state</li>
          <li>Emit ACCP Frame string</li>
        </ol>
      </section>

      <section anchor="decoding-pipeline">
        <name>Decoding Pipeline</name>
        <ol>
          <li>Parse grammar (header, body, metadata)</li>
          <li>Resolve references ($warm.key, $cold.key, schema codes)</li>
          <li>Expand abbreviations (abbreviated keys to full keys)</li>
          <li>Apply schema defaults (fill omitted fields)</li>
          <li>Reconstruct structured message</li>
          <li>Return structured message for LLM context injection</li>
        </ol>
      </section>
    </section>

    <!-- Section 8: Conformance Requirements -->
    <section anchor="conformance">
      <name>Conformance Requirements</name>

      <section anchor="level-1">
        <name>Minimum Conformance (Level 1)</name>
        <t>An implementation <bcp14>MUST</bcp14> support:</t>
        <ul>
          <li>Frame encoding/decoding (<xref target="message-format"/>)</li>
          <li>Core intents (<xref target="core-intents"/>)</li>
          <li>Basic key abbreviations (<xref target="key-abbreviations"/>)</li>
        </ul>
      </section>

      <section anchor="level-2">
        <name>Standard Conformance (Level 2)</name>
        <t>An implementation <bcp14>MUST</bcp14> additionally support:</t>
        <ul>
          <li>Context state management (<xref target="state-management"/>)</li>
          <li>Compression checkpoints (<xref target="compression-checkpoints"/>)</li>
          <li>Schema registry (<xref target="schema-registry"/>)</li>
        </ul>
      </section>

      <section anchor="level-3">
        <name>Full Conformance (Level 3)</name>
        <t>An implementation <bcp14>MUST</bcp14> additionally support:</t>
        <ul>
          <li>Delta encoding (<xref target="delta-encoding"/>)</li>
          <li>Registry negotiation (<xref target="registry-negotiation"/>)</li>
          <li>Token budget enforcement (<xref target="interface-definition"/>)</li>
          <li>Streaming frames (<xref target="core-intents"/>, "stream"/"end" intents)</li>
        </ul>
      </section>
    </section>

    <!-- Section 9: Security Considerations -->
    <section anchor="security">
      <name>Security Considerations</name>
      <ol>
        <li>Opacity risk: Compact formats are harder for humans to audit. Implementations <bcp14>SHOULD</bcp14> provide a "debug mode" that logs decoded human-readable equivalents.</li>
        <li>Injection: Frame parsing <bcp14>MUST</bcp14> validate grammar strictly. Malformed frames <bcp14>MUST</bcp14> be rejected, not partially parsed.</li>
        <li>State store access: Cold state references <bcp14>MUST</bcp14> be scoped to the current session. Cross-session state access requires explicit authorization.</li>
        <li>Registry tampering: Schema registries <bcp14>SHOULD</bcp14> be integrity-checked via hash (<xref target="registry-negotiation"/>).</li>
        <li>Parser DoS Protection: Decoders <bcp14>MUST</bcp14> implement strict limits on array nesting depth (recommended maximum: 5 levels) and limit payload parsing complexity to prevent resource exhaustion attacks.</li>
      </ol>
    </section>

    <!-- Section 10: Domain Profiles -->
    <section anchor="domain-profiles">
      <name>Domain Profiles</name>
      <t>
        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.
      </t>

      <section anchor="chat-profile">
        <name>Chat Profile (CH)</name>
        <t>
          Schema: CH -- fields: role, content, turn, lang, reply_to.
          Defaults: role=assistant, lang=en.
        </t>
        <sourcecode type="accp"><![CDATA[
@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:...]
]]></sourcecode>
      </section>

      <section anchor="tool-profile">
        <name>Tool / MCP Profile (TC)</name>
        <t>
          Schema: TC -- fields: tool_name, arguments, result, status,
          error_code.  Defaults: status=ok.
        </t>
        <sourcecode type="accp"><![CDATA[
@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]
]]></sourcecode>
        <t>
          Tool calls <bcp14>MUST</bcp14> include "correlation_id" in the
          response to link result to request.  Tool errors
          <bcp14>MUST</bcp14> use schema "ER" with code E4002
          TOOL_EXEC_FAILED.
        </t>
      </section>

      <section anchor="transaction-profile">
        <name>Transaction Profile (TX)</name>
        <t>
          Schema: TX -- fields: transaction_id, amount, currency,
          account, reference, status, retryable.  Defaults: currency=USD,
          status=pending, retryable=false.
        </t>
        <sourcecode type="accp"><![CDATA[
@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:...]
]]></sourcecode>
        <t>Transaction safety requirements:</t>
        <ul>
          <li>"transaction_id" <bcp14>MUST</bcp14> be stable across retries (idempotency key).</li>
          <li>"amount" <bcp14>MUST</bcp14> be serialized as decimal (not string) to avoid precision loss.</li>
          <li>"currency" <bcp14>SHOULD</bcp14> follow ISO 4217.</li>
          <li>Retries <bcp14>MUST</bcp14> use the same "transaction_id" with a new "msg_id".</li>
        </ul>
      </section>

      <section anchor="streaming-profile">
        <name>Streaming Profile (ST)</name>
        <t>
          Schema: ST -- fields: chunk_index, total_chunks, data,
          is_final.  Defaults: is_final=false.
        </t>
        <sourcecode type="accp"><![CDATA[
@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]
]]></sourcecode>
        <t>
          All chunks in a stream <bcp14>MUST</bcp14> share the same
          "correlation_id".  The final chunk <bcp14>MUST</bcp14> set
          "is_final=true".  Consumers <bcp14>MUST</bcp14> buffer and
          reorder by "chunk_index" before processing.
        </t>
      </section>

      <section anchor="workflow-profile">
        <name>Workflow Profile (TA)</name>
        <t>
          Schema: TA -- fields: assignee, task, priority, deadline, deps.
          Defaults: priority=medium, deps=[].
        </t>
        <sourcecode type="accp"><![CDATA[
@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:...]
]]></sourcecode>
      </section>
    </section>

    <!-- Section 11: Transport Bindings -->
    <section anchor="transport-bindings">
      <name>Transport Bindings</name>
      <t>
        ACCP frames are transport-agnostic.  The following bindings
        define how frames are carried over common transports.
      </t>

      <section anchor="accp-over-http">
        <name>ACCP-over-HTTP</name>
        <ul>
          <li>Method: POST /accp/v1/frames</li>
          <li>Content-Type: application/accp</li>
          <li>Body: One ACCP frame string per request (UTF-8)</li>
          <li>Response: 200 OK with response ACCP frame, or 400 with ER-schema error frame body</li>
          <li>Streaming: use Transfer-Encoding: chunked with one ST-schema frame per chunk</li>
        </ul>
      </section>

      <section anchor="accp-over-websocket">
        <name>ACCP-over-WebSocket</name>
        <ul>
          <li>Frame type: text</li>
          <li>One ACCP frame string per WebSocket message</li>
          <li>Session established by the first sync:registry frame from the initiator</li>
          <li>Heartbeat: ping/pong intent frames every 30 seconds</li>
        </ul>
      </section>

      <section anchor="accp-over-mcp">
        <name>ACCP-over-MCP</name>
        <ul>
          <li>ACCP frames are carried as MCP resource content with MIME type application/accp</li>
          <li>Tool calls use the TC profile; results are returned as MCP tool responses containing the TC-schema done:tool frame</li>
          <li>Registry sync occurs at MCP session initialization via a sync:registry frame in the system prompt</li>
        </ul>
      </section>

      <section anchor="accp-over-a2a">
        <name>ACCP-over-A2A</name>
        <ul>
          <li>ACCP frames are embedded as A2A message parts with content type application/accp</li>
          <li>A2A task creation maps to ACCP "req" intent; task completion maps to "done"</li>
          <li>A2A streaming artifact parts map 1:1 to ST-schema stream frames</li>
        </ul>
      </section>
    </section>

    <!-- Section 12: IANA Considerations -->
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>
        This document requests IANA registration of the media type
        "application/accp" for ACCP frame payloads.
      </t>
      <section anchor="media-type">
        <name>Media Type Registration</name>
        <dl>
          <dt>Type name:</dt><dd>application</dd>
          <dt>Subtype name:</dt><dd>accp</dd>
          <dt>Required parameters:</dt><dd>N/A</dd>
          <dt>Optional parameters:</dt><dd>N/A</dd>
          <dt>Encoding considerations:</dt><dd>UTF-8</dd>
          <dt>Security considerations:</dt><dd>See <xref target="security"/> of this document</dd>
          <dt>Interoperability considerations:</dt><dd>N/A</dd>
          <dt>Published specification:</dt><dd>This document</dd>
        </dl>
      </section>
    </section>

  </middle>

  <back>
    <!-- Normative References -->
    <references>
      <name>Normative References</name>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5234.xml"/>
    </references>

    <references>
      <name>Informative References</name>

        <reference anchor="MCP">
          <front>
            <title>Model Context Protocol</title>
            <author><organization>Anthropic</organization></author>
            <date year="2024"/>
          </front>
        </reference>

        <reference anchor="A2A">
          <front>
            <title>Agent2Agent (A2A) Protocol Specification</title>
            <author><organization>Google</organization></author>
            <date year="2025"/>
          </front>
        </reference>

        <reference anchor="ACP">
          <front>
            <title>Agent Communication Protocol (ACP)</title>
            <author><organization>IBM</organization></author>
            <date year="2025"/>
          </front>
        </reference>
    </references>

    <!-- Appendix A: Token Comparison Benchmarks -->
    <section anchor="benchmarks" numbered="false">
      <name>Appendix A.  Token Comparison Benchmarks</name>
      <table>
        <thead>
          <tr><th>Scenario</th><th>NL Tokens</th><th>JSON Tokens</th><th>ACCP Tokens</th><th>Reduction</th></tr>
        </thead>
        <tbody>
          <tr><td>Task completion + findings</td><td>85</td><td>62</td><td>22</td><td>74%</td></tr>
          <tr><td>Task request + params</td><td>45</td><td>38</td><td>15</td><td>67%</td></tr>
          <tr><td>Error + escalation</td><td>60</td><td>48</td><td>18</td><td>70%</td></tr>
          <tr><td>State sync (10 fields)</td><td>120</td><td>95</td><td>35</td><td>71%</td></tr>
          <tr><td>Full 5-agent pipeline</td><td>8,500</td><td>6,200</td><td>1,800</td><td>79%</td></tr>
        </tbody>
      </table>
      <t>
        Note: Benchmarks are based on empirical validation of Phase 1
        implementation.
      </t>
    </section>

    <!-- Appendix B: Future Work -->
    <section anchor="future-work" numbered="false">
      <name>Appendix B.  Future Work</name>
      <ul>
        <li>Model-specific tokenizer profiles: Optimize encoding per model's BPE vocabulary.</li>
        <li>Adaptive compression: ML-based encoder that learns optimal compression per domain.</li>
      </ul>
    </section>

    <!-- Acknowledgements -->
    <section anchor="acknowledgements" numbered="false">
      <name>Acknowledgements</name>
      <t>
        The author acknowledges the contributions of the broader AI agent
        protocol community, including the developers of <xref target="MCP"/>, <xref target="A2A"/>, and <xref target="ACP"/>,
        whose work informed the design of ACCP.
      </t>
    </section>

  </back>
</rfc>