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

# Commands

> Complete reference for all MDCMS CLI commands

## `mdcms init`

Interactive wizard that bootstraps a new MDCMS project from an existing repository.

```bash theme={null}
mdcms init
```

The wizard runs through the following steps:

<Steps>
  <Step title="Server URL">
    Prompts for the MDCMS server URL and validates it with a health check.
  </Step>

  <Step title="Project selection">
    Lists existing projects on the server or creates a new one.
  </Step>

  <Step title="OAuth login">
    Opens a browser window for authentication using the device flow (same
    mechanism as `mdcms login`).
  </Step>

  <Step title="Environment selection">
    Choose an existing environment or create one (e.g. `development`, `staging`).
  </Step>

  <Step title="Directory scanning">
    Recursively scans the repository for `.md` and `.mdx` files and groups them by
    top-level content directories.
  </Step>

  <Step title="Locale detection">
    Analyzes file naming patterns to detect locale suffixes (e.g. `post.en.mdx`,
    `post.fr.mdx`) and infers default/supported locale configuration.
  </Step>

  <Step title="Schema inference">
    Parses frontmatter from discovered files to infer content types and their
    field schemas using Zod types.
  </Step>

  <Step title="Config generation">
    Writes `mdcms.config.ts` with `defineConfig` and `defineType` calls reflecting
    all discovered types, directories, and locale settings.
  </Step>

  <Step title="Schema sync">
    Uploads the inferred schema to the server for the selected
    project/environment.
  </Step>

  <Step title="Content push">
    Pushes all discovered content files to the server as draft documents and
    writes the initial manifest.
  </Step>

  <Step title=".gitignore update">
    Appends `.mdcms/` and manifest paths to `.gitignore`.
  </Step>

  <Step title="Untrack managed files">
    Runs `git rm -r --cached` on any managed files that were previously committed to git.
  </Step>
</Steps>

<Note>
  Running `mdcms init` in a repository that already has an `mdcms.config.ts`
  will prompt before overwriting.
</Note>

***

## `mdcms login`

Authenticate with the MDCMS server using a browser-based OAuth flow and store credentials locally.

```bash theme={null}
mdcms login
```

<Steps>
  <Step title="Start challenge">
    The CLI sends a login challenge to the server with a cryptographic state parameter and a loopback redirect URI.
  </Step>

  <Step title="Browser authentication">
    Your default browser opens the server's authorization page. Complete the login
    there.
  </Step>

  <Step title="Receive callback">
    The CLI listens on a local port for the OAuth callback. The browser redirects
    back with an authorization code.
  </Step>

  <Step title="Exchange for API key">
    The CLI exchanges the authorization code for a scoped API key.
  </Step>

  <Step title="Store credentials">
    The API key is stored in the local credential store, scoped to the current server/project/environment tuple.
  </Step>
</Steps>

### Credential storage

Credentials are stored per server/project/environment combination:

* **macOS**: OS Keychain via the `security` CLI (service: `mdcms-cli`), with file-based fallback
* **Other platforms**: `~/.mdcms/credentials.json` with `0600` permissions

### Authentication precedence

When resolving an API key, the CLI checks these sources in order:

1. `--api-key` flag
2. `MDCMS_API_KEY` environment variable
3. Stored credential profile (from `mdcms login`)

### Default scopes

The login flow requests the following scopes:

```
projects:read, projects:write, schema:read, schema:write,
content:read, content:read:draft, content:write, content:delete
```

***

## `mdcms logout`

Revoke the stored API key and clear local credentials for the current server/project/environment tuple.

```bash theme={null}
mdcms logout
```

The CLI attempts to revoke the API key on the server as a best-effort operation. Even if the remote revocation fails (e.g. the server is unreachable), the local credential profile is always removed.

***

## `mdcms push`

Upload local content changes to the MDCMS server.

```bash theme={null}
mdcms push [--force] [--dry-run] [--validate] [--published]
```

| Flag          | Description                                                         |
| ------------- | ------------------------------------------------------------------- |
| `--force`     | Skip all interactive prompts; auto-select all new and deleted files |
| `--dry-run`   | Show the push plan without making any API writes                    |
| `--validate`  | Validate frontmatter against the local schema before pushing        |
| `--published` | Reserved for future use                                             |

### How push works

1. **Load manifest** — Reads `.mdcms.manifest.json` to determine which documents are tracked locally.
2. **Hash-based change detection** — Computes a content hash for each tracked file and compares against the manifest. Only changed files are included in the push plan.
3. **New file detection** — Scans content directories for untracked `.md`/`.mdx` files not yet in the manifest. In interactive mode, you select which new files to upload.
4. **Deletion detection** — Files present in the manifest but missing from disk are flagged as candidates for server-side deletion.
5. **Plan summary** — The CLI prints a summary of changes, new files, and deletions before writing anything.
6. **Confirmation** — Destructive changes (deletions, overwrites) require explicit confirmation unless `--force` is passed.
7. **Execute** — Changed files are uploaded, new documents are created, and deleted documents are removed on the server.
8. **Update manifest** — The local manifest is updated with new document IDs, revision numbers, and hashes.

