openclaw - ✅(Solved) Fix Feature: prompt cache-friendly project context ordering [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#58979Fetched 2026-04-08 02:30:25
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Assignees
Timeline (top)
assigned ×1closed ×1cross-referenced ×1

PR fix notes

PR #61236: fix(cache): order stable project context before heartbeat

Description (problem / solution / changelog)

Summary

  • Problem: workspace project-context files are injected in a fixed order that leaves frequently changing files like HEARTBEAT.md on the stable side of the system-prompt cache boundary.
  • Why it matters: heartbeat churn invalidates the cached project-context prefix even when the stable workspace files did not change, which wastes prompt-cache reuse.
  • What changed: sort known workspace context files in a stable-first order during system-prompt assembly, keep stable files above the existing cache boundary, and move HEARTBEAT.md below that boundary as dynamic project context.
  • What did NOT change (scope boundary): this does not add new config, does not change bootstrap file loading/filtering, and does not try to solve arbitrary hook-injected dynamic context ordering.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Fixes #58979
  • Related #59054
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: loadWorkspaceBootstrapFiles() uses a deterministic but cache-unaware file order, and buildAgentSystemPrompt() injected every context file before the single system-prompt cache boundary.
  • Missing detection / guardrail: prompt-shape tests checked that context files were present, but not that volatile workspace files stayed below the cache boundary.
  • Contributing context (if known): the boundary rollout made this more visible because stable and dynamic prompt regions now matter more explicitly for Anthropic-family caching.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/system-prompt.test.ts
  • Scenario the test should lock in: stable workspace files render before SYSTEM_PROMPT_CACHE_BOUNDARY, while HEARTBEAT.md renders after it.
  • Why this is the smallest reliable guardrail: the bug is in prompt assembly order, so prompt-shape unit coverage is the direct seam.
  • Existing test that already covers this (if any): none specific to stable-vs-dynamic context ordering.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Stable workspace project-context files keep a longer reusable cache prefix, while HEARTBEAT.md no longer invalidates that prefix every turn.

Diagram (if applicable)

Before:
[AGENTS][SOUL][TOOLS][IDENTITY][USER][HEARTBEAT][BOOTSTRAP][MEMORY][CACHE BOUNDARY][dynamic extras]

After:
[AGENTS][SOUL][IDENTITY][USER][TOOLS][BOOTSTRAP][MEMORY][CACHE BOUNDARY][HEARTBEAT][dynamic extras]

Security Impact (required)

  • 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)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local OpenClaw workspace
  • Model/provider: prompt assembly only
  • Integration/channel (if any): N/A
  • Relevant config (redacted): default local test config

Steps

  1. Build a system prompt with stable context files plus HEARTBEAT.md.
  2. Inspect prompt ordering around SYSTEM_PROMPT_CACHE_BOUNDARY.
  3. Confirm stable files stay above the boundary and HEARTBEAT.md lands below it.

Expected

  • Stable project-context prefix remains reusable across heartbeat churn.

Actual

  • This branch keeps stable files before the boundary and places HEARTBEAT.md after it.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: touched-file lint/format checks; direct prompt-shape sanity check confirming stable files precede the cache boundary and HEARTBEAT.md follows it.
  • Edge cases checked: heartbeat-only context still renders correctly under the regular project-context heading.
  • What you did not verify: a trustworthy local pnpm test -- src/agents/system-prompt.test.ts run, because the wrapper pulled in an unrelated current-main plugin-sdk-package-contract-guardrails failure.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: some users may implicitly rely on the old project-context ordering.
    • Mitigation: the change is limited to stable-vs-dynamic ordering of known workspace files, and tests lock the new prompt shape.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/system-prompt.test.ts (modified, +49/-0)
  • src/agents/system-prompt.ts (modified, +94/-21)

Code Example

System prompt structure:
├── [1] Core instructions (OpenClaw runtime, tool definitions)  ← rarely changes
├── [2] SOUL.md, IDENTITY.md                                    ← rarely changes
├── [3] USER.md                                                  ← rarely changes
├── [4] AGENTS.md, TOOLS.md                                      ← changes occasionally
├── [5] MEMORY.md (if loaded)                                    ← changes periodically
├── [6] Skills (available_skills block)                          ← changes on install/update
├── [7] ── DYNAMIC BOUNDARY ──
├── [8] active_context.md                                        ← changes frequently
├── [9] HEARTBEAT.md                                             ← changes every heartbeat
└── [10] Runtime metadata (session info, time, etc.)             ← changes every turn
RAW_BUFFERClick to expand / collapse

Motivation

