Quickstart
pip install veripoint # zero dependencies beyond the stdlib
veripoint init # creates .veripoint/ (ledger, snapshots, reports)
from veripoint import Veripoint, Slot
from veripoint.drivers import HTTPDriver # or SubprocessDriver("claude -p")
from veripoint.verifiers import CommandGate, ReconcileGate
k = Veripoint(".veripoint")
r = k.run(
goal="Reconcile October invoices against the ledger",
driver=HTTPDriver(model="gpt-5", api_key_env="OPENAI_API_KEY"),
slots=[
Slot("extract invoice totals",
verifiers=[CommandGate("python checks/invoices_parse.py")]),
Slot("reconcile vs ledger",
verifiers=[ReconcileGate("recon.json", {
"sum matches ledger": lambda d: d["sum"] == d["ledger_total"],
})]),
],
)
print(r.summary_line())
Every slot runs as its own attempt cycle: restore last verified workspace → brief a fresh agent → run → verify → accept or reject. If attempts are exhausted, Veripoint formally rewinds and the session fails honestly rather than shipping poison.
Core concepts
| Term | Meaning |
|---|---|
Session | One long-running job: goal + policy + full event history. |
Slot | A declared unit of work plus the gates it must pass. |
Attempt / Chunk | One try at a slot by the agent; the chunk is what gates judge. |
Checkpoint | A verified-good save: workspace snapshot + accepted chunk facts. |
Quarantine | Normalized failure signatures of rejected approaches; fed to future briefings. |
Briefing | Clean notes compiled from verified history only — what a restarted agent sees. |
Ledger | Append-only, SHA-256 hash-chained event log outside the agent's context. |
The protocol loop
- Restore the workspace to the newest verified checkpoint (or empty room on first slot).
- Brief a fresh attempt from clean notes: verified progress, key data, known-bad approaches, prior failure reasons for this slot.
- Run under a wall-clock budget via a driver.
- Verify with all gates; any exception inside a gate fails closed.
- Accept: snapshot the workspace, commit a checkpoint, move to the next slot.
- Reject: quarantine failure signatures, retry from step 1 with the failure in the briefing.
- Exhausted: formal rewind event; session marked failed. Resume later grants fresh budgets (bounded by restart limits).
Parallel plans (DAG)
Slots can declare dependencies with depends_on=[...]. Independent slots run
concurrently (bounded by Policy.max_concurrency); dependents start only after
every parent is verified.
k.run(goal="migrate billing", driver=drv, slots=[
Slot("map endpoints", key="map", verifiers=[CommandGate("pytest tests/test_mapping.py -q")]),
Slot("migrate charges", key="chg", depends_on=["map"], verifiers=[...]),
Slot("migrate refunds", key="ref", depends_on=["map"], verifiers=[...]),
Slot("cut over", key="cut", depends_on=["chg", "ref"], verifiers=[CommandGate("./smoke.sh")]),
]) # chg and ref execute in parallel
Isolation: every attempt rebuilds its branch's workspace as an overlay of its
dependency checkpoints — rejected branches evaporate, poison cannot cross parallel branches,
and children always see their parents' verified files. A failed slot blocks its transitive
dependents (slot.blocked) while independent branches drain.
Cost accounting & budgets
Every attempt's token usage is recorded — including rejected attempts, because you pay for those too. Cost is estimated from a pricing table (longest-prefix match on model names; unknown models are tracked as explicit unpriced tokens).
k = Veripoint(".veripoint", pricing={"my-model": (3.0, 15.0)}) # USD per 1M tokens (in, out)
k.policy.session_budget_usd = 5.00 # hard caps — exceeded means no further
k.policy.slot_budget_usd = 1.50 # attempts, budget.exceeded event, FAILED session
k.policy.retention_keep_checkpoints = 20 # auto snapshot GC at session end
Inspect spend with veripoint cost SESSION; prune old snapshots anytime with
veripoint gc --keep 20 [--dry-run].
Gates
Gates answer one question mechanically: can this chunk be proven good? They never ask the agent whether it did the work.
| Gate | Checks | Fails closed on |
|---|---|---|
CommandGate(cmd) | Shell command exits 0 in the workspace (pytest, lint, custom scripts) | non-zero exit, timeout, launch error |
PythonGate(fn) | Your callable over the chunk/workspace | any exception |
FilesExistGate(paths) | Files exist, non-empty (configurable min bytes) | missing/empty files |
ContentGate(path,…) | Must-contain / must-not-contain strings, regexes | missing file or violated constraint |
NoPlaceholdersGate(path) | No TODO/FIXME/placeholder slop left behind | any marker found |
JsonSchemaGate(schema,file|chunk) | Strict JSON-schema subset validation (bool≠int!) | unreadable JSON, violations |
ReconcileGate(file,checks) | Named numeric predicates over parsed artifacts — sums, cross-totals, source recomputation | crashing check, mismatch |
AllOfGate / AnyOfGate | Composition | as children dictate |
Shadow mode + promotion analytics
New gate? Set required=False. It records evidence and builds an agreement track-record
without reject authority. Then run veripoint gates: a shadow gate "agrees" when it passed on
accepted chunks and failed on rejected ones — i.e., enforcing it would never have changed a verdict.
Gates with enough decided runs and high agreement are flagged
PROMOTE → set required=True.
Gate packs
Curated chains for common domains — start with the code/SRE pack:
from veripoint.packs import code
Slot("ship the change", verifiers=[
*code.pack(test_command="pytest -q", # suite must pass
python_paths=["src"], # everything must compile
sweep_globs=["**/*.py", "**/*.md"],# no TODO/FIXME slop
runbook_path="RUNBOOK.md", # must contain Rollback
smoke_command="./smoke.sh"),
])
Anti-Goodhart stance
Prefer reconciliation checks that recompute claims independently from sources (e.g., re-derive totals from raw inputs) over checks that trust the agent's own outputs. A claim that can't cite reality is not evidence of work.
Drivers
| Driver | Use for |
|---|---|
SubprocessDriver(cmd) | Any CLI agent: claude -p, codex exec, aider… Runs with cwd = workspace; $VERIPOINT_BRIEF/$VERIPOINT_WORKSPACE env vars point at the briefing. |
HTTPDriver(...) | OpenAI-compatible APIs (OpenAI, OpenRouter, Ollama at localhost:11434/v1, vLLM) and Anthropic. The model must reply with a JSON chunk report (summary, data, files). |
MockDriver(script) | Deterministic tests & demos; script behavior per (slot, attempt). |
| your own callable | Implement propose(req) → ChunkResult; embed Veripoint in any framework loop via k.submit_chunk(). |
All drivers are stateless between attempts. Veripoint owns the memory — that's what makes restarts clean.
CLI reference
veripoint init # create store
veripoint run job.py # execute a job script + print summary
veripoint status # sessions table (status, saves, spend)
veripoint log [session] # hash-chained event timeline
veripoint show SEQ # inspect one event payload
veripoint checkpoints [session] # list verified saves
veripoint diff CP_A CP_B [--json] # time-travel diff: files + facts as-of
veripoint rewind CP_ID [session] # restore workspace to a save (history kept)
veripoint brief [session] # preview the next attempt's clean notes
veripoint gates [session] # per-gate analytics + shadow promotion report
veripoint retry SESSION --job f.py --driver SPEC # resume failed session
veripoint cost [session] # token/cost breakdown per attempt
veripoint gc [--keep N] [--dry-run] # prune snapshot archives + orphan blobs
veripoint doctor # sqlite integrity + hash-chain + blob audit
veripoint report [session] # write markdown audit report
veripoint serve [--port 7644] # local dashboard UI
veripoint mcp --job job.py # MCP server for Claude Code/Cursor/etc.
Rewind & clean notes
Rewind has two halves:
- Workspace restore — every attempt begins from the last verified snapshot, so poisoned files can't leak forward. Manual rewinds work too:
veripoint rewind cp_…. - Clean-notes regeneration — restarted agents never see raw transcripts. They get compiled briefings: verified progress with evidence, key data fields, the KNOWN-BAD list (quarantined approaches with hit counts and reasons), and why previous attempts failed verification.
$ veripoint brief ses_8f21 --objective "retry the cutover"
# Veripoint BRIEFING — billing-migration
GOAL: Migrate billing service to v2 API
...
## VERIFIED PROGRESS
- [step 0] map endpoints — 41 mappings, tests pass | workspace files: 6
## KNOWN-BAD APPROACHES (do NOT repeat)
- command|exit code # != expected # — failed 2x. Reason: [command] pytest …
## YOUR TASK (attempt 3)
retry the cutover
### Why earlier attempts failed verification
- attempt 1: [command] exit code 1 != expected 0 …
Integrations
MCP server — Claude Code, Cursor, any MCP client
# .mcp.json in your project
{ "mcpServers": { "veripoint": {
"command": "veripoint",
"args": ["mcp", "--job", "veripoint_job.py", "--workspace", "."] } } }
The agent gets eight tools (briefing, submit_work, rewind…) and every claim is gate-checked. Gates live in an operator-authored job file — the agent cannot weaken its own acceptance criteria.
Claude Code / Codex / aider (CLI agents)
SubprocessDriver("claude -p --output-format json")
SubprocessDriver("codex exec \"$(cat $VERIPOINT_BRIEF)\"")
Ollama (fully local)
HTTPDriver(base_url="http://localhost:11434/v1", model="qwen3-coder", api_key="ollama")
LangGraph / CrewAI / your own loop
Use embedded mode: create a session, then submit one slot at a time from inside your graph node or crew step. Your framework keeps doing orchestration; Veripoint owns truth.
s = k.new_session("migration", goal="...", driver=my_driver)
out = k.submit_chunk(s.id, slot_idx=0, slot=my_slot, driver=my_driver)
if not out["ok"]: ... # Veripoint already quarantined + logged everything
Benchmark
Deterministic micro-benchmark over five silent-defect scenarios × 5 seeds.
Agents are scripted simulations — it validates protocol mechanics (catch,
recover, correctness), not model quality. Reproduce:
python3 scripts/benchmark.py --seeds 5.
| scenario | baseline ships wrong | Veripoint caught & recovered | Veripoint failed openly |
|---|---|---|---|
| dropped-rows | 5/5 | 5/5 | 0/5 |
| swapped-fields | 5/5 | 5/5 | 0/5 |
| stale-source | 5/5 | 5/5 | 0/5 |
| placeholder-slop | 5/5 | 5/5 | 0/5 |
| transient-crash | 0/5 | 5/5 | 0/5 |
| total | 20/25 | 25/25 | 0/25 |
API surface
| Call | Returns |
|---|---|
Veripoint(root, pricing={...}).run(goal, slots, driver) | RunReport (success, attempts, rejects, rewinds, blocked/parallel slots, spend via store) |
k.run_plan(goal, slots) / await k.arun_plan(...) | Explicit DAG execution; auto-detected by run() when depends_on present |
k.resume(session_id, slots, driver) | Continues from verified checkpoints; grants fresh attempt budget (DAG-aware) |
k.diff(cp_a_id, cp_b_id) | Time-travel delta: files added/removed/modified + facts as-of both slots |
k.submit_chunk(session, idx, slot, driver) | Embedded single-slot execution |
k.brief_for(session_id, objective) | The compiled clean-notes string |
store.verify_chain() / store.gc(keep=N) | Tamper audit / snapshot retention with orphan-blob sweep |
store.cost_summary(sid) / store.gate_stats(sid) | Spend aggregates incl. unpriced tokens / per-gate analytics |
Slot(objective, key=…, depends_on=[…], verifiers=[…]) | Declaration unit; optional max_attempts; DAG edges |