# SDK CLI Reference

The RiverbankCMS SDK CLI (`riverbankcms`) manages content synchronization between local files and the CMS.

## Global Options

All commands support these options:

| Option           | Description                                                |
| ---------------- | ---------------------------------------------------------- |
| `--json`         | Output in JSON format for machine parsing                  |
| `--quiet`        | Minimal output (suppress non-essential messages)           |
| `--env <target>` | Target environment: `local` (default), `remote`, or `both` |
| `--remote`       | **[Deprecated]** Use `--env=remote` instead                |

**Environment targeting:**

- `--env=local` (default): Target local Supabase/development environment
- `--env=remote`: Target production CMS
- `--env=both`: Run against both environments sequentially

**Safety behavior:**

- Local operations execute immediately
- Remote operations default to dry-run and require `--yes` to execute
- When using `--env=both`, local runs first, then remote with the same safety rules

## Environment Variables

### Local Environment (default)

```bash
# Required
RIVERBANK_LOCAL_SITE_ID=your-site-id
RIVERBANK_LOCAL_DASHBOARD_URL=http://localhost:4000
RIVERBANK_LOCAL_MGMT_API_KEY=bld_mgmt_sk_...

# Optional
RIVERBANK_LOCAL_API_KEY=bld_live_sk_...  # For prebuild/content fetching
```

### Remote Environment (--env=remote)

```bash
# Required
RIVERBANK_REMOTE_SITE_ID=your-site-id
RIVERBANK_REMOTE_DASHBOARD_URL=https://your-dashboard.riverbankcms.com
RIVERBANK_REMOTE_MGMT_API_KEY=bld_mgmt_sk_...

# Optional
RIVERBANK_REMOTE_API_KEY=bld_live_sk_...  # Required for deploy command
```

**Notes:**

- Management API keys start with `bld_mgmt_sk_` (for write operations)
- Content API keys start with `bld_live_sk_` (for read-only operations)
- `RIVERBANK_*_SUPABASE_URL` is deprecated and ignored by media sync

---

## Content Sync Commands

### pull

Download content from the CMS to local files.

```bash
# Pull all content
riverbankcms pull

# Pull from production
riverbankcms pull --env=remote

# Download identifier-based media to content/media
riverbankcms pull --local-media

# Pull specific content types
riverbankcms pull entries              # All entries
riverbankcms pull entries blog-post    # Specific content type
riverbankcms pull entries blog-post welcome  # Specific entry
riverbankcms pull pages                # All pages with blocks
riverbankcms pull pages home           # Specific page with blocks
riverbankcms pull navigation           # Navigation menus
riverbankcms pull settings             # Site settings
riverbankcms pull forms                # Forms
riverbankcms pull theme                # Theme to content/themes/current.json
riverbankcms pull venues               # Event venues
riverbankcms pull event-categories     # Event categories
riverbankcms pull events               # Event series
riverbankcms pull --with-theme         # Pull content and theme together

# Custom output directory
riverbankcms pull --output ./src/content
```

**Options:**

| Option              | Description                                                                          |
| ------------------- | ------------------------------------------------------------------------------------ |
| `--output <dir>`    | Output directory (default: ./content)                                                |
| `--force`           | Overwrite existing files without prompting                                           |
| `--yes`             | Skip confirmation prompt                                                             |
| `--local-media`     | Download media referenced by identifiers to content/media                            |
| `--sync-media`      | Sync media files between environments                                                |
| `--overwrite-media` | When using `--sync-media`, overwrite target media on checksum mismatch               |
| `--with-theme`      | Also pull theme when pulling all content                                             |
| `--name <name>`     | Theme name for `pull theme` / `pull --with-theme` (default: current)                 |
| `--no-meta`         | Skip writing `.meta/` and media manifest files (content files still written)         |
| `--diff`            | Show human-readable field-level diff with before/after values (requires `--dry-run`) |

**Theme files:**

- `riverbankcms pull theme` writes to `content/themes/current.json` (or `contentDir/themes/current.json` if configured).
- `riverbankcms pull` does not pull theme by default. Use `riverbankcms pull theme` or `riverbankcms pull --with-theme`.

### push

Push local content changes to the CMS.

