swapboard
Model management API and dashboard for llama-swap.
swapboard reads your llama-swap configuration, works out which Hugging Face repository each model comes from, reports whether its files are present on disk, and downloads the missing ones on request. It ships two parts:
- a JSON API (FastAPI) that other services can drive, and
- a web dashboard (Flask + HTMX) for doing it by hand.
On macOS it can also deploy itself, running llama-swap and llama.cpp from
pinned, checksummed upstream builds kept in a private directory, so neither
binary lands on your PATH and your own llama.cpp build is left alone.
Install
pip install swapboard # API + client
pip install 'swapboard[ui]' # + web dashboard
pip install 'swapboard[all]' # + macOS deployment and the local runner
Requires Python 3.14 or newer.
Quick start
cp .env.example .env
swapboard-dev --config ./llama-swap.example.yml
swapboard-dev runs llama-swap, the API and the dashboard together with
interleaved logs, and prints the URL to open. On macOS it fetches the pinned
runtimes on first use; elsewhere it falls back to a llama-swap on your
PATH.
Configuration
swapboard derives a model's Hugging Face source from the last three components
of its -m path, so models must be laid out as <org>/<repo>/<filename>. A
model with an --mmproj projector is only reported present once both files
exist.
Refer to llama-server through a macro rather than a bare name, so the binary swapboard manages is the one that gets used:
macros:
models_dir: "${env.MODELS_DIR}"
llama_server: "${env.LLAMA_SERVER_BIN}"
models:
"embeddinggemma-300M":
cmd: |
${llama_server} --port ${PORT}
-m ${models_dir}/ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf
--embeddings
swapboard sets MODELS_DIR and LLAMA_SERVER_BIN when it launches llama-swap.
See llama-swap.example.yml for a fuller example.
Configuration is read from SWAPBOARD_* environment variables, covering the
config file to read, where models are stored, a Hugging Face token for private
or gated repositories, and the addresses the services bind to.
.env.example names every variable, with values suited to
running from a checkout. Left unset, the paths resolve to the installation the
running swapboard belongs to, and --help reports the ports.
API
| Method | Path | Returns |
|---|---|---|
GET |
/health |
{"status": "ok"} |
GET |
/info |
Port llama-swap is serving on |
GET |
/models |
Status of every configured model |
GET |
/models/{name} |
Status of one model |
POST |
/models/{name}/download |
Starts a background download |
Downloads run in the background; poll /models/{name} for progress. A model
already downloading will not be started twice, and a failed download can be
retried without refetching files that already arrived.
Python client
from swapboard import SwapboardClient
client = SwapboardClient("http://127.0.0.1:8771")
status = client.get_status() # never raises; degrades to "unavailable"
for model in status.models:
print(model.name, model.present, model.download_state)
Running the services
swapboard-api --help
swapboard-ui --help
Or point any ASGI/WSGI server at swapboard.api.main:app and
swapboard.ui.factory:create_app().
macOS deployment
swapboard-deploy installs everything under a single prefix and runs it from
launchd. The prefix is derived from the virtualenv the command runs in, so
there is normally nothing to configure:
uv venv ~/.swapboard/venv --python 3.14
uv pip install --python ~/.swapboard/venv/bin/python 'swapboard[all]'
~/.swapboard/venv/bin/swapboard-deploy deploy --config ./llama-swap.yml
Runtimes, models, config and logs all live under that prefix, and the services
run as launchd agents. swapboard-deploy uninstall removes the agents and
runtimes, leaving models and config in place. Apple Silicon and Intel are both
supported.
The pinned runtimes are verified against recorded SHA-256 digests before extraction, and can be managed on their own:
swapboard-runtimes install # or: status, path llama-server, remove
Linux is supported for the API and dashboard; for llama-swap itself, use the upstream container image.
Development
uv sync --all-extras --group dev
uv run ruff check src tests
uv run ty check src tests
uv run pytest --cov
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file swapboard-2026.9.1.tar.gz.
File metadata
- Download URL: swapboard-2026.9.1.tar.gz
- Upload date:
- Size: 103.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2bdff45daf17edec147ed087717c22fcd15561b311df365b1ed85ffe6b32aab7
|
|
| MD5 |
9c6442d3d2f8b22724739c239dfefa4e
|
|
| BLAKE2b-256 |
0e4c6a179d72621b09d635dca2d0c6eaf6a210d2f3d5d6e74856cb30bf5a401a
|
Provenance
The following attestation bundles were made for swapboard-2026.9.1.tar.gz:
Publisher:
ci.yml on dmitriy5181/swapboard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
swapboard-2026.9.1.tar.gz -
Subject digest:
2bdff45daf17edec147ed087717c22fcd15561b311df365b1ed85ffe6b32aab7 - Sigstore transparency entry: 2704475722
- Sigstore integration time:
-
Permalink:
dmitriy5181/swapboard@070f4e87f8aa3d2e120eef55d56702a09cce60fb -
Branch / Tag:
refs/tags/2026.9.1 - Owner: https://github.com/dmitriy5181
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@070f4e87f8aa3d2e120eef55d56702a09cce60fb -
Trigger Event:
release
-
Statement type:
File details
Details for the file swapboard-2026.9.1-py3-none-any.whl.
File metadata
- Download URL: swapboard-2026.9.1-py3-none-any.whl
- Upload date:
- Size: 32.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89da5c44508ec8c3593a59bb9bacb4d2321a746ac57efa30119281e835245ee8
|
|
| MD5 |
21807edfe670a99bb06f3ad4490430d4
|
|
| BLAKE2b-256 |
26a45d95f3a5302718623ea3435f2abeeb22c65b27d77784ff9f57eb74c75845
|
Provenance
The following attestation bundles were made for swapboard-2026.9.1-py3-none-any.whl:
Publisher:
ci.yml on dmitriy5181/swapboard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
swapboard-2026.9.1-py3-none-any.whl -
Subject digest:
89da5c44508ec8c3593a59bb9bacb4d2321a746ac57efa30119281e835245ee8 - Sigstore transparency entry: 2704475761
- Sigstore integration time:
-
Permalink:
dmitriy5181/swapboard@070f4e87f8aa3d2e120eef55d56702a09cce60fb -
Branch / Tag:
refs/tags/2026.9.1 - Owner: https://github.com/dmitriy5181
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@070f4e87f8aa3d2e120eef55d56702a09cce60fb -
Trigger Event:
release
-
Statement type: