Context Window Architecture — a context assembler spec (v2 draft)
CWA
GitHub
Context assembler spec · v2 draft

Context isn't a prompt. It's an assembled request.

CWA is a free specification for assembling everything a model call needs — instructions, state, evidence, history, the live turn — into one payload where every item has an owner, an authority, a lifecycle, a budget, and a place. The assembly is deterministic, and every step of it can be inspected.

Watch it assemble Copy the scaffold
Assembling · {{ mUcName }} {{ mProgress }}
{{ b.tag }}
{{ b.text }}
{{ mTokens }} profile · policy-first-chat/v1
Who it's for
Everyday AI users
Not a developer? No problem. CWA helps you understand how AI uses context, so you can write better prompts and get better results.
Developers & builders
Use CWA to build more reliable AI applications with a consistent way to manage context.
Organizations
Adopt a shared standard for AI context to improve quality, consistency, and governance.
What it is
Not a library
There is nothing to install. CWA is a specification you apply to the payload you already send, and an assembler can be built against it.
Deterministic assembly
Given the same inputs, source versions, and policy, the assembler produces the same payload every time. The model's answer may still vary, but the request it receives does not.
Traceable
Every assembly run emits a trace: what got in, what was compressed, what was refused, and why.
If you are evaluating CWA, read on to Why it works. If you are building, start at the Spec.
The problem

What goes wrong when nobody owns the payload.

Every model call is assembled by a function, and in most systems that function has no name. It has grown arguments for a year, it concatenates whatever the route happens to hold, and it knows nothing about who is allowed to direct the model, how old each piece is, what to shorten when the window is full, or what it sent last time. The failures this produces are not random: they repeat, they have recognisable shapes, and they can be named.

01 Authority inversion A protocol document outranks the never-diagnose rule, and the assistant names a condition. Reproduce · Clinical triage → 02 Instruction-shaped evidence A lint config or a runbook reads as a command, and the bot starts rewriting style or proposing failover. Reproduce · Code review bot → 03 Stale-as-current Last week’s brief is indistinguishable from this week’s data, so old numbers ship as current. Reproduce · Weekly brief → 04 Memory that never expires Corrections from weeks ago become live instructions. Reproduce · Language tutor → 05 Displacement under budget History is unbounded, so by turn thirty the price rule has been pushed out of the window. Reproduce · Support agent → 06 Redundant re-reading The whole menu is re-read on every turn; the reply lands late. Reproduce · Voice ordering → 07 Missing trigger The query is buried or absent, so the turn returns a summary, or nothing. Reproduce · Support agent, query removed →
These are assembly errors, and in most systems today nothing owns the assembly step that would catch them.
Each card opens the demo on the system that reproduces it, shown as the unassembled blob.

Where an item sits in the window matters too, and that question has evidence of its own: Why placement is a profile, not a rule.

Why it works

Prompt construction, promoted to assembly.

01

A shared vocabulary

"Evidence polluted governance" and "history displaced tool results" are sentences a team can act on. Named planes and slots turn vague prompt debates into specific bug reports.

02

Deterministic assembly

Given the same request state, source versions, selection rules, and budget, the assembler emits the same payload in the same order. That is a claim a test can check. "The model will answer the same way" is not, and CWA never makes it.

03

A budget with a policy

Tokens are finite, so when every item is measured and tiered the assembler knows what to protect, what to compress, what to drop, and when to stop and report that the evidence did not fit.

Live assembly

The slots aren't the point. The assembly is.

CWA gives you four planes and eleven typed slots, and no single request fills them all. The assembler admits the items each request actually needs, fits them to a finite budget by priority, and renders them in a tested order. Watch seven very different systems assemble, then pull a slot out or squeeze the budget and see what degrades first.

Input budget
Window fill {{ tokenLabel }}
{{ evictionLabel }}
Protected · instructions, task state, output contract, query Compressible · memory, history, knowledge, tool results Droppable · examples, user facts
Slots {{ usedLabel }}
Click a slot to remove it →
Nothing to click — the slots no longer exist
{{ ucName }} {{ progress }}
{{ line.tag }} {{ line.tokens }}
{{ line.text }}
↓ rendered by {{ profileName }} trace {{ traceId }}
Symptom you'll actually see

