The dsh system prompt, explained
What DeepSeek Harness assembles into the system prompt before every model step — the fixed identity, the persona slots, the tool guidance, and the plugins that rewrite them.
Last updated: 2026-10-04
Every turn starts with a system prompt the model reads before anything you typed. In DeepSeek Harness (dsh) that text is not a hand-edited file — it is assembled at request time by the official system-prompt package (packages/core/system-prompt), which merges a fixed identity line, your deployment persona, first-party tool guidance, and every prompt section registered by plugins into one ordered message.
This page explains what goes into that assembly, who can change it, and how the popular prompt plugins — persona editors, prompt armor, thinking-language injectors — hook in. For what happens after the prompt is sent, read the agent loop guide; this page stays on the text itself.
TL;DR
- ▸The prompt is assembled per step, not stored: the system-prompt package sorts registered sections by order and renders the result with renderPrompt.
- ▸The fixed part is one line — “You are an AI agent powered by DeepSeek Harness.” — controlled by the includeHarnessIdentity config (default true).
- ▸You can add text without code: the personaPrefix and personaSuffix config fields, or a Settings-page persona plugin.
- ▸Plugins inject through ctx.systemPrompt.section(...); a section marked complete replaces the entire prompt for its scope.
Where the dsh system prompt comes from
The official subsystem doc states the contract precisely: the system-prompt package owns the data exchanged between prompt contributors and one assembly call. Contributors register PromptSection entries — each with a unique name, a numeric order, and text that is static or resolved per assembly. Sections concatenate in ascending order (ties break by name), and the merged result is what the model receives as the system message.
Three terms carry the whole design:
PromptSection
One contributed block: name, order, text (static or a per-assembly provider), optional undefined} interpolation. Duplicate names throw at registration.
Assembly
One assemble() call merges the global layer with the requesting scope's layer, resolves tool schemas and variables, and runs the system-prompt/assemble waterfall.
Surface node 0
The rendered text is committed as a system-role message of derived history — surface node 0 on the first step, replaced in place when the text changes. It is not a request field.
What the model receives, in order
With first-party defaults on, the rendered prompt follows a fixed order — every slot below is real, from the −1000 identity line to the 10200 persona suffix, exactly as the package README documents the render order:
- 1
The fixed identity line
order −1000 · includeHarnessIdentity“You are an AI agent powered by DeepSeek Harness.” — the one hardcoded sentence, first in the prompt. includeHarnessIdentity: false omits it, recommended only for deployments that own the complete prompt.
- 2
Deployment persona prefix
order 0 · deployment:persona-prefixYour personaPrefix config — or a persona plugin's contribution. The README notes this slot carries the model-name introduction. Empty by default.
- 3
First-party reusable instructions
first-party guidanceThe generated tools SDK and structured-output guidance: how the model is told to call what is mounted. Registered tool schemas ride along in the same assembly.
- 4
Harness source line
order 10000 · harness sourceThe environment-bearing suffix opens with the harness source entry at order 10000.
- 5
Web surface
order 10100 · Web surfaceThe local Web URLs the deployment exposes, rendered next in the suffix at order 10100.
- 6
Deployment persona suffix
order 10200 · deployment:persona-suffixYour personaSuffix config — the last word of the prompt at order 10200, after all first-party text.
- ↻
Dynamic runtime context
separate channelPromptContext → user-role snapshotOrdered PromptContext entries do not join the system text: they become sourced user-role snapshots in model history — a separate, cache-safer channel. includeRuntimeContext: false or a scoped suppressor removes them.
Anything else a deployment registers lands at whatever order it declares — external contributions may use any finite order. One escape hatch exists: a section with complete: true becomes the sole prompt section. Assembly still resolves tools and variables, then restores that exact text as the whole prompt — and two effective complete sections make assembly fail loudly rather than send a malformed prompt.
Who changes it: the three plugin categories
Almost nobody edits YAML to touch the prompt — the community does it through plugins. Our directory tracks 40+ plugins in this cluster, and they fall into three working categories (stars verified 2026-10-04):
Persona editors
xilin3/dsh-prompt-persona (★14) edits the deployment persona from the Settings page with a live preview — the no-code way to fill the two persona slots. The same slots are reachable through plain personaPrefix / personaSuffix config.
Prompt armor
minglink/dsh-infinite-gen-4 (★2,294, the cluster's top star) is the best-known armor-style entry: it hardens the deployed prompt against probing and extraction instead of adding text — protection, not injection.
Injection & prompt context
len7183/dsh-think-zh (★32) and max-null/dsh-chinese-thinking (★10) inject thinking-language directives (next section); asktheway/dsh-auto-memory (★81) contributes long-term memory as dynamic runtime context rather than prompt text.
The Chinese thinking axis
One demand shaped this cluster early: the model's chain of thought defaults to English even when the conversation is in Chinese. Official discussion #8798 collects the request, and two community plugins answer it from the prompt layer — no fork, no model switch.
len7183/dsh-think-zh (★32) adds a thinking-language switch in Settings — Simplified Chinese or default English — and replies follow the question's language while code and identifiers stay untouched. max-null/dsh-chinese-thinking (★10) is the lighter-weight alternative. Both work by injecting a directive into the assembled prompt, which is exactly what the persona slots and plugin sections exist for.
What it costs — and how the prompt reaches the model
The README is candid about the bill: identity is a fixed per-request cost when enabled, and persona prefixes, suffixes and plugin text repeat on every request, scaling with their rendered length. The offsetting mechanism is caching, not deletion:
- ▸While a rendering is unchanged, the prompt stays prefix-stable: the system nodes in history are left untouched and KV-cache reuse holds from turn to turn.
- ▸Any change — a persona edit, a new tool, a different order — invalidates reuse from the first changed token.
- ▸In a continuing series with systemPromptUpdate: 'in-history', a changed prompt is appended after the cached history, so the prefix through that history stays reusable.
- ▸Context compaction cannot shrink any of this — compaction works on retained history, not on the per-step assembly. The lever is trimming what you register, not compacting harder.
how the dsh agent loop runs one turn. how context compaction works.
FAQ
The most common questions about the dsh system prompt.
Can I change the dsh system prompt?
Yes — three ways, in rising order of power. Config: set personaPrefix and personaSuffix (and includeHarnessIdentity: false to drop the opener) on the system-prompt plugin entry. Settings: a persona editor like dsh-prompt-persona edits the same slots visually, no YAML. Code: register a section with ctx.systemPrompt.section(undefined) — and a section marked complete: true replaces the entire prompt for its scope, though two effective complete sections fail assembly.
Does a longer system prompt slow sessions down?
It costs tokens, and caching absorbs most of that. The identity line plus persona plus plugin text repeats per request, but while the rendering is unchanged the system nodes in history stay untouched, so provider-side KV-cache reuse holds between turns. You only pay full price from the first changed token — which is why persona text that churns every turn is the expensive pattern, and stable text is nearly free after the first request.
How do plugins inject into the prompt?
Through the registry. A plugin calls ctx.systemPrompt.section(undefined), and the section is concatenated in ascending order at every assembly. Registrations made through an agent's own ctx are scoped: they shadow same-named globals for that agent only. After merging, the system-prompt/assemble waterfall can rewrite the result — unless a complete section is in play, which listeners cannot add to or replace.
Do different profiles see different system prompts?
They can. Assembly merges a global layer with the requesting scope's layer, and scoped sections, variables and tool providers shadow the global ones per agent — so a work profile and a personal profile that register different persona sections get different prompts from the same install. The fixed identity line and first-party guidance stay the same unless a profile disables them or ships its own complete section.
Is this the model's built-in system prompt?
No — different layers. The model vendor's behavior tuning lives in the weights and is invisible to dsh. The dsh system prompt is runtime text the harness assembles and sends as a system-role message; its only fixed part is the one-line harness identity. That separation is why the same model can behave differently under dsh than under another harness, and why prompt-level plugins work across every model you mount.
Where can I see the actual assembled prompt?
The two official sources below are the authoritative contract: the subsystem doc lists the exact types, and the package README documents the render order and every config field. At runtime, your session's trajectory records what the model received in a given turn — pair it with the loop's logged system-node replacements to see exactly when a prompt changed mid-session.
Related guides
Where the system prompt sits in the bigger picture.
dsh agent loop, explained
How one dsh turn actually runs: turn lifecycle, plugin hook points, and the loop guards that prevent runaway sessions.
Read the guideDeepSeek Harness subagents: run agent teams in parallel
Spawn a five-subagent squad, monitor each child from the header, read completion reports and pin models per subagent — frame-verified steps
Read the guideThe four modes: Standard, PTC, Minimal, Creator
What each agent preset includes, when it wins, and how to build a preset of your own in Creator mode.
Read the guideBest DeepSeek Harness skills to install
Which skills are worth installing and what each one actually does once enabled — demonstrated step by step
Read the guideSources & evidence
Every mechanism on this page traces to the sources below; commit shas and star counts verified 2026-10-04.
