Skip to content

Prompt assembly scenarios

This page reverse-engineers the major Claude Code prompt shapes from the analyzed cli.renamed.js bundle. It intentionally uses scenario skeletons instead of copying long bundled prompt bodies: the goal is to show which fragments are selected, how they are ordered, and which runtime values fill the gaps.

For exact provider-facing prompt text for one live session, instrument or capture the request after runtime interpolation. The static Prompt template catalog keeps hashes, previews, anchors, and a generated machine-readable JSON catalog for this extracted build; those artifacts are discovery evidence rather than proof of runtime assembly.

Source anchors

Semantic aliasString or symbolMeaning
DynamicPromptBoundary__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__Boundary between cache-stable and per-session/per-machine prompt sections.
SystemPromptResolvervne()Resolves total override, coordinator, agent replacement/append, custom/default base, and late append branches.
DefaultPromptBuilderM2()Builds the default system-prompt fragment array and marks the dynamic boundary.
PromptPartsFetcherfetchSystemPromptParts()Returns {defaultSystemPrompt,userContext,systemContext} and redirects dynamic sections when requested.
WebFetchApplyPromptweb_fetch_applyHelper model call for applying fetched web content to a user task.
WebSearchHelperPromptweb_search_toolWeb-search helper call with a dedicated short system prompt and web-search tool schema.
SubagentRunnerUV()Builds subagent context, prompt, tools, messages, hooks, and cleanup.
SubagentPromptBuilderuqg()y8r(), then pqg()Starts with getSystemPrompt(), appends current subagent/environment notes, and optionally adds scratchpad guidance.
SubagentPromptAppendCLAUDE_CODE_ENABLE_APPEND_SUBAGENT_PROMPT, appendSubagentSystemPromptFeature-gated final fragment appended to the same subagent system-prompt array.
CompactionPromptBuilderquerySource:"compact"Forked and direct compaction helper calls, including the direct short summarizer system prompt.
ApiSystemReminderWrapperN2, kf5, api_systemWraps system reminders and creates mid-conversation provider system blocks.
IssueTitleHelperPromptissue-title helperSmall helper model call for GitHub issue title generation.
SessionNameHelperPromptkebab-case session name helperSmall helper model call that returns a JSON name.
SessionSearchPromptsession_searchAgentic transcript search helper with a specialized system prompt.
StopConditionEvaluatorPromptstop-condition hook evaluatorHook-condition model call that judges transcript/condition satisfaction.
InteractiveAgentBasePromptDefault fragments selected by M2()Main interactive-agent base instructions and behavior-rule fragments.
DynamicEnvironmentPromptW6y(), y8r()Current subagent environment/model/cwd/additional-directory and launch-boundary notes.
ProviderRequestAssemblercallModel()Ead(), qSy(), asSystemPrompt(), KSy(), messages.create(...)Main/helper request assembly, message normalization, provider system blocks, cache metadata, and final dispatch.
MainLoopPromptInputscustomSystemPrompt, appendSystemPrompt, mainThreadAgentDefinitionCurrent main-loop inputs passed to vne().
PromptOverrideFlags--system-prompt, --append-system-prompt, files, --exclude-dynamic-system-prompt-sectionsCLI override/append/dynamic-section controls and file loading.

Current implementation anchors are vne() near line 333575, compact helper calls near lines 347472–348021, subagent assembly near lines 352713–353500, fetchSystemPromptParts() near line 563486, and the default/environment builders near lines 568000–569300. The older Cq5/jX$ aliases are not used as behavioral anchors for 2.1.215.

Notation

The scenario sketches below use this notation:

NotationMeaning
SYSTEM[n]A separate system text block after runtime normalization/cache decoration.
MESSAGE[n]A user/assistant/API-system message in the conversation history.
<...>Runtime-filled value such as cwd, model, git status, settings, memory, tools, or transcript.
[optional]Fragment appears only when the feature or flag is active.
api_systemMid-conversation provider role:"system" block, if supported by the target path/model.
<system-reminder>User-message text wrapper used when a fact should be model-visible without mutating the stable system prefix.