```bash
# Push all content
riverbankcms push

# Preview changes without applying
riverbankcms push --dry-run

# Push to production (requires --yes)
riverbankcms push --env=remote --yes

# Push specific content types
riverbankcms push entries              # All entries
riverbankcms push entries blog-post    # Specific content type
riverbankcms push entries blog-post welcome  # Specific entry
riverbankcms push pages                # All pages with blocks
riverbankcms push pages home           # Specific page with blocks
riverbankcms push navigation           # Navigation menus
riverbankcms push forms                # Forms
riverbankcms push theme                # Push content/themes/{activeTheme|current}.json
riverbankcms push venues               # Event venues
riverbankcms push event-categories     # Event categories
riverbankcms push events               # Event series
riverbankcms push --with-theme         # Also push theme when pushing all content

# JSON diff output for agents
riverbankcms push --dry-run --json-diff=summary
riverbankcms push --dry-run --json-diff=full
```

**Options:**

| Option                 | Description                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------ |
| `--content-dir <dir>`  | Content directory (overrides config)                                                 |
| `--dry-run`            | Show changes without applying                                                        |
| `--yes`                | Skip confirmation (required for `--env=remote` or `--env=both`)                      |
| `--force`              | Push even if remote is newer (skip stale check)                                      |
| `--force-update-asset` | Replace CMS media when identifiers conflict (local media sync only)                  |
| `--allow-truncated`    | Push even if remote content was truncated (may cause incomplete sync)                |
| `--json-diff [mode]`   | Output JSON diff: `summary` or `full`                                                |
| `--with-config`        | Also push SDK config after content                                                   |
| `--with-theme`         | Also push theme when pushing all content                                             |
| `--sync-media`         | Sync media files from local to remote environment                                    |
| `--overwrite-media`    | When using `--sync-media`, overwrite target media on checksum mismatch               |
| `--merge-remote`       | Plan an entries-only three-way merge for `--env=remote` that preserves remote edits  |
| `--delete-orphaned`    | Delete CMS entries not present in local files                                        |
| `--auto-pull-stale`    | Automatically pull stale content and retry push                                      |
| `--no-meta`            | Skip writing `.meta/` and media manifest files (content files still written)         |
| `--diff`               | Show human-readable field-level diff with before/after values (requires `--dry-run`) |
| `--delete-missing`     | **[Deprecated]** Use `--delete-orphaned` instead                                     |

**Theme files:**

- `riverbankcms push theme` reads from `content/themes/{activeTheme}.json` (falls back to `current.json`).
- `riverbankcms push` does not push theme by default (to avoid overwriting dashboard edits). Use `riverbankcms push theme` or `riverbankcms push --with-theme`.

**Delete Missing Entries:**

The `--delete-missing` flag deletes CMS entries that don't exist in your local content file, making local content the source of truth. This is useful for keeping environments exactly in sync.

```bash
# Delete CMS entries not in local file
riverbankcms push entries service-tile --delete-missing

# Preview deletes (dry-run is default for --env=remote)
riverbankcms push entries service-tile --env=remote --delete-orphaned

# Execute deletes on production
riverbankcms push entries service-tile --env=remote --yes --delete-orphaned
```

**Warning:** This is a destructive operation. Always use `--dry-run` first to preview which entries will be deleted.

**Remote-aware entry merge:**

Use `--merge-remote` when pushing entries to production and you want to preserve remote dashboard edits instead of treating local files as the whole source of truth. The CLI compares the last pulled base snapshot, local entry files, and current remote entries, then prints a merge plan. Remote runs still default to dry-run; add `--yes` only after reviewing the plan.

```bash
# Preview a merge for one content type
riverbankcms push entries blog-post --env=remote --merge-remote

# Apply after reviewing the plan
riverbankcms push entries blog-post --env=remote --merge-remote --yes

# Target a single entry
riverbankcms push entries blog-post welcome --env=remote --merge-remote --yes
```

In v1 this mode only supports `entries` with `--env=remote`. It rejects `--env=both`, non-entry scopes, `--force`, `--delete-orphaned`, and `--auto-pull-stale`.

**Stale Content Detection:**

Push compares local metadata timestamps against the remote CMS. If the remote has newer changes than your last pull, push aborts by default to prevent overwriting someone else's edits.

Options for handling stale content:

