Deep Analysis

OpenClaw Prompt Construction & Agent Loop

How a user message flows through string assembly, the pi-agent-core harness, stream wrapping, tool execution, and compaction — with full lineage tracking.

github.com/openclaw/openclaw ~3,290 lines in run/attempt.ts 14 source files analyzed
01
System Prompt Construction
25+ string components assembled into the final system prompt — exact file lineage

System Prompt Assembly — Flow Diagram

Mermaid
Component Lineage Table — 25 String Components
Component / FunctionSource FileLinesDescription
buildAgentSystemPrompt()src/agents/system-prompt.ts439–1048Master builder — orchestrates all sections in order
buildFullBootstrapPromptLines()src/agents/bootstrap-prompt.ts1–13Full bootstrap: read BOOTSTRAP.md, complete workflow
buildLimitedBootstrapPromptLines()src/agents/bootstrap-prompt.ts15–25Limited: explain blocker, suggest next step
BOOTSTRAP.md content.pi/prompts/cl.md58 linesChangelog audit skill — audit entries before release
BOOTSTRAP.md content.pi/prompts/is.md22 linesIssue analysis skill — audit GitHub issues
buildBootstrapPromptWarning()src/agents/bootstrap-budget.tsPrepends "⚠️ Bootstrap budget..." warning if near limit
buildSkillsSection()src/agents/system-prompt.ts156–172Skills instructions: "scan available_skills..."
buildMemorySection()src/agents/system-prompt.ts174–187Memory citations guidance via plugins/memory-state.ts
buildDocsSection()src/agents/system-prompt.ts395–425Docs links: docs.openclaw.ai, GitHub, Discord, ClawhHub
buildMessagingSection()src/agents/system-prompt.ts335–382sessions_spawn, sessions_send, subagents guidance
buildVoiceSection()src/agents/system-prompt.ts384–393TTS hint via buildTtsSystemPromptHint()
buildHeartbeatSection()src/agents/system-prompt.ts127–138"If heartbeat poll: reply HEARTBEAT_OK"
buildExecutionBiasSection()src/agents/system-prompt.ts299–313"Actionable request: act in this turn..."
Safety Constitutionsrc/agents/system-prompt.ts672–678No independent goals, prioritize safety, no manipulation
CLI Quick Referencesrc/agents/system-prompt.ts777–788openclaw gateway status/restart, config.schema.lookup
Self-Update Rulessrc/agents/system-prompt.ts793–803Updates only on explicit user request
Silent Reply Rulessrc/agents/system-prompt.ts955–970SILENT_REPLY_TOKEN when nothing to say
buildProjectContextSection()src/agents/system-prompt.ts95–125Loads workspace files: agents.md, soul.md, identity.md...
CONTEXT_FILE_ORDER mapsrc/agents/system-prompt.ts44–52File priority: agents.md(10) → soul.md(20) → ... → memory.md(70)
buildWebchatCanvasSection()src/agents/system-prompt.ts275–297[embed...] directives for webchat only
buildOwnerIdentityLine()src/agents/system-prompt.ts232–246"Authorized senders: [hash or raw numbers]"
buildTimeSection()src/agents/system-prompt.ts248–253"## Current Date & Time — Time zone: {tz}"
SYSTEM_PROMPT_CACHE_BOUNDARYsrc/agents/system-prompt-cache-boundary.ts"--- SYSTEM PROMPT CACHE BOUNDARY ---" separator
buildRuntimeLine()src/agents/system-prompt.ts1006–1048"Runtime: agent=X | os=Y | node=Z | model=A | channel=B"
Provider overridessrc/plugins/provider-runtime.jstransformProviderSystemPrompt() wraps final output
Context File Loading Priority
Files sorted by CONTEXT_FILE_ORDER map then alphabetically. heartbeat.md is marked dynamic (below cache boundary).
agents.md → 10 soul.md → 20 identity.md → 30 user.md → 40 tools.md → 50 bootstrap.md → 60 memory.md → 70 heartbeat.md → dynamic
Bootstrap Prompt Files
.pi/prompts/cl.md — Changelog Audit
---
description: Audit changelog entries
---
Audit changelog entries for all commits
since the last release.

## Process
1. Find last release tag
2. List commits since that tag
3. Read each package's [Unreleased] section
4. Check: skip changelog updates,
   doc-only, release housekeeping
5. Cross-package duplication rule:
   → duplicate to coding-agent
6. Add New Features section
7. Report missing entries
.pi/prompts/is.md — Issue Analysis
---
description: Analyze GitHub issues
---
Analyze GitHub issue(s): $ARGUMENTS

1. Read the issue in full
2. For bugs:
   - Ignore root cause (likely wrong)
   - Read all related code files
   - Trace code path
   - Propose a fix
