Context
ContextBuilder (nanobot/agent/context.py) caps the self-evolving loop's executor system prompt at MAX_SYSTEM_PROMPT_CHARS = 24000 characters, with per-block caps in _RELEASE_BLOCK_CAPS and BOOTSTRAP_FILES: IDENTITY.md 1,500, SOUL.md 1,800, goals.md 3,200, USER.md 4,000, OPERATING.md 5,000, workspace AGENTS.md 4,000, plus a memory block (1,000) and a generated runtime block (400). Over the cap, the strict (loop) profile drops sections marked droppable and then raises SystemPromptOverflowError.
Measured on the host 2026-09-18, a representative cycle's phase: "system_prompt" ledger row:
{"chars": 21368, "cap": 24000, "rung": "full", "dropped": [], "missing": [],
"sections": {"identity":1244,"soul":1590,"goals":3040,"user":1878,"operating":4335,
"agents":3989,"skills_catalogue":4022,"memory":824,"runtime":390},
"droppable_reserve_chars": 0, "truncated": ["AGENTS.md"]}
The prompt sits at 89% of the cap with zero droppable reserve, and one block is being truncated every cycle.
Problem
The cap is stated in characters and its value has no recorded derivation. At ~3.5 chars/token for this corpus, 24,000 chars is ≈6,100 tokens — while the serving model, un/qwen3.8-27b-gguf (llama-server on the operator's workstation, per T:/Code/localllm-kb), has a 98,304-token context with q8_0 KV and a LiteLLM route max_tokens of 32,768. The cap is not protecting a scarce resource at the value it holds; it is squeezing the one part of the prompt that is authored deliberately, while leaving no reserve for growth.
The naive correction — "make it 24,000 tokens" — is wrong for a different reason. The system prompt is a prefix resent on every turn of an agentic cycle that runs up to 80 tool iterations, so every character added to it is added to every later request in the cycle. Executor prompt_tokens over 1,867 calls (2026-09-16..18, state/llm_calls):
| min |
p50 |
p90 |
p99 |
max |
| 7,099 |
33,080 |
62,154 |
71,672 |
79,804 |
(finish_reason: "length" on 19 of 1,867 calls, 1.0%.) The max already stands at 81% of the window. A 24,000-token system prompt would add ~18,000 tokens to every one of those figures and push the tail past the context window mid-cycle.
What to do
- Raise
MAX_SYSTEM_PROMPT_CHARS from 24,000 to 35,000 (≈10,000 tokens at the measured ratio). Derivation, to be written into the code as a comment beside the constant and kept with the number:
- window 98,304 tokens;
- observed max in-cycle prompt 79,804 tokens with the present ~6,100-token prefix;
- a prefix grown to ~10,000 tokens moves that max to ≈83,700, leaving ≈14,600 tokens of headroom for completion and variance.
- Raise the per-block caps that the deduplicated content needs: workspace
AGENTS.md 4,000 → 8,000 and OPERATING.md 5,000 → 8,000. Leave the others unless the block is measurably being truncated.
- Keep the unit of enforcement as characters — there is no tokenizer on the i386 host, and all existing fit arithmetic, telemetry and tests are in characters. State the budget in tokens in the comment, enforce in chars, and name the chars/token ratio the number was derived from.
- Restore a real droppable reserve: after the raise, the assembled prompt should leave ≥3,000 chars of reserve so a growing block degrades instead of raising
SystemPromptOverflowError.
- Re-derive the ratio from production once
system_prompt_chars is being written to llm_calls rows (that column exists and is currently null; it is populated by the pending role-prompt work). Until then the 3.5 chars/token figure is an estimate corroborated by the 7,099-token minimum observed at turn 1.
Order matters: this issue is to be done after the AGENTS.md deduplication, not before. Deduplication frees ~5,400 chars at no cost to the context window; raising the cap first buys window space for text that is about to be deleted.
Acceptance Criteria
MAX_SYSTEM_PROMPT_CHARS is 35,000 and carries an in-code derivation naming the context window (98,304), the observed max in-cycle prompt, and the chars/token ratio used.
- Workspace
AGENTS.md and OPERATING.md block caps are 8,000 each; every other block cap is unchanged or changed with its own stated reason.
- Over 50 consecutive cycles after deployment, ledger
phase: "system_prompt" rows show rung: "full", truncated: [], dropped: [], and droppable_reserve_chars >= 3000.
- Over the same window, executor
prompt_tokens p99 in state/llm_calls is ≤ 85,000 and finish_reason: "length" is not more frequent than the 1.0% baseline measured 2026-09-16..18.
- Existing overflow tests still pass, including the strict-profile
SystemPromptOverflowError path; no test is relaxed to accommodate the new cap.
- Full
pytest run passes.
Non-goals
- Introducing a tokenizer or token-based enforcement on the host.
- Changing the assembly order, the block list, or the degradation ladder.
- Changing the LiteLLM route's
max_tokens.
Context
ContextBuilder(nanobot/agent/context.py) caps the self-evolving loop's executor system prompt atMAX_SYSTEM_PROMPT_CHARS = 24000characters, with per-block caps in_RELEASE_BLOCK_CAPSandBOOTSTRAP_FILES:IDENTITY.md1,500,SOUL.md1,800,goals.md3,200,USER.md4,000,OPERATING.md5,000, workspaceAGENTS.md4,000, plus a memory block (1,000) and a generated runtime block (400). Over the cap, the strict (loop) profile drops sections marked droppable and then raisesSystemPromptOverflowError.Measured on the host 2026-09-18, a representative cycle's
phase: "system_prompt"ledger row:{"chars": 21368, "cap": 24000, "rung": "full", "dropped": [], "missing": [], "sections": {"identity":1244,"soul":1590,"goals":3040,"user":1878,"operating":4335, "agents":3989,"skills_catalogue":4022,"memory":824,"runtime":390}, "droppable_reserve_chars": 0, "truncated": ["AGENTS.md"]}The prompt sits at 89% of the cap with zero droppable reserve, and one block is being truncated every cycle.
Problem
The cap is stated in characters and its value has no recorded derivation. At ~3.5 chars/token for this corpus, 24,000 chars is ≈6,100 tokens — while the serving model,
un/qwen3.8-27b-gguf(llama-server on the operator's workstation, perT:/Code/localllm-kb), has a 98,304-token context with q8_0 KV and a LiteLLM routemax_tokensof 32,768. The cap is not protecting a scarce resource at the value it holds; it is squeezing the one part of the prompt that is authored deliberately, while leaving no reserve for growth.The naive correction — "make it 24,000 tokens" — is wrong for a different reason. The system prompt is a prefix resent on every turn of an agentic cycle that runs up to 80 tool iterations, so every character added to it is added to every later request in the cycle. Executor
prompt_tokensover 1,867 calls (2026-09-16..18,state/llm_calls):(
finish_reason: "length"on 19 of 1,867 calls, 1.0%.) The max already stands at 81% of the window. A 24,000-token system prompt would add ~18,000 tokens to every one of those figures and push the tail past the context window mid-cycle.What to do
MAX_SYSTEM_PROMPT_CHARSfrom 24,000 to 35,000 (≈10,000 tokens at the measured ratio). Derivation, to be written into the code as a comment beside the constant and kept with the number:AGENTS.md4,000 → 8,000 andOPERATING.md5,000 → 8,000. Leave the others unless the block is measurably being truncated.SystemPromptOverflowError.system_prompt_charsis being written tollm_callsrows (that column exists and is currentlynull; it is populated by the pending role-prompt work). Until then the 3.5 chars/token figure is an estimate corroborated by the 7,099-token minimum observed at turn 1.Order matters: this issue is to be done after the
AGENTS.mddeduplication, not before. Deduplication frees ~5,400 chars at no cost to the context window; raising the cap first buys window space for text that is about to be deleted.Acceptance Criteria
MAX_SYSTEM_PROMPT_CHARSis 35,000 and carries an in-code derivation naming the context window (98,304), the observed max in-cycle prompt, and the chars/token ratio used.AGENTS.mdandOPERATING.mdblock caps are 8,000 each; every other block cap is unchanged or changed with its own stated reason.phase: "system_prompt"rows showrung: "full",truncated: [],dropped: [], anddroppable_reserve_chars >= 3000.prompt_tokensp99 instate/llm_callsis ≤ 85,000 andfinish_reason: "length"is not more frequent than the 1.0% baseline measured 2026-09-16..18.SystemPromptOverflowErrorpath; no test is relaxed to accommodate the new cap.pytestrun passes.Non-goals
max_tokens.