Skip to content

Agents: move bootstrap warnings out of system prompt#48753

Merged
scoootscooob merged 3 commits intoopenclaw:mainfrom
scoootscooob:codex/bootstrap-cache-warning-body
Mar 17, 2026
Merged

Agents: move bootstrap warnings out of system prompt#48753
scoootscooob merged 3 commits intoopenclaw:mainfrom
scoootscooob:codex/bootstrap-cache-warning-body

Conversation

@scoootscooob
Copy link
Copy Markdown
Contributor

Summary

  • Problem: bootstrap truncation warning lines were injected into # Project Context inside the system prompt, which made the cached prefix change when the warning appeared or disappeared.
  • Why it matters: this reduced provider-side prompt cache reuse even though the underlying workspace bootstrap content was unchanged.
  • What changed: keep bootstrap warning visibility, but prepend the warning details to the per-turn prompt body instead of the stable system prompt prefix.
  • Tests: add regression coverage that compares legacy warning-in-system behavior against the new body-prefix behavior and asserts the cache-relevant system prompt stays stable.

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope

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

Linked Issue/PR

User-visible / Behavior Changes

  • Bootstrap truncation warnings are still shown to the model, but they now ride in the per-turn prompt body instead of mutating the system prompt.
  • The system prompt no longer gains or loses a ⚠ Bootstrap truncation warning block across turns.

Security Impact

  • New permissions/capabilities? (Yes/No): No
  • Secrets/tokens handling changed? (Yes/No): No
  • New/changed network calls? (Yes/No): No
  • Command/tool execution surface changed? (Yes/No): No
  • Data access scope changed? (Yes/No): No

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local Node 25 + pnpm
  • Model/provider: anthropic/claude-sonnet-4-5
  • Integration/channel (if any): local prompt construction + live Anthropic cache metrics

Steps

  1. Run targeted tests:
    • pnpm test -- src/agents/bootstrap-budget.test.ts src/agents/system-prompt.test.ts
  2. Run the prompt-cache investigation harness:
    • pnpm exec tsx scripts/investigate-prompt-cache.ts
  3. Run the harness with live cache logging enabled:
    • ANTHROPIC_API_KEY=... OPENCLAW_INVESTIGATE_CACHE_LIVE=1 MODEL_ID=claude-sonnet-4-5 MAX_TOKENS=16 pnpm exec tsx scripts/investigate-prompt-cache.ts

Expected

  • The bootstrap warning scenario should no longer change the system prompt after bootstrap.
  • Live cache behavior for the bootstrap warning path should shift from repeated cache writes to cache reads on later turns.

Actual

  • Targeted tests pass.
  • bootstrap-warning now reports 0 system-change turn(s) after initial bootstrap.
  • Live cache metrics improved materially for the bootstrap warning path.

Evidence

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

Cache hit-rate measurements

Bootstrap warning scenario before this change:

  • cacheRead=25854
  • cacheWrite=51602
  • cached=33%

Bootstrap warning scenario after this change:

  • cacheRead=51494
  • cacheWrite=25747
  • cached=66%

Per-turn bootstrap warning behavior before:

  • t1: write only
  • t2: write only again
  • t3: cached

Per-turn bootstrap warning behavior after:

  • t1: write only
  • t2: 99% cached
  • t3: 99% cached

Overall latest-main harness average before this fix:

  • cacheRead=35523
  • cacheWrite=63056
  • cached=36%

Overall latest-main harness average after this fix:

  • cacheRead=53124
  • cacheWrite=45234
  • cached=54%

Human Verification

  • Verified that bootstrap warning details are still visible to the model, but no longer mutate the system prompt.
  • Verified the cache-specific regression with a dedicated unit test comparing legacy and optimized prompt construction.
  • Verified live Anthropic cache metrics before/after using the same investigation harness.

Compatibility / Migration

  • Backward compatible? (Yes/No): Yes
  • Config/env changes? (Yes/No): No
  • Migration needed? (Yes/No): No

Failure Recovery

  • If this causes issues, revert this PR to restore the old warning placement.
  • Symptom to watch for: missing bootstrap warning visibility in prompt body on truncated runs.

Risks and Mitigations

  • Risk: warning text might become less salient now that it lives in the body prompt instead of the system prompt.
    • Mitigation: the prepended warning block explicitly tells the model to treat project context as partial and read files directly when needed, and tests cover the new body injection path.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S maintainer Maintainer-authored PR labels Mar 17, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 17, 2026

Greptile Summary

