Deterministic AI Verifier — v0.13.0
NoWreck is a deterministic structural verifier for AI-generated code-change claims. When an AI describes a code change, NoWreck compares the claims against structural evidence derived by its own scanners — the verifier never asks another AI for an opinion. Where the evidence comes from depends on the mode: in Pre/Post and Claims modes, from actual before/after repository snapshots; in Prompt Mode, from the model's own proposed diff.
$ nowreck fix "Add email validation to auth.py"
Summary
────────────────────
● 3 claims total
● 2 confirmed
● 1 contradicted
CONFIRMED
─────────
✓ ADD_FUNCTION validate_email → auth.py (conf: 100%)
Evidence: Function 'validate_email' was added in auth.py
CONTRADICTED
────────────
✗ CALLS_FUNCTION validate_email → auth.py (conf: 100%)
Evidence: Function 'validate_email' was added in auth.py
- Hallucinated functions or classes — a claim that something was added when it isn't there
- Fake internal API calls — a claim that a function was called when it wasn't
- Explanation-vs-diff mismatches — a description of a change that doesn't match the actual diff
- Unexplained changes — structural changes that no supplied claim mentioned
NoWreck does not ask: "Is this code good?"
NoWreck asks: "Do the supplied structural claims match the structural changes actually detected in the compared repository states?"
Nothing more, nothing less. NoWreck is deliberately narrow. It is not an AI code reviewer, a test runner, a security scanner, a semantic verifier, or a code-quality judge, and it does not determine whether code is secure, performant, idiomatic, bug-free, or semantically correct.
Claims → structural evidence → deterministic comparison → verdict
The verifier uses no AI judgment. The decision stage never asks an AI whether a claim is true. (NoWreck does use a model in Prompt Mode — to generate the proposed diff and claims — but never in the decision stage.) "Deterministic" describes how NoWreck decides: the scanner and verifier follow explicit structural rules. It is not a promise of perfect analysis — NoWreck is deterministic within its supported structural analysis model (see Limitations).
- What it catches
- Installation
- Configuration
- Quick Start
- Usage Modes
- Command Reference
- How It Works
- Claim Types
- Understanding the Report
- Confidence System
- JSON Output for CI
- Limitations
- Comparison
- Troubleshooting
- Roadmap
- License
Requires Python 3.11+.
# Clone the repository
git clone https://github.com/AstralXVoid/NoWreck.git
cd NoWreck
# Install with pipx (recommended)
pipx install .
# Or with pip
pip install -e .
# Or inside a virtual environment
python3 -m venv .venv
source .venv/bin/activate
pip install -e .pipx install . installs nowreck as a globally available command in your
user environment (PyPI publishing is coming later).
nowreck --version
# → nowreck 0.13.0
nowreck
# → shows banner + usagepipx uninstall nowreck
# or
pip uninstall nowreckNoWreck stores configuration in .nowreck/config.json under the current
working directory.
Before using nowreck fix "<prompt>", configure an API key and model
provider:
# Set your API key (or use the NOWRECK_API_KEY env var instead)
nowreck config set api_key gsk_your_key_here
# Set the API base URL (defaults to https://api.openai.com/v1)
nowreck config set base_url https://api.groq.com/openai/v1
# Set the model (defaults to gpt-4o)
nowreck config set model llama-3.3-70b-versatileSet NOWRECK_API_KEY instead of storing the key in config:
export NOWRECK_API_KEY="gsk_your_key_here"# Temperature (0.0 = deterministic, default)
nowreck config set temperature 0.0
# Max retries on parse failure (default: 1)
nowreck config set max_retries 2
# Explicit provider override (auto-detected from base_url when unset)
nowreck config set provider anthropic # or: gemini, openainowreck config show
# → api_key = gsk_your_key_here
# → base_url = https://api.groq.com/openai/v1
# → model = llama-3.3-70b-versatileHeads-up:
config showprints stored values as-is — including your full API key. Run it only in trusted environments.
| Provider | Base URL | Format |
|---|---|---|
| OpenAI | https://api.openai.com/v1 (default) |
OpenAI-compatible |
| Anthropic | https://api.anthropic.com |
Anthropic Messages API |
| Gemini | https://generativelanguage.googleapis.com |
Gemini generateContent |
| Groq | https://api.groq.com/openai/v1 |
OpenAI-compatible |
| OpenRouter | https://openrouter.ai/api/v1 |
OpenAI-compatible |
| DeepSeek | https://api.deepseek.com/v1 |
OpenAI-compatible |
| Ollama (local) | http://localhost:11434/v1 |
OpenAI-compatible |
| LM Studio (local) | http://localhost:1234/v1 |
OpenAI-compatible |
| Any OpenAI-compatible | Your custom endpoint | OpenAI-compatible |
Since v0.11.0, Anthropic and Gemini are supported natively via provider
adapters. The provider is auto-detected from base_url — set the
matching base URL and NoWreck handles the rest:
# Claude
nowreck config set base_url https://api.anthropic.com
nowreck config set api_key sk-ant-...
nowreck config set model claude-sonnet-4-20250514
# Gemini
nowreck config set base_url https://generativelanguage.googleapis.com
nowreck config set api_key AIza...
nowreck config set model gemini-2.0-flashNote: use the bare domain for Anthropic and Gemini base URLs — do not add a
/v1or/v1betasuffix (NoWreck appends the versioned path itself). If auto-detection ever picks the wrong format, force it withnowreck config set provider anthropic|gemini|openai.
Note for Groq users: Groq currently blocks bare Python
urllibrequests with a Cloudflare 1010 error. NoWreck sends a browser-style User-Agent header to work around this, but if you encounter issues, try OpenRouter or a direct OpenAI API key instead.
Create a small Python project with before and after snapshots:
mkdir -p /tmp/myapp/pre /tmp/myapp/post
# Pre: original code
cat > /tmp/myapp/pre/app.py << 'EOF'
def hello():
return "Hello, World!"
EOF
# Post: add a new function (simulating an AI change)
cat > /tmp/myapp/post/app.py << 'EOF'
def hello():
return "Hello, World!"
def greet(name: str) -> str:
return f"Hello, {name}!"
EOFnowreck fix --pre /tmp/myapp/pre --post /tmp/myapp/postThis is Pre/Post Mode with no claims supplied. NoWreck scans both snapshots, detects the structural changes between them, and reports them as unexplained — because no claims were supplied to match against (NoWreck also prints a few scan-progress lines before the report):
═══════════════════════════════════════════════════════
Nowreck Verification Report
═══════════════════════════════════════════════════════
Summary
────────────────────
● 0 claims total
● 0 confirmed
● 1 unexplained change
UNEXPLAINED CHANGES
───────────────────
! ADD_FUNCTION greet (app.py)
nowreck fix \
--pre /tmp/myapp/pre \
--post /tmp/myapp/post \
--claims '{
"claims": [
{
"type": "ADD_FUNCTION",
"symbol_name": "greet",
"file_path": "app.py",
"confidence": 0.99,
"explanation": "Added the greet function as requested."
},
{
"type": "CALLS_FUNCTION",
"symbol_name": "greet",
"file_path": "app.py",
"caller_name": "greet",
"called_name": "sanitize_input",
"confidence": 0.85,
"explanation": "greet calls sanitize_input before returning."
}
]
}'This is Claims Mode: the claims are supplied externally, and NoWreck
verifies them against the structural changes detected from the two
snapshots. Expected output — the hallucinated CALLS_FUNCTION claim is
caught because the code contains no such call:
═══════════════════════════════════════════════════════
Nowreck Verification Report
═══════════════════════════════════════════════════════
Summary
────────────────────
● 2 claims total
● 1 confirmed
● 1 contradicted
CONFIRMED
─────────
✓ ADD_FUNCTION greet → app.py (conf: 100%)
Evidence: Function 'greet' was added in app.py
CONTRADICTED
────────────
✗ CALLS_FUNCTION greet → app.py (conf: 100%)
Evidence: Function 'greet' was added in app.py
NoWreck has three verification modes. They share the same pipeline and differ in where claims and evidence come from.
Describe a change in natural language. NoWreck calls the configured model and verifies the claims that model produces.
How it works:
- NoWreck sends your prompt to the configured model.
- The model returns a proposed diff plus structured claims describing that diff.
- NoWreck derives the post-change repository state implied by the proposed
diff, scans it against the current state, and produces
DetectedChangefacts. - The deterministic verifier matches each claim against those facts and prints the report.
What Prompt Mode verifies. Since v0.10.0, Prompt Mode uses independent verification: NoWreck captures the repository state before and after the model applies its patch, scans both states independently, and verifies the model's claims against the independently observed changes.
Concretely:
- If the model claims
validate_email()was added but the patch doesn't add it — NoWreck reports CONTRADICTED. - If the model claims a function calls
sanitize_input()but the actual code doesn't — NoWreck reports CONTRADICTED. - If no before/after transition is available — NoWreck reports UNVERIFIABLE (never guesses).
The fundamental invariant: a model claim must never be used as the source of evidence for verifying that same claim.
Requirements: an API key (config or NOWRECK_API_KEY env var) and a
configured model (defaults to gpt-4o).
nowreck fix "Add a validation function to app.py"Two directory snapshots already exist. NoWreck scans both and reports the structural changes between them. No API key or model is required — this mode runs fully offline.
This is the cleanest independent-verification workflow in v0.10.0:
actual before snapshot
+ actual after snapshot
+ external claims (optional, via --claims)
→ deterministic structural verification
The snapshots are real repository states, and any claims — from any AI,
another tool, or a person — can be supplied through --claims. NoWreck
does not generate the claims itself; it only verifies them against the
evidence.
nowreck fix --pre ./repo-before --post ./repo-afterUseful for:
- Manual testing during development
- CI/CD pipelines where you have two checkouts
- Verifying changes without an AI model
Combine Pre/Post Mode with externally supplied claims. NoWreck detects the changes and verifies the claims against them:
nowreck fix \
--pre ./repo-before \
--post ./repo-after \
--claims '{"claims": [{"type": "ADD_FUNCTION", "symbol_name": "greet", "file_path": "app.py"}]}'Because the claims come from outside NoWreck and the evidence comes from real before/after snapshots, Claims Mode — together with Pre/Post Mode — is a genuinely independent verification path. (Since v0.10.0, Prompt Mode is also independent — it captures before/after state automatically.)
Claims must be passed inline via --claims; the CLI does not currently
read claims from stdin. If you keep claims in a file, pass its JSON content
directly as the --claims argument.
nowreck --interactive launches a menu-driven terminal picker for users who
prefer exploring options without memorizing commands:
- Verify with AI prompt — Prompt Mode against the current repository
- Scan two directories for changes — Pre/Post Mode; optionally supply claims afterwards to switch into Claims Mode
- Set up or change your API key — guided configuration
- View last report — re-render the most recent verification report
Great for beginners, one-off verifications, and learning the tool's capabilities.
| Flag | Applies to | Description |
|---|---|---|
--json |
All modes | Output structured JSON instead of coloured text (for CI) |
--no-colour |
All modes | Disable ANSI colour codes |
--verbose |
All modes | Show full deterministic evidence per claim; no-op with --json |
--pre PATH |
Pre/Post, Claims | Path to the pre-change snapshot |
--post PATH |
Pre/Post, Claims | Path to the post-change snapshot |
--claims JSON |
Claims | JSON string of claims to verify |
| Command | Description |
|---|---|
nowreck |
Show help / usage |
nowreck --version |
Show version |
nowreck --interactive |
Launch the interactive terminal picker |
nowreck fix "<prompt>" |
Prompt Mode — describe a change; NoWreck calls the model and verifies its claims |
nowreck fix --pre PATH --post PATH |
Pre/Post Mode — scan two snapshots and detect structural changes |
nowreck fix --pre PATH --post PATH --claims JSON |
Claims Mode — detect changes and verify externally supplied claims |
nowreck fix --json |
Output flag — structured JSON instead of coloured text (works with any nowreck fix mode) |
nowreck fix --no-colour |
Output flag — disable ANSI colours (works with any nowreck fix mode) |
nowreck fix --verbose |
Output flag — full deterministic evidence per claim (works with any nowreck fix mode) |
nowreck config show |
Display current configuration |
nowreck config set <key> <value> |
Set a config value. Keys: api_key, model, base_url, temperature, max_retries, provider |
From the user's perspective, the pipeline is Scan → Detect → Verify.
Architecturally, Scan + Detect form the evidence stage — they parse code
and produce DetectedChange facts — and Verify is the comparison stage,
where the deterministic verifier checks claims against those facts.
claims source repository evidence source
(AI model, or external AI / (actual snapshots, or the
tool / person) model's proposed diff)
│ │
▼ ▼
Claims ──────────────────► Structural scanner
│ │
│ ▼
│ DetectedChange facts (source of truth)
│ │
└───────────────► Deterministic verifier
│
▼
CONFIRMED / CONTRADICTED / UNVERIFIABLE
The two boundaries:
Scanner: source code → structural facts
Verifier: claims + structural facts → verdict
- Claims come from somewhere. In Prompt Mode, the model generates them. In Claims Mode, they are supplied externally. The verifier treats them the same either way.
- The scanner derives structural facts. It parses both states and
produces a
list[DetectedChange]— the single source of truth that the verifier references exclusively. - The verifier compares fields. AST and Tree-sitter parsing happen
upstream, during scanning. The verifier consumes only
DetectedChangerecords and performs deterministic field-based comparison: same type and identity fields → CONFIRMED. Contradicting change → CONTRADICTED. No match → UNVERIFIABLE. - The verifier uses no AI judgment. It never asks an AI whether a claim is correct, and it never re-reads or re-parses the source code itself.
- No guessing. If NoWreck cannot establish a structural fact, it reports
UNVERIFIABLErather than inventing an answer.
Since v0.10.0, all modes use independent verification. Claims and evidence always come from different sources:
Prompt Mode (v0.10.0):
model ──► claims ──────────────────────────────────────────────────────┐
├──► verifier ──► verdict
before state ──┐ │
model patch ───┴──► after state ──► scanner ──► DetectedChange facts ─┘
Pre/Post + Claims:
external AI / tool ──► claims ──┐
├──► deterministic verifier ──► verdict
before snapshot ──┐ │
after snapshot ───┴──► scanner ─┴──► DetectedChange facts
The fundamental invariant: a model claim must never be used as the source of evidence for verifying that same claim.
Recursively discovers source files and parses each with the appropriate parser, building a symbol index of every function, class, and method:
| Language | Files | Parser |
|---|---|---|
| Python | .py |
Built-in ast module |
| JavaScript | .js |
Tree-sitter (tree-sitter-javascript) |
| TypeScript | .ts, .tsx |
Tree-sitter (tree-sitter-typescript) |
| Rust | .rs |
Tree-sitter (tree-sitter-rust) |
| Go | .go |
Tree-sitter (tree-sitter-go) |
All parsers produce the same Symbol / SymbolType data shapes, so the
rest of the pipeline never knows (or cares) which language produced the
data. This is structural parsing, not semantic analysis.
Compares the pre and post symbol indices to find structural changes:
added/removed functions, classes, files, and new function calls. This
produces the single source of truth — a list[DetectedChange] that the
verifier references exclusively.
For each claim, the verifier looks for a matching DetectedChange. If one
exists with the same type and identity fields → CONFIRMED. If a
contradicting change exists (e.g., claim says "added" but detection shows
"removed") → CONTRADICTED. If nothing matches → UNVERIFIABLE.
| Claim type | What it means | Verified by |
|---|---|---|
ADD_FUNCTION |
A function was added | Structural existence check |
REMOVE_FUNCTION |
A function was removed | Structural existence check |
ADD_CLASS |
A class was added | Structural existence check |
REMOVE_CLASS |
A class was removed | Structural existence check |
ADD_INTERFACE |
An interface was added (TS/TSX, Rust, Go) | Structural existence check |
REMOVE_INTERFACE |
An interface was removed (TS/TSX, Rust, Go) | Structural existence check |
ADD_ENUM |
An enum was added (TS/TSX, Rust) | Structural existence check |
REMOVE_ENUM |
An enum was removed (TS/TSX, Rust) | Structural existence check |
ADD_TYPE_ALIAS |
A type alias was added (TS/TSX, Rust, Go) | Structural existence check |
REMOVE_TYPE_ALIAS |
A type alias was removed (TS/TSX, Rust, Go) | Structural existence check |
FILE_CREATED |
A new file appeared | File-list diff |
FILE_DELETED |
A file was removed | File-list diff |
CALLS_FUNCTION |
A function now calls another | Structural call-site detection |
All thirteen are evaluated using deterministic structural evidence. Note
that the mechanisms differ: CALLS_FUNCTION uses call-site analysis, while
the existence-based claim types use symbol-existence comparison.
Every claim accepts:
type— one of the claim types above (required)symbol_name— the symbol the claim is aboutfile_path— path to the file, relative to the scanned rootconfidence— 0.0 to 1.0, how certain the claimer isexplanation— why the change was madeparent_class— required when the symbol is a method inside a classline_number— optional 1-based line number
CALLS_FUNCTION additionally requires caller_name (the function that
makes the call) and called_name (the function being called).
═══════════════════════════════════════════════════════
Nowreck Verification Report
═══════════════════════════════════════════════════════
Summary
────────────────────
● 3 claims total
● 2 confirmed
● 1 contradicted
● 1 unexplained change
CONFIRMED
─────────
✓ ADD_FUNCTION validate_email → auth.py (conf: 100%)
Evidence: Function 'validate_email' was added in auth.py
✓ FILE_CREATED → validators.py (conf: 100%)
Evidence: File 'validators.py' was created
CONTRADICTED
────────────
✗ CALLS_FUNCTION validate_email → auth.py (conf: 100%)
Evidence: Function 'validate_email' was added in auth.py
UNEXPLAINED CHANGES
───────────────────
! REMOVE_FUNCTION legacy_func (app.py)
| Section | Meaning |
|---|---|
| Summary | Counts of total claims, confirmed, contradicted, unverifiable, and unexplained |
| CONFIRMED | Claims that matched a detected structural change |
| CONTRADICTED | Claims that contradict the structural evidence (e.g., a claimed call doesn't exist) |
| UNVERIFIABLE | Claims with no matching detected change one way or the other |
| UNEXPLAINED CHANGES | Structural changes detected from the compared repository states that no supplied claim matched. NoWreck does not infer intent — it cannot tell you whether a change was necessary, correct, or malicious, only that it exists and was not explained |
| Exit code | Meaning |
|---|---|
0 |
Every claim confirmed (none contradicted or unverifiable), nothing unexplained |
1 |
One or more contradicted, unverifiable, or unexplained changes |
Confidence reflects NoWreck's certainty in its verification result, within its supported structural analysis model. It is not confidence that the code change is correct, and it is not a rating of the claim's quality.
| Verdict | Displayed confidence | Meaning |
|---|---|---|
| CONFIRMED | 100% |
The verifier deterministically established that the required structural condition for the claim exists within its supported analysis model |
| CONTRADICTED | 100% |
The verifier deterministically established the structural condition required for that verdict — e.g., the detected change is the opposite of the claim, or the claimed supported structural fact is absent from the analyzed state |
| UNVERIFIABLE | The claimer's original confidence | NoWreck could not establish the claim from its supported structural evidence; it reports the claim's own confidence rather than inventing a number |
A 100% verdict applies to the specific claim being checked, within the
supported analysis model — it does not mean the overall code change is
correct, and it does not prove universal semantic facts. For example,
a CONTRADICTED CALLS_FUNCTION verdict establishes that no matching
call-site change exists among the detected structural facts; it does not
prove the function can never be invoked dynamically elsewhere.
Use the --json flag to get a machine-readable report. The schema depends
on the mode:
nowreck fix "Add validation to auth.py" --json{
"version": "0.13.0",
"mode": "prompt_v10",
"success": false,
"evidence": {
"independent": true,
"patch_applied": true,
"patch_files": ["auth.py"]
},
"summary": {
"total_claims": 3,
"confirmed": 2,
"contradicted": 1,
"unverifiable": 0,
"unexplained_count": 0
},
"results": [
{
"claim": {
"type": "ADD_FUNCTION",
"symbol_name": "validate_email",
"file_path": "auth.py",
"parent_class": null,
"line_number": null,
"caller_name": null,
"called_name": null,
"confidence": 0.99
},
"verdict": "CONFIRMED",
"verifier_confidence": 1.0,
"matched_change": {
"change_type": "ADD_FUNCTION",
"file_path": "auth.py",
"symbol_name": "validate_email",
"parent_class": null,
"line_number": 5,
"caller_name": null,
"called_name": null
}
}
],
"unexplained_changes": []
}The evidence block reports whether the v10 independent-verification path
ran: claims were checked against changes observed in the repository before
and after the model's patch was applied (see
How It Works).
--pre/--post runs omit the mode and evidence fields; everything
else is identical:
{
"version": "0.13.0",
"success": false,
"summary": { "total_claims": 3, "confirmed": 2, "contradicted": 1, "unverifiable": 0, "unexplained_count": 0 },
"results": [ { "claim": {}, "verdict": "CONFIRMED", "verifier_confidence": 1.0, "matched_change": {} } ],
"unexplained_changes": []
}Notes:
successistrueonly when every claim is confirmed (none contradicted or unverifiable) and there are no unexplained changes; otherwise it isfalse. It is a JSON boolean (true/false), not a string.- Claim objects contain exactly:
type,symbol_name,file_path,parent_class,line_number,caller_name,called_name,confidence. The free-textexplanationis not included in JSON output — it is accepted on input and kept on the claim, but NoWreck's reports do not render it.
The simplest and most robust integration is to rely on NoWreck's exit code:
# GitHub Actions — fail the job when verification fails.
# Exit code 0 → all claims confirmed, nothing unexplained.
# Exit code 1 → contradicted, unverifiable, or unexplained changes.
- name: Verify AI changes
run: nowreck fix "Add validation to auth.py" --jsonIf you prefer to parse the JSON instead:
REPORT=$(nowreck fix "Add validation to auth.py" --json)
echo "$REPORT" | python3 -c "import sys, json; d = json.load(sys.stdin); print('success:', d['success'])"
# 'success' is a JSON boolean — compare with True/False, not the string "True".NoWreck verifies structure, not semantics. Be aware of these boundaries:
- Supported languages — Python (
.py), JavaScript (.js), TypeScript (.ts,.tsx), Rust (.rs), and Go (.go). Python uses the built-inastmodule; JavaScript, TypeScript, Rust, and Go use Tree-sitter with their respective grammars. - Dynamic behavior cannot be reliably resolved —
exec(),eval(), dynamic imports,getattr()/setattr()with dynamic arguments, metaclasses, monkey-patching, and reflection fall outside the scanner's supported structural analysis and may be reported asUNVERIFIABLE. CALLS_FUNCTIONchecks direct identifier calls only — it verifies calls of the formsanitize_input(). It does not resolveobj.sanitize_input()or chained expressions, and it does not perform full semantic call-graph resolution.- No cross-file resolution beyond direct name matching.
- No semantic analysis — NoWreck verifies structural facts, not intent, code quality, or correctness.
- Prompt Mode requires a working repository — it runs against the current working directory; without a real repository all claims come back UNVERIFIABLE.
- Interfaces, enums, and type aliases (TS/TSX, Rust, Go) are captured as structural symbols and verified for existence only (added/removed) — not for semantic correctness.
- The verifier works from
DetectedChangefacts, not by re-reading the repository. It is deterministic within its supported analysis model, not infallible.
| Tool | What it does | Relationship to NoWreck |
|---|---|---|
| Cursor / Claude Code / Copilot | Generate and edit code | Complementary — NoWreck verifies claims about changes rather than generating them |
| CodeRabbit / Qodo / Greptile | AI review of a diff's quality | Different focus — AI-assisted review rather than deterministic claim verification |
| Agent Verifier (aurite-ai) | AI agent skill for code quality/security | Different focus — checks quality/security, not claim truthfulness |
| slopcheck / slop-scan | Check third-party package names against registries | Different focus — dependency-name checks, a different hallucination category |
| ESLint / Ruff / Black | Linting and formatting | Different focus — syntax/style enforcement, not structural verification |
NoWreck is designed specifically for deterministic structural verification of claims about code changes.
Configure your API key:
# Option A: store in config
nowreck config set api_key your_key_here
# Option B: set environment variable
export NOWRECK_API_KEY="your_key_here"Your API key is invalid or expired. Check the key and provider URL:
nowreck config show
# Verify api_key and base_url are correctThis happens with some providers (notably Groq) when Python's urllib
doesn't send a realistic User-Agent. Try:
- Upgrade NoWreck (the built-in fix sends a browser UA)
- Switch to OpenRouter or another provider
- Use a direct OpenAI API key
If the model returns malformed JSON, NoWreck automatically retries once by
sending the error details back to the model with a repair request. Failed
responses are saved to .nowreck/failed/ for debugging.
Make sure:
- Both
--preand--postpaths exist and are directories - The directories contain supported files (
.py,.js,.ts,.tsx,.rs, or.go) - The Tree-sitter packages are installed for the languages you scan
(
tree-sitter-javascript,tree-sitter-typescript,tree-sitter-rust,tree-sitter-go) - Files inside hidden directories (names starting with
.) are skipped
NoWreck supports CI/CD pipelines with machine-readable output formats and automated git comparison.
# JSON (for scripting)
nowreck fix --compare HEAD~1 --format json > report.json
# SARIF (for GitHub Code Scanning)
nowreck fix --compare HEAD~1 --format sarif > nowreck.sarif
# JUnit XML (for Jenkins/GitLab CI test reports)
nowreck fix --compare HEAD~1 --format junit > nowreck-junit.xml# Compare current state against previous commit
nowreck fix --compare HEAD~1
# Compare against a specific branch
nowreck fix --compare main
# Verify claims against a PR
nowreck fix --compare main --claims '{...}'name: NoWreck Verification
on: [pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install nowreck
- name: Run NoWreck verification
run: nowreck fix --compare HEAD~1 --format sarif > nowreck.sarif
- name: Upload SARIF to GitHub Code Scanning
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: nowreck.sarifv0.13.0 is the current release. Items marked 🗓 are planned future work, not present in the current release.
| Item | Status |
|---|---|
| Interactive terminal picker | ✅ v0.2.0 |
| JavaScript support (Tree-sitter scanner + symbol index) | ✅ v0.3.0 |
| JavaScript polish (generators, export default, IIFEs) | ✅ v0.4.0 |
| TypeScript support (Tree-sitter scanner + symbol index + full pipeline) | ✅ v0.5.0 |
--verbose mode showing full deterministic evidence per claim |
✅ v0.6.0 |
TSX (.tsx files) support |
✅ v0.7.0 |
| Interfaces / enums / type aliases as claim types | ✅ v0.8.0 |
| Rust + Go language support | ✅ v0.9.0 |
| Independent verification architecture — make independent verification native and convenient: claims can come from any external AI/tool while NoWreck inspects the actual resulting repository state (Pre/Post + Claims already provides independent verification in v0.10.0) | ✅ done in v0.10.0 |
Additional model providers (Anthropic, Gemini) via provider adapters with auto-detection from base_url |
✅ v0.11.0 |
Provider consolidation — single resolve_provider() replaces split _auth_header() + detect_adapter() |
✅ v0.12.0 |
Scan caching — file-level cache in .nowreck/cache/ for faster repeated runs |
✅ v0.12.0 |
| CI/CD integration (SARIF, JUnit, --compare) | ✅ v0.13.0 |
FSL-1.1-MIT (Functional Source License, Version 1.1, MIT Future License)
Source is fully visible — read it, learn from it, use it internally, run it, modify it for your own use. The one restriction: it can't be used to build a competing commercial product or service while this version is under FSL.
Full terms are in LICENSE.
This version converts automatically to the plain MIT license in July 2028 (two years after initial release, per FSL's standard terms). No action is required for the conversion.
NoWreck v0.13.0 — August 2026