{{ ucSymptom }}

{{ n.text }}
What breaks without it
{{ r.tag }} {{ r.text }}
What this one teaches

{{ ucNote }}

Decisions it forces
? {{ q.text }}
The schema

Four planes. Eleven slots. Any number of items.

A plane says why a piece of context exists. A slot is a typed collection inside a plane, with its own admission rules. An item is one governed object in a slot — a policy, a retrieved passage, a tool observation. Newcomers learn the planes; implementers use the slots; the assembler moves the items.

{{ pl.name }}
{{ pl.answers }}

{{ pl.blurb }}

{{ s.name }} {{ s.id }}
{{ layer.meta }}
Holds

{{ layer.purpose }}

Admission rule

{{ layer.value }}

The unit

A slot holds items, not a paragraph.

Real systems put three retrieved passages, two tool observations, and a memory summary plus a task episode into the same request. Each one is a separate item with its own metadata, and without that metadata even a clean slot order produces unpredictable payloads.

{{ f.key }} {{ f.text }}
context_item.yaml evidence.knowledge · 1 of 3
id: "retrieval:refunds-eu:v17#p4" slot: evidence.knowledge type: evidence source: policy-corpus source_version: "2026-09-10" authority: reference_only trust: verified freshness: "2026-09-12T15:30:00Z" scope: refund_request eligibility: "similarity >= 0.82 AND jurisdiction == EU" token_budget: 420 compression: extractive_quote conflict_policy: defer_to_current_tool_result injection_risk: untrusted_content lineage: verbatim placement: evidence_near_query
placement is a hint the route’s profile consumes, not a position. Where items go is a profile decision with evidence behind it: Why placement is a profile, not a rule.
Go deeper

Order alone is not an architecture.

A fixed order reproduces a payload, but it says nothing about who is allowed to direct the model, what wins when sources disagree, whether this order is right for this model, or how anyone would know. The normative rules, the producer contract, and the placement evidence each have a page of their own.

Specification · v2 draft 23 numbered requirements. They cover conformance language, the authority hierarchy and resolution matrix, budget tiers, the profile shape, and the required trace fields. Pure text, permalinked per rule and mirrored to the repo. Read the spec → Producer contract What your tool has to emit. It covers the eight minimum fields, slot defaults, and the rules for retrievers, memory stores, state services, MCP servers, and the capability policy. Paste an item into the linter to see whether an assembler would admit it. Read the contract → Placement evidence Why placement is a profile, not a rule. The evidence covers serial-position research, provider guidance by model generation, the profile format, and how to evaluate one. Five profiles to diff, including one new. Read the evidence →
Evidence selection

Retrieval feeds Evidence through an admission pipeline.

"Retrieval goes in slot three" is memorable, but it is too coarse. Between the vector store and the payload sit eight decisions, and each one is a deterministic rule the trace can point at. For high-stakes answers the slot holds evidence packets, each carrying source, passage, version, relevance, authority, and whether it is binding or informative, rather than undifferentiated "knowledge."

{{ s.n }}
{{ s.name }}

{{ s.text }}

When nothing valid is retrieved
The assembler does not answer from nothing. It retrieves narrower, summarises with traceability, or routes the request for more context — and the trace records which.
When admission yields no valid evidence, an assembler MUST NOT answer from nothing. It MUST retrieve narrower, summarise with traceability, or route for more context, and the trace MUST record which.
Fresh beats retrieved
A tool observation from 0.4 seconds ago and a passage indexed in August are both evidence, but for current facts the observation governs and the passage only cites.
In practice

What an assembled request looks like on the wire.

CWA does not dictate syntax, so tag slots however your stack prefers: XML-style blocks, message roles, or delimited sections. What matters is that every item names its slot and authority, evidence arrives as packets with provenance, and the profile that ordered them is recorded.

