Skip to content

feat(agents): add contextInjection 'never' to disable bootstrap file injection#64094

Closed
xDarkicex wants to merge 0 commit intoopenclaw:mainfrom
xDarkicex:feat/context-injection-never
Closed

feat(agents): add contextInjection 'never' to disable bootstrap file injection#64094
xDarkicex wants to merge 0 commit intoopenclaw:mainfrom
xDarkicex:feat/context-injection-never

Conversation

@xDarkicex
Copy link
Copy Markdown
Contributor

Summary

Add contextInjection: "never" option to agents.defaults config, allowing memory/context plugins to own authored doc delivery via semantic retrieval instead of OpenClaw injecting raw workspace files.

  • Problem: OpenClaw injects AGENTS.md, SOUL.md, and other bootstrap files into every prompt by default. Memory plugins that want to serve authored docs via semantic search have no way to suppress this, resulting in both raw file injection and plugin-served chunks coexisting in context.
  • Why it matters: Enables memory/context plugins to serve partitioned, trust-tiered authored content (hard/soft/variant rules) via semantic retrieval, closing the prompt-injection surface and reducing context-window bloat from uncontrolled file injection.
  • What changed: Added "never" as a third contextInjection option alongside "always" and "continuation-skip". When set, isContinuationTurn evaluates to true unconditionally, skipping all bootstrap file loading and injection.
  • What did NOT change (scope boundary): "always" and "continuation-skip" behave identically. The memory plugin seams (MemoryCorpusSupplement, promptBuilder) are unchanged — this config only controls whether bootstrap files are injected; plugin context is orthogonal.

Change Type (select all)

  • Feature
  • Bug fix
  • 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

  • Closes #
  • Related #

Root Cause (if applicable)

N/A — feature addition, not a bug fix.

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/bootstrap-files.test.tsresolveContextInjectionMode
  • Scenario the test should lock in: contextInjection: "never" is parsed and returned correctly
  • Why this is the smallest reliable guardrail: Direct unit test on the single resolve function
  • Existing test that already covers this (if any): None — new option
  • If no new test is added, why not: New test added for the "never" case

User-visible / Behavior Changes

  • agents.defaults.contextInjection now accepts "never" in addition to "always" and "continuation-skip"
  • When set to "never", workspace bootstrap files (AGENTS.md, SOUL.md, etc.) are never injected into the system prompt
  • Default remains "always" — no behavior change for existing users

Diagram (if applicable)

N/A

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 (only affects prompt injection content)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS / Linux
  • Runtime/container: Node 22+
  • Model/provider: Any
  • Integration/channel (if any): Any agent with memory plugin

Steps

  1. Set agents.defaults.contextInjection: "never" in config
  2. Ensure AGENTS.md and other bootstrap files exist in workspace
  3. Start an agent session
  4. Inspect the system prompt — no # Project Context section should appear

Expected

Bootstrap files are not injected; the memory plugin's promptBuilder and MemoryCorpusSupplement are the sole authored-doc surface.

Actual

TBD (verified manually)

Evidence

Attach at least one:

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

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Unit test passes for "never" mode; type-check, lint, and build all pass
  • Edge cases checked: Schema validation accepts "never", rejects invalid values
  • What you did not verify: Manual end-to-end run with a real memory plugin

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? Yes — new "never" value for agents.defaults.contextInjection
  • Migration needed? No — default is unchanged at "always"
  • If yes, exact upgrade steps:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: User sets "never" without a memory plugin that can serve authored docs, leaving the agent with no authored context.
    • Mitigation: This is opt-in behavior; users must explicitly choose it and are expected to configure a memory plugin accordingly.
  • Risk: None identified for the core change.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime agents Agent runtime and tooling size: XS labels Apr 10, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 10, 2026

Greptile Summary

This PR adds "never" as a third value for agents.defaults.contextInjection, allowing memory/context plugins to fully own authored-document delivery via semantic retrieval by suppressing all workspace bootstrap file injection. The implementation is clean and minimal: the type union, Zod schema, runtime logic in attempt.ts, help text, config reference docs, a unit test, and the changelog entry are all updated consistently.

