fix: raise bootstrap file default limit

This commit is contained in:
Peter Steinberger
2026-06-01 04:02:43 +01:00
parent f879e3d6a0
commit 6deded6698
12 changed files with 79 additions and 22 deletions

View File

@@ -99,7 +99,7 @@ These are the standard files OpenClaw expects inside the workspace:
</AccordionGroup>
<Note>
If any bootstrap file is missing, OpenClaw injects a "missing file" marker into the session and continues. Large bootstrap files are truncated when injected; adjust limits with `agents.defaults.bootstrapMaxChars` (default: 12000) and `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `openclaw setup` can recreate missing defaults without overwriting existing files.
If any bootstrap file is missing, OpenClaw injects a "missing file" marker into the session and continues. Large bootstrap files are truncated when injected; adjust limits with `agents.defaults.bootstrapMaxChars` (default: 20000) and `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `openclaw setup` can recreate missing defaults without overwriting existing files.
</Note>
## What is NOT in the workspace

View File

@@ -122,7 +122,7 @@ By default, OpenClaw injects a fixed set of workspace files (if present):
- `HEARTBEAT.md`
- `BOOTSTRAP.md` (first-run only)
Large files are truncated per-file using `agents.defaults.bootstrapMaxChars` (default `12000` chars). OpenClaw also enforces a total bootstrap injection cap across files with `agents.defaults.bootstrapTotalMaxChars` (default `60000` chars). `/context` shows **raw vs injected** sizes and whether truncation happened.
Large files are truncated per-file using `agents.defaults.bootstrapMaxChars` (default `20000` chars). OpenClaw also enforces a total bootstrap injection cap across files with `agents.defaults.bootstrapTotalMaxChars` (default `60000` chars). `/context` shows **raw vs injected** sizes and whether truncation happened.
When truncation occurs, the runtime can inject an in-prompt warning block under Project Context. Configure this with `agents.defaults.bootstrapPromptTruncationWarning` (`off`, `once`, `always`; default `always`).

View File

@@ -208,7 +208,7 @@ because of the bootstrap file limits below.
</Note>
Large files are truncated with a marker. The max per-file size is controlled by
`agents.defaults.bootstrapMaxChars` (default: 12000). Total injected bootstrap
`agents.defaults.bootstrapMaxChars` (default: 20000). Total injected bootstrap
content across files is capped by `agents.defaults.bootstrapTotalMaxChars`
(default: 60000). Missing files inject a short missing-file marker. When truncation
occurs, OpenClaw can inject a concise system-prompt warning notice; control this with

View File