- **Interactive prompt** (default in TTY): Push asks whether to pull the stale items and retry.
- `--auto-pull-stale`: Automatically pull only the stale items and continue the push. Non-stale local content is preserved.
- `--force`: Skip stale detection entirely and push regardless.
- `--dry-run`: Stale warnings are shown but the push continues (no changes are made).

```bash
# Auto-resolve stale content without prompting
riverbankcms push --auto-pull-stale

# Useful in CI where there's no TTY for interactive prompts
riverbankcms push --auto-pull-stale --yes --env=remote
```

For theme and footer pushes, stale resolution updates only the metadata timestamp (since the local file IS the content being pushed). For entries, pages, navigation, and forms, stale resolution writes the remote version of only the stale items to disk and updates their metadata before continuing the push.

**Local Media (Identifiers):**

- Add `identifier` to media fields (slug only, no extension)
- Place files at `content/media/<identifier>.<ext>`
- Run `riverbankcms push` to upload referenced files (default-on)

**Branding workflow (`content/settings.json`):**

```json
{
  "homepageId": null,
  "seoDefaults": null,
  "logoIdentifier": "positive-play-primary-logo",
  "faviconIdentifier": "positive-play-primary-logo"
}
```

- Use `logoIdentifier` / `faviconIdentifier` to manage the site logo and favicon from the repo
- The identifiers should match files in `content/media/`
- `riverbankcms push` reuses the normal local-media upload flow before updating site settings
- `riverbankcms pull settings` warns and omits a branding field if the current CMS asset cannot be represented by an identifier yet
- Dashboard branding edits and CLI pushes are last-write-wins on the same settings row, so pull before pushing after dashboard-side changes

**Media portability (important):**

- Content JSON is portable across environments; media references must be **identifier-only**.
- The CLI writes identifier-only media objects on pull. Do not add `assetId`, `storagePath`, `storageBucket`, or `src` to your content JSON.
- `--sync-media` copies **bytes** between CMS environments (identifier + checksum verified). It does not “push entries/pages” by itself (content changes still require `push`).

**Sync Behavior** (configured in `riverbank.config.ts`):

```typescript
export default defineConfig({
  siteId: "...",
  sync: {
    existingEntries: "update", // 'skip' (default) or 'update'
  },
});
```

**Status Sync**: Push automatically syncs draft/published status based on the `status` field in your local content files. If local content is "published" but remote is "draft", push will publish it. If local is "draft" but remote is "published", push will unpublish it.

### push-config

Push SDK configuration to the CMS dashboard.

```bash
riverbankcms push-config
riverbankcms push-config --env=remote
riverbankcms push-config --config ./src/riverbank.config.ts
```

Syncs SDK schema/config surfaces such as custom blocks, block field options/extensions, content type definitions/templates, SDK-managed site settings, and footer blocks. Pages, entries, and navigation menus are synced with explicit `riverbankcms push` scopes.

This syncs:

- Custom blocks
- Block field extensions
- Block field options
- Dashboard UI configuration (e.g. navigation visibility)
- Content type definitions and templates
- SDK-managed site settings and footer blocks

**Options:**

| Option              | Description        |
| ------------------- | ------------------ |
| `--api-key <key>`   | Management API key |
| `--dashboard <url>` | Dashboard URL      |
| `--config <path>`   | Config file path   |

---

## Entry Commands

Manage content entries.

### entry upsert

Create or update an entry.

```bash
# With inline JSON data
riverbankcms entry upsert <type> <identifier> --data '{"title": "Hello World"}'

# With JSON file
riverbankcms entry upsert <type> <identifier> --file ./data.json

# With individual fields
riverbankcms entry upsert blog-post my-post \
  --slug my-post \
  --title "My Blog Post"
```

**Arguments:**

- `<type>` - Content type key (e.g., `blog-post`, `product`)
- `<identifier>` - Unique identifier for the entry

**Options:**

| Option            | Description                       |
| ----------------- | --------------------------------- |
| `--data <json>`   | Entry data as JSON string         |
| `--file <path>`   | Path to JSON file with entry data |
| `--slug <slug>`   | Entry slug                        |
| `--title <title>` | Entry title                       |

### entry publish

Publish an entry.

```bash
riverbankcms entry publish <type> <identifier>
riverbankcms entry publish blog-post my-post
```

### entry unpublish

Unpublish an entry (revert to draft).

