DSH Plugins Marketplace

DSH Plugins

Plugins

/

Security & Audit

/

dsh-evidence

d

dsh-evidence

Manifest valid

Pre-claim gate: a commit, push or tag claim like "tests pass" is checked against the session evidence ledger before it is written.

hasBundlePatch

dsh-preclaim

Repository name vs package name: the repo is dsh-evidence; the npm package is dsh-preclaim. They are the same plugin.

A commit message that says "tests pass" is a claim. This checks it against what the session actually ran — and stops the commit if the two disagree.

A DeepSeek Harness plugin. No model, no service, no network, no API key.

$ git commit -m "fix: parser handles empty input; tests pass"

  dsh-preclaim: this session has recorded no evidence at all, so this gate cannot
  tell "it did not happen" from "I did not see it"
  — asserted: CLAIM_TEST_PASSED

  [review] commit anyway, or run the tests first?

Why preclaim and not evidence-gate? Because the obvious names are held by other authors, some of them for plugins asking the same question: dsh-evidence-gate (lory.top), dsh-evidence (tudamu), dsh-claim-gate, dsh-attest. The project's design document checked the registry and picked the free name that describes the right moment: before the claim is written down. scripts/verify-artifacts.mjs fails the build if a later edit drifts back onto a name somebody else owns.

Quick start

dsh plugin --profile web add dsh-preclaim@0.1.3

evidence_status / the pre-execute gate is now available; The gate records what ran in the session and checks a commit/push/README claim against that ledger before it is written.

Why this exists, and why it is not a model

The failure it targets is not a judgement call. "The message claims tests pass" and "no test run is recorded in this session" are both facts, and whether they agree is decidable. A model here would add a confidence interval to a yes/no question, and would occasionally be wrong in a way nobody could reproduce.

So the whole plugin is deterministic:

  • tools/post-execute records what ran into an in-memory ledger for the session.
  • tools/pre-execute reads that ledger before a gated action runs.

Three consequences follow from that split, and they are the design rather than implementation details:

  1. A claim cannot satisfy its own obligation. The action under review is never consulted for evidence. A commit message saying "ran pytest; all tests pass" contributes nothing to its own check.
  2. A failed test run does not count as evidence that tests pass. test-run and build-run require success. ci-check and file-read do not: observing a red pipeline is still observing the pipeline, and reading a file is evidence of reading it whatever the exit code.
  3. Nothing is inferred from prose. The ledger holds what the host reported, and nothing else. There is no transcript reading and no heuristic scanning.

Install

dsh plugin --profile <name> add dsh-preclaim@0.1.3

The bundled patch arms the gate on activation. Every key has a default, so it works with no configuration at all.

What is gated

Shell calls running an asserting git verb — commit, push, tag. A commit carries its message inline; a push asserts through the commits it carries, so the command text is checked and the commit range is left to the human.

Read-only verbs (status, log, diff, show, branch, rev-parse, …) are never gated, and neither are --dry-run, --help, -h or --version: none of those makes a durable claim. git fetch && git commit -m x gates the commit and not the fetch.

README-shaped writes — README*, CHANGELOG*, docs/**/*.md, **/README.md. A README is where a project states what it does and whether it works. Ordinary source writes are left alone; gating those would put a gate in front of every edit. A write outside the working directory is not judged at all.

What counts as a claim

patternwhat it noticesanswered by
CLAIM_TEST_PASSEDsays tests passa recorded test run
CLAIM_VERIFIEDsays something was verifiednothing observable → tool_unverified
CLAIM_RAN_CHECKsays a check was runa recorded test run
CLAIM_BUILD_OKsays the build succeedsa recorded build
CLAIM_CLI_ASSERTIONnames a CLI invocationa CI observation
CLAIM_DEPENDENCYasserts a platform dependencynothing observable → tool_unverified
CLAIM_LINE_REFcites a linea file read
CLAIM_COUNTcites a countnothing observable → tool_unverified
CLAIM_HASH_REFcites a commit hashnothing observable → tool_unverified
CLAIM_FILE_EXISTScites a filea file read

The last column has a rule behind it: evidence has to connect to the claim it answers. file-read answers a citation of a file or a line, because reading that file is the connection. It does not answer "this was verified" — reading some file is not verifying that claim. An earlier version treated it as if it were, which made git commit -m "verified on Windows" pass as soon as anything at all had been read.

The four kinds mapping to nothing are not an oversight. They are claims this gate can observe but cannot adjudicate, so it says so and asks (tool_unverified) rather than making an accusation it cannot support.

If no pattern matches, the action is allowed with no-claim-in-action. The patterns are deliberately syntactic: a wider net means more false stops on honest work, and a gate that cries wolf gets switched off — after which it checks nothing at all.

What happens on a miss

situationverdictwhy
not a watched actionallownothing to check
a watched action carrying no claimallowstill nothing to check
every claim backed by recorded evidenceallowthe claim and the record agree
a claim with no evidence, ledger populatedreviewthe claim is not backed
the ledger is emptyreview, and says socannot distinguish "it did not happen" from "I did not see it"
a claim no observable evidence could answerreview (tool_unverified)a limit of this gate, not an accusation
the gate itself throwsreviewa defect must not become a silent allow

Two of those rows are worth reading twice.

The empty ledger happens whenever the plugin loads mid-session, or when recording failed. Reporting "the tests did not run" in that state would be a confident wrong answer. The gate says what it actually knows instead — and an empty ledger cannot produce either a pass or a factual accusation.

