…; surface on-site-gen trap; fix stale update-check
Closes the dogfood gap where the CLI could discover models but not ASSEMBLE
(no download verb; no base-model filter; the training-zip trap; a stale
version-check).
Feature 1 — `civitai download`:
- Deterministic identifier: positional <version-id>, or `--model <id>` resolves
the model's default (primary/latest) published version. Exactly one required.
- Multi-file: default = primary file; `--file` (exact | unique substring,
ambiguous errors + lists); `--all`. `--out` (single) / `--out-dir` (dir,
parent-dir creation).
- Streams body to `<target>.part`, renames on success (never a truncated final
file); follows the /api/download → signed-storage 302; TTY-aware progress to
stderr; large files never buffered in memory.
- Uses the configured token source automatically (login token or
CIVITAI_API_KEY); actionable 401/403 message for gated/early-access.
- SHA256 verify on by default (mismatch deletes .part + errors; missing hash →
warn+skip, not a hard fail); idempotent skip-if-present + `--force`.
- On-site-gen guard: refuses a selected file whose type != "Model" (training-data
registration) unless `--allow-nonmodel`.
Feature 2 — `models search --base-model` (repeatable) → REST `baseModels` filter
(verified live: repeated keys = OR across values). Distinguishes video
checkpoints that all share `--type Checkpoint`.
Papercut 3b — `models get` / `model-versions get` human output tags a version
whose primary file is not weights `[training data — no downloadable weights]`
(--json unchanged).
Papercut 5 — update-check: root-caused the "Latest release: v0.1.61 while on
v0.1.62" symptom as the GitHub /releases/latest draft-exclusion artifact (now
resolved: the endpoint returns v0.1.62). Made the compare-guard robust
regardless: current >= latest now shows NO notice (was a misleading older
"Latest release" line), and the cache force-refreshes when it pins a "latest"
older than the running version.
Verified live: baseModels param OR-semantics; model-version file fields
(id/name/type/sizeKB/primary/downloadUrl/hashes.SHA256); a real 24 KB download
end-to-end with SHA256 matching the API's published hash, idempotent skip, and
--model/--out dir creation.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
What & why
A blind-dogfood found the CLI is great at discovery but can't assemble: no download verb, no base-model filter, the clean-named "training-zip" trap, and a version-check that reported
Latest release: v0.1.61while runningv0.1.62. This PR closes all four.Feature 1 —
civitai download(the missing verb)download <version-id>= a model-VERSION id;--model <model-id>(mutually exclusive) resolves the model's default (primary/latest) published version. Exactly one required — no numeric-ambiguity guessing.--file <name>selects one (exact, else unique case-insensitive substring; ambiguous/none errors and lists the files);--alldownloads every file.--out <path>(single file only),--out-dir <dir>(server-named files into a dir, works with--all), default = server name in cwd; parent dirs created.<target>.part→ renames on success (never a truncated final file); follows the/api/download→ signed-storage 302 (Go stripsAuthorizationcross-host); TTY-aware progress to stderr; large files streamed, never buffered.CIVITAI_API_KEY); 401/403 → actionable "runcivitai login" / "early-access or gated" message;--anonforces no token..partand exits non-zero with both hashes;--no-verifyskips; no published SHA256 → warn + skip verify (not a hard fail).--no-verify) is skipped;--forcere-downloads.type != "Model"(e.g. a training-data ZIP masquerading as the ~18 MB "version") is refused by default;--allow-nonmodeloverrides.--allskips bundled non-model files with a warning rather than aborting the whole run.Feature 2 —
models search --base-model(papercut #2)Repeatable
StringSliceVar→ RESTbaseModelsparam. Verified against the live API and the civitai source (model.schema.ts:baseModels: z.union([z.string(), z.string().array()]); service doesmv."baseModel" IN (…)) — repeatedbaseModels=keys are OR semantics. This is the key discovery filter for video checkpoints, which all share--type Checkpointand differ only by base model ("Wan Video 2.2 T2V-A14B").Papercut #3b — surface the trap in list/detail output
models get/model-versions gethuman output tags a version whose primary file is not weights with[training data — no downloadable weights].--jsonis an unchanged raw passthrough.Papercut #5 — stale update-check, root-caused
The symptom was the GitHub
/releases/latestdraft-exclusion artifact: whilev0.1.62's release was a draft, that endpoint returnedv0.1.61, so av0.1.62machine compared as "ahead" and the old code printed a misleadingLatest release: v0.1.61line. Confirmed resolved at the source — the endpoint now returnsv0.1.62. Fixed the compare-guard to be robust regardless:current >= latestnow shows NO notice (was the misleading older-"Latest release" line), anddecideNoticeforce-refreshes the cache when it pins a "latest" older than the running version, so a stale pre-publish record can't linger through its TTL.What I verified live
baseModelsparam exists, accepts repeated keys, and applies OR semantics (23 Illustrious + 8 Pony versions forbaseModels=Pony&baseModels=Illustrious).id,name,type,sizeKB,primary,downloadUrl,hashes.SHA256(+ AutoV1/AutoV2/CRC32/BLAKE3)..partrenamed away, idempotent skip on re-run, and--model+--outcreated nested dirs.v0.1.62(draft published), so the original symptom no longer reproduces; the compare-guard is hardened anyway.Test coverage
httptest-server, table-driven, matching the repo's style:
--modelresolution, primary default,--fileexact/substring/ambiguous/no-match,--all,--allskips non-model, SHA256 verify pass + mismatch (deletes.part+ errors), missing-hash warn+skip, non-Modelrefusal +--allow-nonmodel,--out/--out-dir(dir creation),--out+--allconflict, redirect follow,Authorizationsent when a token is configured, anonymous sends none, 401 refresh + non-refreshable 401 preserved, skip-if-present +--force, actionable 401.models get+model-versions get, absent for weights,--jsonunchanged.current >= latest→ no notice; stale-cache force-refresh; behind still notifies.go build ./... && go test ./... && go vet ./...all green (also-race). The branch-protection required checkspins-vs-published+scaffold-currencyare unrelated to this diff.Follow-up
The developer.civitai.com CLI guide (
site/guide/cli.md, civitai-developer-docs) needs a follow-up documentingdownload+--base-model— not touched here (separate repo).🤖 Generated with Claude Code