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

# CLI reference

> Every suchi subcommand: serve, healthcheck, import, gc, taxonomy, doctor, mcp, demo, version.

```
suchi <subcommand> [flags]
```

All configuration is via env vars — see [config](/config).

## `suchi serve`

Runs the HTTP server. Blocks until SIGINT/SIGTERM.

* Applies embedded migrations up to the current schema version.
* Auto-loads the JD starter tree on first boot.
* Starts the durable-outbox dispatcher.
* Logs the effective egress surface at INFO.
* Listens on `LISTEN_ADDR` (default `:8000`).

## `suchi healthcheck`

Probes `LISTEN_ADDR`'s `/readyz` over loopback. Exit `0` if the server
answers `200`, non-zero otherwise. Wired as the Docker `HEALTHCHECK`
so the distroless-static image doesn't need `wget`/`curl`.

## `suchi import paperless [flags]`

Import a compatible export bundle. See [importer](/importer) for the
full walkthrough.

### Flags

| Flag                    | Required                | Purpose                                                                                                    |
| ----------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------- |
| `--from <path>`         | yes                     | Path to the exporter output dir.                                                                           |
| `--owner-email <email>` | yes, unless `--dry-run` | User that will own imported documents.                                                                     |
| `--dry-run`             | no                      | Parse + report counts without writing.                                                                     |
| `--flat`                | no                      | Every doc → inbox. Skip JD resolution.                                                                     |
| `--map-jd <path>`       | no                      | Rules YAML: source metadata → JD code.                                                                     |
| `--auto-jd`             | no                      | Apply built-in JD heuristics (deterministic keyword matches). Off by default — inbox is the safe fallback. |
| `--verify`              | no                      | Dry-diff the bundle against the live DB. No writes.                                                        |

<Info>
  Category-resolution flags (`--flat`, `--map-jd`, `--auto-jd`) are
  mutually exclusive.
</Info>

## `suchi gc [flags]`

Mark-and-sweep the CAS: walks every blob under `$DATA_DIR/blobs/`
and deletes anything **not referenced** by any `documents` row
(including trashed rows). The blob's on-disk mtime gates a grace
window — a fresh-uploaded blob whose `documents` row is still in a
pending write won't be reclaimed.

Dry-run by default. Nothing is deleted until you pass `--apply`.

### Flags

| Flag                      | Default          | Purpose                                             |
| ------------------------- | ---------------- | --------------------------------------------------- |
| `--older-than <duration>` | `720h` (30 days) | Skip blobs newer than this. Longer is safer.        |
| `--apply`                 | off              | Actually delete candidate blobs. Otherwise dry-run. |
| `--verbose`               | off              | Log every kept and every candidate blob.            |

<Info>
  Recommended cadence: nightly `suchi gc --apply` via cron once the
  instance is a few weeks old. The design doc keeps this deliberately
  manual — automatic gc on hostile data is how you lose files.
</Info>

## `suchi taxonomy merge [flags]`

Admin operation for post-import cleanup: after years of use (or a
big import), taxonomy tables accumulate near-duplicates
("BESCOM" and "Bescom", "Tax" and "TAX"). Merge picks one, moves
every reference from the other, deletes the source, and rewrites
any classifier rules that referenced the source name.

Dry-run by default. Reports how many docs would move before you
commit.

### Flags

| Flag                 | Required | Purpose                                               |
| -------------------- | -------- | ----------------------------------------------------- |
| `--kind <k>`         | yes      | One of `tag`, `correspondent`, `document_type`.       |
| `--from-name <name>` | yes      | The row to delete. Every reference moves to `--into`. |
| `--into-name <name>` | yes      | The row that absorbs the references.                  |
| `--apply`            | no       | Actually merge. Default is dry-run.                   |

Example:

```bash theme={null}
suchi taxonomy merge --kind tag \
    --from-name "BESCOM" --into-name "Bescom"

# Ready to commit?
suchi taxonomy merge --kind tag \
    --from-name "BESCOM" --into-name "Bescom" --apply
```

## `suchi doctor`

One-shot diagnostic report. Prints:

* Egress surface (every URL the running binary would call out to,
  with the config key + status)
* Optional binaries on PATH (`qpdf`, `pdftotext`, `pdftoppm`,
  `tesseract`, `ocrmypdf`, `djvutxt`, `msgconvert`, `anydoc`, …) with
  their versions
