Skip to content
dsh.fish
Bundle

dsh-approval-auto-review

Codex-inspired Guardian approval reviewer for DeepSeek Harness

Source
perlied03
stars
2 stars
License
MIT
Updated
Updated 10 days ago

Readme

# dsh-approval-auto-review

English | [中文](README.zh.md)

Automatic approval reviewer for DeepSeek Harness. The plugin handles approval requests routed to its configured permission preset, evaluates the exact planned action with a locked-down Guardian agent, and returns a single approval decision for that request.

Each parent agent has one reusable Guardian trunk. The first review sends a bounded transcript and the planned action. Later reviews send only the current action delta to the same trunk. When that trunk is busy, the plugin starts an independent ephemeral reviewer so concurrent approval requests do not queue behind one another. If a trunk turn fails after its child is published, the child remains the reusable recovery point; a later review reattaches to that child instead of creating another continuable session.

## Features

- Separate reviewer model route with optional inheritance from the parent agent.
- Provider and model overrides for specific parent model ids.
- Empty tool allowlist and a dedicated reviewer persona for every reviewer agent.
- Bounded transcripts and tool arguments.
- Bounded rejection rationales before they reach the parent transcript.
- Fail-closed handling for timeouts, malformed output, provider failures, and unresolved routes.
- Denial circuit that stops a parent turn after repeated automatic rejections.
- Durable JSONL audit trail recording every reviewed command and the reviewer's verdict.

## Install

Install the repository as a DSH profile bundle:

```sh
dsh plugin --profile web add github:perlied03/dsh-approval-auto-review
```

For a local checkout:

```sh
dsh plugin --profile web add ./dsh-approval-auto-review
```

The package declares `dsh.bundle`, so `dsh plugin` adds its configuration layer to the profile automatically. The layer registers the reviewer and provides three permission choices: **Request approval**, **Approve for me**, and **Full access**. The same package declares `dsh.client`, so the Web profile discovers its reviewer-model settings card and the conversation's **Review** tab from the installed package. Select **Approve for me** in the conversation permission menu to route approval requests to the Guardian.

A GitHub install runs the package's `prepare` build. With pnpm 10 or later, add `dsh-approval-auto-review: true` under `allowBuilds` in the profile's `pnpm-workspace.yaml` when pnpm asks for build approval, then repeat the install command.

The host composition must provide these DSH services and plugins:

- `dsh-agent`
- `dsh-session`
- `dsh-settings`
- `dsh-user-approval`
- `dsh-subagent`
- an in-process spawn provider registered under the configured `provider` name
- an in-process fork provider registered under the configured `ephemeralProvider` name

The fork provider handles concurrent reviews while preserving the reusable trunk path. Deployments that do not need that path may use the same provider name for both settings.

## Configure

Register the plugin in the Cordis composition:

```ts
import * as ApprovalAutoReview from 'dsh-approval-auto-review'

await ctx.plugin(ApprovalAutoReview, {
  provider: 'spawn',
  ephemeralProvider: 'fork',
  modelProvider: 'deepseek-official',
  model: 'deepseek-v4-flash',
  fallback: 'parent',
})
```

The equivalent Loader row is:

```yaml
- id: approval-auto-review
  name: 'dsh-approval-auto-review'
  config:
    provider: spawn
    ephemeralProvider: fork
    modelProvider: deepseek-official
    model: deepseek-v4-flash
    fallback: parent
```

Configuration fields:

