CLI reference¶
The CLI is the heim command. Everything centers on your library — the
models in your libraries (a project's, or the default HEIM_LIBRARY_ROOT). Run any command
with --help for full options.
Global flag: heim --debug <command> turns on verbose diagnostics — it prints
the exact model-runtime command and streams the runtime's logs live (instead of
discarding them), which is the first thing to reach for when heim chat
reports a model that "exited before becoming ready". (Also settable with
HEIM_DEBUG=1.)
heim project init¶
Scaffold heim.toml here — heim's primary config (no .env needed) — and
ensure its model is in the library. The generated file is portable — it lists the
libraries this project uses (a project-local models/ plus @shared, the
machine default) plus the assistant ([project] model; tools in .mcp.json).
Idempotent — only pulls the model if it's missing. With no --model it
offers a small curated set and pulls the choice into the project-local library.
heim project init # pick a curated starter model
heim project init --model unsloth/Qwen3.5-4B-GGUF # bind a specific model
heim project init --copy # copy the model into a project-local library/
heim project init --git # also: git init + a .gitignore (excludes library/ + .env)
heim project init --force # overwrite an existing heim.toml
heim project new <dir> scaffolds into a fresh directory instead (like cargo new)
and takes the same --model / --copy / --git / --force flags.
A project is a reproducible assistant: in a project directory both heim chat
and heim serve --ui default to its model, system prompt, and MCP tool servers —
so heim serve --ui boots straight into that model, no manual picking.
heim project show¶
Show the active project (heim.toml) in full: the bound model's detail card
(format, size, capabilities, context, tags, path), the system prompt, and the
actual tools — it connects to the project's MCP servers and lists the tools
they expose (with descriptions), not just the server names. --card also renders
the bound model's model card (README).
heim mcp list / heim mcp add¶
Browse MCP tool servers and attach them via the standard mcpServers JSON. list
shows a curated catalog (DHIS2, fetch, git, sqlite, filesystem, …) plus any
installed heim-mcp-* plugins; a ✓ marks servers already in the current directory's
.mcp.json. add writes a server entry to ./.mcp.json — or the machine-global
~/.config/heim/mcp.json with --global — printing a setup: hint when the command
needs config; remove drops one again.
heim mcp list # curated catalog + installed plugins (ls is an alias)
heim mcp add fetch # add to ./.mcp.json
heim mcp add --global datetime # add to ~/.config/heim/mcp.json (every chat gets it)
heim mcp add dhis2 # then edit the DHIS2_PROFILE in the entry's env
See Tools (MCP) for the full picture.
heim library search <query>¶
Search the Hugging Face Hub for new models to pull (most-downloaded first).
heim library search qwen3 # text search
heim library search qwen3 --gguf # only GGUF (llama.cpp-ready) repos
heim library search qwen3 -n 30 # more results
heim library ls¶
List the models in your library — what you've pulled, ready to run — grouped by format with sizes across the libraries in scope.
heim library formats¶
One row per model with a column per format present (gguf / mlx / safetensors / ollama) and their sizes, plus a NOTE flagging the format-policy cases: a redundant safetensors copy (a GGUF or MLX build of the same model already exists — safetensors is just the convert/fine-tune source and can be dropped) and a model that's only safetensors (no ready-to-run quant — llama.cpp/mlx_lm can't serve it; pull a GGUF or MLX build). The footer totals the space reclaimable by removing every redundant safetensors copy.
heim library rm <name>¶
Remove a model from the library — deletes its files from disk. Resolves like
heim chat (use --format to disambiguate a model kept in more than one format);
all copies of the model are removed (e.g. one on the local disk and one on the
drive). Ollama models keep any blobs still shared with other installed models.
Prompts for confirmation unless --yes.
heim library rm Voxtral-Mini-3B-2507-GGUF # confirm, then delete
heim library rm gemma-4-E4B-it-MLX-4bit --yes # skip the prompt
heim library rm Qwen3.6-27B --format mlx # disambiguate when kept in two formats
heim library sources¶
Browse models sitting in your app caches (Hugging Face cache, Ollama, LM
Studio) that you could pull into the library. The IN LIBRARY column marks what
you already have. Non-chat (embedding/vision) and partial entries are hidden
unless --all.
heim library sources
heim library sources -s ollama # --source: limit to one source
heim library sources --all # include embedding/vision/partial entries
heim library pull <source> <name>¶
Copy a model from a source cache into the library.
heim library pull lmstudio <name>
heim library pull ollama gemma4:31b --move # delete the local source after a verified copy
heim library pull ollama --all # import every model from the local store
heim library pull lmstudio --all --move # import all, freeing local disk as it goes
# Hugging Face:
heim library pull huggingface lmstudio-community/gemma-4-12B-it-QAT-GGUF --include '*Q4_K_M*'
heim library pull huggingface OuteAI/OuteTTS-0.2-500M-GGUF --include '*Q4_K_M*' \
--vocoder ggml-org/WavTokenizer # a TTS model + its vocoder
--move— relocate (copy, verify byte-for-byte, then delete the local source to free disk). Supported for LM Studio and Ollama.--all— import every model from that source's local store instead of a single name (the two are mutually exclusive). Idempotent (skips models already in the library, so it doubles as a sync) and resilient (a failing model is logged and the batch continues; exit code is non-zero if any failed).--include <glob>— Hugging Face only; fetch only matching files (repeatable), e.g. one GGUF quant from a multi-quant repo. Model cards and configs come along.--vocoder <repo>— Hugging Face only; co-locate a vocoder (e.g. WavTokenizer) with the model so it's recognized as a text-to-speech model (seeheim voice speak).
heim library manifest¶
Export your library as a want list — a portable, human-editable TOML file of [[model]]
entries (source + name + format), one per model, enough to re-pull each. Reads each model's
recorded source from its .heim/ sidecar (inferring it for older pulls). Prints to stdout by
default; --save <file> writes it. No state is kept in the library — the manifest is generated
on demand, so you keep the file wherever you like (commit it to a repo, copy it to another drive).
heim library manifest # print the want list (pipeable)
heim library manifest --save models.toml # write it to a file
LM Studio backups (which can't be re-downloaded as such) are recorded as their Hugging Face equivalent; Ollama models are recorded as-is; voice models as their registry id.
heim library sync <wantfile>¶
Re-download every model in a want list that's missing from your library. Diffs the file
against your library (models already present are skipped) and pulls the rest via the normal
per-source paths — the rebuild-a-drive companion to heim library manifest.
heim library sync models.toml # pull everything missing
heim library sync models.toml --dry-run # show the plan, download nothing
heim library sync models.toml --shared # into the shared/default library
One model failing doesn't stop the others; the command exits non-zero if any failed. Ollama
entries need the model in your local Ollama store first (ollama pull <name>), since the
Ollama pull path copies from there rather than the internet.
heim chat <name>¶
Chat with a library model — a full-screen Textual TUI by default, one-shot with -p.
heim chat <name> # interactive full-screen TUI
heim chat <name> -p "prompt" # one-shot, prints just the answer (pipeable)
heim chat <name> -p "prompt" -n 256 # --max-tokens
heim chat <name> --system "..." # session system prompt (overrides heim.toml)
heim chat <name> --mcp <cmd> # attach an MCP tool server (repeatable)
heim chat <name> -p "prompt" --server http://127.0.0.1:8000 # reuse a running `heim serve`
Interactive chat opens a scrolling TUI: markdown replies, collapsible reasoning,
live tool activity, and a context footer. Enter sends; Shift+Return / Ctrl-J / a
trailing backslash insert a newline; type a new message while one streams to
queue it; Esc stops. -p stays a plain scripted one-shot (streamed stdout).
Reuse a loaded model (--server) — by default each heim chat spawns its own
runtime and loads the model, so a one-shot pays that load every time. Point -p at a
running heim serve instead and it attaches to that server's /v1, reusing the
already-loaded model (tools still run):
heim serve --model <name> --port 8000 # load the model once, keep it resident
heim chat -p "what is todays date" # instant — no reload
A loopback heim serve --model <name> is auto-detected: with no --server (and none in
config), heim chat -p finds a running server locked to that model and attaches to it (a ↳
attaching… note goes to stderr). Set an explicit default with heim config set server <url>
(or HEIM_CHAT_SERVER); --server overrides. --server/attach apply to the one-shot (-p)
path; the interactive TUI owns its own runtime.
Multimodal input — for vision/audio models, attach files:
heim chat <name> -p "what is this?" --image photo.jpg # vision model
heim chat <name> -p "transcribe" --audio clip.wav # audio model
--image/-i and --audio/-a are repeatable. In the REPL you can also just
drag a file into the terminal — the inserted path is detected and attached:
image/audio go as OpenAI multimodal content (heim warns if the model lacks that
modality), while text/code files (.md, .py, .json, …) are inlined into
the prompt as fenced blocks, so you can drop a file into any model as context.
Non-chat models (embeddings, vision encoders) are refused with a clear message — heim runs generative LLMs only.
heim voice voices¶
List the built-in Kokoro voices (54 across 9 languages) with their id, language, and gender. Kokoro ships built in (no extra to install).
heim voice speak <text...>¶
Text-to-speech. --voice/-v picks a Kokoro voice (multi-voice engine; run
heim voice voices to list them, model downloaded on first use). Otherwise it uses
llama-tts/OuteTTS — the default, or --model for a library TTS model (see
heim library pull --vocoder). Markdown/code in the text is reduced to prose first.
heim voice speak hello there # default voice, play aloud (macOS)
heim voice speak -v af_heart "hello there" # a specific Kokoro voice
heim voice speak "some text" -o out.wav # write a WAV instead of playing
heim voice speak hi --model OuteTTS-0.2-500M-GGUF # a specific library OuteTTS model
heim setup¶
First-run machine setup — the write-mode companion to heim doctor (machine scope,
whereas heim project init scaffolds one project). It persists per-machine defaults to
~/.config/heim/config.toml (library location + default model), builds the browser UI if
Bun is present, and prints an OS-specific hint for anything it can't install
(the llama.cpp binary). Safe to re-run.
heim setup # interactive first-run setup
heim setup --library-root /path --model <name> --yes # non-interactive
heim config¶
Read and write the machine defaults (~/.config/heim/config.toml) — the lowest-priority
settings source, below HEIM_* env vars and a project heim.toml. Writable keys:
library-root, model (the default model outside a project), and server (a default
heim serve URL for heim chat -p to attach to).
heim config set library-root /path/to/your/library # where your library lives
heim config set model lmstudio-community/gemma-4-12B-it-QAT-GGUF # default model
heim config list # show every stored value (ls is an alias)
heim config get library-root # one value
heim config path # print the config file location
heim doctor¶
Pre-flight system health: are the runtime binaries heim spawns installed
(llama-server, and mlx_lm.server/mlx_vlm.server on Apple Silicon), is the
library reachable and non-empty, and does the project point at a present model.
Exits non-zero if any check fails.
heim serve¶
Run the web server (browse API + /v1 proxy; browser UI with --ui).
heim serve --ui # browse + chat, switch models (auto-picks a free port)
heim serve --ui --port 8000 # pin the port for a stable URL
heim serve --ui --model <name> # locked single-model mode (extension backend)
heim serve --reload # dev auto-reload
Equivalent Makefile targets: make run and make run MODEL=<name>.