Skip to content

mindvm CLI

The mindvm CLI lives beside the server it talks to, in studio-apps-ng. It is the primary authoring surface: a local mindvm/ folder is the source of truth, and the CLI’s verbs move it to and from the platform.

Being in the same repository is what makes mindvm validate worth running. It imports the server’s own schemas, resolver and JavaScript parse — the same code, not a copy — so a folder that validates locally validates on push. There is no second definition of what a valid agent is to drift from the first.

Terminal window
git clone https://github.com/mind-vm/studio-apps-ng
cd studio-apps-ng/apps/mindvm
make cli # builds bin/mindvm

Three environment variables. There is no config file and no login command: the CLI holds no state between invocations, so what it is talking to is always visible in the environment rather than in a dotfile somebody set up months ago.

Terminal window
export MINDVM_URL=https://platform.mindvm.ai # the server
export MINDVM_ORG_ID=<uuid> # the organisation to act in
export MINDVM_API_KEY=mvk_… # a machine credential

Mint a key in the console under API keys. It is shown once. A key scoped read is refused every unsafe method, which is what a CI job that only watches runs should carry; an unscoped key writes.

MINDVM_TOKEN takes a bearer token instead, for a person driving the CLI under their own account rather than a workstation’s key.

Terminal window
mindvm init # a folder with one working agent
mindvm validate # offline: schema, resolution, JS syntax
mindvm dev # push it
mindvm dev --watch # push on every save
mindvm run starter "2 + 2?" # push, run, stream the trace
mindvm eval starter # push, run the suites, exit non-zero on a failure
mindvm deploy # push, then publish a version per agent
mindvm status # what the server holds against what is on disk
mindvm pull # bring server-side files (promoted routines) down

Every command takes --dir (default mindvm).

Scaffolds a folder with one agent that works: a persona, a skill with both halves — the prompt a model reads and the module a script requires — and an eval that passes. Running init, dev and eval in that order shows the whole loop before you have written anything.

The offline gate. It runs the JSON Schemas, follows every declaration in agent.jsonc, and compiles each JavaScript skill. Issues name the file and carry a hint, because the reader is usually a coding tool.

Builds a manifest from the folder and pushes it. Idempotent: an unchanged folder writes no new draft, so --watch in a loop costs one read per save.

A push is all-or-nothing. Three agents stored and a fourth rejected would leave your folder and the server disagreeing about what exists, so a fatal issue stores none of it and the response names what to fix.

Pushes, opens a session, and streams the turns as they happen — the JavaScript the model wrote, what it returned, and the answer. Not a transcript at the end.

Pushes, runs every suite for the agent, prints each case, and exits non-zero if any failed. That exit code is the interface: edit the files, run it, read the code. A tool that had to parse prose to learn whether it had improved things could not iterate.

Terminal window
mindvm eval starter || echo "still failing"

Pushes, then freezes each agent’s current draft as the next numbered version. Deploying an unchanged folder returns the version that already carries its hash rather than minting a duplicate, so deploy in a loop is safe.

Compares the folder against the server without changing either: in sync, changed locally, not synced, or on the server only.

Brings server-side files down — a routine promoted from a successful run is an ordinary file in the agent’s folder, and this is how it reaches your disk. A file that differs locally is left alone and reported; --force overwrites.

The whole gate is two commands and an exit code:

- run: mindvm validate
- run: mindvm eval my-agent
env:
MINDVM_URL: ${{ vars.MINDVM_URL }}
MINDVM_ORG_ID: ${{ vars.MINDVM_ORG_ID }}
MINDVM_API_KEY: ${{ secrets.MINDVM_API_KEY }}

validate needs no server and no credential, so it belongs on every pull request. eval needs both, and is the one that says whether the change was an improvement.