CLI reference
Every command accepts --help. Commands marked (stub) are not implemented
yet: they exit 1 with a "not implemented yet" message. Agent-friendly commands
accept --json and emit exactly one JSON object on stdout.
Exit codes: 0 ok, 1 unexpected, 2 usage, 3 config/credentials,
4 synthesis failed after retries, 5 quality gate failed, 6 structural
lint errors (render refuses unless --force), 130 interrupted by Ctrl-C.
sase listen program name
Under the command plugin (sase plugin install listen), every example on
this page reads sase listen … instead of sase-listen …: usage lines,
error prefixes, epilogs, and "run this next" hints all name the invoked
binary. Version strings, install paths, and the SSH wire command keep the
sase-listen distribution name. Path-like arguments (render/script
source, lint script, --cover, -o/--output, -H/--html, --source,
audition --text) carry sase_completion = "path" for shell completion.
Live progress
render (and the other network-bound commands) always show what you are
waiting for: a live stage checklist with sub-steps, chunk progress, ETAs,
and retry countdowns.
Each row is one stage: Fetch article (or Read ref / Read file), Write
script, Plan episode, Synthesize, Quality gates, Master audio, Save
episode, Publish. The active row shows the current step in plain English
(attempt 2 of 3 · fixing 2 lint findings · waiting on
gemini-3.1-pro-preview); upcoming stages stay visible as dim pending rows.
Synthesize shows a progress bar (done/total), one row per in-flight
chunk with its chapter title, live retry countdowns
(retry 1 of 4 in 14s · rate-limited), and a queued count. Completed rows
collapse to a ✓ line with a summary and duration.
The ETA appears after the first chunk finishes and is deliberately coarse (rounded to 5 s under a minute, whole minutes above) so it never jitters. Treat it as a rough guide, not a promise: it assumes the remaining chunks take as long as the finished ones.
sase-listen render SOURCE [--progress {auto,live,plain,off}]
sase-listen script https://example.com/article [--progress {auto,live,plain,off}]
--progress auto (the default) picks the live checklist on a TTY and
plain lines otherwise; --json always disables progress. live forces
the checklist (useful under script(1)), plain forces line-oriented
stderr with no ANSI escapes, and off silences progress entirely (the
finished checklist still prints to stdout as part of the summary).
Ctrl-C stops promptly: the first press finishes in-flight chunks so they stay cached, then exits 130 with a hint about how to resume; a second press quits immediately without waiting for the cache writes.
render — Markdown in, MP3 out
sase-listen render SOURCE [-o OUT.mp3] [-n NARRATOR] [--voice VOICE]
[--cover IMG | -g/--generated-cover] [--dry-run] [-e {brief,full,verbatim}]
[--html FILE] [--refresh] [--publish | --no-publish] [--no-cache] [--force]
[--progress {auto,live,plain,off}] [--json]
SOURCE is a narration script, a plain Markdown file (normalized
automatically), a local PDF file, or a kind:path artifact ref (fetched
through audited sase artifact read), or an http(s) article or PDF URL. URL
and PDF rendering defaults to the AI-written brief edition; choose full
for an adaptation or verbatim for a deterministic article-text reading.
--html FILE uses a saved browser page (HTML or PDF), and --refresh
fetches or extracts the source again and replaces the cached copy. arXiv
paper URLs (for example /abs/…) are fetched as the paper's PDF; see
Web articles.
--dry-run writes the article script if needed, prints the chunk plan, and
stops.
--publish / --no-publish override the feed.auto_publish config.
--cover IMG uses explicitly chosen artwork; -g / --generated-cover
generates the title card and ignores cover frontmatter and any sibling
<stem>_infographic.png. The two cover options are mutually exclusive.
See Reliability for gates, cache, and manifests.
script — normalize Markdown to a script
sase-listen script SOURCE [-o notes_narration.md] [-e {brief,full,verbatim}]
[--html FILE] [--refresh] [--progress {auto,live,plain,off}] [--json]
For Markdown files, produces an edition: verbatim, producer: deterministic
script plus an omissions report. For article URLs, defaults to an AI-written
brief script; --edition full writes a full adaptation, and verbatim selects
deterministic normalization. SOURCE can be a Markdown file, a PDF file, or an http(s)
article or PDF URL. For URL and PDF behavior and cached source storage,
see Web articles and Narration scripts.
lint — validate a script
sase-listen lint episode_narration.md [--source report.md] [--strict] [--json]
Exits 1 on errors, or on warnings with --strict. --source adds the
number-fidelity check: every number in the script must appear in the source.
A source number may appear as digits or spelled out in words: "thirteen"
matches 13, and "fifty percent" matches 50%.
guide — print the authoring rules
sase-listen guide [--edition {brief,full}]
Prints the packaged rules hand-written scripts must follow (brief by
default; pass --edition full for the full-length edition). The rules ship
in the package so they never drift from the code that enforces them.
audition — compare voices (stub)
sase-listen audition [--voices Charon,Kore] [-n NARRATOR] [--text FILE] [--json]
Intended: render the sample passage once per voice for comparison. Not implemented yet (owner: cli phase follow-up).
ls — list episodes (stub)
sase-listen ls [EPISODE] [--json]
Intended: list library episodes, or show one episode's manifest. Not
implemented yet (owner: cli phase follow-up). Meanwhile, episodes live under
$XDG_DATA_HOME/sase-listen/library/<slug>-<hash>/ with manifest.json.
doctor — check the setup
sase-listen doctor [--online] [--json]
Checks config load, ffmpeg resolution, credential presence, writable
directories, install freshness (install), the exact build (version,
for example 0.1.1 (editable @ 3ae7310)), and feed configuration
(feed:host shows the host build; feed:host-build fails on renderer /
host drift). --version prints sase-listen <build>. --online is
intended to add a one-word live synthesis check; it is a stub today
and reports FAIL: credentials (online check not implemented yet).
cache — inspect the chunk cache (stub)
sase-listen cache [prune] [--all] [--older-than 30d] [--json]
Intended: show cache stats and prune entries. Not implemented yet (owner: cli
phase follow-up). The cache itself works — render reads and writes it; only
the inspection command is missing. --no-cache on render bypasses it.
config — show or start configuration
sase-listen config [--json]
sase-listen config init # write a starter file
sase-listen config path # print the config path
Output annotates every value with its origin (default, env, file).
Secrets never appear. See Configuration.
feed, publish, unpublish — the podcast feed
sase-listen feed [init|prune|rebuild|receive] [--base-url URL] [--json]
[--print] [--qr] [--show-url]
sase-listen publish EPISODE|--latest|--pending [--json] [--show-url]
sase-listen unpublish EPISODE [--json]
EPISODE is an episode id, an episode MP3 path, or --latest.
--pending flushes the retry outbox. feed receive EPISODE_ID --json
is the internal host-only transport (stdin tar); do not call it by
hand. publish supersedes same-title feed episodes (feed copies only;
the library is kept) and reports superseded/replaced in --json.
See Podcast feed and
Multi-machine publish.
Non-TTY and NO_COLOR behavior
--progress auto (the default) is off with --json, live when stderr
is a terminal and TERM is not dumb, and plain otherwise. NO_COLOR
only removes color: the live checklist still renders and animates, just
without color. Plain mode writes line-oriented text to stderr with no ANSI
escapes and no carriage returns, so it is safe to pipe and log. --json
always emits exactly one JSON object on stdout with empty stderr,
regardless of TTY state, for agent consumption.