Preface

The most common way to add constraints to coding Agents is to write rules into the system prompt: do not run pip install directly, use gh for GitHub API requests, use a designated skill to read PDFs. As the number of rules grows, you have to carry all this text into the context window at every step, even though the scenarios that actually trigger them are rare. The context window gets clogged, and the model may still fail to remember them.

The core philosophy of DeepSeek Harness (dsh) is “everything is a plugin”: models, tools, sessions, and UIs can all be added, removed, or replaced via plugins. The community has thus developed many extensions built on this idea. dsh-stream-rules does a narrow thing: it does not stuff rules into the system prompt normally, and only injects a steering prompt when a tool call matches a pattern. It reminds you when needed, and does not occupy context window space otherwise.

First, a clarification: this article covers community plugins. DeepSeek Harness itself is open-sourced by DeepSeek, and the plugin directory site deepseek-harness-plugin.com is an independent community index, with no official affiliation to DeepSeek / Fangxin. It is not an official app store. You should review the source code and license before installing.

What it is

dsh-stream-rules is a “Tools and Capabilities” plugin for DeepSeek Harness, maintained by jiesou, with its repository at jiesou/dsh-stream-rules, licensed under MIT. The npm package name is @jiesou/dsh-stream-rules. As of 2026-08-18, both the GitHub repo and the directory page show 4 stars; the version in the repository’s package.json and on npm is both 0.1.7.

The author positions it as a port of jiesou/opencode-stream-rules to DSH. The README states that the idea is similar to oh-my-pi’s Time-traveling stream rules: rules lie dormant normally, and are only injected when matched, avoiding the context window tax on every round. The implementations differ, however. oh-my-pi will interrupt and retry mid-stream output; dsh-stream-rules hooks into DSH’s tools/pre-execute hook, matching against “tool name + serialized parameters”. The code is concentrated in a single src/index.ts (around 60 lines), without modifying the Harness core or performing monkey-patching.

It will not work by default after installation. You need to write your own rule file for the plugin to inject prompts when matches occur.

How it works

The plugin listens to tools/pre-execute. This is the allow/deny/query waterfall flow documented in DSH: before a tool is actually executed, the plugin can permit it, deny it, or queue a model-visible context segment for subsequent steps. The official documentation notes that context added via agent.inject() is visible to the next model request, and it is not an interface to wake up an idle Agent.

After a tool call comes in, the plugin processes it roughly in the following order:
1. Flatten the tool name and parameters into a single string, then match against the rule list. The first rule that returns true is the hit.
2. Use agentId + rule index for deduplication. Each rule will trigger at most once per session and per agent, consistent with the notified deduplication in the upstream implementation.
3. If the rule has reject: true, the first hit will return { kind: 'deny', reason: prompt }, and this tool call will be rejected; subsequent hits of the same rule will be allowed.
4. If reject is not set, inject a SYSTEM NOTICE: … prompt via agent.inject(), then call next() to allow the current call. The prompt enters the model-visible context for the next pre-step.

These two paths should be considered separately. The README summarizes the overall effect as “the agent retries from the same spot after injecting the prompt”, which is closer to the behavior of reject: true: block the first attempt, let the model see the rejection reason, then retry. The default path will not block the current call, it just queues the prompt into future context. If your goal is “disallow execution the first time”, you need to explicitly write reject: true.

The matching uses ordinary functions, not a regex engine. The input to match is the flattened string, which contains both the tool name and the text from the parameters, so examples like v.includes('pip') && v.includes('install') will work.

Installation and activation

The installation command given on the community directory page, run in the DeepSeek Harness terminal:

dsh plugin add github:jiesou/dsh-stream-rules

For reproducible installations, the directory page recommends pinning the commit hash:

dsh plugin add github:jiesou/dsh-stream-rules#<commit>

The repository README also provides a profile-specific syntax, and recommends installing pre-built artifacts from npm:

dsh plugin --profile <name> add @jiesou/dsh-stream-rules

When installing from GitHub:

dsh plugin --profile <name> add github:jiesou/dsh-stream-rules

You can also add a line to your profile’s cordis.patch.yml:

- id: stream-rules
  name: '@jiesou/dsh-stream-rules'

The current repository already includes compiled lib/ output, and package.json’s main points to lib/index.js. The README states that GitHub installations will run the prepare script to build, but the package.json reviewed at the time of writing does not declare a prepare script. If you choose to install from GitHub, refer to the build artifacts in the repository at that time and DSH’s prompts for git dependency prepare scripts. The official documentation also notes: installing from git means executing third-party code, and newer versions of pnpm may require you to explicitly allow build scripts. Only install sources you have reviewed, and pin commits whenever possible.

