DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
B

dsh-buddy-guard

Buddy Guard

Fix CodeBuddy (Tencent) channel returning 400 'Illegal API invocation from an unapproved channel' in DeepSeek Harness: rewrite the system-prompt identity sentence (the upstream check now ignores leading whitespace) and scrub the two-phrase upstream fingerprint that DSH always ships.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:AsterLuo/dsh-buddy-guard#86af94f42938cd1e9d018157de2469826affdf0c
READMECompatibilityVersions

Compatibility and provenance

Buddy Guard is published as dsh-buddy-guard and currently resolves to version 0.1.2. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
github
Registry updated
10/29/2026

Versions

0.1.2stable
10/29/2026
0.1.1stable
10/27/2026
0.1.0stable
10/21/2026

Related plugins

Loading related plugins…

Latest
0.1.2
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
any
License
MIT
Source
github
GitHub
★ 2
Weekly downloads
0
Last push
10/29/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in security-access.

Cc Safety Netcc-safety-netA coding agent CLI hook - block destructive commands and secret file accessDoctor@linxin666/dsh-doctorTransactional rescue mode for DSH profiles with a supervised launcher, isolated recovery capsule, deterministic repairs, health monitoring, and a local Web recovery consolePocketdsh-pocketPut DeepSeek Harness in your pocket: one package, one settings page, and scan a QR code on your phone to access DSH on your computer in sync (LAN + public network, real-time screen mirroring).Plugin Subscriptionsdsh-plugin-subscriptionsUse ChatGPT (Codex), Claude, Grok (X Premium), GitHub Copilot, and Google Antigravity subscriptions as DeepSeek Harness LLM providers, with OAuth login from the web Settings page

README

dsh-buddy-guard

Fix the CodeBuddy / buddy (Tencent) channel returning HTTP 400 on every request in DeepSeek Harness:

buddy: 请求被拦截,请重新发送 Illegal API invocation from an unapproved channel

中文说明

dsh plugin add github:AsterLuo/dsh-buddy-guard --profile <your-profile>

# pin a version (recommended):
dsh plugin add github:AsterLuo/dsh-buddy-guard#v0.1.2 --profile <your-profile>

Restart DSH afterwards — it is required. Then start a new session on the buddy channel (the guard cannot rewrite a system prompt that is already sitting in session history).

v0.1.2 (2026-10-29) — the upstream tightened block #1 to ^\s*, so a leading space no longer works. The plugin now rewrites the sentence itself. See Third change.

The problem

Pick any model on the buddy channel (hy4-preview, deepseek-v4.1-flash, hy3, …) and every turn fails with HTTP 400 INVALID_REQUEST. The same account and the same endpoint work fine as soon as the request stops carrying the DSH system prompt.

There are three independent upstream rules, all answering 400 / code 11128:

#measuredrule
12026-10-21, tightened 2026-10-29system text starts with the identity sentence
22026-10-27system text contains phrase A and phrase B
3(see below)the identity check ignores leading whitespace

Block 1 — the identity sentence (measured 2026-10-21, tightened 2026-10-29)

The upstream matches the start of the system content. If the system text starts with

You are an AI agent powered by DeepSeek Harness.

it is rejected outright. None of the following matter — every one was changed and the status stayed 400:

  • X-Domain (copilot.tencent.com vs www.codebuddy.cn)
  • X-Product-Code / X-Product / X-Agent-Purpose
  • X-IDE-Name / X-IDE-Type / X-IDE-Version / User-Agent
  • the endpoint (copilot.tencent.com and www.codebuddy.cn behave identically)
  • the model (hy4-preview, hy3, deepseek-v4.1-flash are all rejected)

Boundary tests — the middle column is what worked until 2026-10-29, the right column is what works now:

system content2026-10-212026-10-29
You are an AI agent powered by DeepSeek Harness.400400
same line with one leading space200400
two leading spaces200400
one leading letter / period200200
Note: You are an AI agent powered by …—200
You are an AI agent, powered by …—200
trailing space / newline / period / a whole paragraph400400
the sentence inside a user message200200
only DeepSeek Harness, or lowercase deepseek harness200200

Third change — block 1 was tightened (measured 2026-10-29)

The upstream changed one regex:

- ^You are an AI agent powered by … Harness
+ ^\s*You are an AI agent powered by … Harness

Leading whitespace is now ignored, so any "prefix a character" patch is dead — that is exactly why v0.1.1 (which prefixed one space) started failing while still doing its job. The plugin now rewrites the sentence itself: powered by → , powered by.

The check is a whole-sentence pattern, not a keyword. Measured 2026-10-29 (same account, same endpoint, same user message):

system textresult
DeepSeek Harness alone200
powered by DeepSeek Harness.200
You are an AI agent powered by Foo Harness. (other brand)200
You are an AI agent powered by DeepSeek Harness.400
the same with 1 or 2 leading spaces400
You are an AI agent, powered by DeepSeek Harness.200
Note: You are an AI agent powered by …200
I am an AI agent powered by … / running on … / split into two sentences200

Block 2 — the AND-matched phrase pair (measured 2026-10-27)

There is a second, independent rule. The upstream also rejects the request when the system text contains both of these phrases at once (AND match — either one alone passes):

  • Tokens prefixed with @ are paths the user explicitly referenced
  • Relative paths resolve from the workspace root

