DSH Plugins Marketplace

DSH Plugins

Plugins

/

Tools & Capabilities

/

sleep-not-permitted

s

sleep-not-permitted

Manifest valid

Rejects foreground waiting in DSH agents: waiting commands (sleep, wait, tail -f, watch, ping without -c, infinite loops), blocking wait tools (wait_agent, job_output with wait: true), progress pollin

hasBundlePatch
sleep-not-permitted icon

sleep-not-permitted

中文 · English

A DeepSeek Harness (DSH) plugin that forbids foreground waiting. When an agent tries to run a command whose purpose is waiting (sleep, wait, tail -f, watch, ping without -c, infinite loops), or calls a blocking wait tool (wait_agent, job_output with wait: true), the call is rejected — and the rejection is a set of instructions: run it in the background (run_in_background: true), or end the turn and let the completion notice wake you.

Nothing is silently rewritten: DSH logs and shows tool arguments before dispatch, so a guard can only refuse, not impersonate a different call. The plugin refuses, explains, and gets out of the way.

Why a plugin, and not AGENTS.md or a preset

  • AGENTS.md is per-workspace. You would have to write the rule into every workspace, and every new workspace silently misses it.
  • A preset is per-agent configuration. Every composition needs its own copy, and the user has to pick it.
  • A host plugin is profile-level. Install once and every workspace, session, and subagent is covered. It can carry configuration, be upgraded, disabled, and removed.

Why it is needed

A DSH session moves one step at a time: however long a foreground tool call runs, the session stops with it. bash({ command: "sleep 60" }) looks harmless but freezes the conversation for a minute, and a five-minute wait_agent freezes it for five. DSH has a safety net for slow work (a foreground command that exceeds its timeout is promoted to a background job), but that still burns the timeout first — and waiting is not work at all.

So the plugin does two things:

  1. Prevention — a rule in the system prompt, next to the existing background-jobs section, so the model picks the background form first;
  2. Enforcement — a synchronous ctx.tools.guard() denial when the foreground form is used anyway, with the retry spelled out.

What gets blocked

  • Waiting commands in bash / pwsh / terminal_send: sleep, wait, tail -f, watch, ping without -c, yes, infinite loops, log-follow modes — see the rule table below.
  • Blocking wait tools: wait_agent and job_output with wait: true, when the requested wait exceeds the budget (default 30 seconds).
  • Polling: running the same check command more than pollRepeatThreshold times within pollWindowMs — the "wait a little, check, wait a little, check" substitute for sleeping. It is refused with the same instruction: wrap the waiting itself in a background job.
  • Commands that need human input or confirmation: sudo without -n, ssh without -o BatchMode=yes, login/key-generation flows (npm login, gh auth login, ssh-keygen, …), interactive editors and pagers (vim, less, top, …), docker run/exec -it, read -p, rm/cp/mv -i. They are refused in the foreground and in the background: a background job has no stdin, so it would hang silently — never settling, never notifying.

If what you are waiting for has no DSH job handle (a remote host, an external service), be it a command or a poll: wrap the waiting itself in a background job — for example ssh host 'until [ -f done ]; do sleep 5; done' with run_in_background: true (sleep is allowed inside a background job) — then end the turn; that job's completion wakes the agent. This is the correct replacement for both sleep and polling when there is nothing local to await.

Behavior

  • A foreground wait is rejected with Error: <reason>; the reason contains the exact retry form.
  • A call that already has run_in_background: true passes — that is the shape this plugin wants.
  • Ordinary commands (git status, npm test, curl, grep, …) pass untouched.
  • ask_user_question is not a wait — it is you being asked — and is never blocked.
  • Non-blocking reads (job_output without wait, list_agents, team_task_list) pass.