* DB schema version + whether every migration applied
* `$DATA_DIR` writability, disk-free, sub-directory presence
  (`blobs/`, `rendered/`, `backups/`)
* Operational health: last-backup age (WARN past 2× `BACKUP_INTERVAL`),
  dead-job count, oldest running job (WARN >15m), effective upload cap,
  last boot's reaper count (from the `jobs.reclaimed` audit event —
  a crash-looping box surfaces here without journalctl), CAS-shard
  subdir count, and `audit_events` row total against the retention
  window.

Non-zero exit only on hard errors. Missing optional binaries print but
don't fail — the ingest pipeline degrades gracefully. Useful for
air-gap verification and support tickets.

```sh theme={null}
suchi doctor            # human-readable
suchi doctor --json     # machine-readable
```

## `suchi mcp [flags]`

Start an MCP v2 (Model Context Protocol) server that adapts the REST
surface into MCP tools. See [MCP guide](/mcp) for the client-side
setup + tool reference.

### Flags

| Flag            | Purpose                                                                                  |
| --------------- | ---------------------------------------------------------------------------------------- |
| `--http <addr>` | HTTP+SSE listener address (e.g. `:7000`). Omit for stdio (Claude Desktop, Cursor, etc.). |
| `--url <url>`   | suchi API base URL. Overrides `SUCHI_URL` env.                                           |
| `--token <hex>` | Scoped API token. Overrides `SUCHI_TOKEN` env.                                           |

The binary also responds to `suchi-mcp` when invoked via symlink — the
argv\[0] dispatcher rewrites the command so `command: "suchi-mcp"` in a
Claude Desktop config stays clean.

Uses a scoped API token, not an admin token. Every MCP call is
attributed to that token's owner in the audit log.

## `suchi demo [flags]`

Seed `$DATA_DIR` with a small, representative dataset so a fresh
install has something to click through. See the plan doc's Phase 4.5
notes for the philosophy — "kick-tires-ready without editing a config".

### Flags

| Flag               | Purpose                                                                        |
| ------------------ | ------------------------------------------------------------------------------ |
| `--data-dir <dir>` | Override `$DATA_DIR` for this seed only. Defaults to the env value or `/data`. |

Seeds one admin user (skipped if any user exists — never clobbers
credentials), four correspondents, four document types, four tags,
three sample documents (metadata only — no CAS blobs), one classifier
rule, one automation. Idempotent — re-run without duplicates.

## `suchi refile [flags]`

The "come back and change your mind" primitive — re-run the rules
classifier + enqueue a render/move job for every live doc so a
preset swap, template edit, or new rule actually takes effect across
the existing corpus. Full walkthrough at [refile](/refile).

### Flags

| Flag              | Purpose                                                                                             |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| `--skip-rules`    | Don't re-run the classifier — enqueue render only. Use when only the storage-path template changed. |
| `--skip-render`   | Don't enqueue render jobs — re-run classifier only. Use when only rules changed.                    |
| `--owner-id <id>` | Restrict to docs owned by this user. `0` (default) = every owner.                                   |

Safe against a live server — uploads that arrive mid-sweep use the
normal postingest chain and land under the new tree automatically.

## `suchi export --out FILE.zip`

Portable takeout of everything a user owns. Writes a single zip
containing the original bytes of every live document plus a
`documents/<name>-<id>.json` sidecar in the standard suchi format
(see [formats § JSON sidecar](/formats#json-sidecar-spec)), plus
flat JSON dumps of the taxonomy tables (tags, correspondents,
document types, storage paths, custom fields, JD categories).

```sh theme={null}
suchi export --out /tmp/my-suchi.zip                 # this instance's default admin
suchi export --out /tmp/user-5.zip --owner-id 5      # scope to one owner
suchi export --out /tmp/full.zip --all               # every owner (careful — big)
```

Round-trip: dropping the archive into an fs-watch staging directory
on a fresh suchi instance re-ingests every document with title,
correspondent, tags, JD category, and sensitivity intact.

**Not included** in this version:

* Avatars, thumbnails (derived — regenerate on re-import).
* Document versions history.
* Approvals + audit history.
* Share links + saved views.

Bumps to the export format land a new `version` in `manifest.json`
so importers can gate on it.

## `suchi version`

Prints the binary version, build revision, and the Go version it
was compiled with. `--json` for scripting.
