openclaw - 💡(How to fix) Fix [Feature]: Code-triggered reflection sub-turns for self-evolving SOUL.md

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…

A code-triggered reflection sub-turn fires on signal-keyword user messages and lets the agent decide whether to persist a rule to SOUL.md via a new soul_update tool.

Root Cause

SOUL.md is documented as self-evolving (template: "this file is yours to evolve. As you learn who you are, update it") but the runtime never makes it evolve. Users restate the same preferences ("no em-dashes", "be more terse", "I prefer shorter responses") every session because the file never accumulates from interaction.

Code Example

User: please stop using em-dashes
[Runtime detects "stop"; fires reflection sub-turn]
Agent (reflection): [calls soul_update with rule: "never use em-dashes", evidence: "user requested"]
System: Added to SOUL.md: 'never use em-dashes'
Agent (main): [responds to whatever the user actually asked]
RAW_BUFFERClick to expand / collapse

Summary

A code-triggered reflection sub-turn fires on signal-keyword user messages and lets the agent decide whether to persist a rule to SOUL.md via a new soul_update tool.

Problem to solve

SOUL.md is documented as self-evolving (template: "this file is yours to evolve. As you learn who you are, update it") but the runtime never makes it evolve. Users restate the same preferences ("no em-dashes", "be more terse", "I prefer shorter responses") every session because the file never accumulates from interaction.

Adjacent in-flight work (#82165 preamble override, #77349 hook mutation fix, #54830 provenance metadata) shapes how SOUL.md is composed and weighted but doesn't address evolution.

Proposed solution

A reflection sub-turn mechanism that's code-triggered but agent-decided.

Trigger: runtime detects signal keywords in the user's message (stop, don't, never, please, prefer, no more) OR every N turns (configurable). When triggered, the runtime fires a dedicated reflection sub-turn — separate from the main response.

Reflection prompt: "In recent context, has the user expressed a durable preference, correction, or rule about how you communicate worth persisting? If yes, call soul_update. If no, respond noop."

Tool: soul_update({ rule, evidence, section }) — validates, dedupes, appends to ## Auto-added in SOUL.md with timestamp.

Forced notification: when the tool fires, runtime emits a system message in the conversation — "Added to SOUL.md: 'never use em-dashes'". Cannot be suppressed.

Undo: openclaw soul undo reverses the last entry.

Opt-in: agents.defaults.soul.autoUpdate: false default.

Implementation surface: new src/agents/soul-reflection.ts, new src/agents/tools/soul-update.ts, new src/cli/soul-cli.ts, schema knob in src/config/zod-schema.agent-defaults.ts, runner integration, doc update in docs/concepts/soul.md.

Alternatives considered

  • Prompt-only nudge (system prompt tells agent to update SOUL.md): model frequently ignores; not enforced.
  • Pure code regex extraction (no model involvement): no agent judgment about phrasing or what's worth recording; high false-positive rate.
  • Agent-callable tool with no trigger: model has to decide when to reflect; often forgets.

The forced-moment + agent-judgment combination is the only design where reflection is guaranteed to happen but content remains the agent's decision.

Impact

  • Affected: Users with agents.defaults.soul.autoUpdate: true who want SOUL.md to accumulate without manual editing.
  • Severity: Medium — current state forces manual SOUL.md edits every session for users who want preferences to persist.
  • Frequency: Per-session for active users; signal-keyword turns are common in normal use.
  • Consequence: Static personality file despite documented evolution; user friction every session; the personality layer never matures across interactions.

Evidence/examples

User: please stop using em-dashes
[Runtime detects "stop"; fires reflection sub-turn]
Agent (reflection): [calls soul_update with rule: "never use em-dashes", evidence: "user requested"]
System: Added to SOUL.md: 'never use em-dashes'
Agent (main): [responds to whatever the user actually asked]

Next session, SOUL.md is loaded with the new rule under ## Auto-added. Behavior persists across sessions.

Additional information

Closes the docs-vs-runtime gap documented in the SOUL.md template. Addresses concerns from closed #66847 (security PR on agent writes to instruction files): writes are gated through a structured tool, opt-in default off, with forced notifications and an undo command.

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

openclaw - 💡(How to fix) Fix [Feature]: Code-triggered reflection sub-turns for self-evolving SOUL.md