Your AI says it's done.malveon checks if it really is.

malveon reads the code your AI wrote and checks it against your to-do list. Each item gets a plain answer (hooked up, broken, missing, or half done) and the exact line that proves it. It also catches what your AI added without being asked, and what it broke on the way.

curl -fsSL https://get.malveon.com/install.sh | sh

Windows: irm https://get.malveon.com/install.ps1 | iex. Also on npm, Homebrew, Scoop, and the VS Code and Cursor extension. Free during the beta. No account. Your code stays on your computer.

Terminal · landing-shop
~/landing-shop $ malveon check --features PLAN.mdFIX THESE FIRST==============================================================================  1. BROKEN — `CancelButton` cancels an order with `DELETE /api/orders/[id]`     `CancelButton` exists (src\components\CancelButton.tsx) — but it calls DELETE /api/order/:param (src\components\CancelButton.tsx:5), and no server route handles that  (src\app\api\orders\[id]\route.ts:4)  2. new call to nowhere — DELETE /api/order/:param     DELETE /api/order/:param is a call added this session, and no route in the project serves it  (src\components\CancelButton.tsx:5)  3. HALF BUILT — `OrderNotes` saves a note on an order with `POST /api/notes`     POST /api/notes reaches its server route (src\app\api\notes\route.ts:4), but the route never changes any data: it only reads table `notes` (src\app\api\notes\route.ts:6) — and this line expects a change  (src\components\OrderNotes.tsx:9)OVERVIEW==============================================================================  read from the code ✔ · your build/tests: not run (turn on "exec" in malveon.json, or pass --exec) · your real app: not verified (malveon never runs it)  Plan items built & connected       2 CONNECTED · 1 BROKEN · 1 NOT BUILT · 1 HALF BUILT · 1 REWRITE · 1 SKIPPED (2 not ticked yet, don't block)  Your prompts vs the code           not set up  Frontend & backend agree on data   2 MATCH · 0 MISMATCH  Backend route conflicts            clean  UI elements may overlap            clean  Unplanned code                     2 flagged  New bugs this session              1 found  Unfinished code (TODOs)            clean  Agent's claims vs reality          0 CONFIRMED · 1 MISMATCH · 6 NOT CLAIMED  Build, lint & tests actually ran   not run (pass --exec to include)⋮GATE: blocked — a commit gated on this run should not proceed  - plan items: 1 BROKEN, 0 NOT BUILT, 1 HALF BUILT, 0 REWRITE THIS LINE  - new bugs this session: 1 introduced (something that worked now broken, or a known bug pattern added)  - agent's claims vs reality: 1 claim(s) contradicted by what was actually verified

A real malveon report on a small test app, shortened. It opens with what to fix first: a Cancel button that calls an address the server doesn't have, and a note that never actually saves. The overview also flags an Email receipt button nobody asked for. “GATE: blocked” means “don't ship this yet.”

Built after a week of reading Reddit threads from people whose AI said "fully functional" while half the features didn't actually work.

The AI says the Save button is done.You click it. Nothing gets saved.So you check every file yourself. That was the job you gave the AI.

And it isn't only the Save button.

The second opinion that agrees
So you ask another AI to check the first one. It reads the same files and gives you another opinion. You still don’t know.
The thing that used to work
While fixing one problem, your AI quietly breaks something else. You find out when a user clicks it.
The extra nobody asked for
You asked for one thing. The AI also added an Email receipt button and a new address on your server. You find out when you read the changes, if you do.
For every item on your list

A straight answer for each one

Each item on your list gets one of six answers. These are the exact words malveon prints, with a real example from a test app.

BROKENBroken

It’s there, but it won’t work. The button asks the server for something that doesn’t exist.

Your list saidCancelButton cancels an order with DELETE /api/orders/[id]

malveon foundit calls DELETE /api/order/:param (src\components\CancelButton.tsx:5), and no server route handles that

NOT BUILTMissing

It’s on your list. It isn’t in the code at all.

Your list saidExport all orders as CSV from GET /api/reports/orders

malveon foundnothing in the code serves or calls /api/reports/orders

HALF BUILTHalf done

Part of it is there. A button that leads nowhere, or a Save that never actually saves.

Your list saidOrderNotes saves a note on an order with POST /api/notes

malveon foundthe route never changes any data: it only reads table notes (src\app\api\notes\route.ts:6)

REWRITE THIS LINEToo vague

Your list item is too vague to check. Say which page, button, or file you mean.

Your list saidMake orders better

malveon foundnames no URL, file, or code name, and no code clearly matches its words

CONNECTEDHooked up

It’s built, and the button really reaches the part that does the work and saves it.

Your list saidRefundButton sends a refund to POST /api/refunds, which saves it to refunds

malveon foundinserts into table refunds (src\app\api\refunds\route.ts:6)

SKIPPEDNot a coding task

Something code can’t show, like a color change or a step you do by hand. It says why.

Your list saidButtons use the brand color and a 1.5px stroke icon

malveon founda design or styling change — malveon reads code, it can’t see how the page looks

Every answer points to the exact spot in the code it's based on, so you can check it yourself.

Start to finish

Follow one feature from the button to where it's saved

Clicking a button starts a chain: the page sends a request, code on the server answers it, and something gets saved. malveon follows that chain for every item. If the chain stops before anything is saved, you'll know. Files that merely exist don't count as done.

malveon follows this chain through the code. It never opens your app.

CONNECTED(hooked up: the refund is saved)RefundButton sends a refund to POST /api/refunds, which saves it to refunds

  1. The page

    page /orders

  2. Sends

    POST /api/refunds

    src/components/RefundButton.tsx:5

  3. Server

    route POST /api/refunds

    src/app/api/refunds/route.ts:4

  4. What gets saved

    inserts into table refunds

    src/app/api/refunds/route.ts:6

HALF BUILT(half done: the note is never saved)OrderNotes saves a note on an order with POST /api/notes

  1. The page

    page /orders

  2. Sends

    POST /api/notes

    src/components/OrderNotes.tsx:9

  3. Server

    route POST /api/notes

    src/app/api/notes/route.ts:4

  4. What gets saved

    changes no data: only reads table notes

    src/app/api/notes/route.ts:6

A real one

Every submission failed. The page looked finished.

On a real app we test with, a form sent its answers under one set of names, and the server expected different ones: challengeId instead of challenge_id. So the server turned away every single submission. The AI said it was done, and nothing looked wrong until someone pressed Submit.

malveon checks that what a page sends matches what the server expects. It caught this in one check and pointed to both lines.

What the form sendssrc/components/challenges/ChallengeDetailClient.tsx

133            const res = await fetch("/api/submissions", {134                method: "POST",135                headers: { "Content-Type": "application/json" },136                body: JSON.stringify({137                    challengeId: id,138                    githubRepo: submissionData.githubRepo,139                    demoUrl: submissionData.demoUrl,140                    techStack: selectedTechStack,141                    wrongDecision: submissionData.wrongDecision,142                    defendedDecision: submissionData.defendedDecision,143                }),144            });

What the server expects (and the error it returns otherwise)src/app/api/submissions/route.ts

47    try {48        const body = await request.json();4950        // Basic validation51        if (!body.challenge_id || !body.wrong_decision || !body.defended_decision) {52            return NextResponse.json({ error: "Missing required fields" }, { status: 400 });53        }

malveon's report, word for word:

fields: CONTRACT MISMATCH — POST /api/submissions (src\components\challenges\ChallengeDetailClient.tsx:133) → route (src\app\api\submissions\route.ts:38): the handler reads challenge_id, wrong_decision, defended_decision from the request body, but the call never sends challenge_id, defended_decision, wrong_decision

Along the way

What your AI did that you didn't see

malveon compares your code with how it was when you started working, so it can tell what your AI changed along the way.

What it broke

New bugs this session
did this session's own changes break something that worked, or add a known bug pattern?  NEW CALL TO NOWHERE — DELETE /api/order/:param    src\components\CancelButton.tsx:5    DELETE /api/order/:param is a call added this session, and no route in the project serves it

What nobody asked for

Unplanned code
did the agent build anything this session neither your plan nor your own prompts asked for?  route /api/receipts    method: POST    evidence: src\app\api\receipts\route.ts:4  call /api/receipts    method: POST    evidence: src\components\ReceiptButton.tsx:5

It broke something that worked. If a button that reached the server now points at an address that doesn't exist, malveon says so and shows the line. It also flags a few common leftovers: a debugging line left in, a test switched to “only”, or a secret key from a well-known service pasted into the code. That is a short list plus the before-and-after comparison, not a general bug finder.

It added something nobody asked for. malveon lists every new request your page makes, and every new address your server answers, that neither your plan nor your own prompts asked for. Your AI's own summary doesn't count as asking. It sees buttons that talk to your server. A button that only changes how the page looks, like a dark mode switch, is out of its reach. It lists these for you to review and doesn't block your work.

And what it left behind:

A “done” the code doesn’t back up
When the note your AI writes as it saves its work says an item is done or working, malveon checks that against the code. If they disagree, it shows you the line.
Notes to self
“TODO”, “FIXME” and “not implemented” in lines your AI wrote this session. It reads JavaScript, TypeScript, Python and Go files.
Two places answering one address
If two parts of your server claim the same address for the same kind of request, only one of them can run. malveon lists both.
Layouts that may overlap
A positioned element with nothing to anchor it, a common cause of pieces overlapping on screen. This is a warning about the code. malveon never looks at your screen.
Why it's different

It checks the code, not the AI's word

  • No AI grading AI. malveon reads the code itself, so the same code always gets the same answer, and every answer points to the exact line.
  • Your AI can run it too. It gets the same report you would see. When a decision is needed, like running commands on your computer, malveon asks you, not the AI.
  • It checks what you asked for in chat. Most requests to an AI never make it into a written plan. After a one-time setup, malveon can check those too.
  • It runs your project’s own tests only after you say yes.
  • You can set it to stop half-done work from being saved into your project’s history (a “commit”) until it’s fixed.

When your AI asks to run commands on your computer, this is what you see. Only you can answer it.

In your editor

Save a file. See what broke.

Using VS Code or Cursor? Add the malveon extension and it checks again a few seconds after you save. Problems show up right next to your code, and clicking one takes you to the exact line.

Malveon — landing-shop — Visual Studio Code
Malveon results

Malveon / landing-shop

3 things block a commit

Fix these, then run the check again.

  • Read from the code done
  • Your build and tests: not run
  • Your real app: not verified — malveon never runs it
  • plan items: 1 BROKEN, 0 NOT BUILT, 1 HALF BUILT, 0 REWRITE THIS LINE
  • new bugs this session: 1 introduced (something that worked now broken, or a known bug pattern added)
  • agent’s claims vs reality: 1 claim(s) contradicted by what was actually verified
  • 1 BROKEN
  • 1 NOT BUILT
  • 1 HALF BUILT
  • 1 REWRITE THIS LINE
  • 2 CONNECTED
  • 1 SKIPPED

Plan items

Every line of your plan, checked against the code. From PLAN.md. Change

BROKEN1Would fail for a real user: the screen calls something the server doesn’t serve, or with the wrong method.

CancelButton cancels an order with DELETE /api/orders/[id]

PLAN.md:5

CancelButton exists (src\components\CancelButton.tsx) — but it calls DELETE /api/order/:param (src\components\CancelButton.tsx:5), and no server route handles that; the server route for /api/orders/:id exists (src\app\api\orders\[id]\route.ts:4), but no frontend call to it was found (if something outside the app calls it — a health check, webhook, cron job or public API — say so in the line)

src/app/api/orders/[id]/route.ts:4src/components/CancelButton.tsx:5

NOT BUILT1Your plan names it. The code doesn’t have it.
HALF BUILT1Part of it exists, but it isn’t connected yet.
REWRITE THIS LINE1Names nothing malveon can look up. Add the URL, file, or component it means.
CONNECTED2Built, and the screen reaches its server or database.
main malveon: blocked (3)
How it works

Set it up once, then keep working

01

Install

Paste one line into your terminal, or add the extension to VS Code or Cursor.

02

Show it your list

Point it at the plan or checklist your AI is working from. It remembers it.

03

Keep working

It checks when you save, when your AI asks it to, or whenever you run it.

malveon never runs your app, never runs your project's own commands until you've said yes, and never sends your code or file names anywhere.

Pick the line for your computer

Not sure which? On a Mac or Linux use the first line, on Windows the second. Copy it into your terminal and press Enter.

macOS / Linux
curl -fsSL https://get.malveon.com/install.sh | sh
Windows
irm https://get.malveon.com/install.ps1 | iex
npm
npm install -g malveon
Homebrew
brew tap ladsondavid/malveon https://github.com/LadsonDavid/Malveon && brew install malveon
Scoop
scoop bucket add malveon https://github.com/LadsonDavid/Malveon; scoop install malveon
VS Code / Cursor
Search “malveon” in Extensions

Every download is checked against the release's checksum list before it's installed, and a file that doesn't match is refused. That list is signed with malveon's release key. Updates always check the signature, and so does the Mac and Linux installer when your computer has OpenSSL 3.

FAQ

Frequently asked questions

Ask your AI

Don't take our word for it

Pick one. It opens with a question about malveon already typed, including what malveon can't do. The AI answers from what it finds online, so it can be wrong or out of date about us too. malveon's own answers never come from an AI. They come from your code.

The question it asks

I use AI coding agents (Claude Code, Cursor, Codex, Antigravity). Explain malveon (malveon.com): what it checks when my agent says a task is done, including anything the agent added that I didn’t ask for and anything it broke along the way, how it proves each verdict, what it can’t check, and how to install it. Use malveon.com and github.com/LadsonDavid/Malveon as sources.

Your AI already says it's done. Find out what's actually finished.

curl -fsSL https://get.malveon.com/install.sh | sh

Windows: irm https://get.malveon.com/install.ps1 | iex. Also on npm, Homebrew, Scoop, and the VS Code and Cursor extension. Free during the beta. No account. Your code stays on your computer.