```bash
riverbankcms entry unpublish <type> <identifier>
riverbankcms entry unpublish blog-post my-post
```

### entry get

Retrieve a single entry.

```bash
riverbankcms entry get <type> <identifier>
riverbankcms entry get blog-post my-post
riverbankcms entry get blog-post 00000000-0000-0000-0000-000000000000 --by-id
riverbankcms entry get blog-post my-post --json
```

**Options:**

| Option    | Description                                                                  |
| --------- | ---------------------------------------------------------------------------- |
| `--by-id` | Interpret `<identifier>` as an entry UUID and search within the content type |

### entry list

List entries for a content type.

```bash
riverbankcms entry list <type>
riverbankcms entry list blog-post
riverbankcms entry list blog-post --limit 10 --page 2
riverbankcms entry list blog-post --json
riverbankcms entry list blog-post --columns id,identifier,slug,status
riverbankcms entry list blog-post --columns id,identifier --status published
```

**Options:**

| Option            | Description                                                                                                                                                                                               |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `--limit <n>`     | Number of entries per page                                                                                                                                                                                |
| `--page <n>`      | Page number (1-indexed)                                                                                                                                                                                   |
| `--columns <csv>` | Comma-separated columns (e.g. `id,identifier,slug,status`). Aliases: `unpublished`→`hasUnpublishedChanges`, `updated`→`updatedAt`, `created`→`createdAt`, `published`→`publishedAt`, `type`→`contentType` |
| `--status <draft  | published>`                                                                                                                                                                                               | Filter by status (applies to the returned page only) |

---

## Page Commands

Manage pages.

### page upsert

Create or update a page.

```bash
riverbankcms page upsert <identifier> --title "Page Title" --path /url-path

# Full example
riverbankcms page upsert about \
  --title "About Us" \
  --path /about \
  --seo-title "About Us | Company Name" \
  --seo-description "Learn more about our company"
```

**Arguments:**

- `<identifier>` - Unique identifier for the page

**Options:**

| Option                     | Description               |
| -------------------------- | ------------------------- |
| `--title <title>`          | Page title                |
| `--path <path>`            | URL path (e.g., `/about`) |
| `--seo-title <title>`      | SEO title tag             |
| `--seo-description <desc>` | SEO meta description      |

### page publish

Publish a page.

```bash
riverbankcms page publish <identifier>
riverbankcms page publish about
```

### page unpublish

Unpublish a page (revert to draft).

```bash
riverbankcms page unpublish <identifier>
riverbankcms page unpublish about
```

### page get

Retrieve a single page with its blocks.

```bash
riverbankcms page get <identifier>
riverbankcms page get about
riverbankcms page get about --json
```

### page list

List all pages.

```bash
riverbankcms page list
riverbankcms page list --limit 10 --page 1
riverbankcms page list --json
```

---

## Block Commands

Manage blocks within pages.

### block upsert

Create or update a block on a page.

```bash
# Basic usage
riverbankcms block upsert <page-id> <block-id> --kind <block-kind> --data '<json>'

# Examples
riverbankcms block upsert home hero-main \
  --kind block.hero \
  --data '{"heading": "Welcome", "subheading": "to our site"}'

# With JSON file
riverbankcms block upsert home hero-main \
  --kind block.hero \
  --file ./hero-content.json

# With position
riverbankcms block upsert home new-section \
  --kind block.body-text \
  --data '{"content": "<p>Hello</p>"}' \
  --position 0
```

**Arguments:**

- `<page-id>` - Page identifier
- `<block-id>` - Block identifier (unique within the page)

**Options:**

| Option           | Description                                        |
| ---------------- | -------------------------------------------------- |
| `--kind <kind>`  | Block type (e.g., `block.hero`, `block.body-text`) |
| `--data <json>`  | Block content as JSON string                       |
| `--file <path>`  | Path to JSON file with block content               |
| `--position <n>` | Position in the block list (0-indexed)             |

### block reorder

Reorder blocks on a page.

```bash
riverbankcms block reorder <page-id> <block-id-1> <block-id-2> ...

# Example: Put hero first, then intro, then features
riverbankcms block reorder home hero-main intro-text features-grid
```

### block get

Retrieve a specific block.

```bash
riverbankcms block get <page-id> <block-id>
riverbankcms block get home hero-main
riverbankcms block get home hero-main --json
```

### block list

List all blocks on a page.

```bash
riverbankcms block list <page-id>
riverbankcms block list home
riverbankcms block list home --json
```

---

## Navigation Commands

Manage navigation menus.

### navigation upsert

Create or update a navigation menu.

```bash
# With inline JSON
riverbankcms navigation upsert <menu-name> --data '[{"label": "Home", "url": "/"}]'

# With JSON file
riverbankcms navigation upsert main --file ./main-nav.json
```

**Example menu structure:**

```json
[
  { "label": "Home", "url": "/" },
  { "label": "About", "url": "/about" },
  {
    "label": "Products",
    "url": "/products",
    "children": [
      { "label": "Category A", "url": "/products/a" },
      { "label": "Category B", "url": "/products/b" }
    ]
  }
]
```

### navigation get

Retrieve a navigation menu.

```bash
riverbankcms navigation get <menu-name>
riverbankcms navigation get main
riverbankcms navigation get main --json
```

### navigation list

List all navigation menus.

```bash
riverbankcms navigation list
riverbankcms navigation list --json
```

---

## Delete Commands

Delete content from the CMS.

### delete entry

Delete an entry.

```bash
riverbankcms delete entry <type> <identifier> --yes
riverbankcms delete entry blog-post old-post --yes
```

### delete block

Delete a block from a page.

```bash
riverbankcms delete block <page-id> <block-id> --yes
riverbankcms delete block home old-section --yes
```

**Note:** The `--yes` flag is required to confirm deletion.

---

## Utility Commands

### preview

Render a block preview.

```bash
# Print HTML to terminal
riverbankcms preview <kind> --data '<json>'

# Open in browser
riverbankcms preview block.hero --data '{"heading": "Test"}' --open

# Capture screenshot
riverbankcms preview block.hero --data '{"heading": "Test"}' --screenshot

# With custom CSS
riverbankcms preview block.hero --data '...' --css ./styles.css

# From JSON file
riverbankcms preview block.hero --file ./hero-data.json
```

**Options:**

| Option                    | Description                      |
| ------------------------- | -------------------------------- |
| `--data <json>`           | Block content as JSON            |
| `--file <path>`           | Path to JSON file                |
| `--terminal`              | Print HTML to terminal (default) |
| `--open`                  | Open in browser                  |
| `--screenshot`            | Capture screenshot               |
| `--output <path>`         | Screenshot output path           |
| `--css <paths...>`        | Additional CSS files             |
| `--validation <mode>`     | `strict` or `lenient`            |
| `--preview-stage <stage>` | `published` or `preview`         |

### identifiers backfill

Generate identifiers for content created before the SDK.

```bash
riverbankcms identifiers backfill
riverbankcms identifiers backfill --env=remote
```

Use this when migrating existing content to use SDK identifiers.

### init-docs

Scaffold agent documentation for your project.

```bash
riverbankcms init-docs
riverbankcms init-docs --path ./custom-path
riverbankcms init-docs --config ./riverbank.config.ts
```

**Creates:**

- `.riverbank/docs/` - Agent reference documentation
- `.riverbank/docs/workflows/` - Core workflow guides (always updated):
  - `create-page.md` - Creating new pages via CLI
  - `add-block.md` - Adding blocks to pages
  - `publish-workflow.md` - Publishing content safely
  - `block-extensions.md` - Adding layout variants to system blocks
  - `custom-block.md` - Creating custom blocks
  - `content-types.md` - Content types and block.embed
  - `cmsify-page.md` - Converting hard-coded pages to CMS-driven
  - `editor-workflows.md` - Building manual editor workflows for entries and pages
- `.riverbank/docs/site-workflows/` - Site-specific workflows (preserved on re-run)
- `.riverbank/docs/block-types-site.md` - Site-relevant blocks with config applied (always updated)
- `.riverbank/docs/theme-schema.md` - Theme schema reference auto-generated from Zod (always updated)

**Theme schema documentation:**

The `theme-schema.md` file is auto-generated from the actual Zod schema (`themeSchema` from `@riverbankcms/blocks`). This ensures documentation stays in sync with the schema and shows only current (non-deprecated) fields. Fields are organized by category (Core, Design Axes, Palette, Typography, etc.).

