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

# CLI

> Look up every decktalk command, its options, its output and its exit codes.

The `decktalk` command runs each stage on its own, or the whole pipeline with `decktalk build`.
This page lists every command with its options, and it is generated from the parser, so a flag on
this page is a flag the command takes.

## Global options

These work with every command, before or after the command name.

| Option                            | Meaning                                                                                                                      |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `-p PROJECT`, `--project PROJECT` | The project directory. Defaults to `DECKTALK_PROJECT`, then the current directory. `init`, `install` and `doctor` ignore it. |
| `-v`, `--verbose`                 | Debug logging on stderr, including every ffmpeg command line and the traceback of a bug.                                     |
| `-q`, `--quiet`                   | Warnings and errors only on stderr.                                                                                          |
| `--json`                          | Print one JSON envelope on stdout and nothing else there. Every log line goes to stderr.                                     |
| `--strict`                        | An uncertain finding fails as a certain one does. Only on a command that can report one.                                     |
| `--exit-zero`                     | Exit 0 whatever was found, for a caller that reads the envelope itself. It never hides an error.                             |
| `--version`                       | Print the version and exit 0.                                                                                                |
| `-h`, `--help`                    | Print the usage and exit 0.                                                                                                  |

A `--only` value is a section number, a list or a range: `--only 3`, `--only 3,5`, `--only 7-9`.
The flag repeats, and the values gather into one list.

## Environment variables

