{
  "markdown": "<p align=\"center\">\n  <img src=\"assets/logo.png\" alt=\"Veris\" width=\"130\" />\n</p>\n\n<h1 align=\"center\">Veris</h1>\n\n<p align=\"center\">\n  <em>veris</em> — Latin, <em>“of truth”</em>\n</p>\n\n<p align=\"center\">\n  <strong>Your agent just changed 40 files.<br/>What actually broke, and was any of it checked?</strong>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/vighriday/Veris/actions/workflows/veris.yml\"><img src=\"https://github.com/vighriday/Veris/actions/workflows/veris.yml/badge.svg\" alt=\"CI\"></a>\n  <a href=\"https://www.npmjs.com/package/veris-core\"><img src=\"https://img.shields.io/npm/v/veris-core?color=cb3837&logo=npm&logoColor=white\" alt=\"npm\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT\"></a>\n  <a href=\"docs/MCP_TOOLS.md\"><img src=\"https://img.shields.io/badge/MCP-17_tools-8b5cf6\" alt=\"MCP: 17 tools\"></a>\n  <a href=\"#privacy\"><img src=\"https://img.shields.io/badge/telemetry-none-success\" alt=\"No telemetry\"></a>\n  <a href=\"docs/internal/BUG_TRACKER.md\"><img src=\"https://img.shields.io/badge/self--audit-55_defects_published-orange\" alt=\"Self-audit: 55 defects published\"></a>\n</p>\n\n---\n\n## We pointed Veris at Veris — it found 55 defects\n\nEvery one is published — what broke, why it mattered, the fix, and the test that\nproves it: **[docs/internal/BUG_TRACKER.md](docs/internal/BUG_TRACKER.md)**\n\nThe worst three, in our own tool:\n\n**It invented baselines.**\nWhen git was unavailable, Veris built a \"before\" state from the first 70% of the\ncurrent graph and reported the comparison as a real behavioral diff. No flag. No\nwarning. A verification tool was fabricating the thing it verified against.\n\n**91% of its call edges were guesses.**\nIt matched the trailing name of a call against every declaration sharing that name.\n`console.log()` drew an edge to the project's own `Logger.log`. Measured on a real\ndependency: 2,804 of 3,077 edges pointed at an ambiguous name.\n\n**The graded agent could erase its own failures.**\nExecution results were stored with `INSERT OR REPLACE`. Post `fail`, then post\n`pass`, and the failure was gone.\n\nWe could have fixed these quietly. Publishing them is the point: a tool that tells\nyou what is unverified has no standing to hide its own unverified claims.\n\n**This is also the demo.** That is the analysis Veris performs, run on itself.\n\n---\n\n## What Veris is\n\nA **behavioral diff for AI-written code**, speaking the Model Context Protocol so\nyour agent can ask *while it is still working* — not after you find out in review.\n\nIt answers two questions a line diff cannot:\n\n1. **What behavior changed?** Not which lines — which behaviors, and what reaches them.\n2. **Was any of it actually checked?** Published research puts roughly **65% of\n   agent-authored PRs at zero coverage of their own changed lines**.\n\n**Veris never executes anything.** No tests, no sandboxes, no runtime. It reads,\nmodels, and tells your agent what is at risk and what evidence exists. Running things\nstays with the tools that are good at running things.\n\n<table>\n<tr><th align=\"left\">Veris is not</th><th align=\"left\">Because</th></tr>\n<tr><td>A test runner</td><td>It executes nothing. It tells your runner what is worth running.</td></tr>\n<tr><td>A linter or SAST tool</td><td>No rules about style or known-bad patterns. It models behavior change.</td></tr>\n<tr><td>An \"AI guardrail\"</td><td>That means filtering model output. This is about the code the model writes.</td></tr>\n<tr><td>A coverage tool</td><td>Coverage says which lines ran. Veris says which behaviors changed and what backs them.</td></tr>\n</table>\n\n---\n\n## The 30-second version\n\n```console\n$ npx veris-core . --base-ref=origin/main\n\n-> Baseline: origin/main @ 1bebd2ce2e08 -> head 3ed9031421-dirty\n   Working tree has 4 uncommitted changes; this run is not reproducible from commits alone.\n-> Graph: 326 nodes, 602 edges (head), 131 tracked files\n-> Call resolution: 403 resolved (97.1%), 6 single-candidate, 6 ambiguous (no edge emitted)\n-> Workflows: 15 detected, 3 affected in diff\n-> Adversarial probes generated: 4\n```\n\n**Read lines 2 and 4 again — they are the whole philosophy.**\n\nSix calls were too ambiguous to resolve, so Veris drew **no edge** rather than\nguessing. The head is marked `-dirty` because uncommitted changes were included, so\nthe result is **not reproducible from commits alone**.\n\nMost tools report only what they found. Veris also reports what it could not\ndetermine, because a confident wrong answer is worse than an admitted gap.\n\n---\n\n## Install\n\n**As an MCP server** — one config block, then restart your client:\n\n```json\n{\n  \"mcpServers\": {\n    \"veris\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"veris-core\", \"mcp\"]\n    }\n  }\n}\n```\n\n17 tools light up in Claude Code, Cursor, or any MCP-compatible agent.\n\n**As a CLI:**\n\n```bash\nnpx veris-core .                            # analyze against origin/main\nnpx veris-core . --base-ref=HEAD~1          # explicit baseline\nnpx veris-core . --budget=10 --onboarding   # 10-min plan + onboarding map\nnpx veris-core doctor                       # check git, base ref, deps\n```\n\n> **Needs a git repository with real history.** Veris diffs against the merge-base\n> with your base ref. If it cannot establish one, it **fails and says why** rather\n> than inventing a baseline. In CI: `fetch-depth: 0`.\n\n> **On npm 12, run history needs one extra line.** npm 12 no longer runs dependency\n> install scripts by default, so `better-sqlite3` never fetches its prebuilt binding.\n> Veris still analyzes, diffs, scores risk and plans verification — only run history\n> and cross-run drift need it. The allowlist is per-project and is *not* inherited\n> from a dependency, so it has to go in **your** `package.json`:\n>\n> ```json\n> { \"allowScripts\": { \"better-sqlite3\": true } }\n> ```\n>\n> Then `npm rebuild better-sqlite3`. `veris-core doctor` reports which mode you are in,\n> and never claims persistence is working when it is not.\n\n---\n\n## How it thinks\n\n```mermaid\nflowchart TD\n    A[git-tracked source] -->|ts-morph + TypeScript checker| B[Behavioral graph]\n    B -->|worktree at merge-base| C{Baseline exists?}\n    C -->|no| X[Fail loudly<br/>never fabricate]\n    C -->|yes| D[Diff: added / removed<br/>rewritten-body / edges]\n    D --> E[Risk · Workflows · Fingerprints · Drift]\n    E --> F[Probes · Tiered plan · Budget]\n    F --> G[Coverage from<br/>trust-weighted evidence]\n    G --> H[17 MCP tools · Dashboard · Reports]\n    H -->|agent or CI executes| I[report_execution]\n    I -->|append-only, hash-chained| G\n\n    style X fill:#ff5d6c,stroke:#c1121f,color:#fff\n    style G fill:#8b5cf6,stroke:#6d28d9,color:#fff\n    style B fill:#0ea5e9,stroke:#0369a1,color:#fff\n```\n\nThe red box is a feature. So is the loop back into coverage.\n\n---\n\n## Three ideas that make it different\n\n### 1. Every edge declares how certain it is\n\nMost graph tools give you an edge. Veris tells you **why** it believes the edge:\n\n| `resolution` | Meaning |\n|---|---|\n| `resolved` | The TypeScript checker identified the declaration. Trustworthy. |\n| `heuristic` | Checker couldn't, but exactly one declaration bears that name. |\n| `structural` | Containment or an import relationship. |\n| *(no edge)* | Several candidates and nothing distinguishes them. **Silence, not a guess.** |\n\nAnything that must not reason on a guess — a gate, a policy rule — filters for\n`resolved`. Missing edges understate coupling. They never invent it.\n\n### 2. Evidence is append-only, and knows who said it\n\nThe agent posting results is usually the agent being judged. So:\n\n```jsonc\n{ \"nodeId\": \"src/pay.ts::charge\",\n  \"result\": \"pass\",\n  \"trustClass\": \"harness-observed\",   // ← default is \"agent-asserted\"\n  \"producer\": \"github-actions:e2e\" }\n```\n\n| Trust class | Who | Weight |\n|---|---|---|\n| `veris-derived` | Veris computed it | full |\n| `harness-observed` | An external runner saw it | full |\n| `agent-asserted` | The agent says so — **the default** | **half** |\n\nRecords are hash-chained. A later pass never overwrites an earlier failure; editing\nthe database directly breaks the chain and `verifyEvidenceChain()` reports exactly\nwhere. **An agent cannot raise its own assurance by asserting harder.**\n\n### 3. It catches the rewrite that keeps its name\n\n```diff\n- function chargeCard(amount) { return gateway.charge(amount); }\n+ function chargeCard(amount) { return gateway.charge(amount * 100); }\n```\n\nSame name. Same callees. Same graph shape. Every name-and-topology comparison sees\nnothing. Veris hashes the **normalized body**, so this surfaces as a `modifiedNode` —\nwhile renaming a directory, which used to look like 100% drift, now correctly looks\nlike nothing at all.\n\n---\n\n## What your agent asks\n\n```text\nveris: analyze_pr_behavior with baseRef=origin/main\nveris: list_workflows, then analyze_workflow for the highest-risk one\nveris: generate_adversarial_probes, then allocate_budget minutes=15\nveris: detect_drift\nveris: what_if_revert nodeIds=[...]\n```\n\nProbes are concrete, not nudges:\n\n> **Payments / idempotency** — Submit a charge twice with the same idempotency key\n> inside a 500 ms window.\n> **Invariant:** exactly one ledger entry; the second call returns the first result.\n>\n> ---\n>\n> **Webhooks / replay** — Replay a 24-hour-old signed payload with its original\n> signature.\n> **Invariant:** rejected by timestamp window even though the signature is valid.\n\n---\n\n## Everything else it does\n\n| | |\n|---|---|\n| **Semantic workflows** | 25 domains — Authentication, Payments, Checkout, Webhooks, Queue, Caching… So the unit is \"checkout reliability\", not `GraphModels.ts`. |\n| **Risk model** | Coupling magnitude, inbound-coupling dominance, runtime criticality — three inputs measuring different things. Every weight in `data/risk-config.json`, plain-English reasons attached. |\n| **Drift detection** | Fingerprints across runs. Catches silent rewrites, surface changes, oscillating refactors, and deletions. |\n| **Budget allocation** | Given N minutes, the highest-leverage subset to actually run. |\n| **Counterfactual** | `what_if_revert` — what recovers if this comes out? |\n| **Onboarding export** | Workflow-first markdown for a new engineer, or a new agent, on an unfamiliar codebase. |\n| **Dashboard** | Standalone HTML. Click a workflow, everything filters. Click-to-copy directives. |\n\n---\n\n## Honest limits\n\nStated plainly, so nobody discovers them the hard way.\n\n- **A workflow is a label, not a path.** Classification is a weighted keyword vote over\n  directory names, imports and symbol names. It does not traverse the call graph.\n  Rate-limiting code that imports Redis lands in Caching. *Making workflows real paths\n  is the top roadmap item.*\n- **Coverage is not assurance.** It measures how much planned verification has evidence\n  behind it. It is **not calibrated against real incidents** and does not estimate the\n  probability your code is correct.\n- **Risk is a heuristic.** Good for ranking what to look at first. Not a defect\n  predictor. No ground truth behind it.\n- **Probes are a curated library** — real failure modes, written by hand, selected by\n  domain. Not generated from your code.\n- **TypeScript and JavaScript only.** Python and Go are on the roadmap.\n- **Some calls can't be resolved.** Dynamic dispatch and untyped JS defeat the checker.\n  Those produce no edge, and the count is in the output.\n\n> **Upgrading from 2.x?** 3.0 has real breaking changes — see [UPGRADING.md](UPGRADING.md).\n\n---\n\n## Privacy & security\n\n- **Local-first.** All analysis runs on your machine. **No telemetry, ever.** Nothing\n  about your code leaves the machine.\n- **Zero-retention mode** — `VERIS_STATE_DISABLED=1`.\n- **No network sockets in the analyzer.** stdio and the filesystem only.\n\nVeris is usually pointed at repositories you did *not* write, so repository content is\nuntrusted input. **Plugins execute code from the analyzed repo, so they are off by\ndefault** — `--allow-plugins` opts in, and each plugin's path and SHA-256 is printed\nbefore it runs. There is no sandbox, and [SECURITY.md](SECURITY.md) says so plainly\ninstead of implying otherwise.\n\n---\n\n## Docs\n\n| | |\n|---|---|\n| [MCP tools](docs/MCP_TOOLS.md) | All 17 tools with recommended flows |\n| [Architecture](ARCHITECTURE.md) | Design invariants and the defect each replaced |\n| [Audit tracker](docs/internal/BUG_TRACKER.md) | All 55 findings, with evidence |\n| [Upgrading](UPGRADING.md) | 2.x → 3.0 |\n| [Security](SECURITY.md) | Threat model and reporting |\n| [Roadmap](ROADMAP.md) | What is next — and what will never be built |\n| [Plugins](docs/PLUGINS.md) | Extending classification and risk |\n\n---\n\n## Contributing\n\nThe five things that move the needle most:\n\n1. **Entry-point detection** for a framework you know — routes, handlers, queue\n   consumers. This is what turns a workflow from a label into a path.\n2. **Labelled repositories** for a classification benchmark. The accuracy claim needs\n   ground truth, not more rules.\n3. **Probe provenance.** The shipped probes are good and uncited; one backed by a\n   public postmortem is worth ten that aren't.\n4. **Language adapters** — Python, Go.\n5. **Calibration data** — what Veris flagged that broke, and what it missed. *The\n   second is more valuable.*\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). Open source, sponsor-supported. No paid tier,\nno gated features, no open-core bait.\n\n<p align=\"center\"><sub>MIT — see <a href=\"LICENSE\">LICENSE</a></sub></p>\n",
  "bytes": 13409,
  "sha": "2f88f9536a86b4871f935e24f8e6b4a148b3ad83a5b8eafb9ec5d2ae968dc9a6",
  "repo_slug": "vighriday/veris",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_vighriday_veris_cd5b687f/readme"
}