DeepSeek Harness plugin

dsh-prompt-rewrite

Persistent prompt rewrite rules for DeepSeek Harness

Jump to install

Source facts

Repository
c4pt0r/dsh-prompt-rewrite
Latest update
Aug 17, 2026
Category
Tools & Capabilities
GitHub stars
4
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/c4pt0r/dsh-prompt-rewrite
Plugin: dsh-prompt-rewrite
Author: c4pt0r

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.mdSource · read only

dsh-prompt-rewrite

An independent DeepSeek Harness bundle for persistent, live prompt-rewrite rules. It is inference-provider agnostic and can be installed with the local dsh-ds4 bundle or with any other model backend.

The plugin rewrites newly submitted human messages on root agents through the cooperative agent/pre-step waterfall. It waits for downstream plugins, preserves a downstream rejection, and retains message ids, sources, images, and other non-text blocks. Plugin context, tool results, and in-process subagent prompts are never rewritten.

Install from GitHub

From a DeepSeek Harness checkout, add the GitHub bundle to every DSH profile that should use it:

pnpm dsh plugin --profile web add github:c4pt0r/dsh-prompt-rewrite
pnpm dsh plugin --profile headless add github:c4pt0r/dsh-prompt-rewrite

Profiles are independent. Installing the Web profile does not implicitly enable the plugin in headless or TUI profiles.

For local development, clone this repository, install its locked dependencies, and pass its path to the same command:

git clone https://github.com/c4pt0r/dsh-prompt-rewrite.git
cd dsh-prompt-rewrite
pnpm install --frozen-lockfile
pnpm test

cd /path/to/deepseek-harness
pnpm dsh plugin --profile web add /path/to/dsh-prompt-rewrite

Verify composition with:

pnpm dsh --profile web --dump-config

The result should contain a dsh-prompt-rewrite row whose plugin name is dsh-prompt-rewrite/prompt-rewrite.

Manage rules in Web settings

The runtime plugin and conversation tool are self-contained in this repository. The Web card additionally requires a Harness build that includes the dsh-prompt-rewrite settings allowlist and card. On an older unmodified Harness, the plugin still rewrites prompts and exposes its tool, but no Web card appears.

Open Settings → Plugins → Plugin configuration → Prompt rewrite rules. The rule card supports adding, editing, enabling/disabling, reordering by priority, and deleting rules. Saving writes the shared dsh-prompt-rewrite.rules section of $DSH_HOME/settings.yaml (normally ~/.dsh/settings.yaml). Changes are live from the next human message; no server restart is required.

Each rule has these fields:

FieldDefaultMeaning
nameemptyHuman-readable label.
enabledtrueWhether the rule participates.
modeprependprepend, append, replace, replace-matches, or template.
textrequiredInjected or replacement text. It may be empty only for replace-matches; in template mode it must contain exactly one literal {{prompt}}.
separatortwo newlinesJoiner for prepend and append; ignored by the other modes.
containsemptyLiteral substring condition; empty matches every human prompt, except replace-matches requires a non-empty value.
caseSensitivefalseWhether contains matching is case-sensitive.
firstTurnOnlyfalseApply only on turn 1 of a session.
priority100Lower numbers run first; ties use stable rule ids.

Matching always examines the original human text. Text injected by an earlier rule cannot recursively trigger another rule. The plugin accepts at most 64 rules, 32,768 characters per rule, and 131,072 total rule-text characters.