| Variable                                    | Default             | Meaning                                                                                                                                                                   |
| ------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DECKTALK_PROJECT`                          | none                | Default project directory.                                                                                                                                                |
| `DECKTALK_CONFIG`                           | per platform, below | Per-machine settings file.                                                                                                                                                |
| `DECKTALK_CACHE_DIR`                        | per platform, below | ffmpeg cache. Playwright keeps Chromium in its own cache.                                                                                                                 |
| `DECKTALK_FFMPEG`, `DECKTALK_FFPROBE`       | none                | Paths to your own binaries. Set both. They win over the pinned build and `PATH`.                                                                                          |
| `DECKTALK_<TABLE>_<FIELD>`                  | none                | One tuning field, such as `DECKTALK_VIDEO_PRESET=veryfast`.                                                                                                               |
| `DECKTALK_ALLOW_ANY_API_BASE`               | unset               | Lets `[elevenlabs] api_base` name any host, for a local mock of the API. It is a switch and never a secret, and without it the key goes only to an https ElevenLabs host. |
| `ELEVENLABS_API_KEY`, `ELEVENLABS_VOICE_ID` | none                | Speech provider secrets. Also read from `.env`.                                                                                                                           |

| Default path         | Linux                                                                              | macOS                                                  | Windows                            |
| -------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------ | ---------------------------------- |
| `DECKTALK_CONFIG`    | `$XDG_CONFIG_HOME/decktalk/decktalk.toml`, else `~/.config/decktalk/decktalk.toml` | `~/Library/Application Support/decktalk/decktalk.toml` | `%APPDATA%\decktalk\decktalk.toml` |
| `DECKTALK_CACHE_DIR` | `$XDG_CACHE_HOME/decktalk`, else `~/.cache/decktalk`                               | `~/Library/Caches/decktalk`                            | `%LOCALAPPDATA%\decktalk`          |

Note: a key value that starts with `<` counts as unset, so the placeholders in `.env.example` never
reach the provider. No value of any variable on this page is printed, logged or put in a payload. [Configuration](/reference/configuration) lists every tuning field.

## Exit codes

| Code | Meaning                                                            | How a caller tells                                       |
| ---- | ------------------------------------------------------------------ | -------------------------------------------------------- |
| 0    | The command ran and found nothing, or `--exit-zero` was passed.    | `ok` is true, or `exit_code` is 0 with findings present. |
| 1    | The command ran and found something.                               | `error` is null and a findings count is above zero.      |
| 2    | A usage error: an unknown command, an unknown flag or a bad value. | `error.code` is `USAGE`.                                 |
| 3    | DeckTalk itself could not run. Stop and tell the user.             | `error` is not null and names the error class.           |
| 130  | The run was interrupted. No envelope is promised.                  | The process was signalled.                               |

A non-zero exit with `error: null` is a finding, and the project is what to fix. A non-null
`error.code` is an error, and the run stops.

## The `--json` envelope

Every command prints exactly one object on stdout under `--json`, and an error prints it too.

| Field       | Type           | Meaning                                                                           |
| ----------- | -------------- | --------------------------------------------------------------------------------- |
| `schema`    | integer        | The envelope's shape version, 1 today. It moves only when the shape changes.      |
| `version`   | string         | The installed DeckTalk version.                                                   |
| `command`   | string         | The command as typed.                                                             |
| `ok`        | boolean        | True when the command found nothing and raised nothing. It ignores `--exit-zero`. |
| `exit_code` | integer        | The code the process is about to return.                                          |
| `summary`   | object         | The counts that lead the output. The keys are the command's own.                  |
| `findings`  | object         | `certain`, `uncertain` and `items`, the rows.                                     |
| `written`   | array          | Every file the command wrote, project-relative, in the order written.             |
| `error`     | object or null | `code`, `message`, `hint`, `path` and `line`. Null on success and on a finding.   |
| `<command>` | object         | The command's own payload, under the first word of its name.                      |

`findings.items[]` has one shape on every command, and the certain rows lead it.

| Key       | Type            | Meaning                                                                                                                                                |
| --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `code`    | string          | The verdict code, such as `OFF_CUE`. Match on this. `MISSING` is a file that is not there and `UNREADABLE` is a file that is there and does not parse. |
| `label`   | string          | The printed label, such as `OFF CUE`. Nothing parses it.                                                                                               |
| `certain` | boolean         | True when the finding is certain.                                                                                                                      |
| `section` | integer or null | The section number.                                                                                                                                    |
| `cue`     | string or null  | The cue id.                                                                                                                                            |
| `where`   | string or null  | The file, page or artifact the row is about.                                                                                                           |
| `detail`  | string or null  | One sentence, with any measured number in it.                                                                                                          |

## The progress log

`decktalk build` truncates and then appends JSON Lines to `build/progress.jsonl`, relocatable with
`--progress PATH`, so a caller polls a file instead of tailing a log.

| Key           | Type            | Meaning                                                               |
| ------------- | --------------- | --------------------------------------------------------------------- |
| `ts`          | string          | The event time, as an ISO 8601 timestamp.                             |
| `pid`         | integer         | The process running the build, which is how `status` answers `alive`. |
| `stage`       | string          | A stage this run executes, named as `build` runs it.                  |
| `stage_index` | integer         | The stage's place in this run, counting from 1.                       |
| `stage_count` | integer         | How many stages this run will execute.                                |
| `section`     | integer or null | The section the event is about.                                       |
| `event`       | string          | `start`, `done`, `skip` or `fail`.                                    |
| `detail`      | string or null  | One sentence of detail.                                               |

`decktalk status --json` reads `build/progress.jsonl` and reports `run`, so a caller polls one
command instead of tailing a log. It is null when no build has written a log there, which is also
what a build started with `--progress PATH` leaves behind.

| Key              | Type            | Meaning                                                                    |
| ---------------- | --------------- | -------------------------------------------------------------------------- |
| `pid`            | integer or null | The process that wrote the log.                                            |
| `started`        | string or null  | When the run began.                                                        |
| `stage`          | string or null  | The stage the last event named.                                            |
| `sections_done`  | integer or null | Sections finished, and null until a stage reports per section.             |
| `sections_total` | integer or null | Sections the run will do, and null for the same reason.                    |
| `alive`          | boolean         | True while the run is unfinished and its process is still on this machine. |

## One machine

### `decktalk init`

Create a project: decktalk.toml, script.md, cues.json, a deck page and the runtime.

```text theme={null}
decktalk init [-h] [--name NAME] [--force] [--example NAME] [--no-skills] [-v] [-q] [--json] dir
```

| Option        | Default | Meaning                                                                                          |
| ------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `DIR`         |         | the directory to create, with a working starter deck                                             |
| `--name`      |         | project name (default: the directory name)                                                       |
| `--force`     | off     | write into a non-empty directory                                                                 |
| `--example`   |         | write a packaged example instead of the starter: lesson, product (reserved), tutorial (reserved) |
| `--no-skills` | off     | do not write the packaged skills into the project                                                |

It also takes `--json`, `-v` and `-q`.

### `decktalk install`

Fetch headless Chromium and ffmpeg, once per machine.

```text theme={null}
decktalk install [-h] [-v] [-q] [--json]
```

It also takes `--json`, `-v` and `-q`.

### `decktalk doctor`

Report what is installed and which build a run would use.

```text theme={null}
decktalk doctor [-h] [--report] [-v] [-q] [--json] [--exit-zero]
```

| Option     | Default | Meaning                                              |
| ---------- | ------- | ---------------------------------------------------- |
| `--report` | off     | print a pasteable environment block, with no secrets |

It also takes `--json`, `-v`, `-q` and `--exit-zero`.

## Before a build

### `decktalk status`

Report what the four input files say, what is built, what disagrees and whether a build runs.

```text theme={null}
decktalk status [-h] [-v] [-q] [--json] [--project PROJECT] [--exit-zero]
```

It also takes `-p`, `--json`, `-v`, `-q` and `--exit-zero`.

### `decktalk preflight`

Estimate the takes, resolve the cues and freeze every reveal, spending nothing.

```text theme={null}
decktalk preflight [-h] [--only N] [--no-frames] [--model MODEL] [--allow-unknown-cues] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero]
```

| Option                 | Default | Meaning                                                                       |
| ---------------------- | ------- | ----------------------------------------------------------------------------- |
| `--only`               |         | only these sections: 3, 3,5 or 7-9, and the flag repeats                      |
| `--no-frames`          | off     | skip the frozen frames, so no browser starts                                  |
| `--model`              |         | speech model to check the narration cache for                                 |
| `--allow-unknown-cues` | off     | continue when a cue id in cues.json appears nowhere in the page that plays it |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

### `decktalk words`

Print each spoken section's words, in seconds after the section starts.

```text theme={null}
decktalk words [-h] [--only N] [-v] [-q] [--json] [--project PROJECT]
```

| Option   | Default | Meaning                                                  |
| -------- | ------- | -------------------------------------------------------- |
| `--only` |         | only these sections: 3, 3,5 or 7-9, and the flag repeats |

It also takes `-p`, `--json`, `-v` and `-q`.

### `decktalk screenshots`

Write one PNG per slide, per cue of one slide, or per second of a playing section.

```text theme={null}
decktalk screenshots [-h] [--page PAGE] [--slide ID] [--after ID] [--before ID] [--section SECTION] [--at AT] [-v] [-q] [--json] [--project PROJECT]
```

| Option      | Default | Meaning                                          |
| ----------- | ------- | ------------------------------------------------ |
| `--page`    |         | page file (default: every page in decktalk.toml) |
| `--slide`   |         | only these slide ids                             |
| `--after`   |         | freeze the one --slide at this cue id (repeats)  |
| `--before`  |         | freeze the one --slide just before this cue id   |
| `--section` |         | play this section with its resolved cues         |
| `--at`      |         | seconds after narration t=0 (with --section)     |

It also takes `-p`, `--json`, `-v` and `-q`.

### `decktalk soundscape`

Generate the ambience, the sound effects and the music.

```text theme={null}
decktalk soundscape [-h] [--force] [--dry-run] [-v] [-q] [--json] [--project PROJECT] [NAME ...]
```

| Option      | Default | Meaning                                              |
| ----------- | ------- | ---------------------------------------------------- |
| `NAMES`     |         | only these items: ambience, music, or an effect name |
| `--force`   | off     | regenerate even if the file exists                   |
| `--dry-run` | off     | print every request without sending it               |

It also takes `-p`, `--json`, `-v` and `-q`.

### `decktalk clip`

Cut a span of a built section and its narration into a clip file and its words.

```text theme={null}
decktalk clip [-h] --start SECONDS --end SECONDS --out OUT [--words WORDS] [--gain DB] [--hold SECONDS] [--preset PRESET] [--crf CRF] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero] section
```

| Option     | Default | Meaning                                                        |
| ---------- | ------- | -------------------------------------------------------------- |
| `SECTION`  |         | the page section to cut from                                   |
| `--start`  |         | start, after the section starts                                |
| `--end`    |         | end, after the section starts                                  |
| `--out`    |         | the clip file, relative to the project, such as media/open.mp4 |
| `--words`  |         | the words file (default: the clip's path with .words.json)     |
| `--gain`   | `0.0`   | gain on the clip's sound, in dB                                |
| `--hold`   | `0.0`   | hold the last frame this long, silent                          |
| `--preset` |         | x264 preset for this run (veryfast for drafts)                 |
| `--crf`    |         | x264 quality for this run                                      |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

### `decktalk serve`

Serve the project on the local origin, so a page loads over http.

```text theme={null}
decktalk serve [-h] [--host HOST] [--port PORT] [--open] [-v] [-q] [--json] [--project PROJECT]
```

| Option   | Default     | Meaning                                   |
| -------- | ----------- | ----------------------------------------- |
| `--host` | `127.0.0.1` | the address to bind (default: 127.0.0.1)  |
| `--port` | `0`         | the port to bind (default: any free port) |
| `--open` | off         | open the first page in your browser       |

It also takes `-p`, `--json`, `-v` and `-q`.

## The pipeline

### `decktalk narrate`

Turn script.md into one take per section with its word timestamps.

```text theme={null}
decktalk narrate [-h] [--only N] [--force] [--allow-placeholders] [--dry-run] [--no-voice] [--model MODEL] [-v] [-q] [--json] [--project PROJECT]
```

| Option                 | Default | Meaning                                                      |
| ---------------------- | ------- | ------------------------------------------------------------ |
| `--only`               |         | only these sections: 3, 3,5 or 7-9, and the flag repeats     |
| `--force`              | off     | ignore the cache, and let --no-voice replace voiced takes    |
| `--allow-placeholders` | off     | synthesize a section that still has a \[CAPITAL] placeholder |
| `--dry-run`            | off     | print what a voiced run would send and spend, and stop       |
| `--no-voice`           | off     | placeholder narration with no API key and no spend           |
| `--model`              |         | speech model for this run                                    |

It also takes `-p`, `--json`, `-v` and `-q`.

### `decktalk align`

Resolve each cue phrase in cues.json to a second on its section clock.

```text theme={null}
decktalk align [-h] [--allow-unknown-cues] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero]
```

| Option                 | Default | Meaning                                                                       |
| ---------------------- | ------- | ----------------------------------------------------------------------------- |
| `--allow-unknown-cues` | off     | continue when a cue id in cues.json appears nowhere in the page that plays it |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

### `decktalk record`

Record each page section with headless Chromium, find narration t=0 and check the frames.

```text theme={null}
decktalk record [-h] [--only N] [--seconds SECONDS] [--settle SETTLE] [--no-cues] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero]
```

| Option      | Default | Meaning                                                  |
| ----------- | ------- | -------------------------------------------------------- |
| `--only`    |         | only these sections: 3, 3,5 or 7-9, and the flag repeats |
| `--seconds` |         | override every duration (smoke tests)                    |
| `--settle`  |         | seconds after load before the clock starts               |
| `--no-cues` | off     | preview timing instead of ?cues=                         |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

### `decktalk assemble`

Cut, mix and normalize the sections into the final mp4 and its captions.

```text theme={null}
decktalk assemble [-h] [--no-soundscape] [--no-loudness] [--preset PRESET] [--crf CRF] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero]
```

| Option            | Default | Meaning                                           |
| ----------------- | ------- | ------------------------------------------------- |
| `--no-soundscape` | off     | narration only: no music, no ambience, no effects |
| `--no-loudness`   | off     | skip loudness normalization                       |
| `--preset`        |         | x264 preset for this run (veryfast for drafts)    |
| `--crf`           |         | x264 quality for this run                         |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

### `decktalk verify`

Read the final mp4 and report every section start, cut, seam and cue landing.

```text theme={null}
decktalk verify [-h] [--only N] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero] [SECTION:CUE ...]
```

| Option   | Default | Meaning                                                  |
| -------- | ------- | -------------------------------------------------------- |
| `CHECKS` |         | cues to check (default: every resolved cue)              |
| `--only` |         | only these sections: 3, 3,5 or 7-9, and the flag repeats |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

## The whole run

### `decktalk build`

Run every stage in order, writing progress as it goes.

```text theme={null}
decktalk build [-h] [--no-voice] [--force] [--only N] [--no-soundscape] [--no-loudness] [--allow-unresolved-cues] [--allow-unknown-cues] [--progress PATH] [--from STAGE] [--to STAGE] [--dry-run] [--preset PRESET] [--crf CRF] [-v] [-q] [--json] [--project PROJECT] [--strict] [--exit-zero]
```

| Option                    | Default | Meaning                                                                       |
| ------------------------- | ------- | ----------------------------------------------------------------------------- |
| `--no-voice`              | off     | placeholder narration with no API key and no spend                            |
| `--force`                 | off     | ignore the cache, and let --no-voice replace voiced takes                     |
| `--only`                  |         | re-record only these sections: 3, 3,5 or 7-9, and the flag repeats            |
| `--no-soundscape`         | off     | narration only: no music, no ambience, no effects                             |
| `--no-loudness`           | off     | skip loudness normalization                                                   |
| `--allow-unresolved-cues` | off     | build even if a cue phrase was not found                                      |
| `--allow-unknown-cues`    | off     | continue when a cue id in cues.json appears nowhere in the page that plays it |
| `--progress`              |         | the progress log (default: build/progress.jsonl)                              |
| `--from`                  |         | start at this stage, inclusive: narrate, align, record, assemble, verify      |
| `--to`                    |         | stop after this stage, inclusive                                              |
| `--dry-run`               | off     | print the stages the run would execute, and stop                              |
| `--preset`                |         | x264 preset for this run (veryfast for drafts)                                |
| `--crf`                   |         | x264 quality for this run                                                     |

It also takes `-p`, `--json`, `-v`, `-q`, `--strict` and `--exit-zero`.

## See also

* [Configuration](/reference/configuration) lists every tuning field.
* [Python API](/reference/python-api) lists everything `decktalk.__all__` holds.
