# CLI Reference

Flags-only toolkit shell with exact CLI invocations for every command.

`zever new`, `zever add`, `zever generate`, `zever extract`. See the [command table](#reference).
    `zever compile`, `check`, `breaking`, `fmt`, `doctor`, `config show`, `routes`, `explain`, `check-boundaries`, `graph`. See the [command table](#reference).
    `zever serve`, `dev`, `queue:work`, `schedule:run`, `tinker`. See the [command table](#reference) and [dev and tinker rules](#dev-and-tinker-rules).
    `zever db migrate`, `db rollback`, `db seed`. See the [command table](#reference).

## Purpose

`zever` is a flags-only toolkit shell. Every command has an exact CLI
invocation; run `zever --help` for the grouped command map.

When to use: scaffold, inspect, run, migrate, and document a Zever
project. When not to use: project code stays in Go and `.zen`; the CLI
drives it, never hosts logic.

## Prerequisites

- Install the CLI with the one-line installer (`go install .../cmd/zever@vX.Y.Z` also works from v0.7.2 on). See [Installation](https://zenta-dev.github.io/zever/start/installation/):

```sh
curl -fsSL https://raw.githubusercontent.com/zenta-dev/zever/main/install.sh | sh
```

- `zever --help` prints the grouped map (Scaffolding / Inspection /
  Runtime / Database / Operations).

## Config

Global flags apply to every command:

```sh
zever --quiet <command>     # suppress hints/tips on stderr; errors still print
zever --no-color <command>  # disable styled output
zever --json <command>      # machine-readable JSON envelope (also ZEVER_JSON=1)
zever -V                    # print the CLI version (alias for --version)
```

`zever --help --agent` prints the command map in an agent-friendly form.
Structured `--json` `data` is emitted by the inspection commands
(`compile`, `check`, `explain`, `doctor`, `routes`, `config show`,
`graph`, `breaking`, `check-boundaries`) plus `outbox`, `upgrade`, and
`uninstall`; every other command emits a JSON error envelope on failure.
`doctor --json` reports `ok:false` with a nonzero exit when any battery
fails.
Most commands that write files or touch the database (`new`, `add`,
`extract`, `generate *`, `db migrate`, `db rollback`, `upgrade`,
`uninstall`) accept `--dry-run` to preview without applying.

`--no-color` is also honored via ambient `NO_COLOR` / `TERM=dumb`. Guided
prompts for one-shot commands: `-i` / `--interactive` (before or after the
subcommand) or `ZEVER_INTERACTIVE=1|true|yes` enables `huh` prompts.
`zever <command> -h` always prints flags without running anything.

Bare-command contract: bare `zever` (no subcommand, TTY or not) prints
usage to stderr plus `zever: missing subcommand` and exits 1, so scripts
never hang. All errors go to stderr; stdout stays clean for command
output.

## Resolve

No resolver step: pick the command, pass flags, check the exit code.

| Code | Meaning |
|---|---|
| `0` | success |
| `1` | runtime error (message on stderr) |
| `2` | flag misuse (error on stderr, no usage dump) |

`--help` output goes to stdout; errors and bare-invocation usage go to
stderr.

## Runnable example

```sh
zever --help
zever completion bash > /tmp/zever.bash
zever docs --dir /tmp/zever-docs
ls /tmp/zever-docs
echo exit:$?
```

Expected output:

```text
grouped command map on stdout (Scaffolding / Inspection / Runtime / Database / Operations)
completion script at /tmp/zever.bash
one man page plus one markdown file per command under /tmp/zever-docs
exit:0
```

Schema loop example:

```sh
zever fmt --write schema/
zever check schema/
zever compile --out ./generated
echo exit:$?
```

Expected output:

```text
fmt: normalized files listed, if any
check: silent on success
compile: per-backend output under ./generated
exit:0
```

## Reference

| Group | Equivalent CLI |
|---|---|
| Scaffold | `zever new` (battery picker adds beyond the `log, router` floor; `--profile minimal\|api\|full` presets) |
| Scaffold | `zever add <battery>[/<adapter>]` (adds a battery to an existing project; `zever add -h` prints flags) |
| Scaffold | `zever generate` |
| Scaffold | `zever generate tinker` |
| Scaffold | `zever extract` |
| Inspect | `zever compile` (`--check` gates drift: exit 1 when committed output differs; runs `go mod tidy` when generated code imports modules `go.mod` lacks, skip with `--no-tidy`) |
| Inspect | `zever check` |
| Inspect | `zever breaking` |
| Inspect | `zever fmt` |
| Inspect | `zever doctor` |
| Inspect | `zever config show` |
| Inspect | `zever routes` |
| Inspect | `zever explain` |
| Inspect | `zever check-boundaries` |
| Inspect | `zever graph` |
| Runtime | `zever serve` |
| Runtime | `zever dev` |
| Runtime | `zever queue:work` |
| Runtime | `zever schedule:run` |
| Runtime | `zever tinker` |
| Database | `zever db migrate` |
| Database | `zever db rollback` |
| Database | `zever db seed` |
| Operations | `zever outbox` (`status`, `dlq list`, `dlq requeue`, `dlq purge`, `purge`; see [Outbox Ops](https://zenta-dev.github.io/zever/guides/background/outbox-ops/)) |
| Operations | `zever uninstall` (remove the `zever` and `zever-lsp` binaries; `--dry-run`, `--keep-lsp`, `--yes`/`--force`) |
| Operations | `zever upgrade` (upgrade the `zever` binary to the latest release; `--version`, `--check`, `--dry-run`, `--yes`/`--force`) |
| Tooling | `zever completion <bash\|zsh\|fish\|powershell>` |
| Tooling | `zever docs --dir <dir>` |

| Flag | Effect |
|---|---|
| `--quiet` | suppress hints/tips on stderr |
| `--no-color` | disable styled output |
| `--json` | machine-readable JSON envelope output (also `ZEVER_JSON=1`) |
| `-V` | print the CLI version (alias for `--version`) |
| `--dry-run` | preview file edits / SQL / removals without applying (where supported) |
| `-i`, `--interactive` | guided `huh` prompts for one-shot commands |
| `--batteries a,b` | `zever new`: extra batteries to scaffold beyond the floor (skips the battery prompt) |
| `--profile minimal\|api\|full` | `zever new`: start-small preset (explicit `--batteries` add to it) |
| `--check` | `zever compile`: verify committed output matches a fresh compile, write nothing (exit 1 on drift) |
| `--no-tidy` | `zever compile`: print a hint instead of running `go mod tidy` when go.mod misses modules the generated code imports |
| `--adapters b=a,...` | `zever new`: per-battery adapter overrides (implies the battery, skips its adapter prompt) |
| `-y`, `--yes` | `zever new`: skip all prompts, scaffold floor plus flags only |
| `--list-batteries` | `zever new`: print the battery/default-adapter table to stdout and exit |
| `--module PATH` | `zever new`: Go module path for the new project (default: the app name itself) |
| `--dir PATH` | `zever new`: output directory (default `./<name>`) |
| `--framework-version V` | `zever new`: depend on a published Zever version instead of a local replace directive |
| `--force` | `zever new`: scaffold into a non-empty directory anyway |
| `-h` | print flags without running |

### `zever add`

Adds one core battery to an existing project. Synopsis (exactly one
positional, no prompting):

```sh
zever add <battery>[/<adapter>] [--adapter NAME] [--force] [--module PATH[@VERSION]] [--dry-run]
```

`--adapter` overrides the slash form, `--force` overwrites an existing
`wiring.go` registration, `--module` names a plugin battery's Go module
(required for plugin batteries), and `--dry-run` prints the edits
without writing them.

The adapter may be omitted (`zever add cache` selects
`config.Default()`'s own pick, e.g. `memory`) or pinned explicitly
(`zever add cache/redis`). Empty halves, extra slashes, and unknown
batteries are errors. Run it from the project root (the directory
holding `go.mod`); without one it fails.

Effects (two append-only edits, never overwriting hand-written code):

- `go.mod`: adds `require` entries for the battery's core and adapter
  modules at the version pinned by the framework require (falling back
  to the CLI's built-in framework version). For local checkouts (a
  `replace github.com/zenta-dev/zever => <local-dir>` marker), matching
  local replaces are derived for both modules. Paths already required
  (any version) or already replaced are left untouched.
- `internal/app/app.go`: splices in the adapter's named import plus its
  `Register()` call (gofmt-normalized). Either half already present is
  skipped, so re-adding the same battery is a no-op. Fails if the file
  has no import block or no `func New`, scaffold it with
  `zever generate server` first.

`zever add` does not run `go mod tidy`, run it afterwards so `go.sum`
catches up, then serve:

```sh
zever add cache/redis
go mod tidy
zever serve
```

### `zever outbox`

Inspects and repairs the outbox dead-letter queue without starting the
relay. Every subcommand takes `--dsn` and `--table`;
without `--dsn`/`--table` the values come from environment variables
(`OUTBOX_DSN`, `OUTBOX_TABLE`) plus environment overrides. `--json` gives
machine-readable output on every one.

| Command | Effect |
|---|---|
| `zever outbox status` | Relay counters (`pending`, `processed`, `failed`, `last_error`, `stalled`) |
| `zever outbox dlq list [--limit N]` | Failed messages, oldest first (`0` uses the adapter default page size) |
| `zever outbox dlq requeue --id X` | Requeue one failed message, resetting its attempt count and lock |
| `zever outbox dlq requeue --all` | Requeue every failed message |
| `zever outbox dlq purge --id X` | Delete one failed message by id |
| `zever outbox purge --before 168h` | Delete processed messages older than the given duration |

`--id` and `--all` on `requeue` are mutually exclusive and exactly one
is required. `purge --before` takes a Go duration and must be
non-negative. `dlq purge` needs an adapter that implements
`outbox.Deleter`; only `db` does, so an unsupported adapter reports
`does not support message deletion` rather than deleting nothing. Run
these from a deploy box with database access, not from every replica.
Metrics, alert rules, and the full runbook are in
[Outbox Ops](https://zenta-dev.github.io/zever/guides/background/outbox-ops/).

### `zever uninstall`

Removes the running `zever` binary (resolved via `os.Executable()`,
symlinks followed) plus every `zever-lsp` binary found on `PATH`.
Binaries only: projects, caches, profiles, and config are never touched.

```sh
zever uninstall --dry-run        # print the removal plan, delete nothing
zever uninstall --yes            # confirm without prompting
zever uninstall --keep-lsp --yes # leave zever-lsp in place
```

Without `--yes`/`--force`, a terminal gets a `[y/N]` prompt defaulting
to No; without a terminal the command fails and prints the exact
`zever uninstall --yes` re-run. On Windows the running binary cannot
delete itself, so self-delete becomes a printed `del "<path>"` step
while `zever-lsp` removals stay automatic. `--json` emits the
machine-readable envelope instead of the human plan.

### `zever upgrade`

Upgrades the running `zever` binary to the latest stable release (or
`--version X` for an explicit target). The current version is the
compiled `cliVersion`; the default target comes from
`api.github.com/repos/zenta-dev/zever/releases/latest`.

```sh
zever upgrade --check              # print the available version, exit 0
zever upgrade --dry-run            # print the upgrade plan, download nothing
zever upgrade --yes                # confirm without prompting
zever upgrade --version v0.7.0 --yes
```

Versions compare with `golang.org/x/mod/semver`: an already-current
target prints `already current` and exits 0, and a target older than
the installed binary refuses the downgrade unless `--version`
requested it explicitly. The `runtime.GOOS`/`runtime.GOARCH` asset
(`.exe` suffixed on Windows) plus `SHA256SUMS.txt` downloads from the
release, the asset is verified with `crypto/sha256`, and any mismatch
or network error aborts before anything is replaced. POSIX installs
atomically (temp file in the binary directory, `chmod +x`, rename over
the running binary); Windows stages `zever.new.exe` beside the binary
and spawns a detached `cmd /C` helper that moves it into place after
our PID exits — restart the shell to complete. Confirmation follows
the same TTY rules as `uninstall`; `--json` emits the envelope.

### Dev and tinker rules

- `zever dev` is local watch-only: it prints
  `zever dev: watching <schemaDir> and <serverEntry> … (Ctrl-C to stop)`
  to stdout and restarts the server entrypoint on change. Ctrl-C stops the
  watcher and the server. Never a deployment path.
- `zever tinker` is dev-only: every start prints
  `WARNING: Zever tinker is development-only: it evaluates arbitrary Go
  against a live container, so run it against a development database only.`
  to stderr. The REPL talks to the real container via the per-project shim
  (`project.tinker_entry`, default `cmd/tinker-shim`; scaffold with
  `zever generate tinker`). Never point it at production data.

### Shell completion and generated docs

- `zever completion <shell>` prints that shell's completion script to
  stdout; redirect into the completions dir, e.g.
  `zever completion bash > /etc/bash_completion.d/zever`. The scripts
  complete dynamically: `.zen` files for the schema commands, the
  `generate` kinds, `--backend` (comma lists), `--profile`, `--adapters`
  (`battery=adapter` for `new`, `battery` or `battery/adapter` for `build`).
- `zever docs --dir <dir>` writes one man page plus one markdown file per
  command into `<dir>`; build stripped release binaries with
  `make build-release` (`-trimpath -ldflags="-s -w"`).
- `migrate` / `rollback` mask the DSN (`--dsn ***`) in display and output.

## Production notes

- Script against exit codes, not output text: `0` / `1` / `2` are the
  contract; hint wording may change (and `--quiet` suppresses hints).
- Keep stdout parseable: errors never touch stdout, so pipes and
  `$(...)` capture stay clean.
- `dev` and `tinker` never run in prod: `dev` is watch-only, `tinker`
  evaluates arbitrary Go. Gate both out of deployment images.
- Pin the installed CLI version to the repo release; flag surfaces move
  with releases.

## Troubleshooting

- **Bare `zever` exits 1**: expected; it prints usage to stderr with
  `zever: missing subcommand`. Pass a subcommand or `--help`.
- **Exit 2 with no usage dump**: flag misuse. Re-check flag spelling with
  `zever <command> -h`; only the error prints.
- **`tinker` warns on every start**: by design, the dev-only warning goes
  to stderr each launch. Do not silence it; do not aim it at prod data.
- **`dev` does not restart on edits**: it watches the schema dir and the
  server entrypoint only. Edits outside those paths need a manual restart.
- **Styled output garbles CI logs**: pass `--no-color` or set
  `NO_COLOR=1`; `TERM=dumb` is honored the same way.
- **`zever outbox` reports empty counters**: the resolved `--table` does
  not match the table the relay writes. Compare against
  `OUTBOX_TABLE` environment variable.
- **`zever outbox dlq purge` says the adapter does not support deletion**:
  only the `db` adapter implements `outbox.Deleter`. Switch the
  connection, not the command.

## See also

- [Syntax](https://zenta-dev.github.io/zever/reference/zen-syntax/) for the schema files inspected commands read
- [LSP and Tooling](https://zenta-dev.github.io/zever/guides/extend/editor-setup/) for editor-side inspection
- [Config Reference](https://zenta-dev.github.io/zever/reference/config/) for `config show` output
- [Backends](https://zenta-dev.github.io/zever/concepts/backends/) for `compile` outputs
- [Outbox Ops](https://zenta-dev.github.io/zever/guides/background/outbox-ops/) for `zever outbox` in context
