# CLI reference (`fcc`)

The FetchCatch CLI syncs flows and response types between your repo and a tenant workspace.

## Global options

| Option | Env var | Description |
|--------|---------|-------------|
| `--api URL` | — | API base URL (default from `.fetchcatch/project.json` or `https://api.fetchcatch.com`) |
| `--env NAME` | — | Selects a named environment from `project.json#environments` (v2). Defaults to `defaultEnvironment`. See [environments.md](./environments.md). |
| `--token TOKEN` | `FETCHCATCH_TOKEN` | Override stored credentials for this command. |

## Provenance headers

Every CLI request automatically sets:

| Header | Source | Used by server for |
|---|---|---|
| `X-FCC-Cli-Version` | compiled-in `Program.CliVersion` | Telemetry; tagging the request as "CLI" |
| `X-FCC-Git-Commit`  | `git rev-parse HEAD` (or `FCC_GIT_COMMIT` / `GITHUB_SHA`) | Stamped onto `FlowVersions.GitCommitSha` and `ResourceVersions.GitCommitSha` |
| `X-FCC-Git-Branch`  | `git rev-parse --abbrev-ref HEAD` (or `FCC_GIT_BRANCH` / `GITHUB_REF_NAME`) | Updates `Workspaces.GitBranch` on apply/publish |
| `X-FCC-Host`        | `Environment.MachineName` (export only) | "Last pulled by …" banner in the console |

## Commands

### `fcc install [--dir PATH]`

Copies the binary to a standard location and adds it to PATH.

- Windows: `%LOCALAPPDATA%\FetchCatch\bin`
- macOS/Linux: `~/.local/bin`

### `fcc uninstall [--dir PATH]`

Removes the installed binary and PATH entry.

### `fcc init --workspace SLUG [--api-url URL]`

Creates `.fetchcatch/` in the current directory.

| Option | Env var | Description |
|--------|---------|-------------|
| `--workspace SLUG` | `FETCHCATCH_WORKSPACE` | Workspace slug (normalized to lowercase kebab-case) |
| `--api-url URL` | — | API base URL (default `https://api.fetchcatch.com`) |

Creates:

- `.fetchcatch/project.json`
- `.fetchcatch/sync-state.json`
- `.fetchcatch/flows/`
- `.fetchcatch/response-types/`
- `.fetchcatch/generated/`
- `.fetchcatch/AGENTS.md`

Does **not** download flows; run `fcc pull` after login.

### `fcc login [--email E --password P | --token TOKEN]`

Authenticates and stores credentials under `~/.fetchcatch/`.

| Env var | Purpose |
|---------|---------|
| `FETCHCATCH_TOKEN` | API token (CI) |
| `FETCHCATCH_EMAIL` | Console email (CI) |
| `FETCHCATCH_PASSWORD` | Console password (CI) |

Default (interactive): browser device flow at `{console}/cli/login`.

### `fcc logout [--api URL]`

Clears stored credentials for the API URL.

### `fcc whoami [--api URL]`

Prints current session (tenant, workspace, saved time).

### `fcc workspaces [--api URL]`

Lists workspaces available to the authenticated tenant.

### `fcc pull [--api URL]`

Downloads all flows and response types from the server into `.fetchcatch/`. Updates `sync-state.json`.

If a flow was deleted on the server (e.g. from the console), `fcc pull` also **removes** the
orphaned local file under `.fetchcatch/flows/`.

### `fcc status [--api URL]`

Compares local JSON hashes to the remote manifest. Prints change kinds:

| Kind | Meaning |
|------|---------|
| `NewLocal` | File exists locally but not on server |
| `ModifiedLocal` | Local hash differs from last known remote |
| `ModifiedRemote` | Server changed since last pull |
| `DeletedLocal` | Local file removed since last sync — will delete on server on apply |
| `DeletedRemote` | Resource removed on server — will delete local file on pull |
| `Unchanged` | In sync |

### `fcc apply [--dry-run] [--force] [--json] [--env NAME] [--api URL]`

Pushes local changes to the server. Uses optimistic concurrency via content hashes in `sync-state.json`.

