Bundle
@agent_forge/forge-dsh
Forge quality gates for DeepSeek Harness (dsh): task gates, read-before-edit, bash hazard interception and quality scoring, driven by the forge CLI through DSH's typed interception points.
- weekly downloads
- 1.1k weekly downloads
- License
- Apache-2.0
- Updated
- Updated 2 hours ago
Readme
# @agent_forge/forge-dsh
Forge quality gates for **DeepSeek Harness (dsh)** — task gates, read-before-edit,
bash hazard interception, and quality scoring, enforced inside DSH sessions through
the harness's typed interception points.
[Forge](https://github.com/MjxUpUp/Forge) is an AI-code quality gate engine. This
plugin is a thin Cordis wrapper: it forwards DSH tool/session events to the `forge`
CLI and translates forge's verdicts back into DSH decisions. All gate logic lives in
the forge binary — the plugin itself has **zero runtime dependencies**.
## How it works
> The mapping table below and the fail-open contract at the end of this README
> are the **two-sided bridge contract**, mirrored machine-readably in
> [`contract.json`](./contract.json) and enforced by forge's compat snapshot
> (surface `bridges`). Change all three together: `contract.json`, this README,
> and the tests on both sides.
| DSH interception point | forge hook event | A forge block becomes |
|---|---|---|
| `tools/pre-execute` | `PreToolUse` | `{kind:'deny', reason}` |
| `tools/post-execute` | `PostToolUse` | `{kind:'block', feedback}` (error result) |
| `agent/pre-step` | `UserPromptSubmit` | `{kind:'reject'}` |
| `agent/session-start` | `SessionStart`¹ | context via `agent.inject()` |
| `agent/turn-stopping` | `Stop` | `agent.steer(reason)` → another step |
¹ `source:'compact'` additionally fires forge's `PostCompact` group — DSH rc.7
exposes no dedicated compaction point.
DSH tool names map onto the Claude Code names forge dispatches on
(`write/edit/str_replace_editor→Write/Edit`, `bash/pwsh→Bash`, `read→Read`,
`skill→Skill`); unmapped tools pass ungated. The wired hook roster mirrors
forge's canonical spec (`lib/spec.json`, drift-guarded by a Go test in the Forge
repo) — freeze-guard, task-guard, assertion-check, read-before-edit, bash-guard,
hazard-guard, auto-compile, workflow-test-guard, file-sentinel, tool-track,
test-nudge, failure-track (PostToolUseFailure), subagent-track (SubagentStop),
task-verify, review-stop, skill-trigger, and the session-start group.
failure-track/subagent-track are mirrored in the spec but inert until DSH
exposes the corresponding event points (rc.7 has neither).
## Requirements
- The `forge` CLI on `PATH` (`npm install -g @agent_forge/forge`), with the project
initialized (`forge init`) for task gates to have state to enforce.
- DeepSeek Harness `0.1.0-rc.x` (verified against `0.1.0-rc.7`), Node.js ≥ 18.
- Windows works out of the box: npm lays out `forge` as a `forge.cmd` shim, which
the plugin spawns through `cmd.exe` (a bare spawn cannot execute it); timeout
kills tear down the whole child tree via `taskkill /T`.
## Install
```sh
# from npm
dsh plugin --profile web add @agent_forge/forge-dsh
# or straight from the Forge repo (subdirectory install)
dsh plugin --profile web add "github:MjxUpUp/Forge#main&path:/plugins/forge-dsh"
# local development
dsh plugin --profile web add "link:$(pwd)"
```
Restart `dsh web` after install. Check status inside a session with `/forge-status`.
## Config
```yaml
# profile patch
- insert:
- id: forge-quality
name: "@agent_forge/forge-dsh"
config:
forgeBin: forge # binary name/path (env FORGE_BIN overrides the default)
timeoutMs: 30000 # per-hook ceiling; timeout kills and FAILS OPEN
enabled: true # false unwires every listener
debug: false # log fail-open hook errors to console.error
```
## Fail-open contract
Blocks are read from forge's stdout JSON (`decision:"block"`), never from exit
codes — a forge internal error (exit 1) is indistinguishable from a deny otherwise.
Every infrastructure failure (forge missing, spawn error, unparseable output,
timeout) **fails open**: a forge outage never locks the agent out of its own tools.
Such failures are silent by design; surface them with `/forge-status` or `debug:true`.
Two latency trade-offs to know: hooks run **serially** per event (up to five per
group), so a slow hook chain delays the tool call — and a gate that legitimately
exceeds `timeoutMs` (e.g. `auto-compile` cold-building a large project past 30s)
silently loses that run's feedback to fail-open (visible in `/forge-status`).
Raise `timeoutMs` on big projects.
## Known watch items (dsh preview)
- **No stop-hook loop guard** in rc.7 — a permanently-failing Stop gate steers at
every stop boundary. forge's Stop gates are self-limiting once their gate passes,
but a stuck gate loops the turn.
- **SessionStart context is best-effort** (emit mode, detached): it may miss the
first request of a very short-lived session — same limitation the official
bridges document (`TODO(session-start-gating)`).
- DSH is a developer preview; pin this plugin's version alongside your dsh version.
## Development
```sh
npm install # dev-only: @deepseek-ai/cordis for the wiring tests
npm test # mapping, runner (incl. cross-OS planSpawn units), decision folding, real-cordis wiring
```
`test/doubles/fake-forge.mjs` stands in for the forge binary; the wiring suite
boots a real cordis runtime and asserts dispatch order, short-circuit semantics,
payload shape, and every decision mapping.
Install
dsh plugin --profile web add @agent_forge/forge-dsh@1.62.0
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install agent-forge-forge-dsh from the hub