dsh-inject-head
Inject a fixed block of text at the very top of every DeepSeek Harness system prompt — including presets that normally discard outside contributions.
Zero dependencies. One file to edit. Takes effect on the next turn, no restart.
your text ← line 1, this plugin
You are an AI agent that helps the user… ← harness identity
…deployment persona, tools, policies…
Why this needs two mechanisms
DSH assembles a prompt by sorting sections ascending on (order, name) and joining the non-empty ones with blank lines. A section at order -5000 therefore lands above harness:identity (-1000) and the deployment persona (0):
| Section | Order |
|---|---|
operator:head ← this plugin |
-5000 |
harness:identity |
-1000 |
deployment:persona-prefix |
0 |
| tools / policies | 1000 … 9900 |
deployment:persona-suffix |
10200 |
But a preset declared complete: true (for example minimal) runs sections: [ownPersona] at the end of assembly and throws every other section away. No section can reach it — that is host behaviour, not a limitation of this plugin.
So the plugin registers two things from the same text source:
- the global section
operator:headat order-5000, withinterpolate: falseso braces and{{…}}in your own words can never break an assembly; - the prompt variable
inject_head.
Section-based presets get the text for free. For a complete: true preset, add one line to that preset's persona prefix:
prefix: >-
{{inject_head}}
You are a helpful software engineer assistant.
The same file still drives the text. Nothing else about the preset changes.
Install
The package declares dsh.bundle.patch, so it installs as a normal bundle.
git clone https://github.com/HYBB-rash/dsh-inject-head.git
Then point the plugin manager at the cloned directory — install_bundle with its absolute path — or add it to ~/.dsh/profiles/<profile>/package.json by hand:
{
"dependencies": {
"dsh-inject-head": "link:/absolute/path/to/dsh-inject-head"
},
"dsh": {
"profile": {
"bundles": ["…", "dsh-inject-head"]
}
}
}
Link the package into the profile's node_modules, then restart the harness once. Editing the text afterwards never needs a restart.
Configure
One text source, four levels, highest priority first:
| Priority | Source | Notes |
|---|---|---|
| 1 | DSH_INJECT_HEAD_TEXT |
inline; trimmed |
| 2 | DSH_INJECT_HEAD_FILE |
path to a UTF-8 file; trimmed |
| 3 | $DSH_HOME/inject-head.md |
default path (~/.dsh/inject-head.md) |
| 4 | DEFAULT_TEXT in index.mjs |
'' — inject nothing |
mkdir -p ~/.dsh
printf 'Answer in English. Prefer short answers.\n' > ~/.dsh/inject-head.md
- edit the file → next assembly picks it up (cached on
mtime) - empty the file → injection silently stops
- delete the file → nothing is injected
Use the environment variables when you want the text to travel with the shell rather than with the home directory — useful for per-project overrides.
Verify
Ask the harness to dump the composed prompt, or check the first line of any session:
dsh --profile "$DSH_PROFILE" --dump-config
The plugin row appears as inject-head with name pointing at index.mjs. To check the assembled prompt instead, ask your agent "what is the first line of your system prompt?" — it should be your text verbatim.
Run the plugin's own tests:
npm test # 9/9 passed
Limits
complete: truepresets need the one-line persona edit. The plugin cannot inject a section into them; only the variable route works.- Don't edit a preset persona that another plugin asserts on. Some plugins validate a preset's persona by exact string equality and silently disable themselves when it changes. Adding
{{inject_head}}to such a preset will trip that check — use a different preset, or leave that one uncovered. - The text enters session history. It is part of the system prompt, so it shows up in exported or shared sessions. Never put secrets in it.
- It costs tokens every turn. A short line is negligible; a paragraph is not.
中文说明
在每份系统提示词的最上方注入一段固定文本。
- 唯一真源是
~/.dsh/inject-head.md,改完下一轮即生效,不用重启 - 清空文件即关闭注入,删除文件则什么都不注入
- 也可用
DSH_INJECT_HEAD_TEXT(直接给文本)或DSH_INJECT_HEAD_FILE(指定文件)覆盖
覆盖范围:普通 preset(standard / ptc / cordis 这类按 section 组装的)自动生效;声明了 complete: true 的 preset(如 minimal)在组装末尾会丢弃所有其它 section,需要你在它的 persona 前缀里加一行 {{inject_head}},文本仍由同一个文件驱动。
已知边界:若某个 preset 的 persona 被其它插件按精确字符串校验,改它会让那个插件静默失效 —— 这种情况请换一个 preset,或让它保持不覆盖。注入内容会进入会话历史,导出或分享会话时可见,不要放密钥。
License
MIT © 2026 Herman Hong
No comments yet. Be the first to write one.