Skip to content

Feature: configurable bootstrap file injection order for prompt cache optimization #65438

Description

@rosesandhello

Summary

OpenClaw splits workspace bootstrap files into "stable" (before OPENCLAW_CACHE_BOUNDARY) and "dynamic" (after) for Anthropic prompt cache optimization. Currently, only HEARTBEAT.md is classified as dynamic (DYNAMIC_CONTEXT_FILE_BASENAMES), and the injection order is hardcoded in CONTEXT_FILE_ORDER.

Operators who use additional workspace files (e.g., SESSION_HANDOFF.md, RECENT_SESSIONS.md, STATE.md) that change frequently have no way to:

  1. Mark them as dynamic so they go after the cache boundary
  2. Control the injection order for cache-prefix stability

Proposal

Option A: Config-based dynamic file list

{
  "agents": {
    "defaults": {
      "bootstrapDynamicFiles": ["SESSION_HANDOFF.md", "RECENT_SESSIONS.md"]
    }
  }
}

Files listed here would be added to DYNAMIC_CONTEXT_FILE_BASENAMES at runtime, placing them after the cache boundary.

Option B: Full injection order control

{
  "agents": {
    "defaults": {
      "bootstrapFileOrder": [
        "SOUL.md", "IDENTITY.md", "USER.md", "TOOLS.md",
        "AGENTS.md", "MEMORY.md", "BOOTSTRAP.md"
      ],
      "bootstrapDynamicFiles": ["HEARTBEAT.md", "SESSION_HANDOFF.md"]
    }
  }
}

Why this matters

With cacheRetention: "long", the stable prefix of the system prompt gets cached at 90% discount on Anthropic. Frequently-changing files that land before the boundary invalidate the cache on every change, causing full-price re-reads of the entire prefix. For deployments with large bootstrap contexts (50K+ chars), this can mean $10-30/month in unnecessary cache invalidation costs.

Current behavior (source refs)

  • CONTEXT_FILE_ORDER: hardcoded Map in system-prompt-*.js (AGENTS=10, SOUL=20, IDENTITY=30, USER=40, TOOLS=50, BOOTSTRAP=60, MEMORY=70)
  • DYNAMIC_CONTEXT_FILE_BASENAMES: hardcoded Set containing only heartbeat.md
  • isDynamicContextFile(): checks membership in the above set
  • Files not in CONTEXT_FILE_ORDER get MAX_SAFE_INTEGER priority (alphabetical tiebreak), placed before cache boundary as stable

Environment

  • OpenClaw v2026.4.11
  • Anthropic Claude Opus 4.6 with cacheRetention: "long"
  • 10 workspace bootstrap files totaling ~24KB after optimization

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions