CLI (phase 3)¶
dtk is our own operational surface. Unlike REST, it has no external
standard to comply with: it is consistent with itself, script-friendly, and a
thin adapter over the programmatic core. Inference logic never lives in the
CLI.
Command map¶
| Command | Purpose |
|---|---|
dtk models |
Inspect the local cache and the curated catalog. |
dtk models list |
Every catalog variant, default (*) and cached variants (--license, --quant, --adapter). |
dtk models variants <id> |
Every real variant of one model, with size, role and exact install command. |
dtk models download <id> |
Download the default or --variant quantization (--force, --dry-run). |
dtk models use <id> |
Set the persistent current model and variant (--variant). |
dtk models current |
Show the current model (text as id@variant; JSON separates them). |
dtk models delete <id> |
Delete a cached variant, or --all-variants --yes. |
dtk models verify |
Verify files/hashes/sessions for one model or --all. |
dtk models import |
Import a custom ONNX directory with --adapter and --files. |
dtk decide |
One decision or a JSONL batch. |
dtk classify |
One-label classification with a threshold. |
dtk config |
list, get, set the toolkit configuration. |
dtk serve |
REST server (System One + OpenAI Decisions). |
dtk doctor |
Environment and cache diagnostics. |
dtk version |
Version information. |
dtk completion |
Bash/zsh/fish completion snippet. |
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
Runtime/model failure (not found, not downloaded, backend). |
2 |
Usage or invalid input. |
3 |
Verification failed. |
130 |
Interrupted (Ctrl-C). |
Expected failures print dtk: error: ... to stderr, never a traceback.
--verbose adds logs and tracebacks for debugging.
JSON and logging¶
Every inspection/result command accepts --json:
dtk models list --json
dtk models variants laya --json
dtk models current --json
dtk models verify --all --json
dtk decide ... --json
dtk classify ... --json
dtk config list --json
dtk doctor --json
dtk version --json
When --json is used, informational messages go to stderr and stdout contains
only the JSON document. dtk decide always emits JSON; --pretty indents it.
Global flags:
-q/--quiet: suppress informational messages; results still print.-v/--verbose: debug logs and tracebacks on stderr.--log-level DEBUG|INFO|WARNING|ERROR--log-format text|json--no-color(accepted for scripts).
Questions¶
The shorthand remains:
dtk decide --model gliner2.5-multi --state "..." \
--q 'team=choice:billing=refunds|tech=bugs' \
--q 'urgent=noul:Does it need a reply today?' \
--q 'tone=score:calm|annoyed|furious' --json
For the full contract use a JSON/YAML file:
questions:
team:
type: choice
instructions: Which team?
criteria:
billing: refunds
tech: null
task: route
multi_label: false
urgent:
type: noul
instructions: Does it need a reply today?
region:
type: box
instructions: Where is the object?
criteria: [object]
dtk decide --model gliner2.5-multi --state "..." \
--questions-file questions.yaml --json
task, multi_label, box and arbitrary adapter extensions are preserved
until the core validates them against the selected model's capabilities.
Batch JSONL¶
One state per line. A line can be:
- a JSON string:
"Customer wants a refund." - a JSON object used as the state:
{"ticket": 42, "plan": "pro"} - an envelope with per-line questions and id:
{"state": "Customer wants a refund.", "id": "row-1"}
{"state": "Please change my seat.", "questions": {"urgent": {"type": "noul", "instructions": "Today?"}}, "id": "row-2"}
dtk decide --model gliner2.5-multi \
--input-jsonl states.jsonl \
--questions-file questions.yaml \
--output-jsonl decisions.jsonl \
--batch-size 32
- The model is loaded once for the whole batch.
questionson a line overrides the global questions for that line.- Output is one JSON object per line with
answers,usage,latency_ms,warnings,model,variantandrequest_id. - A per-line
id/nameis copied to the output. - Omit
--output-jsonlto stream to stdout.
Variants and quantization¶
A quantization is a variant. dtk models list always shows every catalogued
variant and marks the default with *; the cached column shows which variants
are already downloaded.
| Model | Variants (default *) | Quantization | Size |
|---|---|---|---|
gliner2.5-multi |
fp16*, fp32 |
fp16 / fp32 | 577.1 / 1131.9 MB |
gliner2.5-decide |
q4f16* |
q4/fp16 | 523.5 MB |
laya |
q8* |
int8 | 527.9 MB |
julia-1 |
fp32* |
fp32 | 618.2 MB |
opendecider-nano |
q8f16*, fp16 |
int8/fp16 / fp16 | 468.8 / 791.9 MB |
# inspect, including the exact download command for each variant
dtk models list --quant
dtk models variants gliner2.5-multi
dtk models variants opendecider-nano --json
# download a different quantization into the cache (does not activate it)
dtk models download gliner2.5-multi --variant fp32
dtk models download gliner2.5-multi --variant fp32 --dry-run
dtk models download gliner2.5-multi --variant fp32 --force
# select it persistently, or only for one command
dtk models use gliner2.5-multi --variant fp32
dtk models current
# gliner2.5-multi@fp32
dtk models current --json
# {"current": "gliner2.5-multi", "variant": "fp32"}
dtk decide --model gliner2.5-multi --variant fp16 --state "..." --q 'cat=choice:a|b'
# verify or remove a specific variant
dtk models verify gliner2.5-multi --variant fp32
dtk models delete gliner2.5-multi --variant fp32
dtk models delete laya --all-variants --yes
dtk models verify --all --json
Downloading is the installation step for a model variant: there is no separate
pip install per quantization. Variants coexist in the cache. download does
not change the selection; use persists it, and --variant on a decision,
classification or serve command overrides it for that command. If --variant
is omitted, the catalog default is used unless dtk models use selected another
one.
models list --json always includes license, quant, adapter, capabilities, all
variants, the default variant, cached variants, current and current_variant.
The text table always shows variants and cached variants; --license, --quant
and --adapter add their columns.
See Variants and quantization for the full table and cache layout.
Custom models¶
dtk decide \
--model ./my-model \
--adapter julia \
--files model=model.onnx \
--files tokenizer=tokenizer.json \
--state "..." --q 'urgent=noul:Today?'
The same --adapter/--files pair works on classify and serve.
models import stores the role map and adapter in the cache metadata:
dtk models import ./my-model --name my-model --adapter julia \
--files model=model.onnx --files tokenizer=tokenizer.json --json
Config¶
dtk config list --json
dtk config get device
dtk config set device cpu
dtk config set current julia-1
dtk config set current_variant fp32
dtk config set cache_dir /data/dtk-models
Writable keys: cache_dir, current, current_variant, device. home is
read-only (use --home). config set current validates through the model
store and resets a variant that belonged to the old model; set
current_variant afterwards when needed.
Serve¶
dtk serve --model gliner2.5-multi --warmup \
--api-key "$DECISION_TOOLKIT_API_KEY" \
--cors-origin http://localhost:3000 \
--workers 2 --log-format json
--workers Nand--reloaduse an internal uvicorn factory;--reloadis for development and cannot be combined with--workers > 1.--max-models,--max-body-mb,--timeout,--warmup,--api-key,--cors-origin,--log-leveland--log-formatare the server's phase 2 controls.- Custom
--adapter/--filesalso apply to the server's default model.
Completion¶
# bash
eval "$(dtk completion bash)"
# zsh
dtk completion zsh > ~/.zfunc/_dtk
# fish
dtk completion fish | source
Examples¶
dtk models list --adapter --quant
dtk models variants gliner2.5-multi
dtk models download gliner2.5-multi --variant fp32
dtk models use gliner2.5-multi --variant fp32
dtk decide --model gliner2.5-multi --variant fp32 \
--state "Acme agreed a 10% discount and will sign next week." \
--q 'cat=choice:meeting|task|contact|idea|other' --json
dtk classify --model laya --text "Dentist next Tuesday at 9" \
--labels reminder,task,idea --json
dtk models verify --all --json
dtk doctor --json
Boundaries¶
- The CLI can use more of the core than REST (batch JSONL, custom file maps, config), but still does not reimplement inference.
- It does not have a compatibility obligation to System One/OpenAI; those are REST contracts.
- Metrics/rate limiting are server-side phase 5 features; see OPERATIONS.md. Wheel/PyPI releases are documented in RELEASE.md.