The only gap is that the JSDoc comment on the contextInjection field in types.agent-defaults.ts still only lists "always" and "continuation-skip" — the new "never" option is missing from the inline docs (P2 only).

Confidence Score: 5/5

Safe to merge — the change is additive, backward compatible, and all affected surfaces (type, schema, runtime, docs, test) are consistently updated.

Only a single P2 finding: the JSDoc on contextInjection in types.agent-defaults.ts omits the new "never" option. No logic bugs, no broken contracts, no missing test coverage for the critical path. Default behavior is unchanged.

src/config/types.agent-defaults.ts — JSDoc comment needs the "never" bullet added.

Comments Outside Diff (1)

  1. src/config/types.agent-defaults.ts, line 162-168 (link)

    P2 JSDoc missing "never" option

    The inline comment for contextInjection still only lists "always" and "continuation-skip"; "never" is absent. A developer reading the type file won't see the new option without also checking AgentContextInjection or the config reference.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/config/types.agent-defaults.ts
    Line: 162-168
    
    Comment:
    **JSDoc missing `"never"` option**
    
    The inline comment for `contextInjection` still only lists `"always"` and `"continuation-skip"`; `"never"` is absent. A developer reading the type file won't see the new option without also checking `AgentContextInjection` or the config reference.
    
    
    
    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/config/types.agent-defaults.ts
Line: 162-168

Comment:
**JSDoc missing `"never"` option**

The inline comment for `contextInjection` still only lists `"always"` and `"continuation-skip"`; `"never"` is absent. A developer reading the type file won't see the new option without also checking `AgentContextInjection` or the config reference.

```suggestion
  /**
   * Controls when workspace bootstrap files (AGENTS.md, SOUL.md, etc.) are
   * injected into the system prompt:
   * - always: inject on every turn (default)
   * - continuation-skip: skip injection on safe continuation turns once the
   *   transcript already contains a completed assistant turn
   * - never: disable injection entirely (useful when a memory/context plugin
   *   serves authored docs via semantic retrieval instead)
   */
```

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

Reviews (1): Last reviewed commit: "Agents/bootstrap: add contextInjection "..." | Re-trigger Greptile

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: 34b2101daa

ℹ️ 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/config/zod-schema.agent-defaults.ts Outdated
Comment on lines +49 to +50
contextInjection: z
.union([z.literal("always"), z.literal("continuation-skip"), z.literal("never")])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Regenerate base config schema for the new contextInjection value

Adding "never" to AgentDefaultsSchema here updates config parsing, but the public schema contract is served from GENERATED_BASE_CONFIG_SCHEMA in src/config/schema.ts:463, and that generated artifact still only lists "always"/"continuation-skip" for agents.defaults.contextInjection (src/config/schema.base.generated.ts:3187-3200, :24201-24204). This leaves schema-driven consumers (including config UI/metadata clients) unaware of the new option even though runtime parsing accepts it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

P1 — Regenerated base config schema
Ran scripts/generate-base-config-schema.ts --write to regenerate schema.base.generated.ts. The contextInjection enum in the
generated schema contract now includes "never" and the help text reflects all three options. Config UI/metadata consumers will
now see the new option.