Anthropic's prompt caching (and similar mechanisms from other providers) works by caching the system prompt from the beginning — the longer the matching prefix, the higher the cache hit rate and the greater the cost savings.

Currently, OpenClaw injects project context files (SOUL.md, USER.md, IDENTITY.md, AGENTS.md, TOOLS.md, HEARTBEAT.md, active_context.md, etc.) into the system prompt, but the ordering is not optimized for caching. If a frequently-changing file like HEARTBEAT.md or active_context.md appears early in the system prompt, it invalidates the cache prefix on every session — even though the stable files (SOUL.md, IDENTITY.md) haven't changed at all.

For heavy users, this can mean thousands of uncached prompt tokens per turn that could have been cached, directly impacting cost and latency.

Proposed Solution

1. Order project context by volatility

Inject project context files in a stable-first, volatile-last order:

System prompt structure:
├── [1] Core instructions (OpenClaw runtime, tool definitions)  ← rarely changes
├── [2] SOUL.md, IDENTITY.md                                    ← rarely changes
├── [3] USER.md                                                  ← rarely changes
├── [4] AGENTS.md, TOOLS.md                                      ← changes occasionally
├── [5] MEMORY.md (if loaded)                                    ← changes periodically
├── [6] Skills (available_skills block)                          ← changes on install/update
├── [7] ── DYNAMIC BOUNDARY ──
├── [8] active_context.md                                        ← changes frequently
├── [9] HEARTBEAT.md                                             ← changes every heartbeat
└── [10] Runtime metadata (session info, time, etc.)             ← changes every turn

Everything above the dynamic boundary benefits from prompt caching across turns and sessions.

2. SYSTEM_PROMPT_DYNAMIC_BOUNDARY marker (optional)

Allow users to place a <!-- SYSTEM_PROMPT_DYNAMIC_BOUNDARY --> marker in their workspace config or a dedicated config file. Files listed before the boundary are treated as "stable prefix"; files after are "volatile suffix."

This gives power users explicit control over cache optimization without requiring them to understand the internals.

3. Configuration option

Add a config option (e.g., projectContext.ordering: "cache-optimized" | "alphabetical" | "custom") so this behavior is opt-in and doesn't break existing setups.

Technical Notes

  • Anthropic's prompt caching charges 25% of base input cost for cache writes and 10% for cache reads. A stable 4K-token prefix that hits cache saves ~90% on those tokens every turn.
  • The ordering should be deterministic — same files in the same order every time, so the cache prefix is stable.
  • File content hashing could be used to detect which files actually changed, placing unchanged files earlier even if they're typically "volatile."
  • This optimization is provider-specific but the ordering heuristic (stable-first) is generally beneficial for any caching system.

Alternatives Considered

AlternativeWhy not
Cache at the application layer (hash and store rendered prompts)Doesn't leverage provider-side caching discounts; adds storage complexity
Exclude volatile files from system prompt entirelyLoses valuable context; HEARTBEAT.md and active_context.md serve important purposes
Let users manually order filesToo much burden on users; most won't understand prompt caching mechanics
Only cache the instruction prefix, load all project files as user messagesChanges the prompt structure significantly; may affect model behavior

extent analysis

TL;DR

Reorder project context files to prioritize stable files first, followed by volatile files, to optimize prompt caching and reduce costs.

Guidance

  • Implement a deterministic ordering of project context files, placing stable files like SOUL.md and IDENTITY.md before volatile files like HEARTBEAT.md and active_context.md.
  • Consider adding a SYSTEM_PROMPT_DYNAMIC_BOUNDARY marker to allow users to customize the cache optimization boundary.
  • Introduce a configuration option, such as projectContext.ordering, to enable cache-optimized ordering while maintaining backwards compatibility.

Example

// Example system prompt structure with stable-first ordering
System prompt structure:
├── [1] Core instructions (OpenClaw runtime, tool definitions)
├── [2] SOUL.md, IDENTITY.md
├── [3] USER.md
├── [4] AGENTS.md, TOOLS.md
├── [5] MEMORY.md (if loaded)
├── [6] Skills (available_skills block)
├── [7] ── DYNAMIC BOUNDARY ──
├── [8] active_context.md
├── [9] HEARTBEAT.md
└── [10] Runtime metadata (session info, time, etc.)

Notes

The proposed solution is provider-specific, but the stable-first ordering heuristic can be beneficial for any caching system. File content hashing can be used to detect changes and further optimize the cache prefix.

Recommendation

Apply the proposed solution by reordering project context files and introducing a configuration option to enable cache-optimized ordering, as this approach leverages provider-side caching discounts and minimizes storage complexity.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING