dsh-auto-mode
CC-style auto-approval layer for DeepSeek Harness. Deterministic rules handle the obvious cases; a model-agnostic classifier decides everything else — with circuit breaker, fail-closed semantics, and a curated trust model for external paths.
Install
dsh plugin add dsh-auto-mode
Or from npm directly:
cd <your-profile-dir>
pnpm add dsh-auto-mode
The plugin registers a dedicated auto permission preset. Switch to it in the DSH UI or in your cordis.patch.yml.
How it works
Tool call arrives
│
├─ [pre-execute gate] (all tools; deny reason reaches the model verbatim)
│ bash-only bands:
│ ① hardDeny regex → DENY envelope
│ ② deletion guard (rm/…) → DENY + "use trash" guidance
│ ③ sensitiveDeny (.ssh/…) → DENY + safer-alternative guidance
│ ④ bypass-suspect → DENY envelope
│ all tools (incl. edit/write):
│ ⑤ escalation intent (sandbox_permissions)
│ → deterministic bands → classifier pre-screen
│ → UNSAFE/FAIL → DENY envelope (verdict cached)
│ ⑥ everything else → pass through
│
└─ [approval waterfall]
① readOnlyTool / allowCommands / allowPaths → allowed-once
② cache hit (pre-execute already classified) → allowed-once
③ everything else → single-stage classifier:
SAFE → allowed-once
UNSAFE → rejected + breaker counter
FAIL → rejected + wait-retry notice (CC semantics, not counted)
④ breaker tripped (3 consecutive / 20 total) → delegate to human;
one approval resumes auto mode
Classifier (model-agnostic)
The classifier is a single LLM call with a safety-monitor prompt. It works across any model thanks to:
- Robust verdict parser (
parseVerdict): accepts strict JSON, markdown-fenced JSON, prose with keywords, and alternate key names (verdict,safe/allow/deny/blockbooleans). Falls back to keyword detection on the full text. Only returns FAIL when there is genuinely no signal. - No
reasoningEffort: avoids silent-empty streams on routes that don't support the parameter (e.g. openrouter stealth). - Strengthened prompt: demands terse JSON-only output, no prose or markdown fences.
Failures (timeout, parse error, empty response) are fail-closed: the action is rejected with a "wait a moment and retry" notice (CC errors-doc wording), NOT counted toward the breaker, and NOT remembered as a bypass signature.
Configuration
Key options in cordis.patch.yml (all have defaults):
| Option | Default | Description |
|---|---|---|
modePreset |
"auto" |
Permission preset this plugin owns. Empty = observe all sessions. |
dryRun |
true |
Shadow mode: decide + record, but always delegate. Set false to enforce. |
hardDeny |
exfil, curl pipe, … | Regexes that always deny. |
sensitiveDeny |
.ssh/, .env, … |
Sensitive targets: deny + safer-alternative guidance. |
allowCommands |
trash *, git status, … |
CC-style prefix globs. Zero-LLM auto-allow. |
allowPaths |
[] |
Curated full-trust directories. Danger-full-access writes here auto-allow. |
breakerConsecutive |
3 |
Consecutive DENY count to trip the breaker. |
breakerTotal |
20 |
Total DENY count to trip the breaker. |
timeoutMs |
45000 |
Classifier call timeout. |
classifyContextChars |
6000 |
Context budget for task-alignment input. |
preExecuteGate |
true |
Enable the pre-execute deny-band + escalation pre-screen. |
Self-test
- Probe tool:
auto_mode_probe— runs synthetic scenarios through the real pipeline and reports verdicts. - Decision log:
GET /auto-mode/decisions— ring buffer of the last 200 decisions. - Unit tests:
node proto/routing.test.mjs(45 cases),node proto/state.test.mjs(12 cases),node docs/band-matrix.mjs(26 cases).
Architecture
lib/index.js Host-side Cordis plugin (ESM; Config schema + apply)
proto/host.js Dynamic prototype (development history; not loaded at runtime)
proto/routing.test.mjs Pure-function dual-source routing tests
proto/state.test.mjs Stateful integration tests (breaker, cache, parser)
cordis.patch.yml Plugin row insertion + permission preset definition
docs/spec-v0.4.md Design specification (Chinese)
The plugin registers with { prepend: true } to sit upstream of the human answerer in the approval waterfall. When it has no verdict, it calls next() to delegate downstream.
No comments yet. Be the first to write one.