快速了解
它能做什么
用于 DeepSeek Harness 的权限预设,在工具调用执行前自动进行审查。
本站提供的是中文说明,不代表该项目或 Plugin 自身提供中文界面;语言支持请以上游文档为准。
deepseek-harness Profile
>=0.1.0-rc.6 <0.2.0
证据已验证
核对日期 2026/9/10 UTC 14:10
有代码证据的贡献
它为 DSH 增加什么
新增 Auto mode 预设,在执行前通过确定性规则和两阶段分类器评估智能体工具调用。
机制证据 ↗选择前先看
dsh-automode 为 DeepSeek Harness 增加 Auto mode 预设。它会确定性地拒绝匹配到的密钥、外泄和敏感路径操作,自动允许已配置的常规操作,并将其余情况交给两阶段 LLM 分类器。分类失败时可默认拒绝;连续多次拒绝后会暂停自动化并交由人工决定。
适合谁
希望减少审批打断、但仍要为自主智能体工具调用保留明确护栏的 DeepSeek Harness 用户。
常见任务
- 在需要连续执行常规工具调用的会话中使用 /auto。
- 在个人配置的 cordis.patch.yml 中增加团队自己的拒绝、允许和分类器规则。
- 查看 JSONL 决策日志,根据实际使用情况调整规则。
权限与数据
插件会评估工具调用详情和会话上下文;可能调用已配置或当前会话的 LLM 路由进行分类,并写入本地审计日志。
权限- 在 Auto mode 中于执行前拦截智能体工具调用。
- 可通过 DSH 审批流程允许或拒绝调用。
- 对于配置在 allowPaths 中的操作,可自动批准所请求的沙箱提权。
- 会将决策事件、工具名称、结果、原因和会话标识追加写入 ~/.dsh/auto-mode/decisions.jsonl。
- 会把任务对齐上下文和近期的直接用户意图作为分类器输入。
- 分类器可使用会话当前的 LLM 路由,或指定的 provider/model。
- 未声明插件专用凭据;所选 LLM 路由可能需要其自身凭据。
局限
- 它不是操作系统安全边界;在 DSH 进程中运行的代码可使用用户账户权限。
- allowPaths 对本插件属于完全信任范围,并可能自动批准提权;应严格限制目录范围。
- 尚未验证与 DSH 0.2.0 及更高版本的兼容性。
- 尚未验证 Linux 和 Windows 的路径行为。
DSHub 已核对
- 已验证固定 Git 交付方式和 DSH Bundle Patch 结构。
- 清单声明的 DeepSeek Harness peer 依赖范围为 0.1.0-rc.6(含)至 0.2.0(不含)。
- 提供的文档称其仅在 macOS 上完成验证。
DSHub 未核对
- 本次收录未实际执行安装或运行时测试。
- 提供的证据中未找到 0.12.0 版本的 npm Registry 分发。
固定版本安装
安装 dsh-automode
这个Plugin Bundle没有 DSH Plugin 安装操作,请根据源码文档使用真实交付方式。
维护者原文
项目 README
dsh-automode ⚡
Claude Code–style auto mode for DeepSeek Harness — let your agent run hands-free, while a deterministic guardrail and a cost-aware reviewer keep the dangerous stuff from ever executing.
<img src="docs/auto-mode-icon.png" width="400" alt="dsh-automode in the permission picker" /></div>🌐 简体中文: README.zh.md · English: README.md
dsh-automode sits between your agent and the harness. It intercepts every tool call before execution — hard deny rules and curated allowPaths decide deterministically (zero LLM cost), and whatever is left goes to a two-stage classifier. Safe actions run on their own; risky ones are blocked, reshaped, or routed to you.
✨ Key features
- 🛡️ Deterministic first line — regex
denybands hard-block exfiltration, secrets, and system paths before any LLM call; prefix-globallowrules approve routine commands for free. - ⚡ Zero-confirmation allowlist —
config.allowPathsis full trust: file ops and bash writes inside it skip the classifier entirely, and escalated calls are auto-granted through the approval bridge (v0.10.0) — no prompt, no round-trip. - 🧠 Cost-aware two-stage classifier — a one-token filter pre-screens; only flagged actions get the structured review, and identical actions reuse the verdict cache for 5 minutes.
- 🔁 Circuit breaker + human fallback — 3 consecutive (or 20 total) DENYs pause auto mode and route decisions to a human; one human decision resumes and resets.
- 📜 Full audit trail — every allow / deny / bridge decision is appended to
~/.dsh/auto-mode/decisions.jsonl. - 🔌 Native preset — flip it on from the permission picker or
/auto; it plays nicely alongside read-only / workspace-write / danger-full-access.
⚠️ Not a sandbox. The plugin runs inside the DSH process; a deliberately malicious plugin can do anything your user account can do. It reduces unsafe autonomous tool use — it is not an OS security boundary.
📚 Table of contents
- Install
- Commands
- How it works
- Rules
- Configuration
- Logging
- Architecture
- Compatibility & contributions
- License
Install
dsh plugin add @log.li/dsh-automode
From a local checkout:
dsh plugin add ./path/to/dsh-automode
Restart dsh web after installing. The permission picker (bottom-left of the chat box) will show Auto mode alongside read-only / workspace-write / danger-full-access.
Commands
/auto # switch this session to auto mode
/auto-status # show diagnostics: preset, approval policy, breaker state
How it works
Tool call arrives
│
├─ [pre-execute gate] (all tools, first defense)
│ ① Read-only tools → allow (unless deny matched)
│ ② Deny rules (regex) → hard reject
│ ③ Allow rules (prefix glob) → approve
│ ④ In-tree file ops → approve (allowInsideWorkingDirectory)
│ ⑤ Escalation intent → classifier pre-screen
│ ⑥ Everything else → pass through
│
└─ [approval waterfall]
① Soft deny rules (prose) → reject
② Soft allow rules (prose) → approve
③ Read-only allowlist → approve
④ Verdict cache hit → reuse (no second LLM call)
⑤ Classifier (two-stage: one-token filter → structured review)
⑥ Failure → fail-closed

