ctxkeeper
Keep your agent working when its conversation outgrows the model's context window. Free, public-domain proxy; install with pip or Docker.
Free · public domain · Python 3.10+, standard library only
A small proxy between your agent and any OpenAI-compatible model server. Your agent keeps its whole
history; the model sees a short, current view — notes it maintains, the opening instructions, the newest turns.
Everything older is archived word for word, searchable through a recall tool the proxy answers itself.
- 2Mtokens tested, hostile stream
- 421/423 · 417/423both seeds, 16/16 audits
- 226/228million-token recall
- 40/40real bugs fixed, 12 min
Install and run
Point your agent at http://127.0.0.1:8000/v1 instead of the model server. Nothing else about the agent changes.
pip
python3 -m venv .venv-ctxkeeper
. .venv-ctxkeeper/bin/activate
python -m pip install \
"https://github.com/steveseguin/b70-optimization-lab/releases/download/ctxkeeper-v1.2.0/ctxkeeper-1.2.0-py3-none-any.whl"
ctxkeeper --recipe qwen \
--upstream http://127.0.0.1:8080
Docker
docker build -t ctxkeeper:1.2.0 \
"https://github.com/steveseguin/b70-optimization-lab/releases/download/ctxkeeper-v1.2.0/ctxkeeper-1.2.0.tar.gz"
docker run --rm --network host \
-v ctxkeeper-state:/state \
ctxkeeper:1.2.0 --recipe qwen \
--upstream http://127.0.0.1:8080
Or take just the two files — ctxkeeper.py and notesdelta.py — from the
release page, which lists every file’s SHA-256.
The upstream must accept managed calls without an API key (client Authorization headers are not forwarded); keep the proxy on localhost or a trusted network.
The full guide covers every option, the status page and the tests.
Measured, not promised
Every row is a real run, graded by the task’s own checker, on Qwen3.8-27B (FP8, vLLM, two Intel Arc Pro B70 cards) with a 32K-token working view.
| Task | With ctxkeeper | Without it |
|---|---|---|
| Fix 40 real bugs in a Python library, one ticket at a time, under three house rules; then 7 questions about the earliest fixes | 40/40 fixed, 40/40 kept every rule, 7/7 right; 12–38 min by settings | Latest 32K only: 22–35 of 40 kept the rules, 0/7 right |
| The same task through a separate agent program that manages nothing itself | 40/40, 40/40, 7/7; 31–33 min | Whole history in a 262K window: same score; 55 min, 29.9M tokens read |
| 228 questions about things said up to a million tokens earlier | 226/228; 50 min | 200K window: 166/228, all 29 rule questions wrong; 228 min |
| Two million tokens, hostile: forged notices and quiet corrections of old entries planted in the stream | Both seeds: 421/423 and 417/423; 16/16 corrections applied on both, every forged line in the notes flagged, no forged value, method, rule or removal ever adopted. Two of 97 forgery-target answers slipped on silent arithmetic while the notes held the right value, so the strictest preregistered bar is not claimed. | Not run at this length |
Release-gated: 1.2.0 was installed from the public release exactly as shown above, then ran the repair task (40/40, 7/7), the 300K demo through the Docker image (4/4), the SDK example (plain, tool call, streaming) and a 100K Gemma check (4/4) — lab campaign 50. One model, one machine; the notes are written by the model and can be wrong.
Which model do I need?
- Measured on Qwen3.8-27B (FP8 on two B70 cards). One card is enough: the repair task scored the same in 21 minutes.
- A quick check on a second family, Gemma 4 26B (Q8, llama.cpp), passed the demo 4 of 4. Other models need checking with your task: they must call tools reliably, keep the notes format, and fit the working view plus server overhead.
- Let the model keep its own notes. A separate smaller keeper model was worse and slower (19 of 39 vs 39/39 on the 240K test): it reads every turn afresh instead of reusing the main model’s cache.
With your agent
ctxkeeper manages Chat Completions requests from clients that resend their full history:
- Use Chat Completions (
/v1/chat/completions). Other endpoints, including Responses, pass through without context management. - Send the whole conversation each time. Turn off the agent’s own history trimming and summarizing. If earlier messages disappear or change, ctxkeeper may treat it as a different conversation.
- Request one reply at a time (
n=1). Streaming is accepted, but the answer arrives in one piece at the end.
If your client supports custom headers, send a unique X-Ctx-Session value per conversation and keep it on every
call, including after a restart. Otherwise ctxkeeper identifies conversations by their model and opening messages; identical
openings can collide. The OpenAI SDK works as-is (api_key="unused" placeholder); a
client example
is in the guide. For new instructions inside tool results, such as tickets or files, --recite-when '(?m)^TICKET \d+'
repeats recorded rules after matching messages.
Tested with 12 coding agents
Twelve open-source coding agents ran through ctxkeeper on the bug-fixing task above, each as it ships (history trimming off). One run each, an hour at most, sorted by time.
| Agent | Bugs fixed | Kept every rule | Answers right | Time |
|---|---|---|---|---|
| mini-swe-agent | 40 | 40 | 7 | 14 min |
| Open Interpreter | 40 | 39 | 7 | 18 min |
| Cline | 40 | 40 | 7 | 24 min |
| Goose | 40 | 40 | 7 | 24 min |
| OpenHands | 40 | 40 | 6 | 24 min |
| Mistral Vibe | 40 | 40 | 7 | 26 min |
| Hermes Agent | 40 | 40 | 7 | 26 min |
| pi | 39 | 39 | 0 | 28 min |
| OpenCode | 40 | 40 | 7 | 33 min |
| Qwen Code | 40 | 39 | 7 | 33 min |
| Kimi Code | 40 | 40 | 7 | 38 min |
| ForgeCode | 25 | 25 | not reached | 60 min, out of time |
Out of 40 bugs and 7 questions. The lab’s own simple agent, for comparison: 40, 39, 7 in 21 min. pi wrote its 7 answers and then deleted them, because a wrong line in its notes said the questions had never been asked (see Limits). ForgeCode was still fixing bugs correctly when its hour ran out. Running the agents found four ways their requests differed from what ctxkeeper expected, such as sending two opening instructions instead of one; version 1.0.1 handles all four.
Settings
A recipe is a set of options that were measured together; any option you give still wins. Both recipes use a 32K working view, about the fastest size found:
| Recipe | Use it for | Measured on the repair task |
|---|---|---|
--recipe agent | Servers accepting the Chat Completions and tool-call format above | 40/40 clean, 7/7; 36 to 38 min |
--recipe qwen | Qwen3 behind vLLM | 40/40 clean, 7/7; 16 min |
Measured working-view sizes
| Working view | 240K-token question stream | Repair task |
|---|---|---|
| 8K | 39/39; 40 min | not run |
| 12K | 39/39; 24 min | 40 fixed, 38 kept the rules; 30 min |
| 16K | 39/39; 10 min | 40/40, 7/7; 35 min |
| 24K | 38/39; 9 min | 40/40, 7/7; 13 min |
| 32K | 39/39; 9 min | 40/40, 7/7; 16 min |
| 48K | 39/39; 8 min | 40/40, 7/7; 23 min |
| 64K | 39/39; 10 min | not run |
One run each; repair times swing with how long the model thinks. Below 16K the notes no longer fit
beside the newest turns, so every cut rewrote them in full; with --inplace-fit they fit, and 8K took 13 minutes and
12K 10. A bigger view is slower because the model reads more on every turn.
Limits, stated
- The notes are written by the model, so they can be wrong. The originals stay archived and searchable, but nothing forces the model to look. In one agent test a wrong notes line said seven questions had never been asked, and the agent deleted answers it had already written.
- Silent arithmetic slips exist. Two 2M-seed answers mis-added while the notes held the right value; the arithmetic check only catches wrong working it can see.
- No login; state is plain text on the machine running it. Bind to localhost (the commands above do). The Docker default binds to all interfaces — keep the explicit
--host 127.0.0.1if you change the run command. - The opening instructions are always kept, so they must fit well inside the working view (default 32,768 tokens).
Evidence and source
- Release 1.2.0Package, source archive, program files, demo, SHA-256 sums. Public domain.
- Full guideEvery option, the status page, where state is kept, how to run the tests.
- 2M hostile auditsHash-bound seed receipts behind the two-million-token row.
- The research trailEvery campaign that shaped the defaults, including what failed.