Assay
New

Real-Time Formal Verification
for AI-Generated Code

PostToolUse hooks check every Write and Edit in Claude Code. Deterministic checks. Zero LLM. Findings land in the AI's context the moment it writes the bug, and it runs outside the AI's control.

0ms
LLM Latency
5
Check Types
1,013
Tests Passing

The Problem

AI writes code. That code ships. Nobody checks if the AI hallucinated a SQL injection, used a non-existent API, or forgot error handling.

Without Hooks

  • 1. AI writes SELECT * FROM users WHERE id = " + userId
  • 2. Code passes review (human or AI — both miss it)
  • 3. Ships to production
  • 4. Vulnerability discovered in prod (or by attacker)
  • 5. Incident response, data breach, trust loss

With Hooks

  • 1. AI writes the same bad code
  • 2. Hook fires instantly — findings injected into the AI's context
  • 3. AI sees: "Assay found 1 potential issue: SQL string concatenation"
  • 4. AI rewrites with parameterized query
  • 5. Cost: $0. Time: milliseconds. Your session never gets bricked by a false positive.

How It Works

The hook fires after every Write and Edit. It reads the full file, scans the changed region, and injects any findings straight into the AI's context. Advisory by design: the AI fixes what it sees, and a false positive can never brick your session.

When code is clean

AI Writes Code
Claude calls Write or Edit
Assay Hook Fires
Reads file, runs 5 checks on changed region
Clean — Allowed
Exit 0. User never notices.

When code has issues

AI Writes Code
Claude writes SQL injection
Assay Hook Fires
Detects string concat in SQL
Advisory Injected
Findings land in the AI’s context.
AI Fixes & Retries
Parameterized query. Hook passes.
Claude Code — PostToolUse Hook
# AI writes a file with SQL injection...
Tool: Write → src/api/users.ts
⚠️ Assay found 2 potential issues in the file you just edited:
- [sql_parameterized] Line 42: SQL string concatenation
- [error_handling] Line 38: async function 'getUser' has no error handling
# The findings land in the AI's context. It rewrites with parameterized query + try/catch...
Tool: Edit → src/api/users.ts (fixed)
✓ Assay hook passed — no findings in changed region

What It Catches

Five deterministic checkers that run in under 100ms. Pure regex. No LLM, no network call, no hallucination possible.

CheckWhat It DetectsSeverityLanguages
SQL InjectionString concatenation in SQL queries instead of parameterized statementscriticalAll
API MisuseNon-existent methods: .flatten(), .contains(), Object.fromPairs()criticalJS/TS, Python
Error HandlingAsync functions with no try/catch or .catch()highJS/TS
Input ValidationDirect use of req.body/params/query without validationhighJS/TS
Null SafetyNon-null assertions (value!.prop) covering nullable accessmediumTypeScript

Two Enforcement Points, One Verifier

The same formal verifier powers both real-time hooks and batch assessment. One engine, two doorways.

Development-Time

  • HookPostToolUse on Write/Edit
  • FormalClaimless pattern scanning
  • FormalDiff-aware region filtering
  • HookAdvisory injected on findings

formal-verifier.ts

Pure TypeScript
Zero dependencies
Can't hallucinate

Assessment-Time

  • LLMMulti-pass claim verification
  • FormalPost-pass overlay on LLM verdicts
  • FormalOverride when formal disagrees
  • FormalReal coverage stats in output

Setup in 30 Seconds

Install the CLI, register the hook, and every Write/Edit gets verified automatically.

Terminal
# Step 1: Install Assay
$ npm install -g tryassay
# Step 2: Register the hook
$ tryassay hooks install
✓ PostToolUse hook registered for Write and Edit
Location: ~/.claude/settings.json
# Step 3: There is no step 3. Start coding.

Why Not Just Use a Linter?

Linters check syntax. Assay checks what the AI claimed vs what the code does.

CapabilityESLint / BiomeAssay HooksAssay Assess
Syntax & style checks
SQL injection detectionPlugin
API misuse (non-existent methods)
Real-time findings in the AI’s context
Claim extraction from code
Multi-pass LLM verification
Formal override of LLM verdicts
Works without AI in the loop
Cost per check$0$0~$1–10 by repo size

Try It Now

Run a full assessment on any project. The hooks come with the CLI.

$ npx tryassay assess ./your-project