**Note:** Core workflow files are always overwritten on `init-docs` to stay current. Site-specific workflows in `site-workflows/` are never overwritten.

---

## Validation Commands

Commands for validating content integrity and comparing environments.

### audit

Validate content integrity by checking for broken references and inconsistencies.

```bash
# Audit against local CMS
riverbankcms audit

# Audit against remote CMS
riverbankcms audit --env=remote

# JSON output for CI/CD pipelines
riverbankcms audit --json
```

**Options:**

| Option                 | Description                                           |
| ---------------------- | ----------------------------------------------------- |
| `--content-dir <path>` | Content directory (default: from riverbank.config.ts) |

**Checks performed:**

- Embed blocks referencing missing entries
- Navigation internal URL paths to missing pages
- Duplicate page paths
- Orphaned entries in CMS (warning only)
- Invalid content type references
- Event/course venue/category/form reference integrity
- Local courses using read-only `completed` status (warning)

**Prerequisites:**

- Local content directory must exist (run `riverbankcms pull` first)
- Environment variables configured for target environment

**Exit codes:**

- `0`: Audit passed (may have warnings)
- `1`: Audit failed with errors

### compare

Compare content between local files and CMS, or between environments.

```bash
# Compare local files vs local CMS
riverbankcms compare entries blog-post

# Compare local files vs remote CMS
riverbankcms compare entries blog-post --env=remote

# Show detailed content diff
riverbankcms compare entries blog-post --diff

# Compare local CMS vs remote CMS
riverbankcms compare entries blog-post --local-vs-remote

# JSON output for scripts
riverbankcms compare entries blog-post --json

# Compare events/courses scopes
riverbankcms compare events
riverbankcms compare courses --env=remote
```

**Arguments:**

- `<scope>`: What to compare (`entries`, `events`, or `courses`)
- `[content-type]`: Content type to compare (required for entries)

**Options:**

| Option                 | Description                                                     |
| ---------------------- | --------------------------------------------------------------- |
| `--content-dir <path>` | Content directory (default: from riverbank.config.ts)           |
| `--diff`               | Show detailed diff for modified entries                         |
| `--local-vs-remote`    | Compare local CMS vs remote CMS (instead of local files vs CMS) |
| `--summary`            | Show only summary counts (default behavior)                     |

**Comparison modes:**

- Default: Compare local JSON files against CMS content
- `--local-vs-remote`: Compare local CMS against remote CMS (requires both env configs)

**Exit codes:**

- `0`: Content is in sync
- `1`: Differences found

### event

Manage event series directly through the CLI.

```bash
riverbankcms event list
riverbankcms event get summer-fest
riverbankcms event upsert summer-fest --file ./content/events/summer-fest.json
riverbankcms event cancel summer-fest
riverbankcms event delete summer-fest --yes
```

### course

Manage course runs directly through the CLI.

```bash
riverbankcms course list
riverbankcms course get beginner-yoga
riverbankcms course upsert beginner-yoga --file ./content/courses/beginner-yoga.json
riverbankcms course cancel beginner-yoga
riverbankcms course delete beginner-yoga --yes
```

### verify

Compare local SDK config content types against target site.

```bash
# Compare with local site
riverbankcms verify

# Compare with remote site
riverbankcms verify --env=remote

# Output as JSON
riverbankcms verify --json

# Custom config path
riverbankcms verify --config ./src/riverbank.config.ts
```

**Options:**

| Option            | Description                                          |
| ----------------- | ---------------------------------------------------- |
| `--config <path>` | Path to config file (default: ./riverbank.config.ts) |

**Output:**

- **Matched**: Content types present in both local config and target site
- **Missing on target**: Content types in local config but not on target site
- **Extra on target**: Content types on target site but not in local config

**Exit codes:**

- `0`: All content types match
- `1`: Mismatches found

---

## Deployment Commands

Commands for deploying SDK sites.

### deploy

Automates the full deploy workflow for SDK sites.

```bash
# Full deploy with cache generation
riverbankcms deploy

# Preview deploy (skip cache generation)
riverbankcms deploy --preview
```

**Options:**

| Option      | Description                                     |
| ----------- | ----------------------------------------------- |
| `--preview` | Preview deploy - skip prebuild cache generation |

**Workflow:**