🖱️ Interactive version: docs/auto-mode-flow.html — pan/zoom, relationship tracing, dark mode. Diagram source:
docs/auto-mode-flow.workflow.json.
The pre-execute gate intercepts ALL tool calls (including those inside the workspace sandbox that would never trigger the approval waterfall). The approval waterfall only runs for calls that actually need sandbox escalation. The pre-execute gate only applies to auto-mode sessions; in other presets (read-only / workspace-write / danger-full-access) it is a no-op so it never contradicts the sandbox the user chose.
Rules
The rule system has two layers:
Hard boundary (deterministic, never goes to classifier)
deny— regex patterns that hard-reject. First match wins. Evaluated before everything else. Use for exfiltration, secrets, sensitive targets, dangerous commands.allow— prefix-glob patterns that approve without any LLM call. Evaluated after deny. Use for routine commands you trust completely.
Classifier guidance (prose, fed to the LLM)
rules.deny— soft-deny descriptions. The classifier reads these as standing rejections. Can be overridden by direct user intent or a matching allow rule.rules.allow— soft-allow exceptions. The classifier reads these as standing approvals that override matching soft-deny rules.rules.environment— context facts (trusted repos, infrastructure, cloud buckets). The classifier uses these to judge whether an action is within the user's environment.
All rules.* arrays support $defaults: using ["$defaults", "my custom rule"] keeps the built-in rules while adding yours. Omitting $defaults replaces the entire built-in list for that section.
Configuration
Configuration goes in your profile's cordis.patch.yml. Everything has defaults; a bare {} config is valid. The table below is the full reference; a minimal example (the allowPaths override) is under Trusting extra directories.
Key options
| Option | Default | Description |
|---|---|---|
deny |
built-in list | Regex patterns that hard-reject. First match wins. |
allow |
built-in list | Prefix-glob patterns that approve without LLM. |
readOnlyTools |
read, glob, grep, list, search | Tools that default-allow (unless deny matched). |
allowPaths |
[] |
Curated full-trust external directories: file ops and bash write-commands inside skip the classifier, and (since v0.10.0) escalated calls are auto-granted (approval-bridge). See Trusting extra directories. |
allowInsideWorkingDirectory |
true |
Allow in-tree file ops without classifier. |
classifier.provider / classifier.model |
'' (follow session) |
Override the classifier's LLM route. Resolution: classifier.{provider,model} → session's active model → agent's configured model. |
classifier.reasoningLevel |
off |
Classifier reasoning effort (off disables reasoning). If a route rejects the effort, the call retries without it. |
rules.deny |
['$defaults'] |
Soft-deny prose for the classifier. |
rules.allow |
['$defaults'] |
Soft-allow prose for the classifier. |
rules.environment |
['$defaults'] |
Environment facts for the classifier. |
failClosed |
true |
Reject on classifier failure vs. fall back to approval chain. |
preExecuteGate |
true |
Enable the pre-execute gate (only applies to auto-mode sessions). |
timeoutMs |
45000 |
Per-call hard timeout for the classifier LLM calls. |
classifyContextChars |
6000 |
Char budget for the task-alignment context given to the classifier. |
maxArgsChars |
4000 |
Char budget of the command signature used for the verdict cache key. |
breakerConsecutive |
3 |
Consecutive classifier DENY to trip the breaker. |
breakerTotal |
20 |
Total classifier DENY to trip the breaker. |
Trusting extra directories (allowPaths)
allowPaths is a curated full-trust list: file ops and bash write-commands whose target resolves inside one of these directories skip the safety classifier entirely (logged as pre-execute-allow / curated allowPath). The shipped default keeps only the universal /tmp/ — personal directories are configured per profile in your profile's cordis.patch.yml. Loader patches replace the targeted row's whole config, so the minimal override below sets only allowPaths (every other field falls back to the plugin's code defaults):
# ~/.dsh/profiles/<profile>/cordis.patch.yml
- id: auto-mode
config:
allowPaths:
- /tmp/
- /Users/<you>/Library/CloudStorage/OneDrive-<tenant>/Projects/<proj>/Proposal/
Only recognized write-commands are trusted (deletion such as rm/trash is never allowlisted), and paths are matched after symlink resolution — both a /Users/<you>/OneDrive - … symlink and the real Library/CloudStorage/… path work. A git add/commit/push inside an allowlisted directory resolves its repository root as the write target, so committing/pushing a repo that lives under an allowPath skips the classifier too (v0.11.1). The verdict-cache fix below still matters: even without an allowPath, once you explicitly authorize an action the classifier re-runs with your intent instead of replaying a cached denial.
Composite write-commands (v0.11.0). A temp→swap export dance like DIR=…; cp a b_tmp && (trash b; true) && mv b_tmp "$DIR/b" is now parsed segment-by-segment (with VAR=… assignment tracking and $VAR expansion), so its destinations still hit allowPaths. cd <dir> is a tracked benign navigator — it updates the effective working directory (so a later git add/commit/push resolves its repo root from it) without invalidating the fast path (cd - stays unpredictable and falls back). The fast path stays guarded: a composite containing a side-effect command (kill, pkill, rm, sh, bash, network/daemon management, …), a command substitution (`…` or $(…)), a file redirection (>file, >>file, 2>file), or any command outside the recognized write/benign set falls back to the classifier exactly as before. A descriptor-dup redirect (2>&1, >&2, >&-) is not a file write and does not invalidate the fast path — so git push … 2>&1 | tail is still allowlist-checked. Benign utilities inside a composite (trash, mkdir, echo, …) ride along with the allowlisted write — their side effects are not re-reviewed once every write target is allowlisted (deletion targets themselves are never allowlist-trusted, and rm still forces a classifier fallback). History-rewriting git commands (reset --hard, clean, rebase, merge) are deliberately not allowlist-trusted.
Zero-confirmation escalations (v0.10.0). An allowlisted path means full trust, so a call that asks to widen the sandbox (sandbox_permissions: danger-full-access) into an allowlisted path is now auto-allowed with no confirmation and no classifier — the pre-execute gate already proves every target sits inside an allowPath, and that verdict is carried to the approval answerer by the call's callId (the audit trail shows curated allowPath → approval-bridge → decision allowed-once). Deny patterns still run first (a deny-listed path such as ~/.ssh/ is hard-rejected even inside an allowPath), and the circuit breaker is never bypassed — while tripped, allowlisted calls still go to a human.
Not a file-sandbox exemption. allowPaths only skips this plugin's review — DSH's file sandbox (the session's file policy) is a separate layer and still applies. A write to an allowlisted directory outside the workspace is blocked by the sandbox unless the call asks for sandbox_permissions: danger-full-access; for an allowlisted path that escalation is auto-granted by the approval bridge (no review), so request the escalation on the first attempt.
Every auto-mode session also receives this knowledge as a system-prompt section (auto-mode:allowlist): the model knows where the per-profile allowPaths lives and how to edit it, so when an action is blocked it can propose the exact config change — and only applies it after you explicitly confirm.
Permission preset icon
The auto-mode preset ships a bolt glyph in the permission picker. Set your own logo by overriding icon on the preset (the permission row of cordis.patch.yml, not auto-mode's config) — an SVG path drawn inside the shield outline:
- id: permission
config:
presets:
auto-mode:
sandbox: workspace-write
approval: ask
name: Auto mode
description: ...
icon: '<your-svg-path-d>' # default bolt: 'M9.15 3.4L5.85 8.55H7.95L7.05 12.6L10.45 7.25H8.25L9.15 3.4Z'
The icon is cosmetic — behavior is identical whether it renders. It shows only on DSH versions that read preset icons (stock DSH ignores it; the local dsh-permission-preset-icon.mjs patch enables it). Leave icon unset for the default bolt.
Two-stage classifier
The classifier uses two stages to minimize LLM cost:
- One-token filter (~1 token): asks the LLM for a single digit (0 = safe, 1 = needs review). Uses a generous token budget and robust digit parsing so reasoning models aren't starved, and honors
classifier.reasoningLevelas the reasoning effort (off= no reasoning). Most routine actions return 0 and skip stage 2. - Structured review: only runs when stage 1 flags the action. Returns a full verdict with reason.
This means most tool calls cost ~1 token of classifier overhead. Only borderline actions incur the full classifier cost.
The classifier is risk-based — it judges the action's real-world impact, not its surface form:
- Read-only and reversible operations are ALLOWED: GET/HEAD requests, inspection/listing/search/state queries, and local changes that can be safely undone (edits, temp files, builds, tests, git-tracked files).
- A sandbox-escalation request is NOT dangerous by itself — the classifier judges the action it enables. A reversible, low-blast-radius, user-aligned action may be allowed even when it needs escalation (e.g. editing a git-tracked skill or config file outside the working directory). Escalation for a genuinely dangerous action (exfiltration, persistence, weakening security, shared/production/external state) stays forbidden.
<recent_user_intent>counts only direct human messages — with one deliberate exception: a user's answer to anask_user_questiontool call is a direct human authorization given through the tool, so it is folded into the intent window (and into the verdict-cache key, so a tool-based grant invalidates a staleDENYjust like a typed message). Ordinary tool results, plugin/system injections, and model messages stay excluded, so the user's real instructions are never crowded out and only a human can grant permission.
Circuit breaker
When the classifier denies 3 actions in a row or 20 total in a session, the breaker trips and auto mode pauses. The approval waterfall delegates to the human answerer. Any human decision (allowing OR rejecting the action) resumes auto mode and resets all counters — a human in the loop breaks the silent-denial loop the breaker exists to catch. If the human cancels the request or no answerer is available, the breaker stays tripped.
At the moment the breaker trips, the plugin injects a hint telling the model to request danger-full-access sandbox escalation directly on its next attempt (which surfaces the human approval window immediately), instead of the "try at current level → hit a denied error → then escalate" round-trip.
Classifier failures (timeout, parse error, empty response) are NOT counted toward the breaker. Cached denies count, however — a repeat of an identical previously-denied action (verdict cache hit) increments the consecutive and total counters, so repeated escalation attempts actually trip the breaker and reach the human instead of spinning forever.
Denial guidance & diagnostics
The classifier is two-state (allow / reject) — there is no "ask" tier. An uncertain action is rejected (fail-closed): a rejected action can be retried in a safer form or escalated to the user, but a wrongly-allowed action cannot be undone.
Routine categories (installs, builds, tests, file edits, git add/commit/status) are a tendency, not a free pass — the classifier must judge the specific command and arguments, never the category label alone (e.g. pipe-to-shell downloads, unknown-package installs with arbitrary postinstall scripts, secret writes, irreversible deletes, pushes to unknown remotes).
When an action is denied, the denial echoes the reviewer's reason AND the model's own stated justification (from the tool call), so the model can see exactly what was rejected and reshape it. It is told to try a safer alternative; if no safer alternative exists, it is instructed to stop retrying and ask the user for explicit permission — a denied action will keep failing, and only explicit user approval lets a later attempt pass (the classifier weighs the user's recent explicit intent via <recent_user_intent>).
Every classifier stream failure (thrown error or an error finish chunk) is logged to the DSH log with the resolved route, effort, error code/message, and raw output, and written to decisions.jsonl as a classifier-fail event — so a recurring classifier returned no verdict is diagnosable from the audit log itself. If a route rejects the configured reasoningEffort (e.g. low on a route that only supports off), the call is retried without an effort before failing.
Verdict cache
Classifier verdicts are cached per session by tool + command + user-intent signature. The user's recent direct instructions — typed messages and ask_user_question answers — are hashed into the key, so a new explicit authorization (a fresh human message or a tool-based grant) invalidates a previously cached verdict and the classifier re-runs with the new intent — a user grant is never swallowed by a cached DENY. Within the same intent window a repeated action still reuses the cached verdict without a second LLM call. Cache entries expire after 5 minutes.
Logging
All decisions are logged to ~/.dsh/auto-mode/decisions.jsonl (JSONL format, append-only, survives restarts). Each entry includes:
at— ISO timestampevent— decision / pre-execute-deny / pre-execute-allow / pre-execute-fileop / pre-execute-bashop / pre-execute-fail-open / classifier-fail / breaker / resume / bootoutcome— allowed-once / rejected / cancelledtool— tool nametier— deny / allow / classify:monitor / classify:cache / classify:fail / ...detail— human-readable reasonsessionId— session identifier
Use the review script to analyze the log and identify rule optimization opportunities:
node scripts/auto-mode-review.mjs
System prompt shadowing
When auto mode is active, the plugin shadows the approval-policy system prompt so the model sees "auto" instead of "ask". This tells the model that tool rejections come from the automated reviewer, not from a human. The model adjusts its retry strategy accordingly (try a smaller/safer action instead of asking the user).
Architecture
src/
index.ts Main entry: preset management, approval answerer, breaker reset, commands, system-prompt shadowing
config.ts Config schema + $defaults mechanism + built-in rule lists
bands.ts Deterministic band engine (deny regex + allow glob)
pre-execute.ts Pre-execute gate (first defense; real-path trust, classifier pre-screen, breaker-trip hint)
classifier.ts Two-stage classifier (+ robust parser, reasoning effort, diagnostics)
rules.ts Prose rule matching for the classifier
prompt.ts Classifier prompt construction (<recent_user_intent> + intent weighting)
cache.ts Verdict cache (shared across enforcement points)
breaker.ts Circuit breaker (3 consecutive / 20 total)
log.ts Shared appendDecision JSONL logger
Compatibility & contributions
Supported dsh versions: 0.1.0-rc.6 – 0.1.x (peer range >=0.1.0-rc.6 <0.2.0). Permission facts (preset / sandbox / approval) are read through two auto-detected paths:
| dsh version | permission read path |
|---|---|
0.1.0-rc.6 – 0.1.4.x |
session.events event log (effectivePermissionPreset & co.) |
≥ 0.1.5-rc.1 |
durable permissions session projection (ctx.sessionProjections.stateOf) |
dsh 0.1.5-rc.1 removed the session.events accessor — without the projection path every auto-mode turn died with Cannot read properties of undefined (reading 'length') while the system prompt was assembled (fixed in v0.11.2). dsh ≥ 0.2.0 is not yet verified — bump the peer range only after testing against a new core.
- Verified on macOS only. Tested against the macOS filesystem, the DeepSeek Harness (DSH) runtime, and the DSH version in use at development time. Path semantics — including the macOS
/tmp→/private/tmpsymlink (handled by realpath-nearest-ancestor resolution) and workspace-path trust — have not been verified on Linux or Windows, and deny-pattern/path matching may differ there. - Found a bug, or an issue on another platform? Bug reports and pull requests are welcome — open an issue or PR at github.com/log-li/dsh-automode.
License
有意识地管理
安装与管理
前置条件与目标 Profile
目标: deepseek-harness Profile
交付方式: Git Bundle — log-li/dsh-automode#aaf35468b0cba81d387bef5f3b161de636333a1d。
验证、更新与移除
显示生命周期命令
dsh plugin --profile deepseek-harness list兼容性与访问范围
DeepSeek Harness plugin; macOS verification is documented: >=0.1.0-rc.6 <0.2.0。
风险事实
证据与编辑审查Manifest、Bundle patch、分发与新鲜度
不可变证据
审查状态与源码活动
首次使用建议从范围很小的 profile 配置开始,尤其不要轻易把目录加入 allowPaths。
AI 审查于 2026/9/10 UTC 14:10。GitHub 事实核对日期: 2026/9/10 UTC 14:10。
自当前证据基线以来,没有记录到重要源码变化。