Scenario 1: normal interactive coding session

The default interactive session is not one giant literal. fetchSystemPromptParts() first constructs three different families, then vne() chooses the base text array. Structured tools remain outside all three:

DEFAULT SYSTEM PROMPT (M2)
main interactive-agent base
- identity as an interactive software-engineering agent
- terminal/markdown/tool-output harness rules
- tool permission mode expectations
- system-reminder and tool-result trust rules
- prompt-injection caution for external tool output
- compaction/context-continuation behavior
- prefer minimal task-scoped changes
- do not over-engineer or add speculative abstractions
- preserve user work and avoid risky destructive actions
- ask/adjust when permission is denied
- respect output style and language settings
stable capability guidance and dynamic sections around
__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__
- model name / model family hints
- cwd, shell, platform, OS version
- additional working directories
- git repository and git status summaries
- settings-derived mode flags
USER CONTEXT MAP
- user/org/project instructions and memory-file context
- context intended to travel with user-visible conversation input
SYSTEM CONTEXT MAP
- dynamic context normally supplied as system-side context
SELECTED SYSTEM PROMPT (vne)
- default prompt, unless another branch replaces or layers it
- appendSystemPrompt last when the selected branch permits it
MESSAGES
- normalized transcript
- user prompt and attachments
- runtime <system-reminder> blocks injected near the relevant turn
STRUCTURED TOOLS
- built-in tools selected for the current mode
- MCP/plugin/custom tools that survived filtering/defer policy

M2() supplies default prompt fragments, fetchSystemPromptParts() supplies the context maps, and the provider request path normalizes/cache-decorates those values later. Memory files and tool schemas should not be described as literal SYSTEM[n] blocks merely because they count toward total context.

Scenario 2: custom --system-prompt

When --system-prompt or --system-prompt-file supplies the overrideSystemPrompt lane, vne() returns [overrideSystemPrompt] immediately. This is a total base-prompt replacement branch.

SELECTED SYSTEM PROMPT
<user supplied override text>
MESSAGES
- transcript and current user message
- dynamic reminders may still appear as messages/api_system blocks
TOOLS
- selected tool schemas still travel separately from the prompt text

Important edge cases:

  • --system-prompt and --system-prompt-file are mutually exclusive; the same is true for append prompt vs append prompt file.
  • --exclude-dynamic-system-prompt-sections is documented as applying only with the default system prompt, so it is ignored when the system prompt is replaced.
  • The total overrideSystemPrompt branch returns before vne()’s ordinary append branch. Do not promise that a separately supplied general append survives this branch unless the caller has already merged it into the override input.
  • Request-level normalization, structured tool schemas, transcript messages, and runtime reminders still exist outside the replaced base prompt.

Scenario 3: default prompt plus appended prompt

The ordinary append path preserves the selected default/custom/agent base and places appendSystemPrompt last.

SELECTED SYSTEM PROMPT
normal default/custom base fragments
<appendSystemPrompt>
MESSAGES / TOOLS
- same as the default interactive session

Upstream CLI/policy wiring can contribute to the value passed as appendSystemPrompt; vne() itself observes one late append input rather than exposing separate guaranteed CLI-versus-policy slots.

Scenario 4: default prompt with dynamic sections excluded

With --exclude-dynamic-system-prompt-sections, fetchSystemPromptParts() keeps the default prompt’s stable fragments but merges the normally system-side dynamic map and the separately generated excluded sections into userContext; it returns an empty systemContext.

SYSTEM
- stable default system prompt sections
- stable tool/capability instructions
- appended prompt, if present
FIRST USER MESSAGE
<redirected user-context sections>
- cwd
- environment info
- memory paths
- git status
SUBSEQUENT MESSAGES
- normal transcript and user turns