This PR fixes a prompt-cache degradation by moving bootstrap truncation warnings out of the stable system prompt and into the per-turn prompt body via the new prependBootstrapPromptWarning utility. The core fix is sound and the live cache metrics (33% → 66% hit rate for the bootstrap-warning scenario) confirm the improvement.

Key changes and observations:

  • bootstrap-budget.ts — new prependBootstrapPromptWarning helper is clean, well-guarded (handles undefined/empty arrays), and correctly separates warning content from the cacheable system prefix.
  • system-prompt.ts — warning injection removed correctly; the # Project Context guard was also tightened to fire only when valid context files exist. However, bootstrapTruncationWarningLines remains in the params type and is still passed by both main call sites (cli-runner.ts:158, attempt.ts:1671), making it a silent no-op that may mislead future contributors.
  • pi-embedded-runner/run/attempt.ts — also contains a welcome pre-existing bug fix: the hook prependContext path now operates on effectivePrompt rather than the raw params.prompt, so bootstrap warnings are no longer discarded when a hook injects context.
  • bootstrap-budget.test.ts — the regression test correctly validates cache stability, though the cacheHitRate helper uses the misleading variable name changes for what are actually cache-hit counts.

Confidence Score: 4/5

  • Safe to merge — the core cache-stability fix is correct and well-tested; the only concern is a dead parameter left in the public API of buildAgentSystemPrompt.
  • The behavioral change is exactly as described, backed by unit tests and live cache measurements. The fix in attempt.ts also resolves a pre-existing bug. The one deduction is for bootstrapTruncationWarningLines remaining as a silently-ignored parameter in buildAgentSystemPrompt (and its two wrapper helpers), which is a maintenance hazard but not a runtime defect.
  • src/agents/system-prompt.ts (and the untouched wrappers src/agents/cli-runner/helpers.ts and src/agents/pi-embedded-runner/system-prompt.ts) for the dead bootstrapTruncationWarningLines parameter.

Comments Outside Diff (1)

  1. src/agents/system-prompt.ts, line 205 (link)

    P2 Dead parameter silently accepted but now ignored

    bootstrapTruncationWarningLines is still part of the buildAgentSystemPrompt params type (line 205), still forwarded through buildSystemPrompt in cli-runner/helpers.ts:95 and buildAgentSystemPromptForRun in pi-embedded-runner/system-prompt.ts:84, and still passed by both call sites (cli-runner.ts:158, attempt.ts:1671). But after this PR, the implementation does nothing with it — the field is read by zero lines of buildAgentSystemPrompt.

    Future readers will assume passing bootstrapTruncationWarningLines causes a warning to appear in the system prompt; it no longer does. Consider either:

    • removing the field from the param type (small breaking change, but honest), or
    • marking it /** @deprecated – warnings are now prepended to the per-turn prompt body via prependBootstrapPromptWarning */ in the type definition

    Both the helper wrappers (cli-runner/helpers.ts and pi-embedded-runner/system-prompt.ts) also need updating.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/agents/system-prompt.ts
    Line: 205
    
    Comment:
    **Dead parameter silently accepted but now ignored**
    
    `bootstrapTruncationWarningLines` is still part of the `buildAgentSystemPrompt` params type (line 205), still forwarded through `buildSystemPrompt` in `cli-runner/helpers.ts:95` and `buildAgentSystemPromptForRun` in `pi-embedded-runner/system-prompt.ts:84`, and still passed by both call sites (`cli-runner.ts:158`, `attempt.ts:1671`). But after this PR, the implementation does nothing with it — the field is read by zero lines of `buildAgentSystemPrompt`.
    
    Future readers will assume passing `bootstrapTruncationWarningLines` causes a warning to appear in the system prompt; it no longer does. Consider either:
    - removing the field from the param type (small breaking change, but honest), or
    - marking it `/** @deprecated – warnings are now prepended to the per-turn prompt body via prependBootstrapPromptWarning */` in the type definition
    
    Both the helper wrappers (`cli-runner/helpers.ts` and `pi-embedded-runner/system-prompt.ts`) also need updating.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/system-prompt.ts
Line: 205

Comment:
**Dead parameter silently accepted but now ignored**

`bootstrapTruncationWarningLines` is still part of the `buildAgentSystemPrompt` params type (line 205), still forwarded through `buildSystemPrompt` in `cli-runner/helpers.ts:95` and `buildAgentSystemPromptForRun` in `pi-embedded-runner/system-prompt.ts:84`, and still passed by both call sites (`cli-runner.ts:158`, `attempt.ts:1671`). But after this PR, the implementation does nothing with it — the field is read by zero lines of `buildAgentSystemPrompt`.