- `--dry-run`: show what would be applied without writing
- `--force`: push even on conflict (CI override; local always wins)
- `--json`: machine-readable summary
- On conflict: remote changed since last sync — pull first
- **Refused** on `DesignerOnly` workspaces (HTTP 400 with remediation message).
- **Deletes flows** when the local file is gone (`DeletedLocal`) — sends `{ "delete": true }`
  to the sync API. Only **flows** support CLI deletion today.

### Deleting a flow (CLI)

```bash
rm .fetchcatch/flows/my-flow.json   # or git rm
fcc plan                            # shows DeletedLocal (-)
fcc apply                           # removes flow on server
```

After deleting in the **console**, run `fcc pull` to drop the local JSON.

### `fcc publish [PATH|SLUG|ID...] [--env NAME] [--json]`

Snapshots draft graph(s) as new published versions. The single source of truth for "ship".

- No arguments → publishes every flow with a draft.
- Arguments may be relative paths (`flows/checkout.json`), flow slugs (`checkout`), or flow ids.
- The active git commit + branch are sent via `X-FCC-Git-Commit` / `X-FCC-Git-Branch` and stored
  on the resulting `FlowVersions` row so the console history panel can render provenance.
- **Refused** on `DesignerOnly` workspaces. Allowed on `Hybrid` and `CodeManaged`.

Exit codes: `0` on success, `1` if any item errored.

### `fcc drift [--env NAME] [--json]`

CI-friendly drift report. Returns:

- Workspace governance + environment kind
- Last git commit the CLI reported + when
- Pending push / pull / conflict counts (3-way diff)
- `designerPublishesSinceLastGitCommit` — the canonical "console diverged from git" signal

Exit codes: `0` clean, `2` pending or drift, `3` conflicts, `1` error.

### `fcc version [--check]`

Prints CLI version. `--check` compares against `https://fetchcatch.com/downloads/manifest.json`.

### `fcc history PATH [--publishes] [--json]`

Version timeline for one resource. Default mode lists every snapshot
recorded by sync (every save / apply); `--publishes` (flows only) shows
only events that changed what `/v1/evaluate/{slug}` returns and marks the
live version with `*`.

Columns: `version`, `date (UTC)`, `source`, `commit` (short SHA), `who`.

```
$ fcc history flows/main-router.json --publishes
*v17    2026-05-26 14:31:02   cli-publish         a1b2c3d   ci-bot@acme.com
 v16    2026-05-25 09:12:44   designer-publish    -         alice@acme.com
 v15    2026-05-24 18:05:01   cli-publish         77abc99   ci-bot@acme.com
(* = currently live version)
```

### `fcc run RUN_ID [--json]`

Fetches a flow run by id with its full step trace. Intended for debugging
paused, failed, or completed evaluate runs — especially useful for AI agents
reviewing loose ends after `POST /v1/evaluate`.

- Requires login (`fcc login` or `FETCHCATCH_TOKEN`); does **not** require
  a local `.fetchcatch/` project unless you need `--env` workspace switching.
- `--json` returns the same shape as `GET /v1/runs/{id}` (machine-readable).

```
$ fcc run 11111111-1111-1111-1111-111111111111
Run 11111111-1111-1111-1111-111111111111
  Status:         waiting
  ...
  >>> Run is paused — loose end:
      Waiting for event: user_confirmed
      Resume with: POST /v1/runs/11111111-1111-1111-1111-111111111111/resume
```

## Exit codes

Cross-command convention (Terraform-style):

- `0` — success / in sync
- `1` — error or not logged in
- `2` — pending changes or drift (plan/status/drift only)
- `3` — conflicts (apply/plan/status/drift)

## Credentials vs project config

| Location | Contents |
|----------|----------|
| `~/.fetchcatch/credentials-*.json` | Auth tokens, tenant/workspace IDs |
| `~/.fetchcatch/workspace-bindings` (encrypted) | Directory → workspace map |
| `.fetchcatch/project.json` | Workspace slug, API URL, environments map (committed to git) |

Never commit credential files. Commit `.fetchcatch/project.json` and resource JSON.

## See also

- [governance.md](./governance.md) — the three workspace governance modes
- [environments.md](./environments.md) — multi-stage `--env` workflow
- [sync-and-ci.md](./sync-and-ci.md) — three-way merge model