Both are part of the DSH system prompt's description of @ path references, so they ship with every request.

Measured (same account, same endpoint):

system textresult
phrase A alone200
phrase B alone200
A and B together400 11128
A rewritten, B kept as-is200
B rewritten, A kept as-is200

The plugin therefore rewrites phrase A only and leaves B intact — B states the relative-path rule that read / write / glob depend on, so keeping its wording is friendlier to the model.

This rule still exists as of 2026-10-29. Control experiment: fix the identity sentence but restore phrase A to its original wording → still 400. Do not delete the A rewrite.

History is a blind spot

The upstream scans every message, so phrase A/B (and the identity sentence) sitting in conversation history triggers the same block. A plugin cannot fix that: agent/request documents that it cannot mutate messages, and the llm/stream options object arrives deep-frozen (mutation throws). If a session has ever quoted these, start a new session.

How this was found (repeatable)

  1. Dump the complete outgoing system text — easiest source is the session log itself: <DSH_HOME>/sessions/…/session.v4.jsonl.zstd, then find the system/message event. ⚠️ That file is multi-frame zstd (header frame + one frame per event batch). zstdDecompressSync() only decodes the first frame, so a naive read looks like a 1-line session. Split on the magic 28 B5 2F FD and decode frame by frame.
  2. Replay that text against the endpoint directly, using the account's own token and the headers from channel-pack's BuddyAdapter.send().
  3. Run a one-variable-at-a-time matrix on the first section (original / leading space / inserted comma / other subject / split sentences). Only then binary-search the full text — if the first section alone already returns 400, there is nothing to bisect.
  4. Replay the full (multi-hundred-kilobyte) system text with the fix — a local pass does not prove the whole request passes, block 2 is still waiting.

A blocked request costs no tokens, so this is cheap.

# ready-made end-to-end check: real plugin load + real upstream request
node docs/tools/buddy-guard-verify.mjs
# expect: upstream(original) 400/11128 → upstream(plugin output) 200

How it works

The plugin listens on system-prompt/assemble and returns a modified assembly that, for the providers listed in config.providers:

  1. rewrites the identity sentence in every section — strip leading whitespace, then replace You are an AI agent powered by with You are an AI agent, powered by (idempotent, do nothing when the text does not start with that phrase);
  2. scans every section and rewrites phrase A to its equivalent.

Do not go back to prefixing whitespace. ^\s* makes it a no-op.

Registration uses { global: true, prepend: true }, and prepend is required: without it, an outer listener that never calls next() (for example dsh-ops' discovery branch, which does return prompt.assemble(context)) would veto the rest of the chain — per cordis, "a listener that does not call next() vetoes the rest of the chain". The plugin would load, log, and show up in --dump-config, yet change nothing.

Why not llm/stream

The first version hooked llm/stream and called next(modifiedOptions). That did nothing, silently. Cordis implements waterfall as:

const next = () => (cbs.shift() ?? inner)(...args);

next takes no arguments — the modified options were dropped on the floor. The plugin loaded, logged, showed up in --dump-config, and the outgoing request was byte-for-byte unchanged.

Replacing arguments only works through a listener's return value.

Install

dsh plugin add github:AsterLuo/dsh-buddy-guard --profile <your-profile>

This copies the package into your profile's node_modules and registers it in dsh.profile.bundles. Your own cordis.patch.yml is left untouched.

Then restart DSH — the config is read once at startup.

Manual install

  1. Copy this repo into <DSH_HOME>/profiles/<profile>/node_modules/dsh-buddy-guard/
  2. Append "dsh-buddy-guard" to dsh.profile.bundles in that profile's package.json
  3. Add "dsh-buddy-guard": "0.1.2" to dependencies in the same file
  4. Verify with --dump-config and look for the buddy-guard row
  5. Restart DSH

Configuration

- id: buddy-guard
  name: 'dsh-buddy-guard'
  config:
    enabled: true
    providers:
      - buddy
  • enabled — master switch.
  • providers — which providers get the patch. Defaults to ['buddy']; other providers pass through untouched.
  • debug — when true, appends one line per guarded request to $DSH_HOME/buddy-guard.log. Off by default, so nothing is written on the hot path.

Verify it worked

After restarting, switch to a buddy model and send a message. A normal reply means it works. Still getting 400?

  1. Re-run --dump-config and confirm the buddy-guard row is there.
  2. Confirm lib/index.js exists and contains PREFIX_REWRITES (0.1.2+) — upgrades overwrite the whole package, so a local hotfix is lost on upgrade.
  3. Confirm the package is listed in dsh.profile.bundles — the most commonly missed step.
  4. Confirm you really restarted DSH and opened a new session.

Full step-by-step troubleshooting (Chinese): docs/troubleshooting.zh-CN.md

Caveat

This bypasses upstream content moderation. The rules can change at any time, and there are now three known ones (two of them reshaped once already). If the same error returns, re-run the dump + one-variable-at-a-time recipe above before changing anything.

The account in question is a CodeBuddy China account (www.codebuddy.cn, the JWT iss points there) while the client sends the international product shape. That mismatch is itself what the upstream means by "unapproved channel" — this plugin only makes it work for now, it does not fix the underlying mismatch. Using workbuddy (international) avoids the check entirely.

Test

npm test

License

MIT