Status: Beta

From vibe coding to Vibe Engineering.

CommandMate builds the engineering discipline into the workflow: a contract before the work, verification gates after it, evidence throughout. Any coding agent turns your requirement into a verified result.

Vibe Engineering — the AI does the building; the system, not your expertise, guarantees the engineering.

npx commandmate@latest

From install to your first session in 60 seconds.
macOS / Linux / Windows (WSL2) · Node.js v22+ · npm · git · tmux

Requirement one line in an issue CommandMate contract and gates Coding agent any of seven CLIs Verified result exit 0, plus evidence contract send gates evidence

The loop

Four beats, and the same four every time. What makes the result reliable is the loop, not how much software engineering the person driving it happens to carry in their head.

  1. The requirement

    It starts where every task starts: one sentence describing what should be true when this is done. Nothing about the agent, the branch or the tooling yet.

    shout() should return the greeting uppercased. npm run test:shout currently fails.”

  2. The contract

    Before the work starts, the sentence is written down as a contract: what may be touched, and which gates decide that it is finished. Two files, both in the repository, both readable by a human.

    .commandmate/verify.yaml

    version: 1
    gates:
      - id: unit
        command: npm test
        timeoutSec: 120

    .commandmate/tasks/fix-shout.yaml

    title: "shout() uppercases the greeting"
    scope:
      allow: ["src/greet.js"]
      deny: ["test/**", ".commandmate/**"]
    verify:
      gates: [issue-shout]
    success:
      requireWorkEvidence: true
      requireScopeClean: true
  3. The agent runs

    The contract is handed to whichever coding agent you want to use, in a Git worktree of its own. Several tasks can run at once because none of them shares a working directory, and you can watch any of them from a browser.

    $ commandmate send wt-shout \
        --contract .commandmate/tasks/fix-shout.yaml >task-id.txt
    Task created: 4d1f8b2a-6c07-4a5e-9f3b-27ac91e0d4c8
    Message sent.
  4. The verdict

    When the agent stops, the gates you declared run for real and the process exit code is the answer — 0 passed, 20 a gate failed, 21 nothing was actually done. Not the agent's own opinion of its work.

    $ commandmate wait wt-shout --verify
    GATE work-evidence PASS (commits=0, uncommitted=1)
    GATE scope PASS (exit=0, 0.1s)
    GATE unit PASS (exit=0, 0.1s)
    RESULT passed
    $ echo $?
    0

What it gives you

Method as a system

The method is not in someone's head — it is installed as Skills and read by the agent.

Verified, not vibe-checked

Gates you declared decide whether the work is done, and the exit code is the verdict.

Any agent, in parallel

One worktree and one contract per task, across seven agent CLIs and local models.

Stay in control, anywhere

When an agent needs you, it reaches you — badge, toast, tab title, push — and you answer from your phone.

Runs 100% locally. No external server, no cloud relay, no account required — the only network traffic is the agent CLI's own API calls.

Quick start, in 60 seconds

Two ways in. Take Track A to see it working, Track B once you keep coming back.

Track A

Just try it

One command, nothing installed first. There is nothing else to type — it runs all four steps below for you.

npx commandmate@latest
  1. Checks your dependencies

    Node.js, npm, git and tmux. Stops with an install hint if one is missing.

  2. Asks the setup questions

    Repository root, additional browsable directories, port, external access, database path.

  3. Starts the server in the background

    Then waits until it actually answers.

  4. Opens your browser

    At http://localhost:3000, once the server is ready.

Step 2 is first-run only. Run it again later and it goes straight to the UI.

Track B

Install it for daily use

Track A runs the server out of npm's cache, where a later npx can swap the files under it. A global install gives a long-running server somewhere stable to live.

  1. Install globally

    npm install -g commandmate
  2. Answer the setup questions

    First run only, and skipped entirely if you already have a .env.

    commandmate init
  3. Start in the background

    Keeps serving after you close the terminal.

    commandmate start --daemon

Either track leaves a server running in the background. commandmate status tells you whether one is up, and commandmate stop shuts it down.

Then run the loop on a real repository

Use a sample repository with two bugs left in on purpose to work through the core of CommandMate in about fifteen minutes. You fork the sample repository before you start, so nothing you do can touch the original repository (upstream). You hand the agent a contract before the work and let the verification gates judge it afterwards, and you read the verdict off the real exit code.

The sample repository — fork this one first:

https://github.com/Kewton/commandmate-tutorial.git

Fork it on GitHub, then paste your fork's URL into Repositories → Add Repository → Clone URL and follow the tutorial. It ships its own .commandmate/verify.yaml and two task contracts, so the gates are real from the first command. No install, no dependencies.

See it running

Twenty seconds each, recorded against a throwaway repository with a stubbed agent. The gates in the first one are executed for real, so the exit codes on screen are the ones that run produced.

Hand the agent a contract before the work starts. Gates run, and the exit code is the verdict.
Waiting reaches you, and you answer from your phone.
One session per worktree, running in parallel.
The method is not in someone's head — it is installed as Skills and read by the agent.

With and without CommandMate

The comparison worth drawing is between two ways of working, not between products.

Dimension Vibe coding Vibe Engineering with CommandMate
What "done" means The agent says it's done A verification run says so — exit 0 / 20 / 21
Scope of change Whatever the agent touched Declared in the contract, enforced by the scope gate
Method In someone's head Installed as Skills from the Catalog (cmate-task-contract, cmate-verify, …)
Evidence A chat transcript Commits, gate logs, verify history, report metrics
Parallel work Terminal tabs One worktree and one contract per task
When it stops You notice, eventually Waiting is surfaced: badge, toast, tab title, push
Which agent Locked to one Claude Code, Codex, Gemini CLI, Copilot, OpenCode, Antigravity, local models

The same sessions in your browser, whichever screen you are on.

Pair your phone with a QR code

One command opens a way in and prints a QR code carrying a one-time pairing code. There is no LAN address to look up, no CM_BIND to widen, and no token to retype on a phone keyboard.

commandmate remote

Bring one of two providers

Tailscale or cloudflared — one of them has to be installed and usable, or remote stops on a dependency error. Tailscale Serve is the preferred route, and stays inside your tailnet.

Nothing public without a yes

A Cloudflare Quick Tunnel is a URL on the open internet, so it is created only after you approve it — --yes when nobody is there to ask. Tailscale being unusable never publishes you instead.

A code that runs out

The pairing code works once and expires in ten minutes by default; --pairing-expires sets that window. No long-lived token travels in the QR code.

One door, and you close it

CM_BIND keeps its 127.0.0.1 default — remote adds one way in and changes nothing else. commandmate remote stop takes down what CommandMate opened, and leaves the server up.

Nothing is exposed until you run it, and the session closes itself — eight hours by default, --expires to change it. commandmate remote status reports the provider, the URL and what is left of both windows, and Auto-Yes stays off unless you turn it on.

The Quick Tunnel is a quick way in rather than a permanent address. Every flag, every exit code and the longer-lived Tailscale route are in the CLI operations guide.

Start in one command

npx commandmate@latest