DeepSeek Harness system prompt sections in a DSH plugin
A DSH plugin adds to the system prompt not by concatenating a string field but by registering contributors through ctx.systemPrompt, which one assembly call resolves, orders, and renders into a surface node (source). This article covers the four contribution kinds and their ordering, why the prompt is "surface node 0" rather than a request field, and the authority and ceiling of the assemble waterfall; where the prompt comes from and why it grows is explained in the system prompt explained, while this article covers the contract a developer must implement.
The four kinds of contribution and their ordering in a DSH plugin system prompt
The system prompt assembly package manages the data exchanged between prompt contributors and one assembly call, across four contribution kinds: section, context, tools, and variable (source).
section— the prompt text itself. APromptSectionhas a uniquename(duplicate registration throws), anorder(concatenated ascending, with equal orders using code-unit name order),text(a static string or a provider evaluated at each assembly, referencing{{variable}}s interpolated later byrenderPrompt), and an optionalcomplete.context— the cache-safe counterpart of a section, materialized as a durable user-role snapshot; aPromptContextis likewise unique byname, joined in ascendingorder, and empty text contributes nothing.tools— a tool schema provider returning aToolProviderResult:schemasis the schema set visible to the model in this assembly, andknownNamesis the pre-restriction name universe used to tell a typo in configuration from a known tool deliberately hidden in this scope.variable— a prompt variable whosenamematches[a-z][a-z0-9_]*; theprovidermay returnundefined, but rendering a section that references that value then fails.
Ordering is two-stage: sections first sort by ascending order, then by code-unit name order. Repository contributors resolve their centrally owned placement via getSectionOrder() (such as DEPLOYMENT_PERSONA_PREFIX / DEPLOYMENT_PERSONA_SUFFIX), and runtime-context contributors resolve a separate allocation via getContextOrder(). By scope, scoped sections and variables shadow same-named globals, and duplicates within one layer and non-finite orders both throw.
A DSH plugin system prompt is surface node 0, not a request field
After cooperative assembly, one effective complete section becomes the sole prompt section; the agent loop renders the sections with renderPrompt and submits the text as the system/message surface node (source). There are three ways it is submitted:
- First step — appended as surface node 0.
- When the rendered text changes — the node is replaced in place.
- Sequence continuation where the prepared call declares
systemPromptUpdate: 'in-history'— the non-empty update is appended after the cached history.
The key takeaway: the system prompt reaches the model as a message in the derived history rather than a request field. Changing the prompt therefore means replacing or appending a surface node, not editing a request header — which is why prompt changes flow through the log and replay uniformly.
The context path is more restrained: assembly resolves and orders those contributions, but the agent loop records it after the retained model history only when the full current snapshot changes or compaction removes it.
The authority and ceiling of the DSH plugin assemble waterfall
system-prompt/assemble is an expert waterfall over the assembled sections, contexts, tools, and variables with scope-filtered dispatch, so scoped listeners receive only that scope's assemblies and the returned value is authoritative (source). Three boundaries cannot be crossed:
- A
completesection is restored after the waterfall — if an effectivecompletesection is registered, assembly restores it as the sole prompt section after the waterfall, so listeners cannot add to or replace that scope's system prompt. More than one effectivecompletesection makes assembly fail. - The signal belongs to this assembly only — the
signalthe waterfall receives controls only this explicit assembly request and must not be retained to control later turns. - Reserved names and suppression — a
tools()provider returning the reservedTOOL_ORDER_RESTname makes assembly fail;suppressRuntimeContext()can suppress every dynamic runtime-context contribution in the calling context's scope without changing the services that own or enforce those facts, and multiple suppressors remain independently disposable.
Also: system-prompt/change is an unfiltered registry notification (a global change affects every scope); ctx.systemPrompt.assemble(context) assembles global and scoped providers, detaches tool parameters, applies canonical ordering, runs the waterfall, then enforces any complete section.
Three self-checks when done: is name unique and order finite; when replacing the whole prompt, did you use complete instead of mutating the waterfall result; and did you avoid caching signal to control later turns. To find community implementations of prompt plugins, search the DSH Plugin Hub; for extension-point ownership see the feature-to-mechanism map.
FAQ
A DSH plugin registers an ordered prompt section in the calling context's scope with ctx.systemPrompt.section(section): a PromptSection needs a unique name, an ascending order, and text that is either a static string or a provider evaluated at each assembly, and the call returns the exact Cordis effect disposer. A scoped section shadows a global section with the same name, while duplicates within one layer and non-finite orders throw.
Prompt assembly in a DSH plugin has four kinds of contribution: section is the prompt text itself, context is dynamic runtime context materialized as a durable user-role snapshot, tools provides the tool schemas visible to the model in this assembly, and variable is an interpolation value referenced by {{variable}}. Both sections and contexts are read-only in-process conventions, ordered by ascending order and then by code-unit name order.
A DSH plugin system prompt is neither a request field nor a history message, but a surface node: the agent loop renders the assembled sections with renderPrompt and submits the text as the system/message surface node — appended as surface node 0 for the first step, then replaced in place when the rendered text changes, or appended after the cached history during sequence continuation when the prepared call declares systemPromptUpdate: 'in-history'. So the prompt reaches the model as a message in the derived history rather than a request field.
The DSH plugin system-prompt/assemble value is authoritative because it is an expert waterfall over the assembled sections, contexts, tools, and variables with scope-filtered dispatch, so scoped listeners receive only that scope's assemblies. It has one ceiling: if an effective complete section is registered, assembly restores it as the sole prompt section after the waterfall, so listeners cannot add to or replace that scope's system prompt.
In a DSH plugin, set a PromptSection's complete to true: that contribution is treated as the complete system prompt, assembly still runs the cooperative waterfall to resolve tools, contexts, and variables, and then restores that exact section as the sole prompt section. Note that more than one effective complete section makes assembly fail, and a tools provider returning the reserved TOOL_ORDER_REST name also fails assembly.
Related Terms
- AssembleContext
- AssembleContext is the merge-extensible context in DeepSeek Harness that identifies the scope layer one prompt assembly resolves, carrying an optional scope and the explicit signal for that request; dsh-agent adds an agent field, assembleContextFor(agent, signal) sets these together, and a bare assembly has neither scope nor signal.— https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/system-prompt
- PromptSection
- PromptSection is the read-only in-process prompt registration convention, carrying a unique name, an ascending order, text that is static or a provider (and may reference {{variable}}s), and an optional complete flag; sections concatenate in ascending order then by code-unit name order, and duplicate registration throws.— https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/system-prompt
- PromptContext
- PromptContext is the cache-safe counterpart of PromptSection, carrying a unique name, an ascending order, and text; assembly resolves and orders these contributions, and the agent loop records it after the retained model history only when the full current snapshot changes or compaction removes it.— https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/system-prompt
- systemPromptUpdate: 'in-history'
- systemPromptUpdate: 'in-history' is a declaration on a prepared call meaning that when the rendered text changes, the non-empty update is appended after the cached history instead of replacing the system/message surface node in place, preserving derived-history semantics for prompt changes during sequence continuation.— https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/system-prompt