L3MS (Local Large Language Model System) is a keyboard-first terminal toolkit for homelab LLM workflows.
App Description
L3MS is built for developers who want script-first control with better ergonomics:
- Manage model download configs with validation and version history
- Run and bench llama.cpp models from curated script folders
- Browse local GGUF inventories with size, quantization, and metadata details
- Edit run/bench scripts in-place with snapshot restore
- Track live process output and runtime resource usage while a model is running
- Use either a full TUI or interactive CLI commands (
--run,--bench)
Public Dashboard
The L3MS profile dashboard publishes the active 12 GB homelab configurations, measured generation throughput, task-level MTP comparisons, and the reasons older profiles were retired.
Open any served profile to get a portable llama-server command generated
from llama-swap.yaml. Public commands replace local model paths with shell
variables and bind to 127.0.0.1 by default.
Install
python3 -m pip install -r requirements-tui.txt
Start TUI
python3 l3ms.py
Show quick-start instructions without opening TUI:
python3 l3ms.py --quickstart
Interactive CLI Modes
List available scripts:
python3 l3ms.py --list all
Interactively run a model script:
python3 l3ms.py --run
Interactively run a bench script:
python3 l3ms.py --bench
Filter script picker and pass extra args:
python3 l3ms.py --run qwen --extra "--ctx-size 32768"TUI Scope
- Workbench shell:
- persistent command bar with context-specific shortcut hints
- richer
Ctrl+Pcommand palette with shortcut column and token filtering
Workbenchtab:- default first screen for quick llama-swap model loading
- live model table from the configured llama-swap endpoint
- fast actions for load, unload, chat, bench, browser, downloads, and jobs
- delegates model loads to Model Ops so job history and resource telemetry stay consistent
Downloadtab:- config load/save/validate/restore
- model row add/apply/delete
- download selected or enabled models
- config snapshots in
.toolkit/download_config_versions/
Model Opstab:- llama-swap run mode and bench script mode
- live run logs + start/stop
- current running model + resource telemetry (CPU/RAM/GPU when available)
- script editor and per-script snapshots in
.toolkit/script_versions/for bench mode
Model Browsertab:- scan any local directory for
.gguffiles - inspect size, quantization, params, architecture, and modified timestamp in a table
- filter/sort results and inspect per-file metadata details
- scan any local directory for
- Additional tabs:
Chat,Maintenance,Jobs
Keyboard-first Controls
Global:
Ctrl+P: command palette?: key binding helpF1: Workbench tabF2: Model Ops tabF3: Chat tabF4: Model Browser tabF5: Download tabF6: Jobs tabF7: Maintenance tabAlt+1..Alt+7: tab fallback when F-keys are unreliableAlt+←/Alt+→: previous / next tab
Workbench:
Ctrl+R/Enter: load selected llama-swap modelCtrl+S: unload selected llama-swap modelCtrl+F: focus model filterCtrl+J: focus model tableCtrl+L: clear workbench logF3: chat with the loaded model endpointF2: open full Model Ops
Download (active only on Download tab):
Alt+T: focus models tableAlt+I: focus model editorAlt+O: load configAlt+W: save configAlt+V: validate configAlt+N: add modelAlt+A: apply model editAlt+K: delete selected modelAlt+D: download selected modelAlt+E: download enabled modelsAlt+Y: clear download log
Model Ops (active only on Model Ops tab):
Ctrl+F: focus model/script filterCtrl+J: focus model/script tableCtrl+U: focus detail/script editorCtrl+M: toggle run/bench modeCtrl+R: load selected llama-swap model or run selected bench scriptCtrl+S: unload selected llama-swap model or stop running benchAlt+P: save edited bench script snapshotCtrl+L: clear run log
Model Browser (active only on Model Browser tab):
Alt+R: scan selected GGUF directoryAlt+G: focus directory path inputAlt+J: focus GGUF table
Project Layout
model_downloader/: Hugging Face downloader + model configllama-swap.yaml: single source of truth for servable models (seedocs/llama-swap-runbook.md)bench-models/: onebench-llama-cpp-*.shscript per modelmaintenance/: system/build scriptsmaintenance/systemd/: user service units (includingllama-swap.serviceandnanobot-gateway.service)l3ms/: TUI app + storesl3ms.py: launcher (TUI and CLI modes)docs/llama-swap-runbook.md: install, start/stop, curl, add-a-modeldocs/model-onboarding-playbook.md: end-to-end checklist for adding new model families
Serving
Models are served by llama-swap on
a single OpenAI-compatible endpoint (http://<host>:8080). The daemon
hot-swaps models on demand and exposes every entry in llama-swap.yaml
under /v1/models. See docs/llama-swap-runbook.md.
The same endpoint serves on-demand embeddings through
nomic-embed-text-v1.5. It starts on the first /v1/embeddings request and
unloads after five idle minutes; see the runbook for the model path, task
prefixes, and verification request.
Downloader CLI (direct)
Run with config file (downloads all enabled models):
./model_downloader/download_hf_model.py --config model_downloader/models_config.json
Pull updates for already-downloaded models (skips models with no local files):
./model_downloader/download_hf_model.py --config model_downloader/models_config.json --update
Single model with pattern filter:
./model_downloader/download_hf_model.py --repo-id Qwen/Qwen3-32B-GGUF --allow-patterns "*Q6_K*"Throttle concurrency (useful on metered connections):
./model_downloader/download_hf_model.py --config model_downloader/models_config.json --slow ./model_downloader/download_hf_model.py --config model_downloader/models_config.json --max-workers 2
| Flag | Short | Description |
|---|---|---|
--config |
-c |
Path to JSON config file |
--repo-id |
-r |
Single repo to download |
--allow-patterns |
-a |
File glob patterns to include |
--ignore-patterns |
-i |
File glob patterns to exclude |
--local-dir |
-d |
Override local destination directory |
--revision |
Specific branch/tag/commit to pin | |
--update |
-u |
Sync updates for models already on disk (skips new ones) |
--force-download |
Re-download all files even if already present | |
--slow |
Throttle to max_workers=4 |
|
--max-workers |
Explicit worker count | |
--base-models-dir |
Override base directory for auto-organized downloads |
Note: Run the script directly (
./model_downloader/download_hf_model.py) rather than viapython3to ensure the correct venv Python is used.
Dashboard Development
The served-profile data and commands in docs/generated-models.js are
generated from llama-swap.yaml. Presentation-only values such as measured
throughput and benchmark comparisons live in docs/dashboard-meta.json. Every
published local profile receives the same evidence fields; missing historical
values are rendered as not recorded rather than inferred from another run.
Reviewed external results live in docs/community-runs.json and follow
docs/community-runs.schema.json. They render in a separate unranked view and
are never merged into the local RTX 4070 profile array. See
docs/community-runs.md for the submission format.
Regenerate after changing either source:
python3 docs/generate_dashboard_data.py python3 -m unittest docs/test_generate_dashboard_data.py
Preview locally:
python3 -m http.server 8080 -d docs
Do not edit docs/generated-models.js by hand.
Versioning
This project uses semantic versioning. See CHANGELOG.md.
Roadmap Note
L3MS is intentionally Python-first for fast iteration. Plan: port L3MS to Rust once feature scope stabilizes.