releases | changelog | guide | pate.sh
Home-grown model library management from a local talent agent.
The models are the talent. vanity keeps the roster: stable names mapped to
{repo, role, runtime, size_hint, revision}, grouped into sets, each pinned to a
commit, fetched over any of three interchangeable backends. One stdlib-only
Python package.
No pip install. No compiled wheels. No Rust toolchain waiting to ambush you on
a new interpreter.
git clone git@github.com:TGPSKI/vanity.git
cd vanity
make doctor # check local tooling
vanity add BAAI/bge-m3 # onboard a model; starts a registry if none exists
vanity fetch bge-m3The byte-moving is the least interesting layer. What you keep is the roster:
{
"description": "Primary runtime models and the persistent STT sidecar",
"models": {
"qwq-32b-awq": {
"repo": "Qwen/QwQ-32B-AWQ",
"size_hint": "~22GB",
"runtime": "vLLM / AWQ",
"role": "reasoning / TSS",
"revision": "dc9f21221581580ccfa51b74077db6056b56cb69"
}
},
"sets": { "reasoning-tss": ["qwq-32b-awq"] },
"aliases": { "qwq": "qwq-32b-awq" }
}That file is a few kilobytes of JSON you commit and review. Pinned to a commit, it answers the question that's actually hard a year later: which revision of which repo is this, and can I get it again? A model changing upstream becomes a pull request instead of a silent behaviour change.
registry/ is your data and is not tracked here. A small
example ships instead.
pyproject.toml declares dependencies = [], and
test_stdlib_only.py walks the package by AST and
fails the build if any import resolves outside sys.stdlib_module_names. The
claim is the product, so it isn't left to review discipline.
Scoped precisely, because the scoped version is the one that holds:
vanity imports nothing but the Python standard library. The
httpbackend needs no external binaries at all — it is the pure, zero-dependency path.git-xetandgit-lfsare optional system accelerators: external binaries you shell out to (likegititself), never imported, never in the Python dependency graph.
This matters on the machine class vanity targets. huggingface_hub pulls in
pydantic, httpx, fsspec, filelock, and hf_xet — a compiled Rust wheel. On a
bleeding-edge interpreter you are one missing wheel away from a source build.
A model downloader that can drag you into a Rust compile is the wrong dependency
to accept.
| Registry | registry/*.json — named keys to repo, role, runtime, size, revision. Validated on every load; a dangling reference is refused by name. |
| Sets & aliases | Fetch a named group as a unit. Alias a key for a short name, or to keep old scripts resolving after a rename. |
vanity add |
Onboard from Hugging Face — size, commit, and runtime derived from what the repo reports. Refuses repos that don't resolve. |
| Provenance | Pin every model to a commit. A fetch on another machine, or a year later, lands the same weights. |
| Backends | http (pure stdlib, no binaries), git-xet (default, chunk dedup), git-lfs. Same manifest either way. |
| Fetch | Resumable, atomic, --jobs N in parallel, per-model locks, backoff on rate limits. |
| State | Atomic writes, stale-lock breaking via PID liveness, a .vanity.json sidecar in every model directory. |
$ vanity add Qwen/QwQ-32B-AWQ
resolving Qwen/QwQ-32B-AWQ ...
found: 19 files, 18.0GB, commit dc9f21221581
key [qwq-32b-awq]:
runtime [vLLM / AWQ]:
role [text generation]: reasoning challenger
size_hint [~18.0GB]:
revision (a commit pins it; "main" tracks the branch) [dc9f2122158158...]:
registry file (challengers, serving, support): challengersSize is summed from the file tree, the revision is the repo's current commit,
and the runtime is inferred from the repo's own tags — AWQ/NVFP4/FP8/GPTQ, GGUF,
sentence-transformers, CTranslate2. Every value is a prompt with that default,
so accept the lot or correct a line. --yes takes them all.
Cloning is enough — the Makefile runs the package straight from src/:
git clone git@github.com:TGPSKI/vanity.git
cd vanity
make listFor a vanity command on your PATH:
make install # pip install -e .Verify the install — no model download required:
make doctor # tooling + resolved store
VANITY_REGISTRY_DIR=examples/registry vanity list # the shipped example
make test # 117 tests, no networkOne home backs the manifests, the weights, and the state, so the normal setup is a single path:
<home>/
registry/ your manifests -- small, versioned, diffable
library/ the weights -- large, gitignored, often on another mount
.state/ fetch state and locks
vanity config --home ~/vanity # the usual case
vanity config --store /mnt/models # only when weights belong on another disk
vanity config # show what resolved, and from whereThe first command that touches your library asks once and remembers. It only prompts on a terminal — scripts and CI take the default rather than blocking.
| you want to… | start here | then |
|---|---|---|
| use it — install, config, registry format, pinning, backends | docs/GUIDE.md | command reference · troubleshooting |
| understand the internals | docs/ARCHITECTURE.md — module map, fetch loop, locking | CHANGELOG.md — every fix and why it mattered |
| contribute (human or agent) | AGENTS.md — selection and verification rules | CONTRIBUTING.md — the invariants that regress quietly |
| assess the security posture | SECURITY.md — trust model, and what a pin does not give you |
GPL-3.0-only. See LICENSE.