Reference assemblers — Context Window Architecture
Context Window Architecture
Reference assemblers

Four assemblers, released as drafts.

Four open-source assemblers implement the specification, in Python, TypeScript, Go and Rust. Each is released at its repository's draft-release tag, which moves with the draft. The table shows how many of the published conformance cases each one passes.

Status: released · tag draft-release Spec target: draft
Reference implementations
languageimplementation · versionrepository · commitconformancecases at
{{ i.language }} {{ i.scope }}{{ i.pkg }}{{ i.version }} {{ i.repo }}{{ t.name }} · {{ i.commit }} {{ i.cases }}{{ i.caseNote }} {{ i.contract }} {{ i.contractSha }}
Live assembly

Three requests, assembled.

Three very different requests, each built from only the slots it needs. Pull a slot out or squeeze the budget, and see what degrades first.

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

An illustration, not a model run: sizes are typical for each slot, not counts of the line shown. Remove the instructions or the query and the assembler refuses, as R-4 requires, with no payload but a trace of what it decided (R-17).

Symptom you'll actually see

{{ ucSymptom }}

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

{{ ucNote }}

Harness engineering

The assembler sits just before your model call.

Your framework, or your own loop, still calls the tools, keeps the state and retries. The assembler decides what each model call holds. Here is that step in the example app. It has no framework, so answer() is the whole loop.

after.pyanswer()
def answer(conversation: Conversation, provider: str, model: str | None, *,           out: TextIO = sys.stdout, runs: Path = RUNS, record: str | Path | None = None) -> str | None:    document, result = build_request(conversation)    save(document, result, runs)    if record:        write(Path(record), document, result)  # --record: this assembly, beside the conversation and the reply    report(document, result, out)    if result.payload is None:        return None  # refused: there is no payload, so nothing can reach a model (R-17)    payload = json.loads(result.payload)  # cwa-messages/v1: {"system": [...], "tools": [...], "messages": [one user message]}    system = [entry["text"] for entry in payload["system"]]    messages = payload["messages"]    if provider == "none":        cli.show_request(system, messages, out)        return None    return providers.ask(provider, model, system, messages, context.reserved_output())

Assemble, stop if it refused, then pass the payload to the SDK as it is. In a framework, the same steps go where it builds each model call's input.

The SDK call, with the official Anthropic and OpenAI SDKs: providers.py →

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.

Tell us what it must do.

The assembler is being built against real routes. If yours has a constraint the spec does not cover, open an issue before the API freezes.

Repository