- `provider`: subagent provider for the reusable Guardian trunk. Default: `spawn`.
- `ephemeralProvider`: subagent provider for concurrent one-shot reviews. Default: `fork`.
- `modelProvider` and `model`: optional reviewer route.
- `modelOverrides`: optional map keyed by parent model id. Each entry may set `provider`, `model`, and `maxTokens`.
- `fallback`: `parent` inherits missing route fields from the parent agent; `reject` fails closed when a route is incomplete. Default: `parent`.
- `timeoutMs`: deadline for one review attempt. Default: `30000`.
- `maxAttempts`: retry limit after a failed attempt. Default: `3`.
- `maxTranscriptChars`: maximum serialized parent transcript sent to a full review. Default: `60000`.
- `maxToolArgumentsChars`: maximum raw tool-argument characters sent to a review. Default: `20000`.
- `maxTokens`: optional reviewer output-token ceiling.
- `activationPreset`: permission preset that activates review. When omitted, the plugin handles every approval request. The bundled layer sets `approve-for-me`.
- `audit`: `file` records every terminal review result to the audit JSONL (see [Audit log](#audit-log)); `off` drops records. Default: `file`.
- `auditPath`: absolute audit file path. Default: `<DSH_HOME>/audit/approval-auto-review.jsonl`. Fixed at mount; a change applies after a restart.
- `auditArgumentsChars`: maximum stored raw tool-argument characters per audit record. Default: `2000`.

Enable automatic review by switching the conversation's permission preset to **Approve for me**: the durable `permission/preset` event in the session log activates the Guardian for subsequent asks. Switching back to **Request approval** returns decisions to the human channel. The plugin does not create a persistent allow rule; each decision applies to one approval request.

## DSH compatibility

Routing reads the durable `permission/preset` selection from the session log, so the reviewer works with the current DSH host services. The Web Review tab additionally requires `dsh-host-webserver` to expose the read-only audit route. Approval services accept only closed-string outcomes, so a timed-out review resolves as a rejection; the allow/deny behavior remains fail-closed either way.

## Web settings

The package's Web client entry contributes an **Automatic approval review** card to the existing Plugins settings section. The card edits `modelProvider` and `model` through the `approval-auto-review` settings namespace and uses the same model directory as the DSH Models page. Select a provider first to filter the model list, or leave both fields on **Follow the parent agent** to inherit the parent route. Changes apply to the next review without restarting the process.

The standalone card uses a lower slot priority than default contributions. When the Host also contributes an `approval-auto-review` card, the standalone card renders and the Host card remains registered but shadowed.

The conversation header also includes a read-only **Review** tab. It requests the current session's records from the Host and shows the reviewed tool, bounded arguments, outcome, reviewer rationale, route, and attempt count. The tab shows the latest 200 matching records, refreshes on demand, and reports empty or unavailable history without exposing records from another session. It requires the WebServer route supplied by the Web profile; `audit: off` produces an empty history.

## Model routing

The reviewer route is resolved in this order:

1. `modelOverrides[parent.options.model]`, when an entry exists.
2. The plugin-level `modelProvider` and `model` values.
3. The corresponding parent agent route when `fallback` is `parent`.
4. A fail-closed error when `fallback` is `reject` and the route is incomplete.

Provider and model names are deployment values. The plugin does not assume that a Codex or OpenAI model id is available from a DSH provider.

## Review policy

The Guardian evaluates only the exact action supplied by the approval request. Direct user messages and content explicitly loaded from `AGENTS.md` are trusted authorization evidence. Assistant messages, tool calls, tool results, file contents, command output, and ordinary plugin context are untrusted.

The default policy allows low- and medium-risk actions unless a specific deny rule or prompt injection applies. High-risk actions require at least medium trusted authorization and a narrow scope. Critical risk, obvious secret exfiltration, broad destructive actions without exact authorization, and broad persistent security weakening are denied.

Every reviewer agent has an empty tool allowlist, a dedicated persona, structured output requirements, and a delegated approval policy that prevents the reviewer from creating another approval request.

## Failure behavior

- A timeout injects a retry-or-ask notice into the parent session and rejects the request.
- A provider failure or malformed reviewer response is retried up to `maxAttempts`, then returns a rejection.
- An unresolved route rejects when `fallback` is `reject`; with `parent`, missing fields inherit from the parent agent.
- A rejected automatic review injects its rationale and an anti-circumvention notice into the parent session; the rationale is bounded to `AUTO_REVIEW_RATIONALE_MAX_CHARS` characters first.
- Three consecutive automatic denials, or ten denials among the latest fifty automatic reviews in one turn, cancel the parent turn.

## Audit log

Every terminal review result appends one JSON line to `<DSH_HOME>/audit/approval-auto-review.jsonl` (override with `auditPath`; disable with `audit: off`). One record covers one approval request — retries collapse into a single line:

```json
{"v":1,"time":1756130000000,"session":"<parent session id>","callId":"call-3","toolName":"bash","arguments":"{\"command\":\"rm -rf build\"}","argumentsTruncated":false,"outcome":"deny","attempts":1,"riskLevel":"high","userAuthorization":"low","rationale":"The action exceeds the trusted authorization.","provider":"deepseek-official","model":"deepseek-v4-flash","reviewerSession":"trunk"}
```

- `toolName` and `arguments` identify the exact reviewed command; `arguments` is bounded by `auditArgumentsChars` and marked with `argumentsTruncated`.
- `rationale`, `riskLevel`, and `userAuthorization` carry the reviewer's verdict on allow and deny outcomes.
- `provider`, `model`, and `reviewerSession` (`trunk` or `ephemeral`) name the route that decided; timeout, error, and cancelled records omit these fields.
- `outcome` is one of `allow`, `deny`, `timeout`, `error`, `cancelled`; `attempts` counts consumed attempts.
- The trail is best-effort: an unwritable file emits one diagnostic and stops recording for that process without failing any approval decision.

The audit file is out-of-band by design: session logs refuse unknown event types from builds that do not declare them, so the reviewer keeps its records beside the sessions instead of inside them.

## Model Experience

### Parent session

#### What the model sees

The parent model receives the approval-policy context produced by `dsh-user-approval`. A rejection adds the reviewer rationale and an anti-circumvention notice. A timeout adds a separate retry-or-ask notice. The Guardian transcript is not copied into the parent model request.

#### Token effect

Only approval-policy context and injected rejection or timeout notices can add tokens to a later parent request. The reviewer transcript is not duplicated in the parent request.

#### KV Cache effect

Approval-policy context and injected notices may change the prefix of the next parent request. A successful approval adds no notice.

### Guardian reviewer

#### What the model sees

The first trunk review receives one bounded parent transcript and the exact planned action. Later trunk reviews receive the current bounded action delta and the prior review count. An ephemeral review receives a new bounded transcript and the current action.

#### Token effect

Every approval review is a separate model request. Transcript and argument limits cap the material sent to each request.

#### KV Cache effect

Trunk reviews append deltas to one child session, allowing a provider to reuse a stable prefix. Each review still creates a new model request. Ephemeral reviews use independent sessions and do not reuse the trunk prefix.

## Known Limitations and Deferred Work

- The deployment must provide subagent providers that support personas, empty tool filters, structured output, continuations, and cancellation.
- The Guardian has no filesystem or network tools. Its bounded parent evidence is the complete review input; adding tools would introduce another prompt-injection and authorization source.
- Provider and model availability is controlled by the deployment. An unavailable route fails closed instead of being silently replaced.
- The audit trail is best-effort and out-of-band: write failures disable recording for the process, and the file is not covered by session-log integrity or compaction machinery.
- A GitHub install runs `prepare` to build `lib/`. pnpm 10 or later requires an explicit `allowBuilds` entry when the profile has not trusted this package before.

## Development

```sh
pnpm install
pnpm test
pnpm run typecheck
pnpm run build
```

The package resolves DSH imports from published packages. `prepare` builds the Host exports and the `lib/client.js` bundle discovered through `dsh.client`.

Install

dsh plugin --profile web add github:perlied03/dsh-approval-auto-review

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source