Open Source · Apache-2.0

Completion Claim Validation Gate.

A Claude Code Stop hook that intercepts an assistant's "done / fixed / deployed" claims and routes them to a local Ollama model prompted to disprove them — blocking the turn when the claim cites no user-observable evidence.

Install

Transcribed from the repository README; not yet executed from a clean environment:

git clone https://github.com/bulletproofsoftware-ai/bulletproof-validation-gate.git
cd bulletproof-validation-gate
ollama pull llama3.2:3b       # any Ollama model works; larger judges better
./install.sh                  # prints the settings.json snippet, paths filled in
# paste the printed "Stop" hook block into ~/.claude/settings.json
Completion Claim Validation Gate architecture infographic
Architecture infographic — from bulletproof-validation-gate/docs/media/
Domain Assurance / Agent Governance
Repository bulletproof-validation-gate
Language Python 3.8+ (stdlib only)
Integration Claude Code Stop hook · Ollama
License Apache-2.0

1Problem Statement

AI coding assistants routinely declare success without proof. The claim "fixed it" arrives with no test output, no rendered page, no command result — and the burden of discovering that nothing was fixed shifts onto the human. Every unverified claim the user has to disprove themselves erodes trust in the assistant.

The conventional mitigations are weak. Asking the model to self-check produces confirmation, not scrutiny: a model that just claimed success is poorly positioned to judge that claim. CI gates catch broken code but run too late and say nothing about whether the assistant's *description* of its work was honest.

This gate moves the check to the moment the claim is made, and makes the verifier adversarial. A second model — running locally, with no stake in the first model's output — is prompted to refute the claim. If it cannot find cited, observable evidence, the turn is blocked and the assistant must substantiate or retract.

2Architecture

The entire tool is a single script, completion_claim_gate.py, invoked by Claude Code on the Stop event. It reads the hook payload from stdin — last_assistant_message, session_id, transcript_path, stop_hook_active — and decides whether to emit a pass-through or a block.

Regex pre-filter

COMPLETION_RE matches 14 patterns (\bdone\b, \bfixed\b, \bdeployed\b, \bshould (?:resolve|work|fix)\b, and similar). No match means no LLM call — emit_pass_through() prints {} and the turn proceeds. This keeps the common case free.

Evidence gathering

read_transcript_tail() reads the last ~40 JSONL transcript entries, truncating each to 1000 characters and capping the whole context at 8000, so the verifier judges the claim against what actually happened in the session.

Adversarial verifier

call_verifier() POSTs to Ollama /api/generate with temperature: 0.1 and num_ctx: 8192. The prompt names three PASS conditions and four FAIL conditions, and instructs the model to disprove rather than confirm.

Defensive parsing

The response parser strips <think> preambles and code fences before json.loads, expecting {"verdict", "reason", "missing_evidence"} and adding latency_ms. Malformed output is treated as UNPARSEABLE, not as a failure.

Fail-open by design

emit_block() prints {"decision":"block", ...} on FAIL only. PASS, ERROR, and UNPARSEABLE all pass through, so an unreachable or slow Ollama can never wedge a session.

Safety Properties

3Requirements

Requirements are derived from the implemented behaviour of completion_claim_gate.py.

IDRequirement
REQ-VG-001Intercept the Claude Code Stop event and read the hook payload from stdin.
REQ-VG-002Apply a regex pre-filter of 14 completion patterns before invoking any model.
REQ-VG-003Pass through immediately when no completion language is present.
REQ-VG-004Read the transcript tail as bounded evidence context (≈40 entries, 8000 chars).
REQ-VG-005Prompt the verifier adversarially — to disprove the claim, not confirm it.
REQ-VG-006Parse verifier output defensively, stripping think-tags and code fences.
REQ-VG-007Block only on an explicit FAIL verdict; pass through on ERROR or UNPARSEABLE.
REQ-VG-008Pass through unconditionally when stop_hook_active is set.
REQ-VG-009Write a per-invocation JSON verdict file and append to an audit log.
REQ-VG-010Never let audit or notification failure affect the gate decision.
REQ-VG-011Operate with zero third-party Python dependencies.

4Interfaces

The gate has no HTTP API, no CLI subcommands, and no MCP tools. It is configured entirely through the Claude Code hook definition and environment variables.

VariableDefaultPurpose
OLLAMA_URLhttp://localhost:11434/api/generateVerifier endpoint
OLLAMA_VERIFIER_MODELllama3.2:3bModel used to judge the claim
OLLAMA_VERIFIER_TIMEOUT_S20Verifier timeout in seconds
OLLAMA_VERIFIER_KEEP_ALIVE24hOllama model keep-alive window
VALIDATION_GATE_VERDICT_DIR(unset)Directory for per-invocation verdict files
VALIDATION_GATE_LOG(unset)Append-only audit log path
VALIDATION_GATE_NOTIFY(unset)Executable invoked on a FAIL verdict

5Integration Points

The gate deliberately has a very small integration surface — a local model and the hook system, nothing else.

6Repository

The implementation is a single script; the remainder of the repository is documentation, install tooling, and assurance evidence.

PathPurpose
completion_claim_gate.pyThe entire implementation — filter, verifier call, parsing, audit
install.shPrints the settings snippet with the absolute path resolved
settings.snippet.jsonHook definition to paste into Claude Code settings
tests/test_gate.shThree smoke tests
docs/OVERVIEW, INSTALL, HOW-TO-USE, ADMINISTRATOR, SBOM
docs/scan/SARIF output, attestation, and scan reports
.github/workflows/ci.ymlPython 3.12 CI with SHA-pinned actions

View source on GitHub

7Implementation Notes

Operational characteristics worth knowing before deployment.