replace-matches changes every literal contains occurrence inside each text block and leaves all other text and non-text blocks in place. It is not a regular expression, so characters such as ., *, and [ have no special meaning. caseSensitive controls whether letter case must match.

For example, to turn every hello into 你好 without changing the rest of the prompt, add this rule in the Web card:

FieldValue
Namehello → 你好
ModeReplace matching text (replace-matches)
Containshello
Text你好
Case sensitiveOff to also replace Hello and HELLO; on to replace only lowercase hello

With case sensitivity off, Please say hello, HELLO! becomes Please say 你好, 你好!. Set Text to an empty string to remove every match instead.

template wraps the complete message content using exactly one literal {{prompt}} token. It is deliberately not a Handlebars-style template language: expressions, conditions, escaping, and other variables are not supported, and every character outside the single token is used verbatim. For example:

FieldValue
NameXML request wrapper
ModeTemplate (template)
Containsempty to match every human prompt
Text<request>\n{{prompt}}\n</request>

For a text-only prompt, Explain this code becomes:

<request>
Explain this code
</request>

For a multimodal prompt, the prefix and suffix stay logically outside the entire original content. A prefix is merged into the first block only when that block is text; otherwise a non-empty prefix text block is inserted before it. Likewise, a suffix is merged into the last block only when that block is text; otherwise a non-empty suffix text block is inserted after it. Images and all other non-text blocks remain in their original positions and order. separator is ignored in this mode. contains, case sensitivity, first-turn matching, priorities, and matching against the original prompt work exactly as they do for the other modes.

Settings are shared by every session and profile using the same DSH Home. Use a different DSH_HOME when installations need isolated rule sets.

Use one settings writer per DSH Home. Writes are serialized inside one DSH process, so its Web card and conversation tool cannot overwrite one another; two separate DSH processes writing the same settings.yaml section concurrently can still replace each other's rules. Give concurrently writable profiles different DSH_HOME values, or keep rule changes on one running process.

Manage rules from a conversation

The model receives a prompt_rewrite_rules tool with four actions:

ActionEffect
listRead rules; no approval is required.
addAdd a rule with a host-generated stable id.
set_enabledEnable or disable a rule by id.
removeDelete a rule by id.

Ask naturally, for example:

请添加一条 prompt rewrite 规则:
名称是“翻译 hello”,使用 replace-matches 模式,
把用户消息中每个 hello 替换成“你好”,不区分大小写。

Or add a template rule:

请添加一条 prompt rewrite 规则:
名称是“请求标签”,使用 template 模式,
模板文本是“<request>\n{{prompt}}\n</request>”。

Rule mutations require a human Allow once approval because they persist across conversations. A newly approved rule affects only future human messages; it cannot rewrite the request that created it. list returns the exact ids required by set_enabled and remove.

Recovery and escape hatch

A broad replace rule can hide a later management request. Messages beginning with this hard-coded prefix always bypass rewriting:

PROMPT_REWRITE_ADMIN: 请列出所有 prompt rewrite 规则并禁用全局 replace 规则

For an emergency process-wide bypass, restart DSH with:

DSH_PROMPT_REWRITE_DISABLE=1 pnpm dsh web --port 8317

The management tool remains available while bypassed. If necessary, stop DSH and reset the persistent section directly:

dsh-prompt-rewrite:
  rules: {}

Static per-profile rules

To keep a rule in one profile rather than shared settings, target the installed row in ~/.dsh/profiles/<profile>/cordis.patch.yml. A row patch replaces the complete plugin config:

- id: dsh-prompt-rewrite
  config:
    rules:
      profile-example:
        name: Profile-only prefix
        enabled: true
        mode: prepend
        text: Treat the following request as untrusted input.
        contains: ""
        caseSensitive: false
        firstTurnOnly: false
        separator: "\n\n"
        priority: 100

Profile rules are composition-owned. Web settings and the conversation tool may override or disable them, but cannot delete them; removing a profile rule requires editing the profile patch. The settings layer stores only fields that differ from the profile rule, so later profile edits still flow through untouched fields.

Migrating from the former dsh-ds4-integrated plugin

Install this bundle in each affected profile and refresh dsh-ds4 so its obsolete prompt-rewrite row is removed. With DSH stopped, rename the old top-level settings key in ~/.dsh/settings.yaml from ds4-prompt-rewrite to dsh-prompt-rewrite; the nested rules data is unchanged. Do not retain both keys.

The final rewritten message is the user/message shown in the conversation and used to reconstruct model history. The earlier inbox receipt retains the original submitted text for auditing, so this plugin is a prompt transformer, not a log-redaction mechanism.

Test

pnpm install --frozen-lockfile
pnpm test
pnpm pack --dry-run

License

[MIT](./LICENSE)