The exact insertion helper later maps that user-context object into early conversation context. The important design point is that cache-stable identity/rules text can remain cacheable while high-churn local state is redirected away from systemContext; structured tools remain separate.

Scenario 5: --bare / minimal mode

Bare mode narrows automatic context discovery. The root help text says it skips hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery; explicit context still works.

SYSTEM
- explicit --system-prompt or default minimal-compatible system sections
- explicit --append-system-prompt, if provided
- explicit --agents / --plugin-dir / --mcp-config surfaces, if provided
OMITTED OR REDUCED
- automatic CLAUDE.md discovery
- automatic memory/context prefetch
- hooks and LSP-driven context
- plugin sync side effects unless explicitly supplied

This scenario is useful when trying to reproduce prompt behavior because it removes many dynamic sources; it does not remove runtime request framing or explicitly configured tools/context.

Scenario 6: coordinator or selected main-thread agent

Prompt selection is controlled by vne(). Its branch matrix is compact enough to state exactly:

if overrideSystemPrompt exists:
SYSTEM = [overrideSystemPrompt]
else if coordinator mode is active and no main-thread agent exists:
SYSTEM = [coordinator prompt, append prompt?]
else if agent prompt exists and agent.appendSystemPrompt is true:
SYSTEM = [custom/default base, agent prompt, append prompt?]
else if agent prompt exists:
SYSTEM = [agent prompt, append prompt?]
else:
SYSTEM = [custom/default base, append prompt?]

The practical consequences are:

  • most custom agents with their own prompt replace the default main-session body;
  • agents marked appendSystemPrompt: true layer their prompt on top of the main-session prompt;
  • --append-system-prompt remains a late append in either case;
  • custom/SDK/plugin agents can add memory-derived text to getSystemPrompt() when the relevant memory feature is active.

The coordinator branch builds its own prompt based in part on whether a comms-role MCP server is present. It does not first build the ordinary default prompt and then append coordinator text.

Scenario 7: subagent / fork / teammate prompt

UV() builds a subagent request from separate prompt, context, message, and tool planes. Unless the caller supplies override.systemPrompt, uqg() calls the selected agent definition’s getSystemPrompt({toolUseContext}) and passes that fragment through y8r(). y8r() appends the launcher-message trust boundary, subagent operating notes, current environment/model/cwd/additional-directory text, and an optional model-specific fragment. If that path throws, uqg() uses the built-in generic agent prompt before applying the same notes.

pqg() can append scratchpad guidance when exact-tools mode is not active. Finally, when CLAUDE_CODE_ENABLE_APPEND_SUBAGENT_PROMPT is true and appendSubagentSystemPrompt is present, UV() appends that text to the same system-prompt array. The implementation does not promise a distinct SYSTEM[1] block for “runtime notes”; normalization and cache decoration happen later.

SYSTEM PROMPT ARRAY
- agent-specific role/task rules from getSystemPrompt()
- launcher-message trust boundary and operating notes
- model, cwd, git/platform, and additional-directory environment
- final-report expectations
- optional model-specific note
- optional scratchpad guidance
- optional feature-gated appendSubagentSystemPrompt
USER CONTEXT / SYSTEM CONTEXT
- caller overrides, or the normal Jw()/ux() context maps
- Explore/Plan omit selected CLAUDE.md or git-status material
MESSAGES
- task prompt supplied by the caller
- optional filtered parent conversation/fork context prepended before it
- hook and preloaded-skill context when applicable
- tool results local to the subagent thread
STRUCTURED TOOLS
- resolved built-in and agent MCP tools after allow/disallow filtering
- deferred-tool attachments when applicable

Worktree paths affect the subagent permission context, additional working directories, and recorded metadata. They are not evidence that tool availability or fork history is embedded as one dedicated system-text block.

Built-in examples visible in cli.renamed.js include:

