by SteelUnion
DeepSeek Harness gate - per-turn persistent-operation counter: remind, instruct the model to stop, then ask for confirmation. Steps aside under sandbox/read-only modes; follows a live permission switch without restart. Verified on real hardware (full -> workspace-write -> read-only -> full). Crafted on an estimated 0.27 USD of model spend.
# Add to your Claude Code skills
git clone https://github.com/SteelUnion/dsh-confirm-gateGuides for using ai agents skills like dsh-confirm-gate.
See how dsh-confirm-gate compares with popular alternatives.
dsh-confirm-gate is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by SteelUnion. DeepSeek Harness gate - per-turn persistent-operation counter: remind, instruct the model to stop, then ask for confirmation. Steps aside under sandbox/read-only modes; follows a live permission switch without restart. Verified on real hardware (full -> workspace-write -> read-only -> full). Crafted on an estimated 0.27 USD of model spend. It has 51 GitHub stars.
dsh-confirm-gate's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/SteelUnion/dsh-confirm-gate" and add it to your Claude Code skills directory (see the Installation section above).
dsh-confirm-gate is primarily written in JavaScript. It is open-source under SteelUnion on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh dsh-confirm-gate against similar tools.
No comments yet. Be the first to share your thoughts!
Available after the catalog security scan passes.
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
Stops your AI agent before it rewrites 20 files and burns a day of budget.
Install it and every action the model takes is counted. As the budget runs down it starts telling the model to brake; at the hard limit the model stops and waits for you to type
confirm. No kernel changes, no required config.
English | 中文 · v0.3.0
The gate now stays active under sandbox modes too. Previously it stepped aside in
read-only and workspace-write, on the reasoning that a sandbox already bounds what
the model can do. That reasoning covered what the model can touch, not how many times
it touches it: 40 file edits inside a workspace-write session are still 40 edits, and
still worth a nudge before the 41st.
So SANDBOX_MANAGED_MODES is now empty and the counter runs in every mode. The
counter, the three reminder tiers, and the confirm release are all unchanged. If you
relied on the old stepping-aside behaviour, set SANDBOX_MANAGED_MODES back to
['read-only', 'workspace-write'] in lib/index.js. Correctness fix only: the streaming
mode-detection path now reads the mode on each call rather than caching it, so switching
permission modes mid-session follows immediately.
You just installed dsh. You have a very capable thing on your hands, and no steering wheel.
It works for a long time without saying anything, and you come back to find it went the wrong way. The same feature got written once last turn, then written again into a brand-new file this turn. You want it to continue, and you have no idea how far it got.
This plugin is the steering wheel.
confirm.No configuration needed. To make it looser or tighter, change two numbers. Even the confirmation word is yours to choose.
The rest of this README is for people who want to know how it works.
The model starts its 11th file change
↓
confirm-gate counts it, past the free budget
↓
Injects into context: "stop now, ask the user for confirm"
↓
The 15th (hard limit) → the tool fails, waits for you
↓
You type confirm → the whole turn is released, counter resets
It is not an interceptor; it is a counter that talks. Every counted call comes with a message. The first 10 nudge the model to ask you; 11–14 escalate to an instruction to stop; only the 15th actually blocks the tool. That gap is what lets the model come to a halt while you are away from the keyboard.
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:SteelUnion/dsh-confirm-gate
Restart DSH and it is on. To tune the budget, edit cordis.patch.yml:
- id: confirm-gate
name: dsh-confirm-gate
config:
freeLimit: 10 # allowed, with a reminder injected
hardLimit: 15 # the 15th stops and asks you
confirmWord: confirm
| Situation | Without it | With it |
|---|---|---|
| The model loops, rewriting the same file | Burns the whole budget | Warns from the 11th call, stops at the 15th |
| You step away for half an hour | You come back to 200 changed files | It stopped before you got back |
| You want it to continue | No idea how far it got | Reply confirm and the whole turn is released |
This is not a security sandbox — sandboxing is DSH's own job. This manages cost and direction: it gives the model the ability to brake before it burns money or drifts.
A bounded-run framework that keeps an AI agent accountable on hosts where you had to grant full permissions.
What — Per-turn counter for persistent operations. Gives the model a brake, not a wall. Verified — Live hot-switch on Windows (full → workspace-write → read-only → full), no restart. The model stopped itself at 11/15. Cost — ~$0.27 model spend. Zero external deps, ready-to-install archive in
dist/.It steps aside under sandbox / read-only modes — complementary to DSH's own sandbox, not a replacement. It blocks mid-turn prompts on the WeChat channel — a turn-based channel cannot carry a mid-turn card; see section 9.
A runtime plugin for DeepSeek Harness. It keeps a per-turn counter of persistent operations, injects a stop instruction once the free budget is spent, and asks the user for confirmation at a hard limit.
Compatibility — built and verified against DSH
0.2.0-rc.2; the peer range is>=0.2.0-rc.2, so it also loads on0.2.1-rc.2and later RC builds. If a future DSH release changes the tool-dispatch hooks this plugin binds to, it will fail loudly rather than silently — see §7.
This is not a security boundary. It is a cost boundary and a course-correction mechanism. It assumes the agent is running without a sandbox holding the boundary, and its purpose is to give the model the ability to brake on its own before it burns tokens or rewrites files. Real sandbox isolation is provided by DSH's own sandbox — complementary to this plugin, not a replacement.
Cost figure is an author's estimate — see dist/COSTS.md. The rest of that day went to environment diagnosis and research, not to this plugin.
The plugin decides, on every tool call, whether it should be counting. The mode comes from two sources, in priority order:
ctx.sessionProjections.stateOf(session, 'permissions').sandbox — the session's current knob value. This is what changes when you hot-switch modes mid-conversation.ctx.shell.sandboxMode — the executor's default mode. Its own documentation calls it "the sandbox mode this executor applies by default"; it does not follow a hot switch, so it is only a fallback.That distinction matters: judged from the default alone, switching into a sandbox and back would leave the plugin reading the value it saw at startup, forever.
Both reads go through ctx.get(name), never ctx.shell directly. cordis resolves dependencies lazily, so touching an undeclared service property throws an inject-gate error — and an exception on that path once made the plugin silently do nothing at all. Soft probing cannot throw.
| Sandbox mode | Plugin counts? | Why |
|---|---|---|
read-only |
❌ No | The sandbox already holds every boundary |
workspace-write |
❌ No | Same |
danger-full-access |
✅ Yes | Nothing is holding the boundary |
custom |
✅ Yes | A custom mix still leaves the boundary unheld |
undefined / no shell service |
✅ Yes | This executor does not confine |
| Unreadable (both sources threw) | ✅ Yes | Fail open: a silent no-op is worse than an extra reminder |
That last row is deliberate. This plugin is an accounting tool, not a security boundary, so the two failure modes are not symmetric:
The second is far worse, so any mode it cannot read counts as "not sandboxed".
Put plainly: under a sandbox this plugin would be redundant — and worse, it would interrupt legitimate operations a second time. So it steps aside wherever something else is already keeping score.
Hooks are always registered; the decision is per call. That is what makes hot-switching work: move the session into a sandbox and the gate goes quiet on the very next call; move it back and counting resumes. No restart needed.
✅ Status: verified, including live hot-switching
Exercised by hand on Windows, DSH
0.2.0-rc.2. The session's permission mode was switched live, without restarting DSH, walking the sequence full → workspace-write → read-only → full:
Mode Write a file pwshGate counted? danger-full-access✅ succeeds ✅ runs ✅ 1/10 → 2/10 → 3/10 workspace-write✅ succeeds ❌ fails with 0xC0000142❌ silent (2 ops) read-only❌ sandbox denies ✅ runs ❌ silent (2 ops) danger-full-accessagain✅ succeeds ✅ runs ✅ 1/10, counting resumed Two things matter here. The silent rows show the division of labour working — the sandbox confined or rejected the operation and the gate stayed out of the way. The last row shows the gate coming back in the same process, which is the whole point of deciding per call instead of at load.
Honest caveat: in this deployment
ctx.get('shell')returnedundefined, so the "not sandboxed" verdict came from the unreadable, therefore fail open branch rather than from a successfully read mode. The behaviour is correct; the path is the fallback one. A deployment that exposesshellwould take the primary path instead.
| Situation | Fits? |
|---|---|
| You granted full permissions and fear unbounded trial-and-error burning tokens | ✅ That is exactly the case |
| You want the agent to ask after N write operations | ✅ |
You want read / grep / web lookups never interrupted |
✅ Non-persistent operations are never counted |
| You want to use it as a sandbox against a malicious |