1. Run verifyCommand (if configured in riverbank.config.ts)
2. Check working directory is clean (git status)
3. Generate prebuild cache (unless `--preview`)
4. Commit cache changes (squashes consecutive unpushed commits)
5. Push to remote

**Prerequisites:**

- Must be in a git repository with remote configured
- `RIVERBANK_REMOTE_API_KEY` required for prebuild cache generation
- Clean working directory (excluding prebuild output)

**Configuration (riverbank.config.ts):**

```typescript
export default defineConfig({
  siteId: "...",
  deploy: {
    verifyCommand: "pnpm verify", // Command to run before deploy
    prebuildOutput: ".riverbank-cache", // Prebuild output directory
  },
});
```

**Notes:**

- CMS failure during prebuild continues with existing cache
- Uses remote environment variables for API access
- Verification failure stops the deploy

---

## Bulk Operations

Commands for bulk content operations.

### publish-all

Publish all entries of a specific content type.

```bash
# Publish all blog posts (local)
riverbankcms publish-all blog-post

# Publish to remote (requires --yes)
riverbankcms publish-all blog-post --env=remote --yes

# Publish to both environments
riverbankcms publish-all blog-post --env=both --yes

# Preview changes
riverbankcms publish-all blog-post --dry-run

# JSON output for scripts
riverbankcms publish-all blog-post --json
```

**Arguments:**

- `<content-type>`: Content type to publish (e.g., `blog-post`, `product`)

**Options:**

| Option      | Description                                                     |
| ----------- | --------------------------------------------------------------- |
| `--yes`     | Confirm publishing (required for remote environments)           |
| `--dry-run` | Preview which entries would be published without making changes |

**Behavior:**

- Publishes entries that are in draft status or have unpublished changes
- Skips entries that are already published with no pending changes
- Continues on failure and reports all results at the end
- Requires `--yes` flag for remote environments (safety measure)

**Exit codes:**

- `0`: All entries published successfully
- `1`: Some entries failed to publish

---

## Content Type Commands

Commands for inspecting content types.

### content-type list

List content types on target site.

```bash
# List content types on local site
riverbankcms content-type list

# List content types on remote site
riverbankcms content-type list --env=remote

# Output as JSON
riverbankcms content-type list --json
```

**Output columns:**

- **Key**: Content type key (e.g., `blog-post`)
- **Name**: Display name
- **Has Pages**: Whether entries have associated pages
- **Singleton**: Whether it's a singleton content type
- **Route Pattern**: URL pattern for entry pages

---

## Common Patterns

### Creating New Content

```bash
# 1. Pull latest
riverbankcms pull

# 2. Create entry
riverbankcms entry upsert blog-post new-post --data '{"title": "New Post"}'

# 3. Create page
riverbankcms page upsert new-page --title "New Page" --path /new-page

# 4. Add blocks
riverbankcms block upsert new-page hero --kind block.hero --data '{"heading": "Welcome"}'
riverbankcms block upsert new-page body --kind block.body-text --data '{"content": "<p>...</p>"}'

# 5. Preview
riverbankcms preview block.hero --data '{"heading": "Welcome"}' --open

# 6. Publish
riverbankcms page publish new-page
```

### Updating Existing Content

```bash
# 1. Pull latest
riverbankcms pull

# 2. Edit local JSON files in ./content/
# ... make changes ...

# 3. Preview changes
riverbankcms push --dry-run

# 4. Push changes
riverbankcms push
```

### Human-Readable Diff

```bash
# Preview push changes with field-level before/after values
riverbankcms push --dry-run --diff

# Preview pull changes with field values
riverbankcms pull --dry-run --diff

# Push without updating .meta/ files (useful for focused content edits)
riverbankcms push --no-meta

# Pull content only, skip metadata (stale detection will be unreliable)
riverbankcms pull --no-meta
```

### Agent-Friendly JSON Output

```bash
# Get entry list as JSON
riverbankcms entry list blog-post --json

# Preview push diff as JSON
riverbankcms push --dry-run --json-diff=summary

# Get page with blocks as JSON
riverbankcms page get home --json
```

### Working with Production

```bash
# Pull from production
riverbankcms pull --env=remote

# Preview production push (dry-run is default for remote)
riverbankcms push --env=remote

# Push to production (requires --yes)
riverbankcms push --env=remote --yes

# Push to both local and remote
riverbankcms push --env=both --yes
```