Agent familyPrompt shape
ExploreRead-only codebase exploration specialist; omits CLAUDE.md and disallows modifying tools.
PlanRead-only architecture/planning specialist; returns implementation plans without editing.
statusline-setupFocused settings-editing agent for creating/updating the status line command.
background jobMain default/background agent with appendSystemPrompt: true, worktree isolation, and classifier-friendly completion conventions.
plugin/custom/SDK agentFrontmatter/JSON prompt becomes getSystemPrompt(); tools, disallowed tools, MCP servers, hooks, memory, and initial prompt are agent metadata.

Scenario 8: tool-heavy main turn

Tools are not only prose in the system prompt. In provider calls they also appear as structured tool schemas. The prompt side explains when/how to use them, while the tools array controls the callable interface.

SYSTEM
- normal main prompt
- tool-use rules and tool-result trust rules
- dedicated tool descriptions/guards for enabled tools
- deferred-tool instructions when large MCP/tool sets are hidden behind ToolSearch
TOOLS ARRAY
- built-in tool schemas
- MCP tool schemas, possibly deferred
- plugin/custom tool schemas
- permission metadata is enforced outside the model by runtime checks
MESSAGES
- user request
- tool_use / tool_result pairs
- <system-reminder> warnings on tool output, file reads, sandbox/permission state, or recalled memory

This explains why a “full prompt” dump must include both the text system blocks and the structured tools payload; the prompt text alone is incomplete.

Scenario 9: WebSearch helper

The built-in web-search tool uses a small helper model path instead of relying only on the main turn. Near cli.renamed.js line 401521, the code creates a user message equivalent to “perform a web search for this query,” uses a short web-search assistant system prompt, passes an extra web-search tool schema, and sets querySource:"web_search_tool".

SYSTEM
- short web-search-tool role prompt
USER
- query transformed into a search-task instruction
TOOLS
- web_search schema selected as the helper tool
OPTIONS
- querySource = web_search_tool
- prompt caching disabled for this helper path

The helper result is then converted back into model-visible search-result content for the surrounding flow.

Scenario 10: WebFetch apply helper

For fetched page content, the helper path near cli.renamed.js line 372379 truncates very large content, builds a user prompt from the page content plus the original task, and invokes the shared model-call wrapper with an empty system prompt array.

SYSTEM
- empty helper system prompt
USER
- fetched page content, truncated when necessary
- user's requested extraction/summarization/application task
OPTIONS
- querySource = web_fetch_apply
- no tools

So WebFetch prompt assembly is mostly user-message construction, not a large dedicated system prompt.

Scenario 11: compaction and continuation summaries

Compaction has multiple prompt surfaces. The direct fallback helper uses a short summarizer system prompt and passes the conversation to summarize. The preferred forked path and reactive compaction use compact-specific messages and call the agent loop with querySource:"compact", with tools denied on the inspected calls.

SYSTEM
- summarization role prompt
- compact-specific preservation rules
USER / MESSAGES
- transcript sections to summarize
- explicit compact instructions
- security-relevant user constraints to preserve
- optional custom compaction instructions
OUTPUT
- compact summary message, marked as compact summary in transcript state

The current call sites near cli.renamed.js lines 347472–348021 first try runForkedAgent() with querySource:"compact", forkLabel:"compact", one turn, and tools denied. The direct fallback calls callModel() with querySource:"compact", prompt caching disabled, and the short system fragment You are a helpful AI assistant tasked with summarizing conversations. Reactive compaction also uses a forked request with querySource:"compact" and forkLabel:"reactive-compact". Catalog entries remain supporting template evidence rather than the behavioral call-path anchor.

The short line numbers retained in Scenarios 12–14 below are legacy catalog/minified-view discovery coordinates, not current cli.renamed.js semantic line anchors. Their exact prompt strings are useful leads, but enclosing current control flow is required before extending those lifecycle claims.

Scenario 12: hook condition evaluator

Stop-condition and hook-condition prompts are dedicated evaluator calls. The runtime can include a truncated transcript, a condition string, and a JSON schema for the answer.

