DeepSeek Harness Plugin

x402/dsh-fail-fast

Stars ★ 1 Downloads (30d) 739 Category Development & Runtime Added 2026-11-02 npm dsh-fail-fast

Fail-fast tool batches for DeepSeek Harness: inside a step, concurrency-safe calls still overlap, but after the first failed call every remaining unstarted call is denied before dispatch and returned to the model as a synthesized `is_error` "not executed" result.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-fail-fast

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:x402/dsh-fail-fast

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

中文 | English

A DeepSeek Harness (DSH) plugin that adds fail-fast behavior to tool calls within a single step. Once any tool call fails, the plugin intercepts all remaining unstarted calls and returns synthesized is_error: true ("not executed") results to the model.

Models frequently emit dependent tool calls in a single response (e.g., write followed by bash). DSH's agent loop already handles execution order: concurrency-safe reads share parallel groups, while other calls run sequentially in their own ordering groups according to model output order. The missing piece is failure handling — when an earlier call fails, DSH still dispatches subsequent calls whose preconditions no longer hold, wasting execution and risking destructive side effects.

Models naturally emit tool calls in dependency order, making the output sequence itself an implicit dependency topology. Leveraging this property, the plugin leaves DSH's concurrency and ordering schedule intact and requires no knowledge of tool semantics or dependency graphs, simply halting unstarted calls after a failure point. Because skipped calls return with an explicit "not executed" reason, the current turn's context stays intact and the model can recover directly on the next turn.

Features

  • Scheduling untouched — the plugin takes over no scheduling: concurrency-safe calls still overlap up to maxParallelToolCalls, other calls keep their ordering groups, and dispatch is never degraded to global serial execution.
  • Stop at the first failure — any final is_error: true result (tool error, policy denial, timeout, post-execute block) cancels every remaining unstarted call; siblings already started in the failing group finish normally.
  • Model-repairable result — skipped calls come back as is_error: true with FailFastSkippedError / SKIPPED_AFTER_FAILURE and an Error: Not executed: … message, so the model can fix the failure and re-issue the remaining calls.
  • Non-invasive — the plugin only observes public DSH extension points (session/event, tools/result, tools/pre-execute); it never replaces the tool executor or rewrites the failing call's own result, and a denied call runs no body and triggers no approval.
  • No dependencies, no config overrides — a single dependency-free ESM Host plugin; cordis.patch.yml only inserts the plugin row and overrides nothing.
  • Scoped — only model-direct top-level calls participate; PTC sub-calls (which carry exec.parent) and subagents (separate sessions) have independent state. Single-call batches and aborted batches are unaffected.

How it works

DSH's agent loop already runs one step's calls as ordering groups, one group at a time: a group is fully drained and committed in model order before the next starts. On top of that the plugin does three things:

  1. Batch tracking — listens to session/event (step/start, tool/call) and records the ordered call ids of the step in flight.

  2. Failure point — listens to tools/result and pins the first is_error: true call in model order.

  3. Cancel the rest — a prepended tools/pre-execute listener denies calls after the failure point that have not started. A denied call never runs its body and never triggers an approval, but the loop still records the normal tool/call + tool/result pair, so the model sees:

    Error: Not executed: the preceding `read` call failed, so fail-fast skipped this call
    and every call that had not started yet in the batch. Fix the failure first, then
    re-issue the remaining calls in dependency order.
    

The failing call's own result is left untouched.

Behavior and boundaries

  • Any final is_error: true result counts as a failure: tool errors, policy denials, timeouts and post-execute blocks all cancel the rest of the batch.
  • Calls already started in the failing group run to completion (they declared themselves concurrency-safe and independent, so their results remain meaningful); no new call starts afterwards. If the failure commits very quickly, a same-group tail that has not been prepared yet is also skipped; that is the conservative direction.
  • Non-concurrency-safe calls (writes, bash, …) are single-call groups, so write → bash dependency order is preserved naturally.
  • A single-call batch is unaffected; batch state resets at every step boundary.
  • Aborted batches are synthesized by the agent loop itself (aborted before dispatch); this plugin stays out of that path.
  • Cost: already-started same-group calls cannot be recalled (they are independent, which is what allows the overlap). Tools that want to stop earlier must honor exec.signal.

Install

The plugin is published on npm as dsh-fail-fast. In the DSH Web Plugins page, choose Add plugin, enter the package name, and click Enable now once it is installed:

dsh-fail-fast

Or install it from a session with the plugin manager tool (installs and enables it):

plugin_manager(action: "install_bundle", target: "dsh-fail-fast")

DSH reports newer versions and updates the plugin in place.

Other install paths

  • Pinned version / preview commit — paste https://github.com/x402/dsh-fail-fast#<tag-or-commit> into the install field. GitHub installs need git and GitHub connectivity, and DSH does not check them for updates, so upgrading means uninstalling and installing again.
  • Local development — clone the repository and install the checkout as a bundle (link: or an absolute path); see AGENTS.md.

The package.json declares DSH compatibility >=0.2.0-rc.2 <0.3.0. Behind a slow network, pick a custom registry mirror in the install dialog.

plugin_manager list_plugins / list_bundles confirm the fail-fast row is enabled.

Acknowledgements

The problem this plugin solves was originally identified by @Golden-Pigeon.

License

MIT © 2026 x402 and the dsh-fail-fast contributors

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.