01 · Quick start

Model to endpoint in four commands

Each release ships one archive per platform with two files — ohmygpu-runtime (the runtime) and ohmygpu (the CLI, aliased omg). Nothing else to install; models and the engines live under ~/.config/ohmygpu. A GPU is used when present — Metal, CUDA or Vulkan — and CPU works too.

# 1 — get the binaries (macOS Apple Silicon shown; see Installation)
$ T=aarch64-apple-darwin
$ curl -LO https://github.com/ohmygpu/ohmygpu/releases/latest/download/ohmygpu-$T.tar.gz
$ tar xzf ohmygpu-$T.tar.gz && sudo install ohmygpu-$T/* /usr/local/bin/

# 2 — start the runtime
$ omg serve

# 3 — download a model (see the catalog: omg model catalog)
$ omg model pull qwen2.5-0.5b-instruct

# 4 — start it (first start also fetches llama.cpp for your platform)
$ omg run qwen2.5-0.5b-instruct

Then call it with anything that speaks OpenAI — the modern Responses API or Chat Completions, both against the same model:

$ curl http://127.0.0.1:10692/v1/responses \
    -H "Content-Type: application/json" \
    -d '{"model": "qwen2.5-0.5b-instruct", "input": "Explain why the sky is blue."}'
# from an existing OpenAI client — verified against the official SDK
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:10692/v1", api_key="not-needed")
r = client.responses.create(model="qwen2.5-0.5b-instruct", input="Hello!")
print(r.output_text)
02 · Installation

One archive per platform

Pinned versions live at releases/download/<tag>/…, and every release carries SHA256SUMS.txt. The binaries are not code-signed yet — if macOS quarantines a browser download, run xattr -dr com.apple.quarantine <dir> (curl downloads are not quarantined). Or build from source with a Rust toolchain, no GPU toolchain needed: make build.

03 · CLI

omg — a thin client, by design

Every command except serve and config is a call to the Management API. Add --json for machine-readable output; point at a non-default runtime with --url or OHMYGPU_URL.

omg serve [--host H] [--port P] run the runtime in the foreground
omg status runtime + backend + models summary
omg hardware detected platform, CPU, memory, GPU
omg model list | catalog installed models / curated catalog
omg model pull <ref> [--id X] catalog id, hf:owner/repo/file.gguf, or URL
 [--mmproj FILE] [--kind llm|whisper] vision projector · force the kind
omg model rm | info <id> delete / inspect
omg run <id> [--context-length N] start (also: --gpu-layers, --threads)
omg stop <id> stop a running model
omg shutdown graceful shutdown, stops all models
omg config [key [value]] read / write config.toml
04 · API · Inference

An OpenAI-compatible subset, stated exactly

Only what is listed is implemented. Unknown fields are ignored; unsupported features return 400 with "code": "unsupported" — never silently wrong output.

POST /v1/responses — canonical

model · input · instructionsstring or item-array input; instructions become the system message
input_image partsvision models onlyimage_url is a data:image/…;base64,… URL or an http(s) URL the runtime fetches itself (png/jpeg/gif/webp/bmp, ≤ 20 MB); other models answer 400 unsupported
tools · tool_choicefunction tools; calls come back as function_call items — your app executes them
temperature · top_p · max_output_tokens · metadatasampling and limits
stream: trueResponses-style SSE, from response.created through response.completed

Not supported (400): previous_response_id, background, hosted tools, file inputs, non-text formats. Response storage is not implemented; store is always false.

POST /v1/chat/completions — ecosystem

messages · tools · tool_choicesystem / developer / user / assistant / tool roles; function tools
image_url partsvision models only — same rules as above
temperature · top_p · max_tokens · stop · seed · penaltiesstandard sampling controls
stream · stream_optionsstandard chat.completion.chunk SSE with data: [DONE]

Not supported (400): n > 1, audio content parts, non-text response_format.

POST /v1/audio/transcriptions — speech to text

file (multipart) · modelwav, mp3, m4a/aac, flac, ogg-vorbis — decoded and resampled by the runtime, no ffmpeg; ≤ 50 MB; a whisper model (kind: whisper)
language · prompt · temperatureISO-639-1 language, default auto-detect
response_formatjson (default), text, verbose_json (segments with timestamps), srt, vtt
timestamp_granularities[]segment only (word → 400)

Not supported (400): stream, word timestamps, /v1/audio/translations. A chat request to a whisper model, or a transcription request to an LLM, answers 400 unsupported. GET /v1/models lists installed models in the OpenAI shape with extra state and kind fields. Legacy /v1/completions is intentionally absent.

Errors — the OpenAI envelope, everywhere

HTTPcodeWhen
400invalid_request · invalid_json · unsupportedmalformed or out-of-subset request
404model_not_foundnot installed or unknown
409model_not_runninginstalled but stopped — message says how to start it
502backend_error · model_start_failedthe engine failed — includes the log tail
503backend_unavailablethe engine went away mid-request
05 · API · Management

The whole lifecycle over HTTP

Everything the CLI can do, your application can do — every state, download percentage and failure reason is visible. Nothing requires the CLI.

Model lifecycle
not_installeddownloadinginstalledstartingrunningstoppingstopped+ error, with the reason
Method & pathPurpose
GET /ohmygpu/v1/health · /status · /hardwareliveness · uptime and inventory · detected GPU and backend
GET /ohmygpu/v1/catalog · /models · /models/{id}curated models · all known models · one model with progress
POST /ohmygpu/v1/models/pull202, idempotent — catalog id, hf: ref, or URL; optional id, mmproj (vision projector), kind
POST /ohmygpu/v1/models/{id}/start?wait=true202 starting — or with wait, 200 running / 502 with the reason
POST /ohmygpu/v1/models/{id}/stop · DELETE /models/{id}stop · stop if needed, delete files, forget
GET /ohmygpu/v1/backend · POST /backend/install[?backend=whisper]llama.cpp / whisper.cpp availability · install ahead of first start
POST /ohmygpu/v1/shutdowngraceful shutdown — stops all models
06 · Configuration

One directory, one file

Everything lives under ~/.config/ohmygpu — or $OHMYGPU_HOME / --data-dir, so a bundling application can give the runtime a private data directory.

# config.toml — the defaults, annotated
[daemon]
host = "127.0.0.1" # local only; no auth yet, keep it that way
port = 10692

[inference]
auto_start = false # 409 for stopped models, or start on demand

[backend.llamacpp]
auto_install = true # fetch the official release if not found
release = "latest" # or pin a tag like "b10437"
context_length = 8192
# server_path = "/path/to/llama-server" # or OHMYGPU_LLAMA_SERVER
startup_timeout_secs = 600

Environment overrides: OHMYGPU_HOME · OHMYGPU_HOST · OHMYGPU_PORT · OHMYGPU_LLAMA_SERVER · OHMYGPU_WHISPER_SERVER · HF_TOKEN · OHMYGPU_LOG (e.g. info,llamacpp=debug to see the engine's own logs). Managed llama.cpp builds cover Metal on macOS, CPU/Vulkan on Linux and Windows; for CUDA on Linux point server_path at your own build.

07 · Recipes

Adapting a model is editing a data file

A recipe is one YAML file per model: where the weights live, which backend runs them, quant variants mapped to hardware requirements, and a smoke test. Hand-authored recipes are YAML (comments, multi-line templates); the wire format is JSON; one schema behind both — recipe-v1.json.

recipes/qwen2.5-7b-instruct.yaml — abridgedyaml
schema_version: 1
id: qwen2.5-7b-instruct
family: qwen2.5
capabilities: { tools: true }
backend: llamacpp
source: { hf: bartowski/Qwen2.5-7B-Instruct-GGUF }
chat: { tool_call_parser: hermes }

variants:
 - name: q4_k_m
 source: { file: Qwen2.5-7B-Instruct-Q4_K_M.gguf }
 size_gb: 4.7
 requires: { vram_gb: 6, ram_gb: 8 }
 - name: bf16 # same model, GPU-box variant
 backend: vllm
 source: { hf: Qwen/Qwen2.5-7B-Instruct }
 requires: { vram_gb: 20, min_compute_capability: "8.0" }

tests:
 - prompt: "Reply with exactly: pong"
 expect_contains: pong

The minimal recipe is an id and a source — backend and format are inferred. A default recipe (vLLM with the Transformers fallback, once the vLLM backend lands) means most models will need no recipe at all; the compiled-in catalog migrates to recipes/*.yaml as this ships. Status: schema, validation and examples are in the tree; the hardware resolver is next.

08 · Embedding

Ship it inside your application

The runtime is built to be bundled: no UI, no global state outside its data dir, structured logs on stderr, graceful shutdown that stops its engine children.

# 1 — launch with a private data dir and port
ohmygpu-runtime --data-dir /your/app/data --port 17742
# 2 — wait for readiness
GET /ohmygpu/v1/health {"status":"ok", …}
# 3 — ensure model exists, start it, infer
POST /ohmygpu/v1/models/pull → 202, poll download progress
POST /ohmygpu/v1/models/{id}/start?wait=true
POST /v1/responses
# 4 — on quit
POST /ohmygpu/v1/shutdown (or SIGTERM)

By default a request for a stopped model returns 409 model_not_running — deliberate, so your app owns the start moment. Set inference.auto_start = true to start on first request instead.

09 · Contributing

Free, open source — and staying that way

OhMyGPU is Apache-2.0 with no commercial edition planned. The most valuable contribution is the day-to-day one: model adaptations as recipes — and honest issue reports from real hardware.

$ make test # unit + API tests, mock backend — fast, no GPU or network
$ make check # fmt + clippy
$ OHMYGPU_E2E=1 cargo test -p ohmygpu_daemon --test e2e_llamacpp -- --ignored
 # real llama.cpp + a small model, ~480 MB download

Architecture notes and the llama.cpp-vs-Candle decision are in docs/architecture.md. To propose a model: open a PR adding one file under recipes/ that validates against the schema and passes its own smoke test. Each accepted adaptation gets its post on the news page.