▶ On this page
CLI reference
Binary name: onpremo. Canonical first-run path:
recommend → pull → run /
chat → optional serve. Commands below
match the live binary; also see agent and
discover in onpremo --help and
docs/agents.md.
onpremo inspect <model.gguf>
Inspect GGUF metadata without loading weights.
--json emit machine-readable JSON instead of a table
onpremo inspect smollm2-135m-instruct-q4_k_m.gguf
onpremo inspect smollm2-135m-instruct-q4_k_m.gguf --json
onpremo check <model.gguf>
Test model compatibility with a device profile without loading the model.
--profile <name|path> built-in name or TOML path (default: pi-1gb-safe)
--json emit machine-readable admission outcome
Exit codes: 0 admitted or downgraded, 2 rejected,
1 for bad paths or invalid profiles.
onpremo check model.gguf --profile micro-500mb
onpremo check model.gguf --profile pi-1gb-safe --json
onpremo run <model.gguf>
One-shot inference with streaming tokens on stdout and immediate cleanup.
--profile <name|path> built-in name or TOML path; see onpremo profile suggest for a host-fit profile (default: pi-1gb-safe)
--prompt <text> required prompt string
--max-tokens <n> default: 64
--temperature <f> default: 0.7
--seed <u64> optional RNG seed for reproducible sampling
--report print machine-readable run report JSON to stderr
--chat treat --prompt as a single user chat message (model chat template, or a role-prefixed fallback)
--system <text> system message prepended when --chat is set (requires --chat)
--json-schema <path> JSON Schema file compiled to a GBNF grammar for constrained generation; output is validated after generation
--lora <path> optional LoRA adapter file (file size counted in admission)
Exit codes: 0 admitted or downgraded, 2 rejected,
3 schema violation (with --json-schema),
1 other errors (bad paths, invalid profiles, load failures).
onpremo run model.gguf \
--profile pi-1gb-safe \
--prompt "Return the intent as JSON" \
--max-tokens 32
onpremo run model.gguf \
--profile pi-1gb-safe \
--prompt "hello world" \
--max-tokens 4 \
--report 2>report.json
onpremo run model.gguf \
--profile pi-1gb-safe \
--chat --system "Reply in one sentence" \
--prompt "What is admission?" \
--json-schema schema.json
onpremo chat <model.gguf>
Interactive multi-turn terminal chat. Loads the model once; streams
each turn. In-REPL: /exit quits, /clear
resets history (keeps the system message). EOF / Ctrl-D also exits
cleanly.
--profile <name|path> default: pi-1gb-safe (Pi certification identity; on a laptop prefer the profile recommend printed)
--system <text> optional system message kept across /clear; with --agent, appended after the manifest system
--agent <path> agent manifest TOML (master prompt + tool registry). Tool calls print for the operator to type a result at tool result>, except the implicit escalate tool which is auto-executed
--max-tokens <n> per turn (overrides agent default; default 128)
--temperature <f> overrides agent default; default 0.7
--seed <u64> optional
--lora <path> optional LoRA adapter (overrides manifest lora = "…")
onpremo chat model.gguf --profile pi-1gb-safe
onpremo chat model.gguf --profile pi-1gb-safe --system "Be brief"
onpremo chat model.gguf --agent examples/agents/workshop-gateway.toml
onpremo benchmark <model.gguf>
Repeatable workload; writes a machine-readable JSON report (schema version 1).
--profile <name|path> default: pi-1gb-safe
--context <n> optional context override
--batch <n> optional batch override
--max-tokens <n> default: 64
--iterations <n> default: 3
--warmup <n> default: 1
--prompt <text> default: Summarize: the pump pressure is low.
--output <path> write JSON here (default: stdout)
onpremo benchmark model.gguf \
--profile pi-1gb-safe \
--context 512 \
--batch 16 \
--max-tokens 64 \
--iterations 3 \
--warmup 1 \
--output result.json
onpremo serve <model.gguf>
Bounded local HTTP API. Memory budget is owned by
profiles + admission (there is no free-form
--memory-limit flag). Binds loopback by default.
On start, serve prints both GUI URLs on stderr:
onpremo serve: listening on 127.0.0.1:11500 (profile=…, backend=…)
chat: http://127.0.0.1:11500/
status: http://127.0.0.1:11500/status
Web chat at / is the primary GUI
(embedded browser UI). /status is the secondary
operator page (model, admitted config, live memory). Both are
always printed so discovery does not require reading docs.
--profile <name|path> default: pi-1gb-safe
--bind <addr> default: 127.0.0.1:11500
--idle-unload <secs> unload after idle seconds; 0 disables (default: 30)
--max-request-bytes <n> hard body ceiling (default: 65536)
--agent <path> agent manifest applied to every conversation
--lora <path> refused: the server load path does not apply LoRA in this build (use run/chat)
--no-tray skip the menu bar / system tray icon (macOS, Windows, and Linux builds made with --features tray-linux; board builds have no icon to skip)
onpremo serve model.gguf \
--profile pi-1gb-safe \
--bind 127.0.0.1:11500
Menu bar / system tray (built-in on macOS and
Windows; Linux via opt-in tray-linux):
while serve runs, a mascot icon appears in the menu bar
(macOS), notification area (Windows), or StatusNotifier tray
(Linux when compiled in). Menu items, in order:
model label (disabled), Open chat (opens
/), Open status page (opens
/status), Quit OnPremo. The icon is
rasterized at startup from the same 19×19 mascot grid as
site/mascot.svg — no image assets. The mark is
black-and-white and matches the bar it sits on: macOS registers
it as a template image so the menu bar recolors it per
appearance, and Windows reads the taskbar theme at startup and
picks the black or white variant accordingly.
Desktop Linux gets the same menu when the binary is built with the
opt-in tray-linux cargo feature: a StatusNotifierItem
over the session D-Bus (pure Rust, no GTK), shown out of the box
on Ubuntu, KDE Plasma, and XFCE; stock Debian GNOME needs the
AppIndicator shell extension. Default Linux builds — including
every published board binary — omit the tray so the certified
musl/armv7 images stay lean; use the printed URLs (or
onpremo status) instead. Headless SSH sessions: pass
--no-tray. If the icon cannot be created (no window
server, no D-Bus), serve falls back to a plain foreground process
with a warning.
Non-loopback binds are refused unless
ONPREMO_ALLOW_NONLOCAL=1 is set. When allowed,
serve prints a one-time startup warning: the API has
no authentication.
onpremo pull [NAME]
Download a model via the system curl (falling back to
wget): a catalogue name, or any GGUF by
URL with --url. The OnPremo binary links
zero network crates; only this convenience command
uses the network, and only by shelling out — same approach as the
installer. Inference itself never needs the network.
NAME catalogue model name (case-insensitive exact or unique substring); with --url, optionally overrides the saved filename (must end in .gguf)
--list list catalogue entries (name, quantization, size, license, status, verified)
--dir <path> destination (default: $ONPREMO_MODELS_DIR or ~/.onpremo/models)
--catalogue <dir> TOML manifests (default: embedded catalogue)
--allow-unverified allow download when the catalogue entry has no SHA-256 pin
--url <URL> direct URL to a .gguf (bring your own model); filename derived from the URL
--sha256 <hex> with --url: verify a fresh download, or verify an already-downloaded file in place without re-fetching
Bring your own model. With --url the
verification story inverts: no pin exists until you create one, so
the first pull is unverified and the computed SHA-256 is printed
prominently — pin later pulls (and CI installs) with
--sha256. Split multi-part GGUFs
(-00001-of-000NN) are refused: download all parts into
one directory, then point onpremo run at the
-00001-of- file (llama.cpp loads the rest). And pull
is a convenience, not a gate — every model-consuming command
accepts a plain path to any local .gguf, and
recommend ranks uncatalogued files in the models
directory alongside catalogue entries.
pull --list prints a VERIFIED column:
sha256 for pinned entries, or
UNVERIFIED for unpinned ones. A
footer reports how many entries are SHA-256-pinned.
onpremo pull <name> refuses
unverified entries unless --allow-unverified is
passed; after an unverified fetch it prints the observed hash and
size so you can pin them in the manifest. Size column uses exact
size_bytes when known, else admission
approx_weight_bytes.
onpremo pull --list
onpremo pull SmolLM2-135M
onpremo pull some-unpinned-model --allow-unverified
onpremo pull --url https://huggingface.co/<repo>/resolve/main/<model>.gguf
onpremo pull --url <same-url> --sha256 <printed-hash> # pin: verifies in place
onpremo recommend
Probe live memory and rank catalogue / local models by admission
against a profile. When --profile is omitted, the
profile is derived with the same pure suggestion math as
profile suggest.
--profile <name|path> built-in name or TOML path; omit to auto-suggest from the host
--catalogue <dir> catalogue TOML directory (default: embedded)
--models-dir <dir> local *.gguf directory (default: $ONPREMO_MODELS_DIR or ~/.onpremo/models)
--json stable JSON array of recommendation rows
Ranking (first-experience default). Candidates order by admission verdict first: admitted → downgraded → rejected → no-specs. Within admitted (and within downgraded):
- Already downloaded locally (a real
.ggufbeats a pull) - Catalogue-verified (non-empty SHA-256) before unverified
- Smaller weight first
- Name ascending as a stable tie-break
Unverified multi-GB catalogue entries therefore sink toward the bottom of the admitted band even when they fit. Human output prints up to two headlines when they differ:
headline: best first pick = …— top of the first-experience order (safe default next step)headline: largest admitted = …— heaviest admitted model (capability signal; omitted when it is the same row)
Every run action line carries an explicit
--profile <name-or-path> matching the profile
used for admission. When recommend auto-suggested the profile
(no --profile flag), suggested names are not loadable
as built-ins, so actions are a two-step form:
onpremo profile suggest --out <path> then
run … --profile <path>. Pull actions stay
onpremo pull <name> (pull does not take a profile).
Exit codes: 0 if any candidate is admitted or
downgraded, 3 if nothing fits.
run/chat/serve still default
to pi-1gb-safe when you type them by hand — that is
the Pi certification identity; prefer the profile recommend printed.
onpremo recommend
onpremo recommend --profile pi-1gb-balanced
onpremo recommend --json
onpremo profile suggest
Probe host memory and emit an honest hardware profile whose process budget, context/batch tiers, and safety margin scale with actual RAM (and a tighter cgroup limit when present). The three fixed built-ins cover the certified tiny tier; this command is the first-class path for every other host.
--name <n> default: suggested-<total-GiB-rounded>gb
--out <path> write the profile here instead of stdout; refuses to overwrite unless --force
--force allow replacing an existing --out file
--json emit the same Profile as JSON
--streaming include a [streaming] table when this build's Profile supports it
Default stdout is TOML with documented budget-math comments.
Unprobed platforms (total_bytes == 0) print an error
and exit 1. Suggested TOML loads with
--profile <path> on
check / run / chat /
serve / agent like any other profile.
onpremo profile suggest
onpremo profile suggest --out ~/.onpremo/profiles/suggested-16gb.toml
onpremo profile suggest --json
onpremo status
Scripting twin of the embedded /status page. Fetches
GET /v1/status and, when present,
GET /v1/agent via system curl/wget (no network crates).
Requires a running onpremo serve.
--url <base> server base URL, no trailing path (default: http://127.0.0.1:11500)
--json one merged JSON object (status + optional agent) on a single stdout line
Human output is a compact table. Exit 0 when healthy,
1 when unreachable or malformed.
onpremo status
onpremo status --json
onpremo status --url http://127.0.0.1:11500
Profiles
Built-in device profiles ship as TOML under profiles/;
the three fixed tiny profiles below are the certified tier. For any
other machine, onpremo profile suggest probes host
memory and emits a profile scaled to it. Pass a name
(pi-1gb-safe) or a path to a custom TOML file.
| Name | Process budget | OS reserve | Default context / batch | KV types | Max out | Notes |
|---|---|---|---|---|---|---|
micro-500mb |
300 MiB (314572800) |
200 MiB | 384 / 16 (256–512 / 8–16) |
f16, q8_0, q4_0 | 64 | ~500 MB total RAM or 300 MB process budget; 135M Q4 and smaller; require_no_swap |
pi-1gb-safe |
600 MiB (629145600) |
400 MiB | 512 / 16 (512–1024 / 16–32) |
f16, q8_0 | 128 | 1 GB total RAM, conservative; 135M–360M Q4; CLI default |
pi-1gb-balanced |
750 MiB (786432000) |
250 MiB | 512 / 16 (256–1024 / 16–32) |
f16, q8_0, q4_0 | 192 | Minimal OS reserve; measured headroom for selected 0.5B models |
Safety margin ratios: micro-500mb 0.15,
pi-1gb-safe 0.10, pi-1gb-balanced 0.08.
Memory model summary
Memory management is the central product feature. The runtime distinguishes model file size from peak process memory. Required memory is estimated as:
Required memory =
model residency
+ KV cache
+ compute buffers
+ tokenizer/runtime overhead
+ operating-system reserve
+ safety margin
The process budget (weights + KV + compute + overhead + margin) is distinct from the OS reserve. Admission enforces the process ceiling; the OS reserve is reported for device-level capacity.
Admission flow
- Read the device profile and current available memory
- Inspect model metadata and quantization without fully loading
- Estimate a conservative initial configuration
- If needed, reduce batch, context, and KV precision in a fixed order
- Reserve OS and emergency margin
- Load only after the estimate passes
- Monitor RSS and terminate cleanly if the hard process budget is approached
- Record measured peak memory vs. the estimate
Downgrade order
- Start with the requested profile
- Reduce prompt batch size
- Reduce context length
- Select a lower-memory KV-cache type
- Reduce maximum output tokens
- Reject with a machine-readable reason code if still incompatible
memory.peak / memory.current when a cgroup
limit applies; process RSS is a secondary field.
Measured footprint
Idle process RSS and release binary sizes are measured and labeled
honestly (development-host aarch64 macOS figures; Pi / musl board
certification still pending) in
docs/footprint.md
— re-run with scripts/measure-footprint.sh. Those numbers
are not a substitute for admission math or cgroup peak under load.
HTTP API
Bounded local interface served by onpremo serve. One
request at a time, request-size ceiling, optional idle unload, loopback
by default. On start the process prints
chat: (GET /, primary GUI) and
status: (GET /status, secondary operator page).
| Method | Path | Description |
|---|---|---|
POST |
/v1/generate |
JSON body GenerateRequest → GenerateResponse
(text + stats). Fields:
prompt (required), optional
max_tokens, temperature,
top_p, seed, stop.
max_tokens is clamped to the admitted config.
|
POST |
/v1/chat/completions |
OpenAI-compatible chat (optional stream). Used by the embedded web chat and peer escalation. |
GET |
/v1/health |
Liveness: {"status":"ok","model_loaded":bool} |
GET |
/v1/model |
Model GGUF summary and active RunConfig |
GET |
/v1/models |
OpenAI-compatible model list |
GET |
/v1/status |
Live status: model, config,
model_loaded, requests_served,
memory (current / peak RSS vs process budget)
|
GET |
/v1/agent |
Loaded agent registry (name, system, tools). 404 JSON when no manifest. Never includes executor wiring. |
GET |
/ |
Primary GUI — embedded web chat |
GET |
/status |
Secondary status page (mirrors /v1/status + agent)
|
curl -sS http://127.0.0.1:11500/v1/generate \
-H 'content-type: application/json' \
-d '{"prompt":"Summarize: the pump pressure is low.","max_tokens":64}'
# Scripting twin of the status page
onpremo status --json
curl -sS http://127.0.0.1:11500/v1/status
Surfaces: CLI, API, UI, tray
Four surfaces, one capability contract — CLI, HTTP API, embedded web
UI, and (where compiled in) the desktop tray are thin views over the
same engine. Operating-loop capabilities have full CLI/API/UI parity;
provisioning (pull, discover, benchmark, recommend) is CLI-first by
design: a LAN-facing gateway page must not mutate the machine. The
tray is built-in on macOS and Windows during
onpremo serve; Linux gets it only via the opt-in
tray-linux feature so default board and desktop images
stay lean.
| Capability | CLI | API | UI | Tray (built-in macOS/Windows; Linux via opt-in tray-linux) |
|---|---|---|---|---|
| Chat | onpremo chat |
POST /v1/chat/completions |
GET / (primary GUI) |
Open chat → browser / |
| Tool calls + confirmation | chat --agent, agent step/loop |
OpenAI tools on chat (no exec) |
Web chat tool-call bubble | —(by design) |
| Model / config | inspect, check, status |
GET /v1/model, /v1/status |
/status model + config |
Open status page → /status |
| Live memory | onpremo status |
GET /v1/status → memory |
/status memory meter |
via Open status page |
| Agent registry | agent validate, --agent |
GET /v1/agent |
/status agent section |
—(by design) |
| Structured one-shot | run --json-schema |
response_format on chat |
—(by design) | —(by design) |
| Pull / discover / benchmark | pull, discover, benchmark |
—(by design) | —(by design) | —(by design) |
| Process lifecycle | Ctrl-C / process exit | —(by design) | —(by design) | Quit OnPremo (built-in macOS/Windows; Linux via opt-in tray-linux) |
Benchmark report fields
Schema version 1. Every compatibility claim should be
reproducible from a documented command. Top-level JSON object:
{
"schema_version": 1,
"device": { "...": "DeviceInfo" },
"model": { "...": "ModelSummary" },
"backend": "mock",
"profile_name": "micro-500mb",
"admission": { "decision": "admitted", "...": "..." },
"config": { "...": "RunConfig or null" },
"prompt_chars": 42,
"iterations": [ { "...": "IterationResult" } ],
"aggregate": { "...": "Aggregate or null" }
}
Field groups
| Group | Contents |
|---|---|
| Device | hostname, os, kernel, arch, cpu_model, total_memory_bytes, runtime_version |
| Model | GGUF summary: name, architecture, quantization, file/tensor sizes, layer/head/context/vocab counts |
| Admission |
admitted | downgraded (with steps) |
rejected (reason + detail). Rejected runs leave
config/aggregate null and iterations empty.
|
| Config | context, batch, kv_cache_type, max_output_tokens, threads |
| Per iteration |
GenerationStats (prompt/generated tokens, load/TTFT/total ms, tokens/s),
RssReport (start/peak/end RSS, optional cgroup peak),
swap before/after, completed
|
| Aggregate | Mean/min/max generation tokens/s, mean prompt tokens/s, mean load and first-token ms, max peak RSS, max swap delta |
Certification expects repeatable completion without swap use or OOM termination, peak memory under the declared process budget with a documented safety margin, and disclosure of thermal throttling.
Uninstall
Default install prefix is $HOME/.onpremo on Unix and
%USERPROFILE%\.onpremo on Windows (override with
ONPREMO_PREFIX). Uninstallers remove the binary and PATH
entry; they do not stop services (none are installed). Models under
the prefix are left alone unless you delete the whole prefix when
prompted.
Linux / macOS
curl -fsSL https://onpremo.org/uninstall.sh | sh
Non-interactive: set ONPREMO_UNINSTALL=1 and/or
ONPREMO_NONINTERACTIVE=1 as documented by the script.
Manual removal: delete $HOME/.onpremo/bin/onpremo and the
# >>> onpremo PATH >>> …
# <<< onpremo PATH <<< markers from your shell profile.
Windows
irm https://onpremo.org/uninstall-windows.ps1 | iex
# Or:
powershell -ExecutionPolicy Bypass -c "irm https://onpremo.org/uninstall-windows.ps1 | iex"
Same env knobs: ONPREMO_PREFIX,
ONPREMO_NONINTERACTIVE=1, and
ONPREMO_UNINSTALL=1 (required in non-interactive mode to
proceed). Removes onpremo.exe from the prefix bin dir and
the matching user PATH entry.
Build from source
Requirements: stable Rust toolchain, cmake, and a C++ toolchain when enabling the real inference backend. Linux (ARM64 / x86-64) or macOS for development.
# Mock backend (default — development and CI)
cargo build --workspace
cargo build -p onpremo-cli
# Binary: target/debug/onpremo
# Real llama.cpp backend
cargo build -p onpremo-cli --features backend-llama
# or
cargo install --path crates/onpremo-cli --features backend-llama
One-liner installer that clones and builds with the llama backend:
curl -fsSL https://onpremo.org/install-from-source.sh | sh
backend-llama in CI; mock-backend workspace
tests are the default gate. Published installer / bin-dist
assets are llama-backed for all six targets (see
bin/FLAVORS — every line is
tagged llama) and
SHA256SUMS. The mock backend
is for development and CI only, not the shipped binary.