### Concurrency control

Push uses optimistic concurrency via the `draftRevision` field. If the server's current revision does not match the manifest's recorded revision, the push for that document is rejected. Run `mdcms pull` to reconcile before retrying.

<Warning>
  Push requires a valid schema hash from a previous `mdcms schema sync`. If the
  schema has never been synced or the local hash is missing, the command will
  fail.
</Warning>

***

## `mdcms pull`

Download content from the MDCMS server to your local filesystem.

```bash theme={null}
mdcms pull [--published] [--force] [--dry-run]
```

| Flag          | Description                                            |
| ------------- | ------------------------------------------------------ |
| `--published` | Pull published snapshots instead of draft heads        |
| `--force`     | Skip overwrite confirmation for locally modified files |
| `--dry-run`   | Show the pull plan without writing any files           |

### Change categories

The pull command classifies each document into one of these categories:

| Category              | Behavior                                                                                  |
| --------------------- | ----------------------------------------------------------------------------------------- |
| **Both Modified**     | Local and server changes detected. Prompts for confirmation before overwriting            |
| **Server Modified**   | Server has newer content. File is updated automatically                                   |
| **Locally Modified**  | Only local changes exist. File is skipped (not overwritten)                               |
| **New**               | Document exists on server but not locally. File is created                                |
| **Moved/Renamed**     | Server path differs from manifest path. File is moved to the new location                 |
| **Deleted on Server** | Document was removed server-side. Prompts for confirmation before deleting the local file |
| **Unknown Type**      | Document type has no matching config entry. Skipped with a warning                        |
| **Unchanged**         | Content hashes match. No action taken                                                     |

<Note>
  Use `--force` to skip confirmation prompts in non-interactive environments
  (e.g. CI pipelines). Locally modified files will be overwritten.
</Note>

***

## `mdcms schema sync`

Upload the local schema definition to the MDCMS server.

```bash theme={null}
mdcms schema sync
```

This command:

1. Parses `mdcms.config.ts` and resolves all type definitions
2. Applies environment-specific overlays if an `environments` block is defined in the config
3. Builds a schema sync payload and uploads it to the server via `PUT /api/v1/schema`
4. Persists the returned `schemaHash` to `.mdcms/schema/<project>.<environment>.json`

The schema hash is required by `mdcms push` to ensure content is validated against the correct schema version.

### Overrides

Schema sync respects the standard `--project` and `--environment` global flags:

```bash theme={null}
mdcms schema sync --environment staging
```

<Warning>
  At least one content type must be defined in `mdcms.config.ts` before running
  schema sync. The command will fail with a `NO_TYPES_DEFINED` error if the
  `types` array is empty.
</Warning>

***

## `mdcms status`

Compare local content and schema state against the server.

```bash theme={null}
mdcms status
```

The status command reports:

* **Content drift** — Documents that have been modified locally, modified on the server, or are out of sync
* **Schema drift** — Whether the local schema hash matches the server's current schema

### Drift categories

| Category             | Description                                              |
| -------------------- | -------------------------------------------------------- |
| `modified_on_server` | Server has newer content than the local manifest records |
| `modified_locally`   | Local file has changed since last push/pull              |
| `both_modified`      | Both local and server content have diverged              |
| `new_on_server`      | Document exists on server but not in the local manifest  |
| `deleted_on_server`  | Document is in the manifest but no longer on the server  |
| `moved_renamed`      | Server path differs from the manifest path               |
| `unchanged`          | Everything is in sync                                    |

### Exit codes

| Code | Meaning                            |
| ---- | ---------------------------------- |
| `0`  | Everything is in sync              |
| `1`  | Drift detected (content or schema) |

<Tip>
  Use `mdcms status` in CI pipelines as a gate. A non-zero exit code can block
  deployments when content or schema is out of sync.
</Tip>

***

## `mdcms migrate`

Generate and apply content migrations when the schema changes.

```bash theme={null}
mdcms migrate [--apply]
```

| Flag      | Description                                                   |
| --------- | ------------------------------------------------------------- |
| `--apply` | Execute the generated migration instead of just previewing it |

### How migrations work

1. **Detect schema changes** — Compares the current `mdcms.config.ts` types against the server's active schema
2. **Generate transforms** — Creates per-document migration operations (e.g. adding default values for new required fields, renaming fields)
3. **Preview** — Without `--apply`, the CLI prints a summary of what would change
4. **Apply** — With `--apply`, each document is transformed and pushed as a new draft revision. If the document was previously published, a new version is auto-published

<Note>
  Migrations are forward-only. Always review the preview output before running
  with `--apply`.
</Note>