The plugin runs with the permissions of the current dsh process, and may execute code during installation. Please review the source code repository and MIT license before installing.

Writing rules

Installing the plugin just hooks it into your profile. You need to write your own rules. The repository’s rules/ directory currently only has rules.js.example, and files starting with _ will be skipped.

First, locate the plugin directory. $DSH_HOME defaults to ~/.dsh:

$DSH_HOME/profiles/<name>/node_modules/@jiesou/dsh-stream-rules

Then rename the example file to your local rules file:

mv rules/rules.js.example rules/rules.local.js

rules/*.local.js is already ignored by the repository’s .gitignore, making it suitable for local rules. Directly modifying files in node_modules will risk them being overwritten when the plugin is updated. A more robust approach is to place your rules in your own directory, then point to them via config.rules:

- id: stream-rules
  name: '@jiesou/dsh-stream-rules'
  config:
    rules: /path/to/your/rules

The example rules are taken from the repository README, and can be used directly as a starting point:

// rules/rules.local.js
export default [
  {
    match: (v) =>
      v.includes('pip') &&
      v.includes('install') &&
      !v.includes('uv pip') &&
      !v.includes('uvx'),
    reject: true,
    prompt: 'Use `uvx` or `uv venv` + `uv pip` instead of `pip install` directly',
  },
  {
    match: (v) => v.includes('curl') && v.includes('api.github.com'),
    prompt: 'Prefer using `gh` cli over `curl https://api.github.com/...`. gh offers more requests limits.',
  },
  {
    match: (v) => v.includes('pdf'),
    prompt: 'Use the `markitdown` skill to read PDF files.',
  },
  // add your rules here
]

The meanings of the fields are as follows:
- match: Required. Type (v: string) => boolean. Each tool call will be flattened into a string before matching.
- prompt: Required. The guidance text injected into the model; when reject: true, it also serves as the rejection reason.
- reject: Optional. When set to true, the first hit will reject that tool call, and subsequent hits of the same rule will be allowed.

The first example blocks bare pip install commands, prompting the user to use uvx or uv pip instead, while excluding calls that already use uv. The reject: true only blocks the first attempt, allowing retries afterwards, as explained in the README: to guide boundaries without locking the model in, for example, allowing installations when the environment is already in a container. The second and third examples only have prompt, and will inject the guidance without blocking the current call.

The rule file can be .js or .ts, exporting an array by default. If loading fails, the plugin will print [dsh-stream-rules] failed to load … to the console, and will not block all tool calls.

Use cases and considerations

It is suitable for users already using DeepSeek Harness who want to constrain tool habits with a small number of local rules. For example, unifying package managers, guiding the use of gh instead of handwritten curl requests, or reminding users to use a specific skill to read PDFs. It is not a permission system or sandbox: reject: true only takes effect for the first hit of the rule on that agent, and will allow subsequent hits; the default path will not even block the current call. For policies that require hard blocking, you should use DSH’s own tools/pre-execute permission gates, ctx.tools.guard(), or sandbox plugins, rather than relying solely on this lightweight guidance.

Matching uses substring matching, not structured schema validation. The tool name and parameters are concatenated into a single text string, so rules that are too broad may cause false positives, while rules that are too narrow may miss matches. Each rule will only trigger once per agent, so if the model uses a different spelling to violate the rule again in the same session, the rule will not trigger again.

Technically, it depends on peer dependencies such as @deepseek-ai/cordis, @deepseek-ai/dsh-llm, and @deepseek-ai/schemastery, and declares a requirement for two services: tools and agents. DeepSeek Harness is still in developer preview, so incompatible changes to extension points may require community plugins to update accordingly. Refer to the installed dsh version and the plugin source code at the time.

Once again: the plugin runs with the permissions of the current dsh process. Installing community plugins means executing third-party code on your local machine. Please review the repository, license, and cordis.patch.yml first, and pin commits when you need reproducible environments.

Summary

dsh-stream-rules extracts “behavior boundaries” from the system prompt and turns them into on-demand injections tied to tool calls. You write your own rules, and the plugin only speaks when a match is found, without occupying context window space when there are no matches. The implementation is small, and uses only the existing tools/pre-execute and agent.inject() extension points documented in DSH.

Directory page: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-stream-rules/

GitHub: https://github.com/jiesou/dsh-stream-rules