Script clikart-cli
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:
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.
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:
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:
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.