$ 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
What it catches
- 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).
Table of Contents
- 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
Installation
Requires Python 3.11+.
# From PyPI (recommended)
pipx install nowreck
# or: pip install nowreck
# From source (development)
git clone https://github.com/AstralXVoid/NoWreck.git
cd NoWreck
pip install -e .
Verify installation
nowreck --version
# → nowreck 0.15.0
nowreck
# → shows banner + usage
Uninstall
pipx uninstall nowreck
# or
pip uninstall nowreck
Configuration
NoWreck stores configuration in .nowreck/config.json under the current
working directory.
Required settings for Prompt Mode
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-versatile
Alternative: environment variable
Set NOWRECK_API_KEY instead of storing the key in config:
export NOWRECK_API_KEY="gsk_your_key_here"
Optional settings
# 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, openai
View configuration
nowreck config show
# → api_key = gsk_your_key_here
# → base_url = https://api.groq.com/openai/v1
# → model = llama-3.3-70b-versatile
Heads-up:
config showprints stored values as-is — including your full API key. Run it only in trusted environments.
Compatible providers
| 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-flash
Note: 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.
Quick Start
Step 1 — Pick a test repo
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}!"
EOF
Step 2 — Pre/Post Mode: run detection (no claims)
nowreck fix --pre /tmp/myapp/pre --post /tmp/myapp/post
This 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)
Step 3 — Claims Mode: run with claims
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
Usage Modes
NoWreck has three verification modes. They share the same pipeline and differ in where claims and evidence come from.
Prompt Mode
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"
Pre/Post Mode
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-after
Useful for:
- Manual testing during development
- CI/CD pipelines where you have two checkouts
- Verifying changes without an AI model
Claims Mode
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 can be passed inline via --claims, or read from a file using the
@ prefix — useful for large claim sets and CI pipelines that generate
claims files:
# Read claims from a file (@ prefix)
nowreck fix --pre ./repo-before --post ./repo-after --claims @claims.json
Interactive Mode
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.
Flags
| 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 Reference
| 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 |
How It Works
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.
Independence in v0.10.0
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.
Stage 1 — Scan
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.
Stage 2 — Detect
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.
Stage 3 — Verify
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 Types
| 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.
Claim fields
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).
Understanding the Report
Sample output
═══════════════════════════════════════════════════════
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)
Sections explained
| 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 codes
| Exit code | Meaning |
|---|---|
0 |
Every claim confirmed (none contradicted or unverifiable), nothing unexplained |
1 |
One or more contradicted, unverifiable, or unexplained changes |
Confidence System
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.
JSON Output for CI
Use the --json flag to get a machine-readable report. The schema depends
on the mode:
Prompt Mode schema
nowreck fix "Add validation to auth.py" --json
{
"version": "0.15.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 and Claims Mode schema
--pre/--post runs omit the mode and evidence fields; everything
else is identical:
{
"version": "0.15.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.
CI integration
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" --json
If 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".
Limitations
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.
Comparison
| 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.
Troubleshooting
"Error: No API key provided"
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"
"API returned 401"
Your API key is invalid or expired. Check the key and provider URL:
nowreck config show
# Verify api_key and base_url are correct
"API returned 1010" (Cloudflare block)
This 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
JSON parsing errors
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.
No changes detected
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
CI/CD Integration
NoWreck supports CI/CD pipelines with machine-readable output formats and automated git comparison.
Output Formats
# 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
Git Comparison
# 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 '{...}'
GitHub Actions Example
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.sarif
Roadmap
v0.15.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 |
--claims @file.json — read claims from a file instead of inline JSON only |
✅ v0.14.0 |
PyPI publishing — pip install nowreck |
✅ v0.15.0 |
License
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.15.0 — September 2026
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nowreck-0.15.0.tar.gz.
File metadata
- Download URL: nowreck-0.15.0.tar.gz
- Upload date:
- Size: 179.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca32af45fb6c21808bfc361258e5796ac07504b4619de7c866ade0780e08ae84
|
|
| MD5 |
f9ec4989d081f011e65b6e7094c2b27b
|
|
| BLAKE2b-256 |
9f2db5084aa746a3b463fa00a202462f0a86e2f8ad1e9de94ca4fe9732539dc6
|
Provenance
The following attestation bundles were made for nowreck-0.15.0.tar.gz:
Publisher:
publish.yml on AstralXVoid/NoWreck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nowreck-0.15.0.tar.gz -
Subject digest:
ca32af45fb6c21808bfc361258e5796ac07504b4619de7c866ade0780e08ae84 - Sigstore transparency entry: 2702565206
- Sigstore integration time:
-
Permalink:
AstralXVoid/NoWreck@8bb43c08cc2351ccb70fddcaf68b3ffef1bcc7aa -
Branch / Tag:
refs/tags/v0.15.0 - Owner: https://github.com/AstralXVoid
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8bb43c08cc2351ccb70fddcaf68b3ffef1bcc7aa -
Trigger Event:
push
-
Statement type:
File details
Details for the file nowreck-0.15.0-py3-none-any.whl.
File metadata
- Download URL: nowreck-0.15.0-py3-none-any.whl
- Upload date:
- Size: 98.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b33642766ff087b5991ff056a41e7f195512d537fbd993a23a33e34bf78f846
|
|
| MD5 |
626c684adff0c91f5e6650677cf5edd2
|
|
| BLAKE2b-256 |
bf9290da75d82ac562ba51c055bc88c6c95c76669ed78ee0ec477746837a15c3
|
Provenance
The following attestation bundles were made for nowreck-0.15.0-py3-none-any.whl:
Publisher:
publish.yml on AstralXVoid/NoWreck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nowreck-0.15.0-py3-none-any.whl -
Subject digest:
6b33642766ff087b5991ff056a41e7f195512d537fbd993a23a33e34bf78f846 - Sigstore transparency entry: 2702565227
- Sigstore integration time:
-
Permalink:
AstralXVoid/NoWreck@8bb43c08cc2351ccb70fddcaf68b3ffef1bcc7aa -
Branch / Tag:
refs/tags/v0.15.0 - Owner: https://github.com/AstralXVoid
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8bb43c08cc2351ccb70fddcaf68b3ffef1bcc7aa -
Trigger Event:
push
-
Statement type: