Docs / Terminal

Use malveon from the terminal

The terminal is the text window where you type commands (Terminal on a Mac, PowerShell on Windows). Run one command before your AI starts and one after it says it’s done. The second one tells you what is really built.

Check it’s installed

Open a new terminal window. The one you installed from doesn’t know about the change yet. Then type:

malveon

You should see a list of commands. If you see “command not found”, close the terminal, open another and try again. Not installed yet? Pick the line for your computer.

The two commands

Run both from inside your project’s folder.

1. Before your AI starts

malveon session start

This saves a snapshot of your code, so malveon can tell later what changed. Changes you haven’t committed yet are part of the snapshot, so they aren’t blamed on your AI. Forgot? The first malveon check starts one for you and says so. It then covers changes from that moment on, but not work that was already committed before it.

2. After your AI says it’s done

malveon check

malveon finds your plan, reads your code and your git history, and prints a report. It exits with an error if anything is proven wrong.

Your plan file

You don’t have to point malveon at your plan. It looks through the project for a file named like one (anything with “plan”, “feature”, “checklist” or “todo” in the name). If none matches, it looks for a Markdown checklist or a feature list in JSON. It always shows you what it found and asks before using it:

found a possible plan file (by name): docs/PLAN.md — use it? [Y/n]

Skip the question by naming the file. Use the option more than once to check several plan files in one run.

malveon check --features docs/PLAN.md

A plan can be a Markdown checklist, a JSON list, or plain text with one item per line:

- [ ] Refund button
- [x] Cancel order
  • Tick a box when the plan says the item is done. A ticked line (- [x]) or a plain bullet blocks when the code disagrees. An unticked line (- [ ]) is still checked and listed, but it only blocks if it is BROKEN.
  • Be specific. “Refund button” works if some code mentions refunds. A line that names its URL, file or component is checked exactly, like `RefundButton` sends a refund to `POST /api/refunds`. A line that names nothing malveon can look up is skipped, and the report lists the closest routes and pages so you can add the right name.

Keep the choice with your project

Commit a file called malveon.json at the project root, so you, your AI and your git hook all check the same way. malveon offers to write it the first time you pick a plan.

malveon.json

{
  "plans": ["docs/PLAN.md"],
  "exec": true
}

A flag on the command line always wins over the file.

Reading the result

This is a real run on a small demo app (an orders dashboard where an AI cancelled an order through the wrong address and left a note that saves nothing). It is the full output, so scroll inside the box.

Terminal · landing-shop
~/landing-shop $ malveon check --features PLAN.md

VERDICT: FAILED
==============================================================================
  3 problems are proven wrong in the code (details below):
  - plan items: 1 BROKEN, 0 NOT BUILT, 1 HALF BUILT
  - 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
  malveon reads the code; it never ran your app, so a real click or page load is still yours to try.

FIX 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. claim contradicted — `OrderNotes` saves a note on an order with `POST /api/notes`
     said "OrderNotes saves notes, ready to ship.", but claimed this works, but the plan-items check says HALF BUILT: 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…
  …and 1 more — details below

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 · 2 SKIPPED (1 of those name nothing malveon can look up) (1 not ticked yet, don't block)
  Your prompts vs the code           not set up (malveon hooks install)
  Frontend & backend agree on data   2 MATCH · 0 MISMATCH (request fields compared on 2)
  Backend route conflicts            clean
  UI elements may overlap            clean
  Unplanned code                     2 flagged
  New bugs this session              1 found
  Unfinished code                    clean
  Agent's claims vs reality          0 CONFIRMED · 1 MISMATCH · 6 NOT CLAIMED
  Agent's words vs the code          clean
  Build, lint & tests actually ran   not run (pass --exec to include)

Plan items — built and connected? (wiring check)
for every plan line: is it in the code, and does the screen actually reach the server?
(CONNECTED means built and connected in the code — read from it, not run or clicked through)
------------------------------------------------------------------------------
BROKEN (1) — built, but it won't work as written: fix these first
  `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; 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)
    evidence: src\app\api\orders\[id]\route.ts:4
    evidence: src\components\CancelButton.tsx:5

NOT BUILT (1) — the plan names it, the code doesn't have it
  Export all orders as CSV from `GET /api/reports/orders`  (not ticked in your plan yet, so it doesn't block)
    nothing in the code serves or calls /api/reports/orders

HALF BUILT (1) — one part exists, the other doesn't
  `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
    path: page /orders → POST /api/notes (src\components\OrderNotes.tsx:9) → route POST /api/notes (src\app\api\notes\route.ts:4) → changes no data: only reads table `notes` (src\app\api\notes\route.ts:6)
    evidence: src\components\OrderNotes.tsx:9
    evidence: src\app\api\notes\route.ts:4
    evidence: src\components\OrderNotes.tsx
    evidence: src\app\api\notes\route.ts:6

CONNECTED (2) — built and connected in the code
  Orders page at `/orders` lists orders from the `orders` table
    path: page /orders → reads table `orders` (src\app\orders\page.tsx:16)
  `RefundButton` sends a refund to `POST /api/refunds`, which saves it to `refunds`
    path: page /orders → POST /api/refunds (src\components\RefundButton.tsx:5) → route POST /api/refunds (src\app\api\refunds\route.ts:4) → inserts into table `refunds` (src\app\api\refunds\route.ts:6)

SKIPPED (2) — not checked, and not a problem in your code
  a design or styling change — malveon reads code, it can't see how the page looks (1)
  names no URL, file or code name, and no code clearly matches its words (1)
    - Make orders better
      closest in the code: `/orders` (src\app\orders\page.tsx:1); `DELETE /api/order/:param` (src\components\CancelButton.tsx:5); `DELETE /api/orders/:id` (src\app\api\orders\[id]\route.ts:4) — name one in backticks if it's what this line means
  to have a line checked, name the URL, file or component it's about, in backticks
  every skipped line, with its reason, is in the JSON report (malveon check --json report.json)

Unplanned code (not-in-plan check)
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

New bugs this session (hero-act check)
did this session's own changes break something that worked, or add a known bug pattern?
(compared with the code at the session start, read straight from git and the code, never from the agent)
------------------------------------------------------------------------------
  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

Agent's claims vs reality (confidence check)
when the agent said "done"/"working" in a commit message, did the other checks actually agree?
------------------------------------------------------------------------------
CONFIDENCE MISMATCH (1) — claimed done, but not what got verified
  `OrderNotes` saves a note on an order with `POST /api/notes`
    claimed: OrderNotes saves notes, ready to ship.
    reason: claimed this works, but the plan-items check says HALF BUILT: 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

GATE: blocked — a commit gated on this run should not proceed
  - plan items: 1 BROKEN, 0 NOT BUILT, 1 HALF BUILT
  - 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

How to read it, top to bottom:

  • VERDICT is the one-line answer: FAILED, NEEDS YOU or VERIFIED BY CODE.
  • FIX THESE FIRST lists up to three of the most serious problems, each with the file and line behind it. It only appears when something blocks.
  • OVERVIEW has one line per check. A check that found nothing says “clean” and has no section below.
  • GATE says whether a commit gated on this run should go ahead.

The command exits with code 1 when the gate is blocked and 0 when it is clean.

Stopping a bad commit

By default malveon check fails whenever the gate is blocked. To make that stop a commit, add a git hook, a small script git runs before it saves a commit. malveon never installs one for you.

Save this as .git/hooks/pre-commit, then run chmod +x .git/hooks/pre-commit:

.git/hooks/pre-commit

#!/bin/sh
malveon check

A hook can’t answer questions, so it needs a committed malveon.json that names your plan file. Without one the check stops right away instead of waiting for an answer nobody can give.

WhatDoes it block?
BROKEN, NOT BUILT, HALF BUILTYes.
A request the page sends that the server doesn’t expectYes.
A new bug the AI introducedYes.
A claim in the AI’s notes that the code contradictsYes.
Code your plan never asked forNo. It’s listed for you to review.
Unfinished-code notes and layout warningsNo. A function that throws “not implemented” and that something calls does block.
Plan lines malveon couldn’t look upNo.
Unticked lines that are NOT BUILT or HALF BUILTNo, until you tick them.

Want the full report but never a failing exit code? Add --no-gate.

Running your build and tests

malveon check --exec

This also runs your project’s own build, lint, type check and test commands, and reports what they really said. It only runs commands your project already defines (a Makefile target, a package.json script, Go’s standard tools, Python tools on your PATH). Nothing is invented. It is off by default because it can take a few minutes.

malveon asks before running a project’s commands. A malveon.json comes with the project, so one you just cloned shouldn’t be able to run its scripts the moment you check it. The first time, malveon shows the exact commands and asks. Your answer is remembered for that project until its malveon.json changes. To approve ahead of time, for example so a git hook can run them:

malveon trust

Typing --exec yourself needs no approval. You asked for it. Each command gets three minutes by default; change it with --exec-timeout 5m. A command that times out is reported as “no proof”, not as a pass or a fail.

All commands

CommandWhat it does
malveon checkChecks your plan and prompts against the code. Exits with an error if something is broken or missing.
malveon session startMarks where the AI’s work begins, so “what changed” has a baseline.
malveon trustApproves running this project’s own build and test commands.
malveon hooks installAlso checks the prompts you type to Claude Code, Codex, Cursor or Antigravity. Add --gate shadow or --gate enforce for Claude Code’s edit and “done” hooks.
malveon prompt drop NStops checking prompt number N, for one you cancelled.
malveon prompt confirm NApproves the lines your AI wrote for prompt N. Needs a terminal.
malveon prompt waive N wordsSays you will check some words of prompt N yourself.
malveon mcpRuns malveon so your AI tool can call it. See Let your AI run the check.
malveon updateInstalls the latest version.
malveon versionPrints the version.
malveon registerOpens a pre-filled GitHub discussion where you can ask for a check for your stack.

Options for malveon check

OptionWhat it does
--features <path>Use this plan file and skip the question. Repeat it for several files.
--execAlso run your build, lint, type check and tests.
--exec-timeout <time>How long each command gets. Default 3 minutes. Example: 5m, 90s.
--no-gatePrint the full report but always exit successfully.
--json <path>Also write the full report as JSON. Use - to send the JSON to the terminal output and the text report to the error output.
--root <path>Check a project in another folder.
--no-telemetryDon’t send the anonymous usage signal for this run.

Privacy switches

malveon sends one small anonymous usage signal per run and checks GitHub once a day for a newer version. Neither includes anything about your project.

  • Turn the usage signals off: add --no-telemetry, or set DO_NOT_TRACK=1.
  • Turn the daily update check off: set MALVEON_NO_UPDATE_CHECK=1.

The full list of what is sent is in the privacy policy.

If something goes wrong

  • “command not found”. Close the terminal and open a new one.
  • “found a possible plan file, but there’s no terminal to confirm it”. A script can’t answer the question. Name the file with --features, or commit a malveon.json.
  • My build and tests didn’t run in a git hook. Run malveon trust once in the project, from a normal terminal.
  • It says no session was started. Run malveon session start, or run malveon check again, which starts one for you.

Still stuck, or using a stack malveon handles badly? Open a discussion. That’s the one place the person who built it is reading.

Run the check on your own project.

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.