3. For features:
   - Read related files
   - Propose concise implementation
   - List affected files

Do NOT implement unless asked.
02
The Agent Run Attempt
From runEmbeddedAttempt() to the turn loop — all 3,290 lines of the core harness

runEmbeddedAttempt() — High-Level Flow

Mermaid
runEmbeddedAttempt() — 12-Phase Breakdown
PhaseLinesKey FunctionsPurpose
1. Setup579–610resolveUserPath(), AbortController, mkdir workspaceResolve paths, create abort controller, ensure workspace exists
2. Model ResolutionresolveModelAsync(), normalizeResolvedModel()Resolve provider, model ID, API format (openai/anthropic/etc.)
3. SandboxresolveSandboxContext()Determine if running in Docker sandbox, mount paths
4. Session Manager1284–1290SessionManager.open(), guardSessionManager()Open/update session file, install tool result guards
5. System Prompt1200–1201buildSystemPromptOverride() → buildEmbeddedSystemPrompt()Assemble all 25+ prompt components from Section 01
6. Tool Setup1330–1413splitSdkTools(), toClientToolDefinitions(), createAgentSession()Build tool allowlist, create session with tools
7. Stream Wrapping1556–186610 x wrapStreamFn*() wrappersWrap streamFn with transforms (see Section 03)
8. History Prep1869–1967sanitizeSessionHistory(), limitHistoryTurns(), filterHeartbeatPairs()Prune, truncate, sanitize transcript before LLM call
9. Hook Runner2258–2267resolvePromptBuildHookResult()Fire llm_input hooks (async, fire-and-forget)
10. Prompt Submit2649–2702activeSession.prompt() — THE CORE CALLSend to LLM; pi-agent-core handles turn loop internally
11. Compaction Wait2750–2784waitForCompactionRetryWithAggregateTimeout()Wait for background compaction (up to 60s aggregate)
12. Result ReturnEmbeddedRunAttemptResultReturn transcript, usage metrics, compaction count
Key Insight: Turn Loop is Inside pi-agent-core
activeSession.prompt() delegates the turn loop to @mariozechner/pi-agent-core. That library's prompt() method:
  • Sends the current transcript (messages + system prompt) to the LLM API
  • Receives a streaming response
  • When the model emits tool_use blocks → executes tools sequentially
  • Appends each tool_result back to the transcript
  • Loops back until stop_reason ≠ "tool_use"
  • Emits streamed text blocks back to OpenClaw via subscription callbacks
03
Stream Wrapping Chain
10 sequential wrappers applied bottom-up to transform the raw LLM stream

Stream Wrapper Stack — Applied Bottom-Up

Mermaid
Stream Wrapper Detail
#Wrapper FunctionSourceWhat It Does
1resolveEmbeddedAgentStreamFn()stream-resolution.ts:64Selects transport: OpenAI WS, Anthropic Vertex, or pi streamSimple
2Yield Abort Gateattempt.ts:1778Intercepts "sessions_yield" abort; returns createYieldAbortedResponse()
3wrapStreamFnSanitizeMalformedToolCalls()attempt.ts:1791Fixes malformed tool call JSON in streaming response
4wrapStreamFnTrimToolCallNames()attempt.ts:1796Trims whitespace from tool names; guards against unknown-tool loop (3 strikes)
5wrapStreamFnRepairMalformedToolCallArguments()attempt.ts:1810Repairs malformed JSON args in tool call input blocks
6wrapStreamFnDecodeXaiToolCallArguments()attempt.ts:1816Decodes HTML entities (e.g. <) in xAI tool call arguments
7createAnthropicPayloadLogger().wrapStreamFn()anthropic-payload-log.tsLogs full request/response payloads for debugging
8wrapStreamFnHandleSensitiveStopReason()attempt.ts:1829Catches provider-specific "sensitive" stop reasons before error bubble
9streamWithIdleTimeout()llm-idle-timeout.tsAborts if model is silent for > idleTimeoutMs (configurable per trigger)
10wrapStreamFnWithDiagnosticModelCallEvents()attempt.ts:1853Emits diagnostic events per model API call (runId, sessionId, provider...)
Conditional wrappers (applied additionally when conditions are met):
C1wrapStreamFnTextTransforms()plugin-text-transforms.tsProvider-specific input/output text transforms
C2cacheTrace.wrapStreamFn()cache-trace.tsRecords prompt cache stages for observability
C3Google Prompt Cachegoogle-prompt-cache.tsUses Google's cached prompt feature if available
04
Turn Loop & Parallelism
Sequential tool execution, parallel compaction, async hooks — precise boundaries

Turn Loop — Tool Execution & Parallelism

Mermaid

Compaction — Preemptive vs Background

