dsh-decision-review
The primary model keeps deciding; a second model only advises.
Independent review as a DeepSeek Harness tool, not a replacement for the decision maker.
简体中文 · English
> [!NOTE]
> This bundle installs with `mode: off` and makes no calls. Enabling it requires a compatible
> `POST /v1/decision` service plus an explicit `model` and `baseUrl`.
## Why this plugin
Asking one model to check its own answer usually repeats its own reasoning. A second opinion is
useful only when the reviewer sees the question, the primary choice, the evidence, and the
constraints without joining the original reasoning or holding tool permissions.
The primary model must commit to `primaryChoice` before review starts. The suggestion and its
confidence return to the primary model, which still decides whether to adopt, keep, or ask the user.
```mermaid
flowchart LR
A[Primary model picks primaryChoice] --> B[__decision_review tool]
B --> C[POST /v1/decision]
C --> D[choice + confidence]
D --> E{confidence}
E -->|>= minConfidence| F[ok: adoptable]
E -->|>= abstainBelow| G[not_adoptable]
E -->|< abstainBelow| H[abstained]
F --> I[Primary model decides]
G --> I
H --> I
```
## Capabilities
| Capability | Behaviour |
| --- | --- |
| Three modes | `off` registers nothing; `shadow` logs only; `advisory` returns a suggestion |
| No decision hijack | Review returns advice and confidence; the primary model still chooses |
| Structured output | `status`, `recommendation.choice`, `confidence`, `reasonCode` |
| Confidence tiers | Adoptable, keep-but-not-recommended, or abstained |
| No retries | A failed review returns immediately; the primary judgement stands |
| Redacted logs | Point, status, reason code, model, HTTP status, request id, input fingerprint, latency |
| Observability | One stderr line per review with `traceparent` tracing; failures distinguish "no response headers yet" from "reading the body" |
| Permission isolation | Permissions, approvals, writes, network targets, and allowlists never reach the reviewer |
## Protocol
```text
POST {baseUrl}/v1/decision
Authorization: Bearer {DECISION_API_KEY}
```
The body has exactly three top-level fields: `{ model, state, questions }`.
| Field | Source |
| --- | --- |
| `state.question` | Tool input `question` |
| `state.primaryChoice` | Tool input `primaryChoice` |
| `state.evidence` | Tool input `evidence` |
| `state.constraints` | Tool input `constraints` |
| `questions.recommendation.criteria` | Tool input `options` |
| Response | `answers.recommendation.choice` and `confidence` |
`probabilities` are informational only. `baseUrl` is the gateway root; an address already ending in
`/v1` or the endpoint path is rejected at startup.
## Install
```sh
dsh plugin --profile