tool_unverified is the honest answer for a claim this plugin could never check. A commit saying reverts abc1234 cites a hash; nothing the ledger observes confirms or contradicts that. Calling it "unbacked" would be an accusation the gate cannot support, so it says so and asks.

Set decision: deny to refuse outright instead of asking.

Configuration

- insert:
    - id: preclaim
      name: dsh-preclaim
      config:
        triggerTools: [pwsh, bash, write, edit, str_replace_editor]
        readmeGlobs: ['README*', 'CHANGELOG*', 'docs/**/*.md', '**/README.md']
        decision: review      # review | deny
        audit: true
        ledgerLimit: 500
        pushMessageLimit: 20

There is deliberately no configuration value that lets an unbacked claim through. decision chooses between asking and refusing, and nothing else — a gate with an off switch is a gate that gets switched off. resolveConfig throws on decision: allow.

pushMessageLimit caps how many commit messages a push is checked against, so the cost does not grow with repository age. The cap is reported when it bites, because a silently truncated check reads as a complete one.

The evidence_status tool

evidence_status({ text: "fix: tests pass" })

Reports the ledger's state, which claims that text makes, whether the session has the evidence, and what the gate would decide. Call it before acting, so a stop costs a rewrite rather than a rejected action.

Two parsing details that are load-bearing

ANSI escapes are stripped before anything else. Captured output can carry escape sequences even through a pipe, so a flag can arrive as \u001b[1;33m--version\u001b[0m. Every plain-text pattern then fails to match and the gate silently stops recognising the commands it exists to inspect.

Commands are split on operators that are not inside quotes. Splitting on ; alone cuts git commit -m "a; b" in half, and the surviving half no longer looks like a commit — so a claim inside a message would be missed entirely.

Both are pinned by tests.

What it does not do

It does not read the transcript, does not call a model, and does not judge whether the work is good. It checks one narrow thing: whether a claim and the session's record of itself agree.

It also does not persist the ledger. Evidence is a property of this session, so a ledger restored from disk would be evidence for a different run.

It is a seatbelt, not a sandbox. Everything here is text matching over a ledger. git commit -m "$(cat claim.txt)", a test command the patterns do not recognise, or simply not using git all go around it. It catches the ordinary case — a claim written slightly ahead of the work — and it is not a defence against a session that wants to deceive it. Do not describe it as one.

Deliberately not built yet

The project's design specifies an optional second tier: when the deterministic layer lands in a grey zone, ask the local 150M Phocinae model once, and fail closed if the service is unreachable. That tier is not in this release. The result object already carries the fields it would fill (model_verdict, model_calls), and model_calls is reported as 0 because it is a real counter.

It is left out because the deterministic tier is where the measured value is, and a tier that adds a model call needs the same evidential standard as everything else — a measurement, not an assumption. Shipping the counter and calling it 0 is more honest than shipping a tier nobody measured.

Requirements

Node ^22.19.0 || >=24.0.0. No runtime dependencies. @deepseek-ai/cordis is an optional peer.

Testing

npm test                  # 64 tests, no host required
npm run verify:artifacts   # what npm publish would actually ship

The suite covers shell parsing (ANSI, quoting, operators, -C, read-only verbs, dry-run suppression), the claim table, the ledger's per-kind success rules, glob matching after path normalisation, next() call discipline, and the "must never allow" paths: an unknown decision, a throw inside the gate, and a payload with no tool name.

License

Apache-2.0.

Comments

Loading…

Similar plugins

dsh-evidence-gate

by AaronandWork

Evidence-first conclusion gate that cross-checks first-hand claims against a durable per-session tool-activity index, blocks unverified guesses and tracks blocked-versus-converted metrics.

Development & InfrastructureTerminal & ClientsManifest valid

★ 6

↓ 159/wk

MIT

JavaScript

Sep 12, 2026

dsh plugin --profile web add @aaronandwork/dsh-evidence-gate

Commitment write-gate: operator-authored rules enforced before a tool call runs — a deterministic guard tier plus an LLM-judge tier, fail-closed by default, every block written to a contradictions log

Security & AuditDevelopment & InfrastructureManifest valid

★ 0

↓ 54/wk

dsh plugin --profile web add dsh-write-gate

by LosEcher

DSH plugin wrapping verify-gate as the verify_run agent tool: declarative checks, pass/fail report, strict exit codes

Manifest valid

★ 0

MIT

JavaScript

Sep 28, 2026

dsh plugin --profile web add dsh-verify-gate

by PerryLink

证据清单齐备性核对(按待证事实与证据要素核对清单自洽,仅提示差异,不作出定性结论)

Tools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 0

NOASSERTION

TypeScript

Oct 7, 2026

dsh plugin --profile web add dsh-evidence-check

by dingchenhui0618-arch

Adversary review gate for DeepSeek Harness: an independent small model reviews destructive tool calls before they run, and reports every verdict. · DSH 对抗式审查门:危险工具调用在执行前由一个独立小模型复核。

Security & AuditTerminal & ClientsManifest valid

★ 0

MIT

JavaScript

Oct 8, 2026

dsh plugin --profile web add dsh-warden

by zhengqiuyang

Deterministic write gate: scope policy denies out-of-scope write/edit calls before they touch the disk, residue rules scan the written text, and every decision lands in a content-hashed JSONL ledger;

Security & AuditManifest valid

★ 0

MIT

JavaScript

Oct 19, 2026

dsh plugin --profile web add dsh-pr-gate