verify.sh — The Missing Feedback Loop for AI IDEs
Published September 4, 2026
Every AI IDE — Cursor, Claude Code, Copilot, Windsurf, Aider — has the same failure mode. You ask it to add a feature. It writes code. It says “done, I’ve added deleteUser to the users service.” You go to use it. TypeScript screams. Import missing. Wrong parameter type. Test file broken.
Then you paste the error back. It fixes one thing, breaks another. You iterate 4-5 rounds until the code actually works.
The problem is not the model. It’s the missing feedback loop. The model has no way to know its code doesn’t compile. It just trusts its own output.
The fix (two parts)
Part 1: verify.sh at the project root
#!/usr/bin/env bash
set +e
pnpm typecheck && pnpm lint && pnpm test --run
Swap the commands for your stack:
- Rust:
cargo fmt --check && cargo clippy -- -D warnings && cargo check && cargo test - Python:
ruff check . && mypy . && pytest -x -q - Go:
go vet ./... && golangci-lint run && go test ./...
That’s it. A single command that runs your project’s actual checks and returns exit code 0 (green) or non-zero (something’s broken).
Part 2: One rule in .cursorrules / CLAUDE.md
## Verification protocol (closed-loop feedback)
- After ANY code change, run `./verify.sh` from the project root.
- If exit code is non-zero, read the output top to bottom.
- Fix the FIRST error only — do not attempt to fix everything at once.
- Re-run `./verify.sh`.
- Repeat until exit code is 0.
- Do NOT declare the task complete until `./verify.sh` returns 0.
- Never silence errors (`#[allow]`, `// eslint-disable`, `# type: ignore`) to make verify pass unless the error is a genuinely false positive AND you note WHY in a comment.
Why this works
Three things happen when you add this pattern:
- The AI gets ground truth. Before this, “done” was a model’s own claim. Now “done” is what the compiler says. Big difference.
- The AI iterates on real errors, not guessed ones. Instead of pattern-matching what a fix might look like, the model reads the actual TypeScript error and addresses it specifically.
- The AI stops declaring tasks complete prematurely. The rule “do NOT declare complete until exit 0” removes the escape hatch of “I think this should work.”
What it does NOT fix
Being honest — this isn’t magic. verify.sh doesn’t help with:
- Wrong behavior that still compiles. If the AI writes syntactically valid code that does the wrong thing, verify.sh returns 0 and the AI stops. You still need code review + real tests that exercise real behavior.
- Hallucinated APIs where the file appears to compile. Import from a fake package that doesn’t exist? npm install fails at verify time, so this catches most. But if the fake API is aliased to something real, you’ll only find out at runtime.
- Design flaws. verify.sh checks syntax + tests, not architecture. The AI can still write bad code that passes.
Time savings we’ve measured
Rough numbers from our own use (NJPTEAM):
- Before: 4-5 back-and-forth rounds per non-trivial task, ~15-20 min babysitting per task
- After: 1-2 rounds, most of the iteration happens inside the AI’s own loop
- Net: roughly 15 min saved per task. Compounds fast for multi-hour AI sessions.
Per-stack templates
We ship per-stack verify.sh scripts (Next.js, FastAPI, Rust+Axum) as part of our €15 Stack Pack. Each one is configured with the right toolchain for the stack and includes better error output formatting for AI consumption.
But the pattern above is 90% of the value. If you’re only using one stack, copy the 5-line version and go.
FAQ
Does this work with Cursor?
Yes. Cursor reads .cursorrules at the project root and applies it as a system prompt. Add the verification protocol block there.
Does this work with Claude Code?
Yes. Claude Code reads CLAUDE.md at the project root at every session start. Add the same block there.
Does this work with Copilot / Aider / Windsurf?
Partial. Aider reads a similar CONVENTIONS.md. Copilot’s rules support is more limited (.github/copilot-instructions.md). Windsurf has its own .windsurfrules file. The pattern still works, but adjust the file name for the tool.
What if my project doesn’t have a linter?
Comment out that line. verify.sh degrades gracefully — even just running the typechecker + tests catches most silent failures.
Won’t the AI just skip running the script?
Some models will. That’s why the rule is explicit: “Do NOT declare complete until exit 0.” Well-primed models (Claude Sonnet 4.6+, GPT-5-class) follow this reliably. If yours doesn’t, escalate the rule wording to be more emphatic.
Where to go next
- .cursorrules generator with verification-protocol chips — free, in-browser
- CLAUDE.md generator with the same chips — free
- AI Hallucination Benchmark — see the pass-rate delta between no-rules, free rules, and paid kit rules
- €15 Stack Pack — includes pre-tuned
verify.shfor Next.js / FastAPI / Rust plus the full kit contents