Comment on lines +455 to +456
contextInjectionMode === "never" ||
(contextInjectionMode === "continuation-skip" &&
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 Honor "never" mode during compaction prompts

This new branch only skips bootstrap files in runEmbeddedAttempt, but compaction still unconditionally loads and injects bootstrap context via resolveBootstrapContextForRun and contextFiles in src/agents/pi-embedded-runner/compact.ts:514 and :776. In sessions that trigger compaction, agents.defaults.contextInjection: "never" still injects AGENTS/SOUL content, so the mode is not actually “never” across the full embedded runner flow.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

P2 — Honor "never" during compaction
Added resolveContextInjectionMode import to compact.ts and wrapped the resolveBootstrapContextForRun call at line ~514 with a
skip check:

const skipBootstrapInjection = contextInjectionMode === "never";
const { contextFiles } = skipBootstrapInjection
? { contextFiles: [] }
: await resolveBootstrapContextForRun({ ... });

With this, contextInjection: "never" is respected across the full embedded runner lifecycle — both in runEmbeddedAttempt (which
was already fixed) and in compaction prompts (this change).

@xDarkicex xDarkicex force-pushed the feat/context-injection-never branch from 34b2101 to 67e91dc Compare April 10, 2026 16:37
@xDarkicex
Copy link
Copy Markdown
Contributor Author

P1 — Regenerated base config schema
Ran scripts/generate-base-config-schema.ts --write to regenerate schema.base.generated.ts. The contextInjection enum in the
generated schema contract now includes "never" and the help text reflects all three options. Config UI/metadata consumers will
now see the new option.

P2 — Honor "never" during compaction
Added resolveContextInjectionMode import to compact.ts and wrapped the resolveBootstrapContextForRun call at line ~514 with a
skip check:

const skipBootstrapInjection = contextInjectionMode === "never";
const { contextFiles } = skipBootstrapInjection
? { contextFiles: [] }
: await resolveBootstrapContextForRun({ ... });

With this, contextInjection: "never" is respected across the full embedded runner lifecycle — both in runEmbeddedAttempt (which
was already fixed) and in compaction prompts (this change).

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: 67e91dca5f

ℹ️ 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/config/zod-schema.agent-defaults.ts Outdated
Comment on lines +49 to +50
contextInjection: z
.union([z.literal("always"), z.literal("continuation-skip"), z.literal("never")])
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 Keep contextInjection tests aligned with new "never" mode

Adding "never" to AgentDefaultsSchema changes the accepted config contract, but the existing unit test suite still asserts that AgentDefaultsSchema.parse({ contextInjection: "never" }) should throw (src/config/zod-schema.agent-defaults.test.ts). That makes the schema tests fail in any test lane that includes this file, obscuring real regressions and blocking merges until the expectation is updated to accept the new mode.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The test was rejecting "never" as invalid after it was added to the schema. Fixed by updating the test to accept "never" and
checking "unknown" instead for the rejection case.

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: 9a4fe68610

ℹ️ 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".

trigger: params.trigger,
runTimeoutMs: params.timeoutMs !== configuredRunTimeoutMs ? params.timeoutMs : undefined,
});
const idleTimeoutMs = resolveLlmIdleTimeoutMs(params.config);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pass idle-timeout options object to resolver

resolveLlmIdleTimeoutMs expects an options object ({ cfg, trigger, runTimeoutMs }), but this call passes params.config directly. That leaves cfg unset, so configured agents.defaults.llm.idleTimeoutSeconds, cron-trigger exemptions, and per-run timeout overrides are ignored and the resolver falls back to the 60s default. Runs that intentionally disable or extend idle timeout will now time out early.

Useful? React with 👍 / 👎.

Comment on lines 789 to 792
const appendPrompt =
resolveSystemPromptOverride({
config: params.config,
agentId: sessionAgentId,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore provider prompt/text transforms in embedded runs

This commit stops applying provider transform hooks in the embedded runner: appendPrompt is now used directly without transformProviderSystemPrompt, and the stream wrapping for resolveProviderTextTransforms/wrapStreamFnTextTransforms was also removed. Any provider plugin relying on transformSystemPrompt or textTransforms will silently lose its compatibility rewrites (prompt/input/output replacements), changing runtime behavior for those providers.

Useful? React with 👍 / 👎.

Comment on lines 1234 to 1238
export async function compactEmbeddedPiSession(
params: CompactEmbeddedPiSessionParams,
): Promise<EmbeddedPiCompactResult> {
const harnessResult = await maybeCompactAgentHarnessSession(params);
if (harnessResult) {
return harnessResult;
}
const sessionLane = resolveSessionLane(params.sessionKey?.trim() || params.sessionId);
const globalLane = resolveGlobalLane(params.lane);
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 Keep harness compaction delegation before PI fallback

compactEmbeddedPiSession now goes straight into PI compaction and no longer checks maybeCompactAgentHarnessSession first. That means harnesses implementing compact() through the agent-harness contract are skipped, so manual compaction calls from src/gateway/server-methods/sessions.ts will force PI compaction even when a non-PI harness is selected, which can break harness-managed session/compaction behavior.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation gateway Gateway runtime size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant