Architecture
contexel lives at exactly one place: the boundary where a tool's raw output becomes the model's context. Everything below is that one idea, mechanized.
The pipeline — click any stage
A record is a plain dict; a collection is
list[dict]. Every stage is (records, **params) →
records, never mutates its input, and composes with the rest:
Two layers, one policy
@shaped — the model never sees raw
Wrap the tool with a named pipeline. Every call returns bounded, reshaped records — the same lens on the repo whether it is step 1 or step 100. This is the context contract: versioned beside the code, changed only by intention.
Inline — for what a given step needs
The sandbox imports the stages, so when the model writes code it composes vetted transforms instead of improvising string surgery. Both layers stack; only the distilled result re-enters context.
@shaped([ # the contract, pinned at the boundary
stage(select, fields=["path", "line", "snippet", "score"]),
stage(dedupe, key=["path", "line"]),
stage(trim_to_budget, max_tokens=2000),
])
def search_code(query: str) -> list[dict]:
return repo.search(query) # raw, heavy — shaped identically, every call
Try it — the budget, live
A faithful miniature of select → dedupe → rank → trim_to_budget
running in your browser on twelve search-hit records (three are duplicates,
all carry noise fields). Records are priced the way the library prices them
— ≈4 chars/token on the serialized record, +2 framing per record.
Token accounting — two pluggable axes
How text is priced
Default: a dependency-free ~4-chars/token estimate.
tokens.use_tiktoken() for exact counts,
set_tokenizer(fn) for your own. Measured accuracy per
content type is in the benchmarks.
What encoding is priced
Budgets are encoding-relative: a record costs the tokens of its
serialized text. Canonical JSON by default;
set_serializer(fn) prices records in the encoding your
boundary actually emits — e.g. an ISON
table, where the same budget holds more records.
The reference agent loop
The repo ships a complete code-execution agent
(python -m reference_agent, no API key) that closes the loop:
result enters context→
repeat until answer
Its tests prove the headline guarantee: two runs build byte-identical context even though the raw tool layer returns fresh request ids on every call.
GitHub