#22220: feat(bootstrap): cache session's bootstrap files so we don't invalidate prompt cache when modifying MEMORY and friends
gateway
agents
size: S
## Summary
- **Problem:** Bootstrap files (SOUL.md, AGENTS.md, MEMORY.md, etc.) are re-read from disk on every agent turn. Memory flush itself writes new content to `memory/YYYY-MM-DD.md`. If these files are modified they will bust the cache.
- **Why it matters:** Each prefix cache miss forces full prompt re-processing on every subsequent turn. Local models feel this significantly. Additionally, a lot of the time we modify these files, we're writing out lessons learned from a long context life. Not a great time to invalidate the cache.
- **What changed:** New `bootstrap-cache.ts` module snapshots bootstrap files on first load per session key. All subsequent calls within the same session — including compaction's `resolveBootstrapContextForRun()` and the memory flush sub-run — return the snapshot instead of re-reading disk.
- **What did NOT change:** Memory flush still writes to disk normally (available to next session). Post-compaction context (`readPostCompactionContext`) still reads AGENTS.md fresh from disk — intentional, it's re-orienting the agent after compaction, and we're already busting the cache pretty hard. No config changes, no new hooks, no changes to the hook system.
This change was mostly planned by Opus and executed by Sonnet, and then the human went and told them to delete 2/3 of what they wrote, so, at this point, it's her problem, not theirs.
## Change Type
- [ ] Bug fix
- [x] Feature
- [x] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [x] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
## User-visible / Behavior Changes
Memory written during a session (via memory flush or tool calls to `memory/*.md`) will not appear in the system prompt until the next session. Neither will anything written to SOUL, AGENTS, etc.
Additionally, models all seem to think this stuff doesn't update live. For example, just in this section alone I had to delete a line the model wrote about how it "was already true in most cases." It's uncanny.
Anyway, if you think about it, right now (before this change), when we ask a model to write something in one of these files, we're then killing that context and replacing it with one where it always thought that. It must be very weird to read a conversation about something you know the ending of already.
## Security Impact
- New permissions/capabilities? No
- Secrets/tokens handling changed? No
- New/changed network calls? No
- Command/tool execution surface changed? No
- Data access scope changed? No
## Repro + Verification
Locally tested before/after and validated that caching behavior is much nicer when working with memory documents.
### Environment
- OS: Linux (Debian)
- Runtime/container: Node.js
- Model/provider: Anthropic (claude-* models with prefix caching)
- Integration/channel: any
- Relevant config: default
### Steps
1. Work in a long session.
2. Ask the agent to modify its memory.
3. Send another message.
### Expected
- System prompt same in this session for next turn
### Actual (before this PR)
- System prompt changed (updated MEMORY) so cache is invalidated
## Evidence
- [x] Perf numbers (if relevant)
100% cache hit rate after mod of memory, well worth it especially on local.
## Human Verification
- Verified scenarios: cache serves stable content across multiple calls with same session key; different session keys are isolated; long haul test doesn't leak memory all over the floor
- Edge cases checked: restart of gateway with pending change causes cache invalidation (expected result; not a regression from today's behavior anyway)
- What you did **not** verify: Massively parallel long sessions. But I have done a couple shorter parallel ones.
## Compatibility / Migration
- Backward compatible? Yes
- Config/env changes? No
- Migration needed? No
## Failure Recovery
- How to disable/revert this change quickly: revert `bootstrap-files.ts` to use `loadWorkspaceBootstrapFiles()` directly (one line)
- Files/config to restore: `src/agents/bootstrap-files.ts`
- Known bad symptoms to watch for: The initial onboarding experience might get weird.
## Risks and Mitigations
- Risk: Cache entries accumulate in long-running processes with many sessions
- Mitigation: None currently. A previous version had a TTL system but this was discarded in favor of simplicity. If the sessions leave memory then so do the cache entries, and we delete the cache when we reset a session or delete it too.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Implements session-scoped caching for bootstrap files (`AGENTS.md`, `MEMORY.md`, `SOUL.md`, etc.) to preserve prompt cache when these files are modified during a session.
**Key changes:**
- New `bootstrap-cache.ts` module provides simple Map-based caching keyed by `sessionKey`
- `resolveBootstrapFilesForRun` in `bootstrap-files.ts` uses cached files when `sessionKey` is provided
- Cache is cleared in `sessions.ts` during session reset/delete via `clearBootstrapSnapshot`
- Post-compaction context (`readPostCompactionContext`) continues to read `AGENTS.md` fresh from disk, as mentioned in PR description
**Impact:**
- Memory writes during a session (e.g., via memory flush) will not appear in the system prompt until the next session
- Maintains 100% cache hit rate after memory modifications within a session
- Memory accumulates in the cache Map for the lifetime of the gateway process, cleared only on session reset/delete
<h3>Confidence Score: 4/5</h3>
- Safe to merge with careful monitoring of cache behavior in production
- Implementation is clean and straightforward with good test coverage. The cache invalidation is properly wired to session lifecycle events (reset/delete). However, the cache uses only `sessionKey` without `workspaceDir`, which relies on the assumption that a session key is always bound to a single workspace - this was an intentional simplification per commit de20b013. The PR explicitly documents the behavior change where memory modifications won't appear until next session. One minor concern is long-running processes with many sessions could accumulate cache entries, but the PR acknowledges this and notes that cache entries are cleared when sessions are deleted or reset.
- No files require special attention - implementation is clean and well-tested
<sub>Last reviewed commit: aa82281</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#20267: feat: workspace-aware post-compaction context
by nickjlamb · 2026-02-18
79.6%
#8919: Pr/memory flush improvements
by shortbus · 2026-02-04
78.7%
#23639: fix(agents): stop re-resizing session history images on every turn ...
by yinghaosang · 2026-02-22
77.8%
#10591: feat(hooks): add session-start-memory bundled hook
by morningstar-daemon · 2026-02-06
77.2%
#13877: perf: Comprehensive performance optimizations - caching, model rout...
by trevorgordon981 · 2026-02-11
77.2%
#20148: fix(memory): persist session dirty state and fix reindex gate
by togotago · 2026-02-18
76.7%
#5343: fix(memoryFlush): correct context token accounting for flush gating
by jarvis-medmatic · 2026-01-31
76.6%
#8900: fix: improve default memory flush prompts with urgency and specifics
by joetomasone · 2026-02-04
76.5%
#6060: feat(onboarding): add Memory Optimization step to onboarding wizard
by GodsBoy · 2026-02-01
76.5%
#14576: Fix/memory loss bugs
by ENCHIGO · 2026-02-12
76.3%