SYSTEM
- hook-evaluator role prompt
- decide whether the supplied condition is satisfied
- return a constrained JSON result
USER / MESSAGES
- condition text
- transcript content or transcript path
- hook event metadata
OUTPUT
- JSON decision, reason, and optional impossible/error fields

The catalog discovery anchors are line ~8903 for stop-condition evaluation and line ~8918 for broader hook evaluation with tool access and transcript-path context.

Scenario 13: small helper prompts

Many helper calls use the shared model-call wrappers with either an empty system prompt or a short task-specific system prompt. These are not the main session prompt, but they are prompt surfaces worth tracking.

HelperPrompt shapeAnchor
Teleport/session title + branchEmpty system prompt; user prompt asks for title/branch JSON from a description.line ~2783
GitHub issue titleShort system prompt with issue-title rules; user prompt is bug report content.line ~5597
Session titleShort title-generation system prompt; conversation wrapped as data.line ~6606
Kebab-case conversation nameShort system prompt requiring JSON {name}; conversation wrapped as data.line ~6623
Session searchSpecialized search-agent system prompt; transcript dirs/query are user/context.line ~6653
Agent creationAgent-architect prompt plus existing memory/context; expects JSON agent spec.line ~7088
Date/time parserShort parser system prompt; natural-language date is user input.line ~9343
Insights/usage analysisOften empty system prompt; user prompt contains analysis task and usage data.line ~7975-7994

Scenario 14: /insights usage report prompts

Reverse-engineering the /insights anchors shows a prompt pipeline rather than a static report writer.

StageSource anchorPrompt/data role
Session scan and branch pruningcli.renamed.js, line ~7973extractToolStats reads session messages and deduplicateSessionBranches keeps the most representative branch per session.
Usage-report aggregationcli.renamed.js, line ~7973generateUsageReport batches session metadata and cached analyses into a report input.
Facet synthesiscli.renamed.js, line ~7982A helper prompt requires RESPOND WITH ONLY A VALID JSON OBJECT for structured goal/outcome analysis.
Reader summarycli.renamed.js, lines ~8015, ~8078The At a Glance prompt asks for a user-facing summary of usage patterns and opportunities.
Final response promptcli.renamed.js, lines ~7973, ~8884buildInsightsResponsePrompt wraps insightsJson, report URL/path, facets directory, and summary text for the final /insights response.

This makes /insights a helper-model workflow around local session analytics. The exact prompts are not part of the main turn prompt, but they can read derived transcript statistics and produce structured JSON before the final user-facing answer.

How to capture a concrete full prompt

For a live session, the exact provider-visible request exists only after runtime interpolation and normalization. Useful capture points are:

  1. after M2() / Jw() / ux() and vne() in the main loop, where the query handoff contains messages, systemPrompt, userContext, systemContext, selected tools, and cache-breaker state;
  2. at callModel() / Ead() entry, where the resolved system-prompt array, transcript, thinking configuration, selected tools, and model-call options meet;
  3. after qSy() message normalization, to compare messagesPreNormalize with messagesForAPI and see whether api_system survived as provider role:"system" or took the fallback path;
  4. after asSystemPrompt() and KSy(), where runtime prefix blocks are prepended and system-block cache metadata is applied;
  5. in the request-body builder immediately before messages.create(...), where the final model, normalized messages, system, structured tools, tool_choice, betas, metadata, thinking/effort, cache controls, and extra body parameters are all present.

The first point captures Claude Code’s assembled query inputs, while the fifth captures the provider-visible body for a particular attempt. They can differ because normalization, capability gates, retries, and cache decoration occur between them. Capture tooling must redact secrets and sensitive local context; authorization headers are transport data, not part of the prompt.

The static catalog answers “which prompt templates exist?” The scenario map above answers “how do major paths assemble them?” A runtime capture answers “what exactly did this specific request send?”

Created and maintained by Yingting Huang.