Bug type
Behavior bug
Beta release blocker
No
Summary
With contextInjection: "always", the bootstrapFiles array is not reset between turns. Hooks that inject files into bootstrapFiles on the agent:bootstrap event cause the array to grow cumulatively — one duplicate per turn — bloating the system prompt, polluting instructions, and breaking LLM provider prompt cache on every turn.
Steps to reproduce
- Enable
contextInjection: "always" (or leave default)
- Install or register an
agent:bootstrap hook that pushes a virtual file to event.context.bootstrapFiles
- Example hook (
~/.openclaw/hooks/example/handler.js):
const handler = async (event) => {
if (event.type !== 'agent' || event.action !== 'bootstrap') return;
if (Array.isArray(event.context.bootstrapFiles)) {
event.context.bootstrapFiles.push({
path: 'EXAMPLE_VIRTUAL.md',
content: 'Example content',
virtual: true,
});
}
};
module.exports = handler;
- Enable
diagnostics.cacheTrace in openclaw.json and restart
- Have a multi-turn conversation (4+ turns)
- Check cache-trace logs: each turn's system prompt grows by one copy of the virtual file
Expected behavior
Expected behavior
In contextInjection: "always" mode, each turn's agent:bootstrap event should receive a fresh bootstrapFiles array (only containing the current turn's resolved workspace files). Hooks can safely push virtual files without worrying about accumulation.
Actual behavior
Actual behavior
bootstrapFiles array grows cumulatively — Turn N contains N copies of the hook's virtual file. This causes:
- System prompt prefix grows ~19 lines (706 bytes) per turn per virtual-file hook
- LLM provider prompt cache prefix mismatch on every turn (cache miss)
- Wasted tokens proportional to conversation length
OpenClaw version
OpenClaw version
2026.4.15
Operating system
Operating system
Ubuntu 24.04 on WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2 x64)
Install method
Install method
npm global
Model
Model
zai/glm-5-turbo (also reproducible with any model — it's a framework-level bug)
Provider / routing chain
Provider / routing chain
openclaw -> zai (智谱 GLM API)
Logs, screenshots, and evidence
Logs, screenshots, and evidence
Debug method: cache trace + prefix diff
Enabled diagnostics.cacheTrace with includeSystem: true, collected 4 turns of data, then compared system prompt prefixes before <!-- OPENCLAW_CACHE_BOUNDARY -->.
import json
turns = []
with open('cache-trace-frozen.jsonl') as f:
for line in f:
r = json.loads(line)
if r.get('stage') == 'session:loaded':
turns.append(r['system'])
for i, t in enumerate(turns):
pre = t.split('<!-- OPENCLAW_CACHE_BOUNDARY -->')[0]
count = pre.count('SELF_IMPROVEMENT')
print(f'Turn {i+1}: prefix={len(pre)} chars, {len(pre.split(chr(10)))} lines, virtual file ×{count}')
Results
| Turn |
Prefix chars |
Prefix lines |
Virtual file copies |
| 1 |
28,108 |
629 |
1 |
| 2 |
28,814 |
648 |
2 |
| 3 |
29,520 |
667 |
3 |
| 4 |
30,226 |
686 |
4 |
- First 618 lines are identical across all 4 turns ✅
- Difference starts at line 619: each turn inserts one more copy of the virtual file before
## Silent Replies
- Each copy is ~19 lines / 706 bytes, inserted at a fixed offset from the previous copy
System prompt structure (simplified)
L1~L599: Stable prefix (tools, skills, workspace files) — identical all turns ✅
L600: SELF_IMPROVEMENT_REMINDER.md (copy 1) ← hook virtual file
L619: SELF_IMPROVEMENT_REMINDER.md (copy 2) ← Turn 2+
L638: SELF_IMPROVEMENT_REMINDER.md (copy 3) ← Turn 3+
L657: SELF_IMPROVEMENT_REMINDER.md (copy 4) ← Turn 4+
## Silent Replies
<!-- OPENCLAW_CACHE_BOUNDARY --> ← shifts right each turn
Dynamic content (unchanged)
Hook source that triggered the issue
~/.openclaw/hooks/self-improving-agent/handler.js — the self-improving-agent bundled hook pushes a SELF_IMPROVEMENT_REMINDER.md virtual file on every agent:bootstrap event. With always mode, bootstrap fires every turn, and bootstrapFiles is not reset, causing the accumulation.
Impact and severity
Impact and severity
- Affected: All users with
contextInjection: "always" (default) who have any agent:bootstrap hook that injects files into bootstrapFiles
- Severity: Medium — does not crash but silently degrades every multi-turn session
- Frequency: Always reproducible (4/4 turns)
- Consequence:
- Prompt cache breakage: LLM provider prompt cache is invalidated every turn because the prefix changes, eliminating cache read savings entirely
- Prompt pollution: Duplicate instructions accumulate in the system prompt (1→2→3→4 copies...). The model receives increasingly redundant context, which may confuse instruction-following and dilute other system prompt sections
- Token waste: Each turn adds ~706 tokens per hook-injected file (scales with conversation length)
- In a 20-turn conversation with one hook: 20 consecutive cache misses, 20 copies of the same instruction polluting the prompt, and ~14KB wasted prefix
Additional information
Additional information
Bug type
Behavior bug
Beta release blocker
No
Summary
With
contextInjection: "always", thebootstrapFilesarray is not reset between turns. Hooks that inject files intobootstrapFileson theagent:bootstrapevent cause the array to grow cumulatively — one duplicate per turn — bloating the system prompt, polluting instructions, and breaking LLM provider prompt cache on every turn.Steps to reproduce
contextInjection: "always"(or leave default)agent:bootstraphook that pushes a virtual file toevent.context.bootstrapFiles~/.openclaw/hooks/example/handler.js):diagnostics.cacheTraceinopenclaw.jsonand restartExpected behavior
Expected behavior
In
contextInjection: "always"mode, each turn'sagent:bootstrapevent should receive a freshbootstrapFilesarray (only containing the current turn's resolved workspace files). Hooks can safely push virtual files without worrying about accumulation.Actual behavior
Actual behavior
bootstrapFilesarray grows cumulatively — Turn N contains N copies of the hook's virtual file. This causes:OpenClaw version
OpenClaw version
2026.4.15
Operating system
Operating system
Ubuntu 24.04 on WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2 x64)
Install method
Install method
npm global
Model
Model
zai/glm-5-turbo (also reproducible with any model — it's a framework-level bug)
Provider / routing chain
Provider / routing chain
openclaw -> zai (智谱 GLM API)
Logs, screenshots, and evidence
Logs, screenshots, and evidence
Debug method: cache trace + prefix diff
Enabled
diagnostics.cacheTracewithincludeSystem: true, collected 4 turns of data, then compared system prompt prefixes before<!-- OPENCLAW_CACHE_BOUNDARY -->.Results
## Silent RepliesSystem prompt structure (simplified)
Hook source that triggered the issue
~/.openclaw/hooks/self-improving-agent/handler.js— theself-improving-agentbundled hook pushes aSELF_IMPROVEMENT_REMINDER.mdvirtual file on everyagent:bootstrapevent. Withalwaysmode, bootstrap fires every turn, andbootstrapFilesis not reset, causing the accumulation.Impact and severity
Impact and severity
contextInjection: "always"(default) who have anyagent:bootstraphook that injects files intobootstrapFilesAdditional information
Additional information