The default budget (30 s) exists so short coordination waits keep working out of the box (DSH's own Agent Teams guidance has the Lead wait for teammates). Waits above the budget — the five-minute wait_agent(timeout_ms: 300000) case — are rejected. Set maxBlockingWaitMs: 0 for strict mode: not a single second of foreground waiting.

After a background job finishes

A completion notice means the job finished, not that it succeeded. The notice carries the status (completed / failed / killed) plus the label; read the output and exit code with job_output before continuing, and diagnose a failed/killed job instead of retrying blindly.

Background jobs have no timeout of their own. A job that dies mid-flight or hangs while waiting for something that never happens never settles — and so never notifies. Bound it yourself: wrap the command in timeout N, keep a deadline in retry loops, or write a marker/report file at the end. For cross-machine waits the same applies to the remote wait loop: give it a maximum wait and let it exit with a failure marker on timeout, so the local job always settles and always notifies.

If the work needs a human decision in the middle, do not background it: confirm first (ask_user_question, or the DSH approval channel), then start it with non-interactive flags.

Rules

idmatches
sleepsleep N in command position (sudo sleep, timeout 30 sleep, do sleep, && sleep, …)
sleep-nested-shellnested shell payloads such as bash -c "sleep 10"
sleep-scripttime.sleep(30), python -c "...sleep(5)"
waitthe shell builtin wait
tail-followtail -f / tail -F / tail --follow
watchwatch <cmd> (re-runs forever)
ping-foreverping without -c
yesbare yes (endless output)
infinite-loopwhile true / while : / until false
follow-logsdocker/podman logs -f, journalctl -f, kubectl logs -f

Plain text inside quotes does not count (echo "sleep 30", grep 'sleep 30' file pass); in multi-line scripts, command position is evaluated per line.

Configuration

Override the bundle patch row from the profile's cordis.patch.yml, or edit the plugin's cordis.patch.yml:

- id: sleep-not-permitted
  name: 'dsh-plugin-sleep-not-permitted'
  config:
    enabled: true                 # false = turn the whole guard off
    tools: [bash, pwsh, terminal_send]
    blockingTools: [wait_agent]   # blocking wait tools: reject above the budget
    blockingWaitFlagTools: [job_output]  # reject when wait: true and above the budget
    maxBlockingWaitMs: 30000      # 0 = reject every foreground wait
    antiPolling: true             # refuse repeated check commands (busy-poll)
    pollRepeatThreshold: 3        # max times one command may appear inside the window
    pollWindowMs: 120000          # polling window, milliseconds
    interactiveGuard: true        # refuse commands that wait for input/confirmation
    disabledInteractiveRules: []  # switch off individual interactive rule ids
    language: auto                # auto | both | zh | en (message + prompt language)
    announceInPrompt: true        # false = enforcement only, no prompt rule
    disabledRules: []             # switch off individual rule ids from the table
    extraRules:                   # add your own rules; pattern is a regex string
      - id: long-curl
        pattern: 'curl\s+[^|;&]*--max-time\s+\d{3,}'
        label: long-timeout curl
        reason: This curl can hang for a long time — run it in the background.

Invalid configuration fails loud at mount time (unknown rule id, empty tools, invalid regex, non-boolean switch, unknown language) — there is no "installed but silently inactive" state.

Message language

language: auto (the default) follows the user's system language: it checks DSH_LOCALE, LC_ALL / LC_MESSAGES / LANG, then the macOS system language preference, then Node's Intl default, and falls back to English. A Chinese system gets Chinese-only messages and a Chinese-only prompt section (roughly half the prompt cost); both emits both languages; zh / en pin one explicitly. Resolution happens once at mount.

Install / uninstall

The package is a standard DSH bundle (dsh.bundle.patch → cordis.patch.yml).

git clone https://github.com/JJJACKsong/sleep-not-permitted.git

# desktop profile (managed by the Electron app): use plugin_manager install_bundle
#   with the absolute path of the cloned directory
# other profiles:
dsh plugin --profile web add /path/to/sleep-not-permitted

Prebuilt tarball (no clone, no build):

dsh plugin --profile web add https://github.com/JJJACKsong/sleep-not-permitted/releases/download/v0.1.0/dsh-plugin-sleep-not-permitted-0.1.0.tgz

Uninstall:

dsh plugin --profile web remove dsh-plugin-sleep-not-permitted
# desktop: plugin_manager remove_bundle dsh-plugin-sleep-not-permitted

Disable without uninstalling: set enabled: false, or toggle the sleep-not-permitted row in the plugin manager.

Tests

node --test test/detect.test.mjs test/plugin.test.mjs
  • test/detect.test.mjs — detector positives and negatives (command position, quotes, nested payloads, false-positive protection);
  • test/plugin.test.mjs — a minimal ctx double checks deny/pass, defaults, strict mode, message language, and fail-loud configuration.

Verify it works

  • Foreground sleep 5 → rejected immediately with Error: …;
  • wait_agent(timeout_ms: 300000) → rejected (budget 30 s);
  • Background sleep 5 (run_in_background: true) → returns a job id at once, notify on completion;
  • The system prompt contains the rule block (announceInPrompt: true).

Compatibility

Tested against DSH 0.1.5-rc.2 and 0.2.1-rc.3. It relies on two host seams — ctx.tools.guard() and ctx.systemPrompt.section() — and fails loud at mount if they change.

Boundaries

  • Does not guess "might be slow". npm install, cargo build and other commands that make progress still run in the foreground; the tool timeout promotes them to a background job (default 120 s, capped at 600 s).
  • Does not block work. Long synchronous tasks such as workflow or deliver_gate are not waits and are left alone.
  • Does not rewrite arguments. A denied call costs one retry round trip; the system-prompt rule is there to keep that rare.
  • Does not inspect script files. How long bash script.sh sleeps inside cannot be judged statically; the tool timeout is the backstop.

Compatibility

DSH 0.2.2-alpha.2: failed

Versions

Latest versionPublishedSize
0.4.0——

Comments

Loading…

Similar plugins

dsh-wait-subagent

by john-walks-slow

wait_subagent tool for DeepSeek Harness: block until a background continuable subagent settles and return its stop reason and closing message — event-driven, zero polling.

Tools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 1

MIT

JavaScript

Oct 26, 2026

dsh plugin --profile web add dsh-wait-subagent

by cxv117793-blip

Counts agent steps and, every N of them, adds a progress-report instruction to the batch that is about to be sent, so the agent states what it is doing, what it finished and what comes next, then carr

Workflow & AutomationManifest valid

★ 4

MIT

JavaScript

Oct 30, 2026

dsh plugin --profile web add dsh-step-pause

by Kaiji-Z

An RTS-style orchestration dashboard where commands replace chats: a resident commander agent decomposes each order into task briefs with acceptance criteria, typed subagent troops (recon/engineer/med

Workflow & AutomationManifest valid

★ 3

↓ 420/wk

MIT

TypeScript

Sep 30, 2026

dsh plugin --profile web add dsh-plugin-stardeck

by Martlet-Tech

Explain what a pending dsh approval will actually do, with one LLM call: an Explain button beside Allow/Reject in the DeepSeek Harness Web GUI.

Security & AuditManifest valid

★ 2

MIT

JavaScript

Sep 22, 2026

dsh plugin --profile web add dsh-approval-explain

by yaopushen

Antigravity-style run_command for DSH: short commands return inline within a configurable wait window (default 10s) while longer ones auto-promote into ctx.jobs for later collection and completion not

Workflow & AutomationSecurity & AuditManifest valid

★ 1

MIT

TypeScript

Oct 25, 2026

dsh plugin --profile web add dsh-plugin-background-tasks

by kiterunner1

DSH 插件:任务结束或命令卡死时用本机人声提醒,自动中断卡住的 pwsh 调用并把「怎么继续」写回工具结果,并在 spawn 之前拦掉已知的性能陷阱写法。仅 Windows。 / Beeps + stuck-command watchdog + command guard for DeepSeek Harness. Windows only.

Manifest valid

★ 0

MIT

JavaScript

Sep 15, 2026

dsh plugin --profile web add dsh-attention-beep