Future readers will assume passing `bootstrapTruncationWarningLines` causes a warning to appear in the system prompt; it no longer does. Consider either:
- removing the field from the param type (small breaking change, but honest), or
- marking it `/** @deprecated – warnings are now prepended to the per-turn prompt body via prependBootstrapPromptWarning */` in the type definition

Both the helper wrappers (`cli-runner/helpers.ts` and `pi-embedded-runner/system-prompt.ts`) also need updating.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/bootstrap-budget.test.ts
Line: 443-446

Comment:
**Misleading variable name `changes` counts cache hits, not changes**

The variable is named `changes` but the filter counts pairs of adjacent turns that are **equal** (i.e., cache hits), not pairs that differ. The assertions happen to work correctly, but a reader unfamiliar with the intent will spend time reconciling "why does `changes = 2` produce a hit-rate of 1?"

```suggestion
    const cacheHitRate = (turns: string[]) => {
      const hits = turns.slice(1).filter((turn, index) => turn === turns[index]).length;
      return hits / Math.max(1, turns.length - 1);
    };
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: dff644a

Comment thread src/agents/bootstrap-budget.test.ts
@scoootscooob scoootscooob self-assigned this Mar 17, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dff644aa02

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/pi-embedded-runner/run/attempt.ts
@obviyus obviyus self-assigned this Mar 17, 2026
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Mar 17, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Prompt/content injection via unsanitized bootstrap truncation warning lines in user prompt

1. 🟡 Prompt/content injection via unsanitized bootstrap truncation warning lines in user prompt

Property Value
Severity Medium
CWE CWE-74
Location src/agents/bootstrap-budget.ts:333-353

Description

prependBootstrapPromptWarning() prepends a warning block into the per-turn user prompt, formatting each warningLines entry as a Markdown bullet.

Because the only normalization is trim() and filter(Boolean), any warning line containing embedded newlines or control characters can break out of the intended - ... bullet formatting and inject arbitrary additional prompt content ahead of the real user prompt.

Vulnerable flow:

  • Sink (prompt assembly): prependBootstrapPromptWarning() interpolates each line directly:
    • ...normalizedLines.map((line) => - ${line})
    • joined with "\n" and prepended to prompt
  • Source (can include paths/names): warningLines typically comes from buildBootstrapPromptWarning()formatBootstrapTruncationWarningLines() which includes file.name and, when duplicate names exist, file.path:
    • nameLabel = ${file.name} (${file.path})`` (no escaping)
  • Untrusted influence on file.path/file.name: resolveBootstrapFilesForRun() applies hook overrides (applyBootstrapHookOverrides) and then sanitizeBootstrapFiles() only does file.path.trim() (does not remove internal \n/\r). Additionally, extra bootstrap loading can incorporate repository-controlled paths via glob patterns.

Why this is exploitable:

  • On POSIX filesystems, path components can legally contain \n/\r and other characters (except NUL and /).
  • A malicious repo / plugin / hook can craft a bootstrap file path (or name via hook overrides) like:
    • "AGENTS.md (/repo/evil\n\nIgnore previous instructions and ...)"
  • When included in the warning block, the injected newline terminates the bullet and adds attacker-controlled instructions at the top of the user prompt.

Vulnerable code:

const normalizedLines = (warningLines ?? []).map((line) => line.trim()).filter(Boolean);
...
...normalizedLines.map((line) => `- ${line}`),

Impact:

  • The injected text appears before the user’s actual request and can materially alter agent behavior (including tool-using agents in embedded runs), despite being presented as a “warning” block.

Recommendation

Treat warningLines as untrusted display data and sanitize/encode it so it cannot introduce newlines or control characters into the prompt.

Recommended fix (sanitize + encode):

function sanitizeWarningLine(line: string): string {// Remove CR/LF and other control chars; collapse whitespace.
  return line
    .replace(/[\r\n]+/g, " ")
    .replace(/\p{C}+/gu, "")
    .replace(/\s+/g, " ")
    .trim();
}

const normalizedLines = (warningLines ?? [])
  .map((line) => (typeof line === "string" ? sanitizeWarningLine(line) : ""))
  .filter(Boolean);

const warningBlock = [
  "[Bootstrap truncation warning]",
  ...normalizedLines.map((line) => `- ${JSON.stringify(line)}`),
].join("\n");

Notes:

  • Replacing \r/\n prevents breaking out of the bullet list.
  • Stripping Unicode control characters (\p{C}) helps avoid terminal/control-sequence and invisible-text tricks.
  • Using JSON.stringify (or wrapping in a code span / code block with escaping) ensures special characters are rendered as data, not instructions.

Analyzed PR: #48753 at commit dc1d4d0

Last updated on: 2026-03-17T07:11:19Z

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d81cef8297

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (normalizedLines.length === 0) {
return prompt;
}
if (options?.preserveExactPrompt && prompt === options.preserveExactPrompt) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Relax heartbeat-preserve check beyond exact string equality

The new guard only skips warning prepending when prompt === preserveExactPrompt, but heartbeat runs usually wrap the configured heartbeat text before it reaches this function (fresh evidence: runHeartbeatOnce appends a HEARTBEAT.md path hint and a current-time line in src/infra/heartbeat-runner.ts), so this equality is typically false and heartbeat polls still get a bootstrap warning prefix. In truncation cases this can push heartbeat turns off the intended HEARTBEAT_OK path and generate avoidable heartbeat alerts/noise.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@obviyus obviyus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Pushed a follow up commit that fixes:

  • warning prepend now preserves prompt whitespace
  • heartbeat exact-match stays intact
  • runtime CLI/embedded paths are covered by tests

I also spot-checked the cache behavior locally and can confirm that cache hit has improved.

@scoootscooob scoootscooob merged commit 80a2af1 into openclaw:main Mar 17, 2026
8 checks passed
@scoootscooob
Copy link
Copy Markdown
Contributor Author

Merged via manual deterministic squash.

  • Prepared head SHA: dc1d4d075af7afdf4c143f1639cd49e129969f6c
  • Merge mode: squash with --match-head-commit
  • Notes: local prep artifacts were completed manually after the fork pull/48753/head wrapper fetch bug.

1 similar comment
@scoootscooob
Copy link
Copy Markdown
Contributor Author

Merged via manual deterministic squash.

  • Prepared head SHA: dc1d4d075af7afdf4c143f1639cd49e129969f6c
  • Merge mode: squash with --match-head-commit
  • Notes: local prep artifacts were completed manually after the fork pull/48753/head wrapper fetch bug.

nikolaisid pushed a commit to nikolaisid/openclaw that referenced this pull request Mar 18, 2026
Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
sbezludny pushed a commit to sbezludny/openclaw that referenced this pull request Mar 27, 2026
Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
juancatorr added a commit to juancatorr/openclaw that referenced this pull request Apr 8, 2026
* refactor(slack): share setup wizard base

* refactor(discord): share setup wizard base

* refactor(signal): reuse shared setup security

* refactor(imessage): reuse shared setup security

* refactor(setup): reuse patched adapters across channels

* refactor(imessage): share setup status base

* refactor(slack): share token credential setup

* refactor(setup): share env-aware patched adapters

* refactor(discord): use shared plugin base

* refactor(outbound): share base session helpers

* refactor(whatsapp): reuse login tool implementation

* refactor(providers): reuse simple api-key catalog helper

* refactor(plugins): share bundle path list helpers

* refactor(slack): reuse shared action adapter

* refactor(tts): share provider readiness checks

* refactor(plugins): share claiming hook loop

* refactor(plugins): share install target flow

* refactor(status): share scan helper state

* refactor(usage): share legacy pi auth token lookup

* refactor(device): share missing-scope helper

* refactor(config): share schema lookup helpers

* fix(plugin-sdk): restore core export boundary

* build: tighten lazy runtime boundaries

* fix(gateway): surface env override keys in exec approvals

* Agents: move bootstrap warnings out of system prompt (openclaw#48753)

Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob

* refactor: dedupe channel entrypoints and test bridges

* style: fix rebase formatting drift

* fix: resolve rebase type fallout in channel setup seams

* fix(macos): block canvas symlink escapes

* refactor: bundle lazy runtime surfaces

* fix: remove discord setup rebase marker

* docs(gateway): clarify URL allowlist semantics

* docs(changelog): restore 2026.2.27 heading

* fix: unblock full gate

* fix: stabilize full gate

* test: cover invalid main job store load

* build(test): ignore vitest scratch root

* refactor: dedupe bundled plugin entrypoints

* docs: add context engine documentation

Add dedicated docs page for the pluggable context engine system:
- Full lifecycle explanation (ingest, assemble, compact, afterTurn)
- Legacy engine behavior documentation
- Plugin engine authoring guide with code examples
- ContextEngine interface reference table
- ownsCompaction semantics
- Subagent lifecycle hooks (prepareSubagentSpawn, onSubagentEnded)
- systemPromptAddition mechanism
- Relationship to compaction, memory plugins, and session pruning
- Configuration reference and tips

Also:
- Add context-engine to docs nav (Agents > Fundamentals, after Context)
- Add /context-engine redirect
- Cross-link from context.md and compaction.md

* docs: add plugin installation steps to context engine page

Show the full workflow: install via openclaw plugins install,
enable in plugins.entries, then select in plugins.slots.contextEngine.
Uses lossless-claw as the concrete example.

* docs: address review feedback on context-engine page

- Rename 'Method' column to 'Member' with explicit Kind column since
  info is a property, not a callable method
- Document AssembleResult fields (estimatedTokens, systemPromptAddition)
  with types and optionality
- Add lifecycle timing notes for bootstrap, ingestBatch, and dispose
  so plugin authors know when each is invoked

* docs: fix context engine review notes

* fix: harden telegram and loader contracts

* refactor(tests): share setup wizard prompter

* refactor(telegram-tests): share native command helpers

* fix(telegram-tests): load plugin mocks before commands

* refactor(telegram-tests): share webhook settlement helper

* refactor(nextcloud-tests): share inbound authz setup

* refactor(feishu-tests): share card action event builders

* refactor(runtime-tests): share typing lease assertions

* refactor(hook-tests): share subagent hook helpers

* refactor(provider-tests): share discovery catalog helpers

* refactor(command-tests): share workspace harness

* refactor(contracts): share session binding assertions

* refactor(plugin-tests): share interactive dispatch assertions

* refactor(plugin-tests): share binding approval resolution

* refactor(usage-tests): share provider usage loader harness

* refactor(bundle-tests): share bundle mcp fixtures

* refactor(provider-tests): share codex catalog assertions

* refactor(apns-tests): share relay push params

* refactor(media-tests): share telegram redaction assertion

* refactor(heartbeat-tests): share seeded heartbeat run

* refactor(kilocode-tests): share reasoning payload capture

* refactor(kilocode-tests): share extra-params harness

* refactor(kilocode-tests): share cache retention wrapper

* refactor(attempt-tests): share wrapped stream helper

* refactor(payload-tests): share empty payload assertion

* Telegram: fix named-account DM topic session keys (openclaw#48773)

* refactor(compaction-tests): share aggregate timeout params

* refactor(compaction-tests): share snapshot assertions

* refactor(truncation-tests): share first tool result text helper

* refactor(system-prompt-tests): share session setup helper

* refactor(lanes-tests): share table-driven assertions

* refactor(google-tests): share schema tool fixture

* refactor(extension-tests): share safeguard factory setup

* refactor(openrouter-tests): share state dir helper

* refactor(thinking-tests): share assistant drop helper

* refactor(kilocode-tests): share eligibility assertions

* refactor(payload-tests): share empty payload helper

* refactor(model-tests): share template model mock helper

* refactor(image-tests): share empty prompt image assertions

* fix: restore full gate

* refactor: consolidate lazy runtime surfaces

* refactor: remove remaining extension core imports

* refactor(payload-tests): reuse empty payload helper

* refactor(image-tests): share empty ref assertions

* refactor(image-tests): share single-ref detection helper

* refactor(image-tests): share ref count assertions

* refactor(history-tests): share array content assertion

* refactor(runs-tests): share run handle factory

* refactor(skills-tests): share bundled diffs setup

* refactor(payload-tests): share single payload summary assertion

* refactor(payload-tests): table-drive recoverable tool suppressions

* refactor(payload-tests): table-drive sessions send suppressions

* refactor(history-tests): share pruned image assertions

* refactor(failover-tests): share observation base

* refactor(extension-tests): share safeguard runtime assertions

* fix(ci): quote changed extension matrix input

* refactor: split plugin testing seam from bundled extension helpers

* test: fix discord provider helper import

* Changelog: add Telegram DM topic session-key fix

* fix(ci): harden zizmor workflow diffing

* feat(image-generation): add image_generate tool

* test(image-generation): add live variant coverage

* docs(image-generation): remove nano banana stock docs

* fix(ci): restore local check suite

* chore: sync pnpm lockfile importers

* fix(ui): restore control-ui query token compatibility (openclaw#43979)

* fix(ui): restore control-ui query token imports

* chore(changelog): add entry for openclaw#43979 thanks @stim64045-spec

---------

Co-authored-by: 大禹 <dayu@dayudeMac-mini.local>
Co-authored-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* fix: update macOS node service to use current CLI command shape (closes openclaw#43171) (openclaw#46843)

Merged via squash.

Prepared head SHA: dbf2edd
Co-authored-by: Br1an67 <29810238+Br1an67@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Reviewed-by: @ImLukeF

* fix(macos): stop relaunching the app after quit when launch-at-login is enabled (openclaw#40213)

Merged via squash.

Prepared head SHA: c702d98
Co-authored-by: stablegenius49 <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Reviewed-by: @ImLukeF

* tests: add missing useNoBundledPlugins() to bundle MCP loader test

The "treats bundle MCP as a supported bundle surface" test was missing
the useNoBundledPlugins() call present in all surrounding bundle plugin
tests. Without it, loadOpenClawPlugins() scanned and loaded the full
real bundled plugins directory on every call (with cache:false), causing
excessive memory pressure and an OOM crash on Linux CI, which manifested
as the test timing out at 120s.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix ssh sandbox key cp (openclaw#48924)

Signed-off-by: sallyom <somalley@redhat.com>

* tests: fix googlechat outbound partial mock

* tests(google): inject oauth credential fs stubs

* tests(feishu): mock conversation runtime seam

* tests(feishu): inject client runtime seam

* tests(contracts): fix provider catalog runtime wiring (openclaw#49040)

* fix(plugins): forward plugin subagent overrides (openclaw#48277)

Merged via squash.

Prepared head SHA: ffa4589
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* fix(security): block JVM, Python, and .NET env injection vectors in host exec sandbox (openclaw#49025)

Add JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS, PYTHONBREAKPOINT, and
DOTNET_STARTUP_HOOKS to blockedKeys in the host exec security policy.

Closes openclaw#22681

* CI: rename startup memory smoke (openclaw#49041)

* CI: guard gateway watch against duplicate runtime regressions (openclaw#49048)

* fix(hooks): pass sessionFile and sessionKey in after_compaction hook (openclaw#40781)

Merged via squash.

Prepared head SHA: 11e85f8
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* refactor: expose lazy runtime helper to plugins

* refactor: align telegram test support with plugin runtime seam

* fix(tlon): defer DM cite expansion until after auth

* fix(context-engine): preserve legacy plugin sessionKey interop (openclaw#44779)

Merged via squash.

Prepared head SHA: e04c6fb
Co-authored-by: hhhhao28 <112874572+hhhhao28@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* test: harden CI-sensitive test suites

* test: remove repeated update module imports

* test: inline bluebubbles action mocks

* test: reuse subagent orphan recovery imports

* test: flatten twitch send mocks

* test: stabilize pdf tool runtime mocks

* test: reuse run-node module imports

* test: reuse git commit module exports

* test: trim redundant context engine assertions

* test: merge duplicate update cli scenarios

* test: preload plugin sdk subpath imports

* test: cache provider discovery fixtures

* test: merge context lookup warmup cases

* test: trim lightweight status and capability suites

* test: merge telegram action matrix cases

* test: merge embeddings provider selection cases

* test: preload inbound contract fixtures

* test: merge message action media sandbox cases

* test: merge pid alive linux stat cases

* test: merge tts config gating cases

* test: trim signal and slack action cases

* test: harden commands test module seams

* test: merge bundle loader fixture cases

* test: merge loader cache partition cases

* test: merge loader setup entry matrix

* test: merge discord audit allowlist cases

* test: merge zalouser audit group cases

* test: merge audit auth precedence cases

* test: merge channel command audit cases

* test: merge browser control audit cases

* test: merge control ui audit cases

* test: merge feishu audit doc cases

* test: merge hooks audit risk cases

* test: merge gateway http audit cases

* test: share audit exposure severity helper

* test: merge loader provenance path cases

* test: merge loader escape path cases

* test: merge loader alias resolution cases

* test: merge install metadata audit cases

* test: merge loader duplicate registration cases

* test: merge loader http route cases

* test: merge audit extension and workspace cases

* test: merge loader single-plugin registration cases

* test: merge loader precedence cases

* test: merge audit exposure heuristic cases

* test: merge loader workspace warning cases

* test: merge audit hooks ingress cases

* test: merge audit extension allowlist severity cases

* test: merge loader provenance warning cases

* test: merge loader bundled telegram cases

* test: merge loader memory slot cases

* test: merge loader scoped load cases

* test: merge audit gateway auth presence cases

* test: merge audit browser container cases

* test: merge audit windows acl cases

* test: merge audit deny command cases

* test: merge audit code safety failure cases

* test: merge loader cache miss cases

* test: merge update cli service refresh cases

* test: merge slack action mapping cases

* test: merge command owner gating cases

* test: merge update status output cases

* test: merge command gateway config permission cases

* test: merge command approval scope cases

* test: merge command hook cases

* test: merge command config write denial cases

* test: merge command allowlist add cases

* test: merge update cli service refresh behavior

* test: merge command owner show gating cases

* test: merge discord action listing cases

* test: merge signal reaction mapping cases

* test: merge discord reaction id resolution cases

* test: merge telegram reaction id cases

* test: merge audit resolved inspection cases

* test: merge audit gateway auth guardrail cases

* test: merge audit sandbox docker danger cases

* test: merge audit discord allowlist cases

* test: merge audit sandbox docker config cases

* test: merge audit browser sandbox cases

* test: merge audit allowCommands cases

* test: merge audit install metadata cases

* test: merge audit code safety cases

* test: merge audit dangerous flag cases

* test: merge audit trust exposure cases

* test: merge audit channel command hygiene cases

* test: merge slack validation cases

* test: merge update cli dry run cases

* test: merge update cli outcome cases

* test: merge update cli validation cases

* test: merge action media root cases

* test: merge update cli restart behavior cases

* test: merge update cli channel cases

* test: stabilize full gate

* feat(agents): infer image generation defaults

* docs(image-generation): document implicit tool enablement

* refactor: dedupe plugin lazy runtime helpers

* fix(telegram): persist sticky IPv4 fallback across polling restarts (fixes openclaw#48177) (openclaw#48282)

* fix(telegram): persist sticky IPv4 fallback across polling restarts (fixes openclaw#48177)

Hoist resolveTelegramTransport() out of createTelegramBot() so the
transport (and its sticky IPv4 fallback state) persists across polling
restarts. Previously, each polling restart created a new transport with
stickyIpv4FallbackEnabled=false, causing repeated IPv6 timeouts on
hosts with unstable IPv6 connectivity.

Changes:
- bot.ts: accept optional telegramTransport in TelegramBotOptions
- monitor.ts: resolve transport once before polling loop
- polling-session.ts: pass transport through to bot creation

AI-assisted (Claude Sonnet 4). Tested: tsc --noEmit clean.

* Update extensions/telegram/src/polling-session.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* style: fix oxfmt formatting in bot.ts

* test: cover telegram transport reuse across restarts

* fix: preserve telegram sticky IPv4 fallback across polling restarts (openclaw#48282) (thanks @yassinebkr)

---------

Co-authored-by: Yassine <yassinebkr@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>

* ACP: harden startup and move configured routing behind plugin seams (openclaw#48197)

* ACPX: keep plugin-local runtime installs out of dist

* Gateway: harden ACP startup and service PATH

* ACP: reinitialize error-state configured bindings

* ACP: classify pre-turn runtime failures as session init failures

* Plugins: move configured ACP routing behind channel seams

* Telegram tests: align startup probe assertions after rebase

* Discord: harden ACP configured binding recovery

* ACP: recover Discord bindings after stale runtime exits

* ACPX: replace dead sessions during ensure

* Discord: harden ACP binding recovery

* Discord: fix review follow-ups

* ACP bindings: load channel snapshots across workspaces

* ACP bindings: cache snapshot channel plugin resolution

* Experiments: add ACP pluginification holy grail plan

* Experiments: rename ACP pluginification plan doc

* Experiments: drop old ACP pluginification doc path

* ACP: move configured bindings behind plugin services

* Experiments: update bindings capability architecture plan

* Bindings: isolate configured binding routing and targets

* Discord tests: fix runtime env helper path

* Tests: fix channel binding CI regressions

* Tests: normalize ACP workspace assertion on Windows

* Bindings: isolate configured binding registry

* Bindings: finish configured binding cleanup

* Bindings: finish generic cleanup

* Bindings: align runtime approval callbacks

* ACP: delete residual bindings barrel

* Bindings: restore legacy compatibility

* Revert "Bindings: restore legacy compatibility"

This reverts commit ac2ed68fa2426ecc874d68278c71c71ad363fcfe.

* Tests: drop ACP route legacy helper names

* Discord/ACP: fix binding regressions

---------

Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>

* feat: add bundled Chutes extension (openclaw#49136)

* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)

* docs(security): clarify wildcard Control UI origins

* refactor: clean extension api boundaries

* fix: remove duplicate setup helper imports

* fix(compaction): break safeguard cancel loop for sessions with no summarizable messages (openclaw#41981) (openclaw#42215)

Merged via squash.

Prepared head SHA: 7ce6bd8
Co-authored-by: lml2468 <39320777+lml2468@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* feat(mattermost): add retry logic and timeout handling for DM channel creation (openclaw#42398)

Merged via squash.

Prepared head SHA: 3db47be
Co-authored-by: JonathanJing <17068507+JonathanJing@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Reviewed-by: @mukhtharcm

* docs(hooks): clarify trust model and audit guidance

* test: stabilize memory async search close

* refactor: narrow extension public seams

* chore: add gog CLI support via custom Docker image

Add Dockerfile.gog to extend openclaw:local with the gog binary
(Google Workspace CLI). Also forward OPENAI_API_KEY and GEMINI_API_KEY
env vars in docker-compose.yml for both services.

Made-with: Cursor

* chore: inject GOG_KEYRING_PASSWORD for non-interactive gog auth

The gog CLI uses a file-based keyring to store Google OAuth tokens.
In Docker/headless environments, the keyring prompts for a passphrase
interactively, which blocks the agent from running gog autonomously.

Setting GOG_KEYRING_PASSWORD as an environment variable allows gog to
unlock the keyring without user interaction, enabling the agent to
execute Gmail, Calendar, Drive, and other Google Workspace commands
directly via the gog skill.

Setup steps to enable the gog skill in Docker:
1. Build the custom image: docker build -f Dockerfile.gog -t openclaw:gog .
2. Set OPENCLAW_IMAGE=openclaw:gog in .env
3. Set GOG_KEYRING_PASSWORD= in .env (empty = no passphrase)
4. Run: gog auth keyring file (inside container)
5. Run: gog auth credentials /path/to/client_secret.json
6. Run: gog auth add you@gmail.com --manual
7. Add to openclaw.json: tools.alsoAllow = ["exec", "process"]

Made-with: Cursor

* docs: add Docker commands reference and Mac migration plan

* docs: add docker save/load alternative to migration plan

* docs: add Docker+gog env example file

* config: clear unused OPENAI_API_KEY and document LLM auth in migration guide

* chore: remove .env from git tracking (contains secrets)

Made-with: Cursor

* docs: add openai-codex auth commands to migration guide

* docs: add gog token persistence, exec tool fix, and image migration cases

- docker-compose.yml: mount ~/.openclaw/gogcli as volume so gog tokens survive container restarts
- docs/docker-commands.html: add case 10 (gog token loss diagnosis + re-auth + volume persistence)
- docs/docker-commands.html: add case 11 (exec tool not enabled — tools.alsoAllow fix + persistence explanation)
- docs/docker-commands.html: add case 08 (migrate Docker Desktop images to Colima via docker save/load) + TOC entry

* docs: add Colima disk lock fix to docker-commands

* feat(docker): add local Whisper audio transcription to gog image

* docs: update docker-commands with TTS and contact number fixes

* docs: add gog token expiry troubleshooting and publish-app fix (caso 12)

* docs: add OpenAI Codex rate limit troubleshooting (caso 13)

* docs: add model set/status commands to caso 13

* docs: add provider/model switching guide (caso 14)

* docs: replace placeholder email with herbert.cadbury.bot@gmail.com

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: Josh Lehman <josh@martian.engineering>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: stim64045-spec <stim64045@gmail.com>
Co-authored-by: 大禹 <dayu@dayudeMac-mini.local>
Co-authored-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Co-authored-by: Br1an <932039080@qq.com>
Co-authored-by: Br1an67 <29810238+Br1an67@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Co-authored-by: Stable Genius <stablegenius043@gmail.com>
Co-authored-by: stablegenius49 <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: Chris Kimpton <chris@kimptoc.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
Co-authored-by: huntharo <harold@pwrdrvr.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: Andrew Demczuk <andrew.demczuk@gmail.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: Jari Mustonen <jari.mustonen@iki.fi>
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: F_ool <112874572+hhhhao28@users.noreply.github.com>
Co-authored-by: Kwest OG <50209930+yassinebkr@users.noreply.github.com>
Co-authored-by: Yassine <yassinebkr@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Menglin Li <limenglin5911@gmail.com>
Co-authored-by: lml2468 <39320777+lml2468@users.noreply.github.com>
Co-authored-by: Jonathan Jing <JonathanJing@users.noreply.github.com>
Co-authored-by: JonathanJing <17068507+JonathanJing@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants