Theme

CLI

mimeo — pull your Mimeo's definitions into a git repo, edit them, and push them back through a diff, a validation pass and a rehearsal.

Two facts up front. There is nothing to install — the CLI is a single file at bin/mimeo in your manager repo, running on the Ruby that ships with macOS and every mainstream Linux. And Mimeo never touches gitpull and push here move definitions between your working tree and your Mimeo over HTTPS; your Mimeo never reads your git repo, and no remote is required.

The CLI is small on purpose: init, auth, pull, diff, push. It carries no knowledge of the file formats at all — it reads your repo into { path => contents }, posts that to your Mimeo, and prints what comes back. Serialization, diffing, validation and dry-running all happen on your Mimeo, so the repo format has exactly one implementation and it's always the one your Mimeo is actually running.

Getting it

It ships inside the manager repo template as bin/mimeo. The easiest start is Settings → Agents & API → Manager repo on your Mimeo, which mints a token and hands you these commands with real values filled in:

git clone https://github.com/buildermethods/mimeo-manager.git my-mimeo
cd my-mimeo
git remote remove origin
./bin/mimeo init --host https://your-mimeo.com --token mm_your_token

The remote remove disconnects your clone from the template, so nothing ever pushes back to it. init is auth plus a first pull: it checks the connection, writes every definition into files, points the committed .mcp.json at your Mimeo's MCP server, and prints the first-snapshot commit to run. The URL lands in .mimeo/config.yml, which is committed so everyone on the repo points at the same place. The token lands in .mimeo/token, which is gitignored — and the CLI adds that line to .gitignore itself if it's missing, because a token in a commit is a token you have to rotate.

Every command below is written ./bin/mimeo because that's what it is — the file in your repo. Nothing lands on your PATH.

The loop

./bin/mimeo pull      # sync down first, always
                      # ... edit files, or ask your agent to ...
./bin/mimeo diff      # what a push would change — nothing is applied
./bin/mimeo push      # diff → validate → rehearse → apply
./bin/mimeo pull      # after a structural push: pick up ids Mimeo minted

Pull before editing — someone may have changed something in the admin UI since your last sync, and pushing a stale file would quietly revert it. And pull again after a push that added steps or emails: Mimeo mints their ids, and the second pull is how your files catch up.

Commands

CommandWhat it does
mimeo init First-time setup: auth, then a first pull, then your next steps printed. Takes --host and --token, or asks.
mimeo auth Point this repo at your Mimeo (and re-point .mcp.json). Takes --host and --token, or asks.
mimeo pull Write your Mimeo's definitions and media here, overwriting. Reports created, updated and removed files.
mimeo diff What a push would change, with validation and a rehearsal of every changed flow. Changes nothing.
mimeo statusThe same thing, by its other name.
mimeo push Show the diff, validate, dry-run, then ask before applying.

Push options

FlagEffect
--prune Also remove what's on your Mimeo but not in the repo. Off by default: a stray rm or a bad merge shouldn't delete a flow. Absences are always reported either way. Emails are archived rather than destroyed, and a flow people have run through refuses regardless — its history is theirs.
--force Apply despite the identity warnings (node_id_freed, node_id_repurposed). Never gets past an actual error, and never past a file that couldn't be read.
--yes, -yDon't ask before applying.

What push actually does

Four steps, in this order, and it stops at the first that fails:

  1. Diff. What changes on your Mimeo, per file. Steps are named by their handle (10-send-pitch) — the same thing the diagram, the logs and the traces call them. A step pointed at a different email is described in the chooser's own terms ("now uses emails/0043-x.md, shared with 3 other places") rather than as an anonymous id change, because it's the same consequential decision.
  2. Validate. Every definition, not just the changed ones. Errors block. Warnings are shown. Definitions that were already broken on your Mimeo are reported separately and don't block — you can't fix them by not pushing.
  3. Rehearse. Every changed flow is dry-run against a real person, with event details that satisfy that flow's own trigger. Nothing is sent and nothing is written.
  4. Apply. All of it or none of it, in one transaction.

Applied changes appear live on any admin page you have open — no refresh.

The two things it refuses over

A step's id is what the runs of people standing on it point at. Give a new step an id an old step had, and everyone parked there silently lands somewhere they were never sent. Nothing in a flow file shows this — an id is just a positive integer — so Mimeo compares against the definition being replaced:

CodeWhat happened
node_id_freed A new step carries an id this flow handed out and gave up in an earlier save.
node_id_repurposed The delete and the replacement are in the same file, so the id never looks free — what gives it away is that the step under it is a different kind of step than it was.

Both are warnings in the validator and both block a push. The message says how many people are parked on that id right now. The fix is almost always to remove the id from the new step and let Mimeo mint one; --force exists for the operator who knows those runs are gone.

Environment

VariableEffect
MIMEO_HOSTYour Mimeo's URL, overriding .mimeo/config.yml.
MIMEO_TOKENAn API token, overriding .mimeo/token. Read first, so a secret manager never needs a file on disk.
NO_COLORPlain output.

Media syncs too

The media library rides along with every pull and push: the files themselves land under media/, and media.yml records what each one is on your Mimeo — its hosted URL, alt text and id. Emails reference a media item by that hosted url, never by its local path.

What it touches

Only flows/, segments/, guards/, sequences/, emails/, templates/, media/, fields.yml, products.yml, themes.yml, settings.yml and media.yml — the definition files reference. Your README, your agent skills, your notes and any dotfile inside those directories are yours and are never read or removed — as is any file in media/ your Mimeo doesn't have yet, which is an upload waiting for a push.

Mimeo never touches git. Committing, branching and merging are yours; the CLI only ever talks to your Mimeo over HTTP.

See also: your manager repo · the file layout · the API underneath · MCP server · files or MCP?