Your AI agent says it's done.malveon reads the code and tells you if it is.

Point it at your plan. Every line comes back CONNECTED, BROKEN, NOT BUILT, or HALF BUILT, with the file and line that proves it. It never asks the agent.

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.

Terminal · landing-shop
~/landing-shop $ malveon check --features PLAN.mdOVERVIEW==============================================================================  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  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                     clean  New bugs this session              clean  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, 1 NOT BUILT, 1 HALF BUILT, 1 REWRITE THIS LINE  - agent's claims vs reality: 1 claim(s) contradicted by what was actually verified

Real output from malveon v0.3.3 on a small demo app. The full report goes on to explain every line.

Built after a week of reading Reddit threads from developers whose agents said "fully functional" while half the routes didn't exist.

The agent says it "wired up" the endpoint.You open the code. Nothing on the other end.So you re-read every file yourself. That was the job you handed off.

For every line of your plan

One straight answer per line

BROKEN

Built, but it won’t work. It calls a URL nothing serves, or with a method the server doesn’t accept.

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

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

NOT BUILT

Your plan names it. Your code doesn’t have it.

Export all orders as CSV from GET /api/reports/orders

nothing in the code serves or calls /api/reports/orders

HALF BUILT

Part of it is there. A route nothing calls, a save that never writes, a file nothing uses.

OrderNotes saves a note on an order with POST /api/notes

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

REWRITE THIS LINE

Too vague to check. Name the file, URL, or component it’s about.

Make checkout feel faster

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

CONNECTED

Built, and the screen really reaches its server route or database.

RefundButton sends a refund to POST /api/refunds, which saves it to refunds

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

SKIPPED

Not a code task: a heading, a design note, a manual step. The reason is shown.

Buttons use the brand color and a 1.5px stroke icon

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

The examples are from the same demo run. Every answer names the file and line it's based on. Open it and check.

End to end

Follow one feature from the button to the database

For every connected line, malveon traces the route through your code: the page, the call, the server route, and what it changes. A save button whose route never writes anything comes back HALF BUILT. The files existing isn't enough.

CONNECTEDRefundButton sends a refund to POST /api/refunds, which saves it to refunds

  1. Screen

    page /orders

  2. Call

    POST /api/refunds

    src/components/RefundButton.tsx:5

  3. Server

    route POST /api/refunds

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

  4. Changes

    inserts into table refunds

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

HALF BUILTOrderNotes saves a note on an order with POST /api/notes

  1. Screen

    page /orders

  2. Call

    POST /api/notes

    src/components/OrderNotes.tsx:9

  3. Server

    route POST /api/notes

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

  4. Changes

    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 Next.js and Supabase app we test against, the challenge form sent challengeId. The server read challenge_id. Every submission came back 400. The agent said done, and nothing complained until someone pressed Submit.

malveon compares what each screen sends with what its route reads. It flagged the mismatch, with both file lines, in one check.

src/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            });

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        }

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

What it checks

Proof you can open in your editor

  • Reads your code, not the agent’s word. The checks don’t call an AI model. malveon looks up every URL, file, and component your plan names.
  • Your agent can’t grade its own homework. Run it as an MCP server and Claude Code, Cursor, or Antigravity calls malveon itself. When something needs a decision, malveon asks you in a dialog, never the agent.
  • Checks your prompts too, not only the plan doc. Most of what you ask an agent for is typed into chat and never reaches a plan. Turn on prompt checking and each request gets a verdict too.
  • Runs your real build and tests when you say so. Add --exec for a real pass or fail. A repo can’t run its own scripts on your machine until you approve them.
  • Stops a bad commit. Add it as a pre-commit hook and anything BROKEN, NOT BUILT, or HALF BUILT blocks the commit.

What you see when an agent asks malveon to run your build. The agent can't answer it for you.

In your editor

Save a file. See what broke.

The VS Code and Cursor extension checks again a few seconds after you save. Results show in the sidebar, the Problems panel, and the status bar. Click any line to jump to the code.

Malveon — landing-shop — Visual Studio Code
Malveon results

Malveon / landing-shop

2 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, 1 NOT BUILT, 1 HALF BUILT, 1 REWRITE THIS LINE
  • 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

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 (2)
No overclaiming

Three things can be true. malveon tells you which.

Read from the code

Checked on every run.

Your build and tests

Passed, failed, or not run. Only as real as the run behind it.

Your real app

Never claimed. malveon doesn’t open a browser or start your server, and it won’t pretend it did.

Your agent says "done" about all three at once. malveon reports each one separately.

How it works

Set it up once, then keep working

01

Install

The one-line command, or the VS Code and Cursor extension.

02

Pick your plan

Choose your plan files once. malveon.json remembers them for you and your agent.

03

Work as usual

The check runs when you save, when your agent calls it, or when you type malveon check.

Install

However you install things

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 release is signed. The installer and malveon update check the signature before anything runs.

Your code stays yours

Nothing about your project leaves your machine

Your code, file names, plans, and prompts stay local. Each run sends one anonymous event: your OS, CPU type, and whether the result was clean or blocked. Turn it off with --no-telemetry or DO_NOT_TRACK=1. The extension follows VS Code's telemetry setting.

FAQ

Frequently asked questions

What's next

The hosted version is next

The CLI and the editor extension are out. A hosted service, where checks run without a terminal, is being built. Leave your email and we'll tell you when it's ready. That's all we'll use it for.

Your agent already says it's done. Find out which lines actually are.

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.