Mermaid
✓ Parallel Activities
  • Compaction — background while LLM thinks. compactWithSafetyTimeout() with grace period. If it overruns, run proceeds with pre-compaction state.
  • LLM Input Hooksllm_input hooks fire asynchronously before each LLM call (fire-and-forget, attempt.ts:2539–2566).
  • Payload LoggingcreateAnthropicPayloadLogger records without blocking.
  • Context EngineassembleAttemptContextEngine() preprocesses messages in parallel (attempt.ts:1923–1958).
✗ Sequential Only
  • Tool calls within a turn — always sequential, order-dependent. Each tool_result appended before the next LLM call.
  • History truncation — synchronous: limitHistoryTurns() must complete before activeSession.prompt().
  • Stream wrapper application — synchronous chain applied before any LLM I/O.
  • Abort timer scheduling — synchronous: scheduleAbortTimer() sets up timeout before prompt starts.
05
Harness Selection
How OpenClaw picks between the built-in pi harness and plugin harnesses (Codex, Claude Code...)

Agent Harness Selection — Decision Tree

Mermaid
Harness Policy Resolution
Selection ReasonConditionHarness
pinnedagentHarnessId pinned via configpi or plugin (forced)
forced_piruntime="pi" in policypiHarness (embedded)
forced_pluginruntime="plugin-id" (specific)Named plugin harness
forced_plugin_fallback_to_piplugin not registered + fallback≠nonepiHarness
auto_pluginruntime="auto" + plugin supports providerHighest-priority supporting plugin
auto_pi_fallbackruntime="auto" + no plugin supportspiHarness (built-in)
pi-agent-core Imports
Two core packages from @mariozechner:
@mariozechner/pi-agent-core @mariozechner/pi-coding-agent
These provide: createAgentSession(), SessionManager, DefaultResourceLoader, and the StreamFn type.
06
Core Types & Tool Payloads
EmbeddedRunAttemptParams, tool call/request/result types, and session manager interfaces
EmbeddedRunAttemptParams — Key Fields
FieldTypeDescription
sessionIdstringUnique run session ID
sessionKeystringRouting key (user/session)
sessionFilestringDisk path to session JSON file
providerstring"anthropic" | "openai" | "openai-codex"...
modelIdstring"claude-sonnet-4-7-20250514"
modelProviderRuntimeModelResolved model with api, baseUrl, contextWindow
promptstringCurrent user message
thinkLevelThinkLevel"off" | "fast" | "medium" | "high"
reasoningLevelReasoningLevel"off" | "summary" | "block"
timeoutMsnumberRun timeout (default: from config)
configOpenClawConfigFull runtime config
workspaceDirstringAgent working directory
authStorageAuthStorageAPI key storage
toolsAllowstring[]Explicit tool allowlist
abortSignalAbortSignalExternal abort from gateway
Tool Result Payload Flow
ToolUse:      { id, name, input: Record<string, unknown> }
ToolResult:   { toolUseId, content: string }
StopReason:   "tool_use" | "end_turn" | "max_tokens" | "stop_sequence" | ...

// Per-turn message flow:
UserMessage
  → activeSession.prompt()
  → LLM emits: tool_use{id, "read", {path:"/foo.txt"}}
  → ToolExecutor.execute("read", {path:"/foo.txt"})
  → ToolResult{toolUseId: id, content: "file contents..."}
  → transcript.push(tool_result)
  → LLM (next iteration)
  → until stop_reason ≠ "tool_use"
07
Complete Architecture
End-to-end flow from user message to LLM API call to response

Full System Architecture

Mermaid
Key Files Referenced
FileRoleLines
src/agents/system-prompt.tsMaster system prompt builder — all 25+ sections1,048
src/agents/bootstrap-prompt.tsBootstrap prompt lines builder (full/limited)25
src/agents/context.tsMemory section and context file handling
src/agents/pi-embedded-runner/run/attempt.tsrunEmbeddedAttempt — THE core harness3,290
src/agents/pi-embedded-runner/compact.tsBackground compaction orchestration1,287
src/agents/pi-embedded-runner/model.tsModel resolution + context window cache1,121
src/agents/pi-embedded-runner/stream-resolution.tsStream transport selection (WS/HTTP/Vertex)132
src/agents/harness/selection.tsHarness selection decision tree399
src/agents/pi-embedded-runner/run/payloads.tsTool call/request/result type definitions
src/plugins/provider-runtime.jsProvider plugin hooks + system prompt transforms
src/plugins/memory-state.jsMemory citations prompt section builder
src/agents/bootstrap-budget.tsBootstrap warning prepend logic
src/agents/session-write-lock.jsSession write lock for concurrent safety
src/agents/session-compaction-checkpoints.jsCompaction checkpoint snapshot system
.pi/prompts/cl.mdBootstrap skill: Changelog Audit58
.pi/prompts/is.mdBootstrap skill: Issue Analysis22