payload.txtprofile · policy-first-chat/v1
<!-- governance.instructions · authority=governing · v12 -->
<system>You are Ada, a support agent for Northwind.
Never quote prices you cannot verify with a tool.</system>
<!-- state.user · authority=state · scope=session -->
<user_profile>plan=pro; region=EU; tone=concise</user_profile>
<!-- evidence.knowledge · authority=reference_only · 2 of 12 candidates -->
<evidence id="refunds-eu:v17#p4" trust="verified" as_of="2026-09-10">
Pro plans refund in full within 30 days of purchase.
</evidence>
<evidence id="billing-faq:v3#p1" trust="verified" as_of="2026-08-02">
Refunds return to the original payment method.
</evidence>
<!-- state.task · authority=state · canonical, app-owned -->
<task>refund_request: verify_eligibility=done, issue=pending</task>
<!-- interaction.memory · authority=generated · lineage=summary -->
<memory>User bought Pro in March, EU billing.</memory>
<!-- interaction.history · authority=user · verbatim, last 6 -->
<history>user: is my order refundable?</history>
<!-- governance.capabilities · authority=governing · source=capability-policy:support-chat@v3 -->
<tools>lookup_order(id), issue_refund(id, amount)</tools>
<!-- evidence.tool_results · authority=observation · age=0.4s -->
<observation call="lookup_order(8821)">{"total": 240, "days": 12}</observation>
<!-- governance.output_contract · authority=governing -->
<format>Max 3 sentences. No bullet lists.</format>
<!-- interaction.query · authority=user · the trigger -->
<query>Can you just process it now?</query>
<!-- trace ctx_01J9K · 3 items excluded · 0 conflicts · policy-first-chat/v1 -->
Where it fits

It augments what you already use.

Your existing tools supply the materials, and CWA is the assembly step between them and the model.

RAG

Retrieval produces candidates for the Evidence plane. CWA decides which are admitted, how they're packetized, and what they may never overrule.

Read →
Model Context Protocol

MCP is the transport for tools and resources. CWA governs what it returns — tool specs proposed to the route's capability policy and admitted into Governance, observations in Evidence, each with freshness and authority.

Read →
Agent frameworks

Frameworks orchestrate the loop. CWA assembles the payload each step of that loop actually sends, and emits the trace for it.

Read →
Prompt engineering

Prompting is craft at the sentence level and CWA is structure at the payload level, so you need both.

Read →
Harness engineering

Already using a framework? The assembler goes inside it.

Your framework is the harness: it runs the loop, calls the tools, keeps the state, and retries the failures. It is deliberately unopinionated about the one thing that decides answer quality, which is what actually lands in the window on each pass. CWA fills that gap. Pick your stack:

Runtime loop · {{ fwName }} Framework territory
01
Receive input
02
Plan / route
03
Resolve tools
04 · yours
{{ fwSeamStage }}
05
Call model
06
Parse & act ↻
Inside stage 04 Your territory · CWA specifies this
The framework hands you an empty array and a place to put a string. Everything below is a decision you are already making — usually implicitly, in one function, with no names for the parts.
{{ c.label }}
seam · {{ fwSeam }}
Your harness already owns
{{ o }}
It leaves you a blank
{{ b }}
What that costs you
{{ c }}
Should you use CWA with {{ fwName }}?
{{ fwVerdict }}
Skip it if
You send one fixed prompt with no retrieval and no history. An assembler for a single slot is bureaucracy.
Skip it if
You never use more than a fifth of the window. Nothing competes, so nothing needs priority.
Skip it if
It's a prototype you'll delete on Friday. Come back when someone asks why it answered that.
Take it with you

Copy the scaffold and start today.

The getting-started guide takes you in six steps from your current prompt to a payload with owners. It includes a migrator that proposes slots for your prompt and five files to copy: an assembly function, an empty payload, the item schema as YAML and JSON Schema, and a cwa.md for coding agents.

Getting started →

Adopt the spec. The assembler comes next.

Name the slots you already send, give every item an authority and a source, and see how much of your payload had no owner. A reference assembler that implements this spec, covering admission, fitting, profiles, and traces, is in progress, and we want to hear what it must do. A future revision will describe request intent as a typed tree that items bind to.

View on GitHub Read the docs
{{ tourKicker }} {{ tourCount }}
{{ tourTitle }}
{{ tourBody }}