Skip to main content
Flat-file sync lets you work on a project as files instead of only through Studio. Pull a project into a directory, edit the files with any editor or coding agent, and push the changes back. It’s a good fit for keeping a project in version control alongside the application that consumes it, or for pointing a coding agent at a project the same way it would work on source code.

How It Fits With Studio

  • The server is always the source of truth. A local directory is a checkout that can drift and needs to be reconciled.
  • Nothing is written back until a push is planned and applied.
  • Edits are detected by content, not by timestamp, so an untouched directory always reports zero changes — background recompiles and other server-side updates never show up as an edit.
  • A push that would overwrite a change made in Studio is refused, not merged. You choose how to resolve it.

The Core Loop

push only ever writes drafts. Nothing it writes is visible to your published MCP app until you run publish — the file workflow has the same draft/published separation as Studio.

Project Layout

Assets are pulled so the rest of the project can reference them, but they stay out of the default push scope — an edit to assets/assets.json is discarded rather than sent. Studio remains the place to manage asset binaries. .metabind/ holds the baseline the CLI uses to tell a local edit from a remote one. It’s not meant to be hand-edited or committed. metabind.resolved is safe — and useful — to commit; it gives you a readable record of project state over time.

Resolving Conflicts

metabind push --plan shows, per entity, whether it would be created, updated, or left unchanged, and flags anything in conflict before it writes anything. An entity that changed both in your local files and on the server — someone edited it in Studio while you were editing the same file, for example — is refused rather than merged. To resolve it:
  • Re-pull into a clean directory and reapply your edit, or
  • Run metabind push --theirs to keep the server’s version for every conflicting entity in that push.
There’s no partial apply. If any entity is in conflict, the whole push is refused, so you never end up with some changes applied and others silently dropped.

Renaming a file

If you rename a file without changing its contents, push detects the rename on its own. If you also changed the contents, push can’t tell a rename from a delete-and-create, so it stops and asks. Use metabind mv to make the rename explicit instead of guessing:
mv moves the file and updates the local sync state in the same step, so the entity keeps its id, its version history, and any published references to it. In a script, push --rename <old>=<new> does the same thing without moving the file yourself first. Renaming a tool changes its public name — anything calling it by the old name breaks, and if it’s already published, its slug won’t change to match.

Repairing Local State

If .metabind/state.json goes missing or gets corrupted — a bad merge, a partial checkout, a stray edit — push stops rather than guess which file is which entity. Rebuild it without losing local edits:
sync repair matches files to server entities by name and rebuilds the mapping, reporting anything it can’t match rather than guessing: a file with no server match, or a server entity with no local file. Add --plan to see what it would do first. A fresh metabind pull also fixes this, but it discards every uncommitted local edit, so reach for sync repair first.

Sharing a Project as Files

Two more commands round out the loop for working with a project written somewhere else — a template, a starter project, or one shared by a teammate.

Check what a directory would do

Before pushing to or installing a directory you didn’t write yourself, see what it asks for:
inspect reads a directory offline — no project context, no network call — and reports the secrets it references, the external hosts it would call, and the server-side handlers it declares. Use it before trusting a project tree from outside your organization.

Turn a directory into a project

install creates a new project from a directory and mints fresh ids for everything in it, so a tree written in another organization can’t accidentally reference something there. It refuses to run until you pass --yes to accept the capabilities inspect would show you. Pass --project <id> to install into an existing project instead of creating a new one, and --source-repo / --source-commit to record where the tree came from. Like push, install only creates drafts — publish when you’re ready to serve it.

Next Steps

Workflow Patterns

Build, publish, and roll back changes with the CLI.

CI Publish Lane

Publish from GitHub Actions without a stored credential.