> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Flat-File Sync

> Edit a project as files on disk, then sync changes with the CLI

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

| Step      | Command                | Effect                                                    |
| --------- | ---------------------- | --------------------------------------------------------- |
| Check out | `metabind pull`        | Writes the project to a directory and records a baseline. |
| Edit      | any editor or agent    | Ordinary file edits.                                      |
| Preview   | `metabind push --plan` | Reports what would change. Writes nothing.                |
| Apply     | `metabind push`        | Writes the changes to the server as drafts.               |
| Release   | `metabind publish`     | Promotes drafts to published, same as in Studio.          |

`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

| Path                  | Contents                             | Hand-editable              |
| --------------------- | ------------------------------------ | -------------------------- |
| `metabind.jsonc`      | Project configuration and settings   | Yes                        |
| `mcp-instructions.md` | Instructions surfaced to MCP clients | Yes                        |
| `agent/`              | Agent configuration                  | Yes                        |
| `components/view/`    | View components                      | Yes                        |
| `components/data/`    | Data components                      | Yes                        |
| `tools/`              | Data tool definitions                | Yes                        |
| `content/`            | Content items, one file per item     | Yes                        |
| `assets/`             | Asset metadata and references        | No — edit assets in Studio |
| `metabind.resolved`   | Record of what was last synced       | No — generated             |
| `.metabind/`          | Local sync state the CLI depends on  | No                         |

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:

```bash theme={null}
metabind mv components/view/Card.ts components/view/ProductCard.ts
```

`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:

```bash theme={null}
metabind sync repair
```

`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:

```bash theme={null}
metabind inspect --dir ./cloned-project
```

`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

```bash theme={null}
metabind install --dir ./cloned-project --yes
```

`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

<CardGroup cols={2}>
  <Card title="Workflow Patterns" icon="list-checks" href="/cli/workflows">
    Build, publish, and roll back changes with the CLI.
  </Card>

  <Card title="CI Publish Lane" icon="github" href="/cli/ci-publish">
    Publish from GitHub Actions without a stored credential.
  </Card>
</CardGroup>
