---
title: Script clikart-cli
description: "The contracts that make clikart-cli scriptable: exit codes, the stdout/stderr split, option templates and shell completion."
---

The `clikart-cli` executable is built to be driven by scripts, and the contracts below are stable interfaces, not implementation details. A script that branches on them keeps working across releases.

## stdout is the payload, stderr is everything else

Every command writes exactly its payload to stdout: generated text, a transcript, the catalog, a fetched path, CSV. Banners, progress bars, timings, warnings and errors all go to stderr. Capturing a result is therefore safe by construction:

```bash
MODEL_DIR=$(clikart-cli fetch Qwen/Qwen2.5-0.5B-Instruct)
ANSWER=$(clikart-cli "$MODEL_DIR" prompt "Two plus two is" --greedy --max-new-tokens 4)
```

`-q` mutes stderr down to warnings and errors, `-v` raises it to debug (including the effective-options report showing which value came from which source), and `--no-color` strips styling (also honored automatically for non-TTY output, `NO_COLOR`, and `TERM=dumb`). The runtime's own `[ClikaRT]` log lines follow the same rule: the level tag is colored only when stderr is a terminal, `NO_COLOR` is unset or empty, and `TERM` is not `dumb`, so a captured stderr holds no escape bytes. None of these change the payload.

Machine-readable forms exist where the payload is tabular: `devices --json` and `devices --csv` print the hardware report as a document instead of the human view, `check --csv` prints the fit verdict table (one row per device, every term of the law a column) as CSV, `list --json` prints the registry as one document (per family: the vendor, the Hugging Face pipeline tags it serves, the modalities, the served and refused model types and GGUF architectures, the advertised verbs, whether it is runnable), and `info --json` / `info --csv` print the supported-models document, or its table as CSV, for one source (a one-entry document), several sources or `@FILE` (one source per line): per model the family, the resolved commit, the parameter count and where it was read from, the license, the gate, and one row per weight variant with the files a fetch lands and their sizes, which a catalog generated from the registry reads. The grammar is `clikart-cli info <source... | @FILE> [--weights SEL] [--json | --csv] [--schema] [--dry]`: one source with no form flag prints the human description, `--schema` prints the document's JSON Schema and needs no source, and a source the hub refuses is a warning on stderr while the document carries the rest and the exit code is 1.

## The exit-code contract

Four values, fixed:

| Exit | Meaning | Example |
| --- | --- | --- |
| 0 | success | the payload is on stdout |
| 1 | runtime failure | download interrupted, weights failed to load |
| 2 | usage error | unknown flag, missing argument, unselected weight options |
| 3 | the model cannot do this here | a verb the family does not provide, an identity-only family, an unsupported variant |

The distinction between 2 and 3 is the useful one: 2 means fix the invocation, 3 means fix the model choice. A retry loop should retry 1 and never 2 or 3.

```bash
SRC=openai/whisper-large-v3-turbo    # the model this script expects
FILE=meeting.wav                     # the input it transcribes
if ! clikart-cli "$SRC" transcribe "$FILE" > out.txt; then
  case $? in
    2) echo "bad invocation, check the flags" >&2; exit 2 ;;
    3) echo "$SRC has no transcribe; pick a speech-to-text model" >&2; exit 3 ;;
    *) echo "runtime failure, retrying" >&2 ;;
  esac
fi
```

## Options as a file

`generate-template` writes a JSON file with every root option at its default (null where there is no built-in default); `--template` loads one, and explicit flags always win over it. This is how a deployment pins its configuration in version control instead of a growing alias:

```bash
clikart-cli generate-template defaults.json
clikart-cli info "$SRC" --template defaults.json
clikart-cli fetch "$SRC" --template defaults.json --cache-dir /data/models
```

A family's own verbs are their own contract; the template governs the root verbs. Secrets stay out of both: the Hugging Face Hub token comes from `HF_TOKEN` in the environment or from the token a Hub login stored, never a flag and never a template key, so neither shell history nor a committed template can leak it.

## Completion

`clikart-cli` generates its own shell completion:

```bash
source <(clikart-cli completion bash)     # zsh and fish work the same way
```

Completion covers the root verbs and flags; model commands are discovered per source at run time, which completion cannot see, and that is the one place tab-completion ends and `<source> --help` takes over.