@@ -103,11 +103,11 @@ Per-agent override: `agents.list[].contextInjection`. Omitted values inherit
### `agents.defaults.bootstrapMaxChars`
Max characters per workspace bootstrap file before truncation. Default: `12000`.
Max characters per workspace bootstrap file before truncation. Default: `20000`.
```json5
{
agents: { defaults: { bootstrapMaxChars: 12000 } },
agents: { defaults: { bootstrapMaxChars: 20000 } },
}
```
@@ -138,7 +138,7 @@ injection behavior from the shared defaults. Omitted fields inherit from
agents: {
defaults: {
contextInjection: "continuation-skip",
bootstrapMaxChars: 12000,
bootstrapMaxChars: 20000,
bootstrapTotalMaxChars: 60000,
},
list: [

View File

@@ -631,6 +631,48 @@ lives on the [First-run FAQ](/help/faq-first-run).
</Accordion>
<Accordion title="Can I make SOUL.md bigger?">
Yes. `SOUL.md` is one of the workspace bootstrap files injected into the
agent context. The default per-file injection limit is `20000` characters,
and the total bootstrap budget across files is `60000` characters.
Change the shared defaults in your OpenClaw config:
```json5
{
agents: {
defaults: {
bootstrapMaxChars: 50000,
bootstrapTotalMaxChars: 300000,
},
},
}
```
Or override one agent:
```json5
{
agents: {
list: [
{
id: "main",
bootstrapMaxChars: 50000,
bootstrapTotalMaxChars: 300000,
},
],
},
}
```
Use `/context` to check raw vs injected sizes and whether truncation happened.
Keep `SOUL.md` focused on voice, stance, and personality; put operating rules
in `AGENTS.md` and durable facts in memory.
See [Context](/concepts/context) and [Agent config](/gateway/config-agents).
</Accordion>
<Accordion title="Recommended backup strategy">
Put your **agent workspace** in a **private** git repo and back it up somewhere
private (for example GitHub private). This captures memory + AGENTS/SOUL/USER

View File

@@ -20,7 +20,7 @@ OpenClaw assembles its own system prompt on every run. It includes:
prompt surface. It is bounded by `skills.limits.maxSkillsPromptChars`, with
optional per-agent override at `agents.list[].skillsLimits.maxSkillsPromptChars`.
- Self-update instructions
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus `MEMORY.md` when present). Native Codex turns do not paste raw `MEMORY.md` from the configured agent workspace when memory tools are available for that workspace; they include a small memory pointer in turn-scoped collaboration developer instructions and use memory tools on demand. If tools are disabled, memory search is unavailable, or the active workspace differs from the agent memory workspace, `MEMORY.md` uses the normal bounded turn-context path. Lowercase root `memory.md` is not injected; it is legacy repair input for `openclaw doctor --fix` when paired with `MEMORY.md`. Large injected files are truncated by `agents.defaults.bootstrapMaxChars` (default: 12000), and total bootstrap injection is capped by `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `memory/*.md` daily files are not part of the normal bootstrap prompt; they remain on-demand via memory tools on ordinary turns, but reset/startup model runs can prepend a one-shot startup-context block with recent daily memory for that first turn. Bare chat `/new` and `/reset` commands are acknowledged without invoking the model. The startup prelude is controlled by `agents.defaults.startupContext`. Post-compaction AGENTS.md excerpts are separate and require explicit `agents.defaults.compaction.postCompactionSections` opt-in.
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus `MEMORY.md` when present). Native Codex turns do not paste raw `MEMORY.md` from the configured agent workspace when memory tools are available for that workspace; they include a small memory pointer in turn-scoped collaboration developer instructions and use memory tools on demand. If tools are disabled, memory search is unavailable, or the active workspace differs from the agent memory workspace, `MEMORY.md` uses the normal bounded turn-context path. Lowercase root `memory.md` is not injected; it is legacy repair input for `openclaw doctor --fix` when paired with `MEMORY.md`. Large injected files are truncated by `agents.defaults.bootstrapMaxChars` (default: 20000), and total bootstrap injection is capped by `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `memory/*.md` daily files are not part of the normal bootstrap prompt; they remain on-demand via memory tools on ordinary turns, but reset/startup model runs can prepend a one-shot startup-context block with recent daily memory for that first turn. Bare chat `/new` and `/reset` commands are acknowledged without invoking the model. The startup prelude is controlled by `agents.defaults.startupContext`. Post-compaction AGENTS.md excerpts are separate and require explicit `agents.defaults.compaction.postCompactionSections` opt-in.
- Time (UTC + user timezone)
- Reply tags + heartbeat behavior
- Runtime metadata (host/OS/model/thinking)

View File

@@ -634,11 +634,11 @@ describe("makeBootstrapWarn", () => {
warn: (message) => warnings.push(message),
});
warn?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
warn?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
warn?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
warn?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
expect(warnings).toEqual([
"workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating (sessionKey=agent:main:test-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating (sessionKey=agent:main:test-session)",
]);
});
@@ -653,12 +653,12 @@ describe("makeBootstrapWarn", () => {
warn: (message) => warnings.push(message),
});
first?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
second?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
first?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
second?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
expect(warnings).toEqual([
"workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating (sessionKey=agent:main:first-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating (sessionKey=agent:main:second-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating (sessionKey=agent:main:first-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating (sessionKey=agent:main:second-session)",
]);
});
@@ -675,12 +675,12 @@ describe("makeBootstrapWarn", () => {
warn: (message) => warnings.push(message),
});
first?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
second?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating");
first?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
second?.("workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating");
expect(warnings).toEqual([
"workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating (sessionKey=agent:main:shared-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 12000); truncating (sessionKey=agent:main:shared-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating (sessionKey=agent:main:shared-session)",
"workspace bootstrap file MEMORY.md is 36697 chars (limit 20000); truncating (sessionKey=agent:main:shared-session)",
]);
});
});

View File

@@ -85,7 +85,7 @@ export function stripThoughtSignatures<T>(
}) as T;
}
export const DEFAULT_BOOTSTRAP_MAX_CHARS = 12_000;
export const DEFAULT_BOOTSTRAP_MAX_CHARS = 20_000;
export const DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS = 60_000;
export const DEFAULT_BOOTSTRAP_PROMPT_TRUNCATION_WARNING_MODE = "always";
const MIN_BOOTSTRAP_FILE_BUDGET_CHARS = 64;

View File

@@ -101,7 +101,7 @@ describe("buildContextReply", () => {
omitBootstrapLimits: true,
}),
);
expect(result.text).toContain("Bootstrap max/file: 12,000 chars");
expect(result.text).toContain("Bootstrap max/file: 20,000 chars");
expect(result.text).toContain("Bootstrap max/total: 60,000 chars");
expect(result.text).not.toContain("Bootstrap max/file: ? chars");
});

View File

@@ -1121,7 +1121,7 @@ export const FIELD_HELP: Record<string, string> = {
"agents.defaults.contextInjection":
'Controls when workspace bootstrap files are injected into the system prompt: "always" (default) or "continuation-skip" for safe continuation turns after a completed assistant response.',
"agents.defaults.bootstrapMaxChars":
"Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 12000).",
"Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).",
"agents.defaults.bootstrapTotalMaxChars":
"Max total characters across all injected workspace bootstrap files (default: 60000).",
"agents.defaults.experimental":

View File

@@ -133,6 +133,21 @@ describe("renderQuickSettings", () => {
expect(container.querySelectorAll(".qs-card--span-all")).toHaveLength(1);
});
it("shows the current bootstrap default when config omits the explicit limit", () => {
const container = document.createElement("div");
render(renderQuickSettings(createProps({ configObject: {} })), container);
const stat = Array.from(container.querySelectorAll<HTMLElement>(".qs-profile-stat")).find(
(candidate) =>
candidate.querySelector(".qs-profile-stat__label")?.textContent?.trim() ===
"Bootstrap Per File",
);
expect(stat?.querySelector(".qs-profile-stat__value")?.textContent?.trim()).toBe(
"20,000 chars",
);
});
it("lets operators change browser and tool profile from Security quick settings", () => {
const onBrowserEnabledToggle = vi.fn();
const onToolProfileChange = vi.fn();

View File

@@ -327,7 +327,7 @@ type ProfileSettings = {
};
const DEFAULT_PROFILE_SETTINGS: ProfileSettings = {
bootstrapMaxChars: 12_000,
bootstrapMaxChars: 20_000,
bootstrapTotalMaxChars: 60_000,
contextInjection: "always",
};