This page documents the full localm command-line interface. For a quick introduction, see the README.
localm run MODEL [opts] # chat or single prompt
localm gui [MODEL] [opts] # browser GUI (chat + coder + plugin tabs)
localm serve [MODEL] [opts] # OpenAI-compatible server
localm benchmark MODEL [opts] # TTFT and tok/s at increasing prompt sizes
localm coder [TASK] [opts] # AI coding agent (coder plugin)
localm job ... [opts] # scheduled recurring jobs (jobs plugin)
localm mcp [opts] # MCP stdio server (mcp plugin)
localm doctor # check Python, llama.dll, GPU driver, VRAM, packages
localm info # paths + current config
localm setup-llama [opts] # provision native llama.cpp binaries
localm setup-music [opts] # install native music generation (ACE-Step 1.5 through KoboldCpp)
localm setup-sdcpp [opts] # install the native image runtime (stable-diffusion.cpp)
localm setup-browser [opts] # download Chromium for the automated browser--debug on gui, serve, and run writes a log to <data dir>/logs/ with request timing and the native llama.cpp stderr stream (including crash abort reasons). Outside privacy mode it also writes the raw model output, before marker scrubbing, to that log; the reply you see is always scrubbed.
localm run mymodel --prompt "What is 42?"
localm run mymodel --system "You are terse." --prompt "How does TCP work?"
echo "Translate 'hello' to Japanese." | localm run mymodel
localm run mymodel # interactive chat
localm run mymodel --max-tokens 256 # max tokens to generate
localm run mymodel --temperature 0.5 # sampling temperature
localm run mymodel --ctx 8192 # context window (GGUF only)
localm run mymodel --gpu-layers 99 # GPU layers (GGUF only; 99=all)
localm run mymodel --image photo.jpg --prompt "Describe this image."
localm run asr-model --audio clip.wav --prompt "Transcribe this."
localm run mymodel --debug # write debug log
localm run mymodel --mode privacy # privacy/log/full persistence mode
localm run mymodel --pin-model # always answer with mymodel
localm run mymodel --mmproj mmproj-model-f16.gguf --image photo.jpg # explicit vision projector (GGUF)
localm run hf-model --device cpu # HuggingFace models: device override (cuda / cpu)
localm run mymodel --no-server # load the model in this processBy default run attaches to the localm server already serving the current directory, so no second copy of the model is loaded. When none is running it starts one in the background (localm gui --no-browser --api-mode), which keeps running after run exits; localm stop ends it. If that server holds a different model, or has no model loaded, run exits 1 instead of answering with it - use --no-server to load MODEL in this process.
A message mymodel cannot handle - an image it cannot read, or a conversation
that has outgrown the context window it was trained for - is answered by an
installed model that can, followed by a line naming that model and why.
--pin-model keeps every message on mymodel instead. Loaded in this process
(--no-server), the other model is swapped in for those messages and
mymodel is loaded again afterwards. A message with an image the answering
model cannot read or decode is withdrawn entirely, text included, with a
note printed to say so, so later messages are not refused for it.
MODEL can be a registered name or a direct path:
localm run gemma4-12b
localm run D:\models\llama3.gguf
localm run D:\hf-models\gemma-3-4b-itlocalm gui # picks the first registered model, opens browser
localm gui mymodel # or name one
localm gui --no-model # open model-less, straight to the Models page
localm gui --no-browser # start the server, open the URL yourself
localm gui --pull <spec> # start a download immediately
localm gui -H 0.0.0.0 # bind to all interfaces (requires auth key)
localm gui --qr # [PoC] scannable QR of LAN URL for phones (needs a network bind)
localm gui -p 8650 # explicit port (must be free, else errors)
localm gui -c 8192 -g 99 # context window, GPU layers
localm gui --mode log # privacy (default) | log | full session persistence
localm gui --keep-diagnostics # keep diagnostics (hang trace, debug log) even in privacy mode
localm gui --project D:\path\to\project # project root that keys this instance
localm gui --new # start a fresh server instead of attaching to the running one
localm gui --isolated # private server invisible to discovery (implies --new)
localm gui --api-mode # API only, no Web GUI
localm gui --mmproj mmproj.gguf --device cuda:0 # projector file, explicit deviceChat, the coder agent, model management, and any enabled plugin tabs in one page. The model preloads in the background so the first reply is fast. See docs/gui.md for details.
A second localm gui for the same project attaches to the server already running instead of starting another (--new or --isolated start one). gui and serve run in the foreground until Ctrl+C.
Past loopback, built-in TLS is on by default: --no-tls serves plain HTTP, and --tls-cert FILE --tls-key FILE use your own PEM certificate instead of localm's local-CA one. Without an API key, a bind past loopback is refused unless --insecure is passed (see Configuration).
localm serve mymodel
localm serve --no-model # start with nothing loaded; load a model later over the API
localm serve mymodel --port 8650 # explicit port (must be free, else errors)
localm serve mymodel --ctx 8192 # context window
localm serve mymodel --gpu-layers 99 # GPU layers
localm serve mymodel -H 0.0.0.0 # bind to all interfaces
localm serve mymodel --debug # debug logging
localm serve mymodel --mode log # privacy (default) | log | full session persistence
localm serve mymodel --new # start another server even if one already serves this projectserve takes the same --project, --isolated, --insecure, --no-tls, --tls-cert, --tls-key, --mmproj and --device options as gui (see above), serves the API only, and opens no browser. When a server is already serving the project, serve reports it and starts nothing unless --new is passed.
localm owns the port range 8642-8741: the default is 8642, and when no --port is given the server bumps to the next free port in that range automatically if it is taken. An explicit --port is different - it must be free, or startup errors rather than moving you onto another port. Use it with any OpenAI client - set base_url="http://localhost:8642/v1" and api_key="localm".
The streaming usage block adds ttft_ms and tokens_per_sec. See docs/server-api.md for the full API surface, including scope-gated management endpoints.
localm benchmark mymodel
localm benchmark mymodel --gen-tokens 256 # tokens per run (default 128)
localm benchmark mymodel --prompts "64,512,2048" # prompt sizes to test
localm benchmark mymodel --ctx 8192 # context window
localm benchmark mymodel --gpu-layers 99 # GPU layersRuns a fixed prompt padded to each requested size, streams tokens, and reports time to first token, tokens per second, and total time.
localm bench-mtp mymodel
localm bench-mtp mymodel --gen-tokens 256 # tokens per round (default 160)
localm bench-mtp mymodel --rounds 3 # measurements to average (default 2)
localm bench-mtp mymodel --ctx 8192 --gpu-layers 99
localm bench-mtp mymodel --draft-tokens 3 # draft tokens per step for the MTP runs (1-3)Loads the model twice per round, once with Multi-Token Prediction off and once on, and reports which was faster, how many drafted tokens the model accepted, and whether the replies were identical to MTP off. Nothing is written to your config; the settings are left as they were.
localm bench-spec mymodel # n-gram drafting vs none
localm bench-spec mymodel --source mtp # MTP vs none
localm bench-spec mymodel --source draft --draft-model small # a draft model vs none
localm bench-spec mymodel --draft-tokens 4 # draft tokens per step for the "on" runs (MTP 1-3, otherwise 1-16)
localm spec-drafts mymodel # downloaded models that can draft for mymodelSame comparison for any draft source (--source ngram, the default, mtp, or draft with --draft-model, which defaults to the spec_draft_model setting), over the MTP prompts plus a rewrite that repeats its input, and it also reports whether a greedy reply matched. For ngram and draft it prints the step costs measured at load and the step times seen per draft length. Takes the same --gen-tokens, --rounds (1-5; default 3 here, 2 for bench-mtp), --ctx and --gpu-layers options. Nothing is written to your config. spec-drafts reads each downloaded GGUF's metadata, loads nothing, and lists the causal chat models that share the model's vocabulary, smallest first.
# Specific GGUF from any HF repo (split files are handled automatically)
localm pull owner/repo:model-Q4_K_M.gguf
# Full HuggingFace model directory (transformers format)
localm pull owner/repo
# Direct URL, with optional integrity check
localm pull https://example.com/m.gguf --sha256 <hash>
# Alias for the downloaded model
localm pull owner/repo --name myalias
# Force a fresh download even if an identical model is already registered
localm pull owner/repo:model-Q4_K_M.gguf --redownload
# Download an mmproj vision projector alongside the main model
localm pull owner/repo:model-Q4_K_M.gguf --mmproj mmproj-model-f16.gguf
# Set the model type explicitly instead of relying on auto-detection
localm pull owner/repo:model-Q4_K_M.gguf --type llmDuplicate downloads are detected by path and SHA256. When you add or pull something already registered, localm offers alias / copy / move / register / skip instead of silently duplicating gigabytes. Two downloads to the same destination (from the CLI, the GUI, or both) are serialised rather than allowed to interleave their bytes into one file; starting a download that is already running is refused up front, and one interrupted by a crash resumes instead of restarting.
localm search qwen2.5 7b instruct # find GGUF repos
localm search bartowski/Qwen2.5-7B-GGUF --files # quants + sizes + VRAM fit
localm search qwen2.5 -n 25 # up to 25 results (default 10)An empty query lists the most downloaded repos.
CivitAI is a second, independent model source for checkpoints, LoRAs, VAEs, and textual inversions used by the media plugins - core CLI, no plugin required.
localm search --source civitai detail tweaker # search CivitAI instead of HF
localm search --source civitai --files 135867 # a version's downloadable files
localm search --source civitai <query> --nsfw # include NSFW results (off by default)
localm search --source civitai --files <id> --legacy-formats # include older, riskier file formats
localm pull civitai:<versionId> # download a specific model version
localm pull civitai:<versionId>:<fileId> # a specific file within that versionContent flagged as depicting a minor is always excluded, regardless of
--nsfw. --mmproj and an explicit destination directory do not apply to a
CivitAI pull: the downloaded file is verified against CivitAI's own checksum
and placed automatically in the active ComfyUI's matching models/<type>
folder (checkpoints, loras, embeddings, vae, controlnet, or upscale_models) -
the managed ComfyUI's folder if one is active, otherwise your configured
comfy_workdir. With neither configured, the pull fails outright rather than
falling back to localm's own models folder.
Versions of one CivitAI model often share a filename. A file already in that
folder is reused only when it is shown to be the requested version's: its
SHA256 matches CivitAI's (or the one you pass with --sha256), or, when
CivitAI lists no SHA256, localm's registry records it as that version and its
size matches the size CivitAI lists, when it lists one. Any other file is left
untouched and the pull stops with the steps to replace it. --redownload replaces a file only once no model
registered from another source points at it.
An optional CivitAI API token, and a matching one for HuggingFace, raise rate limits and reach gated or login-required models on search and download. Neither is required - both sources keep working anonymously with nothing set.
localm config civitai_api_key <key> # or the CIVITAI_API_KEY env var
localm config hf_token <token> # or the HF_TOKEN env varA stored value (via localm config, or Settings > Model > Model Library &
Sources) takes precedence over the matching env var. localm config civitai_api_key "" (a blank value) clears the stored token; in Settings,
leaving the box blank and saving leaves the existing token alone - use the
field's Clear button to remove it. Neither is ever echoed back by localm info or localm config.
localm add D:\models\mymodel.gguf
localm add D:\models\my-hf-model --name mymodel
localm add D:\ollama\manifests\registry.ollama.ai\library\<model>
localm add D:\models\mymodel.gguf --on-duplicate alias # ask|alias|copy|move|register|skip
localm add D:\models\bulk-dir --fast # dedup on file size, skip the SHA256 hash
localm add D:\models\mymodel.gguf --type embedding # set the type instead of auto-detecting it
localm alias mymodel short # second name for the same file
localm rename mymodel newname # rename it outright (unlike alias, the old name stops working)add takes a model file, a HuggingFace model directory, or a folder of models (every GGUF and safetensors model inside is registered). It also reads where other tools keep models: the Hugging Face hub cache, an Ollama model store, Jan's data folder, GPT4All's download folder (finished GGUF files only), and a .llamafile (its model is unpacked into <data dir>/models). --type takes the values listed under Model type (default auto).
localm rename also updates, best effort, the references to the old name inside the data directory (config, jobs, Knowledge collections); a per-project .localcoder/config.toml model setting is not touched. When a localm server is serving the current directory it performs the rename, so a loaded model keeps serving under its new name.
Duplicate detection is two-tier: the resolved path first, then the file's SHA256 against digests already in the registry (large files hash off the main thread with a progress bar; --fast skips the hash and dedups on file size alone; --no-hash disables content-level dedup entirely). --on-duplicate picks the answer non-interactively instead of prompting (default ask).
By default add (and pull with a local path) registers the file where it already is - nothing is copied or moved. Pass --store copy or --store move to bring it into <data dir>/models first and register it from there instead, so it's managed exactly like a pulled model:
localm add D:\models\mymodel.gguf --store copy # duplicate into <data dir>/models, keep the original
localm add D:\models\mymodel.gguf --store move # relocate into <data dir>/models--store moves/copies a split GGUF's every part and a sibling mmproj vision-projector file together with the model, so multi-part loading and vision capability survive the move. It refuses (no changes made) if a different file already occupies that name in <data dir>/models, if there isn't enough free disk space, or if a copy's SHA256 doesn't match the original afterward.
Every registered model has a type, detected deterministically from the file
itself, never from fuzzy tag matching: a GGUF or Ollama blob is classified from
its own metadata (an adapter signal makes it lora, a vision-projector signal
makes it mmproj, an embedding/pooling signal makes it embedding, otherwise it
is an llm); a HuggingFace directory is read from its config.json
architectures (or adapter_config.json for a lora). Anything without a hard
signal is left as unknown rather than guessed. The types are llm, mmproj, diffusion-unet,
text-encoder, vae, lora, embedding, tts, upscaler, and unknown.
An unknown model still runs when you name it explicitly (localm run NAME, or an
API request naming it), but is never auto-picked as the default chat model, so a
diffusion checkpoint or text encoder cannot get loaded as if it were a chat model.
Correct a misdetected or unknown type at any time:
localm set-type MODEL llm # types: llm mmproj diffusion-unet text-encoder vae lora embedding tts upscaler unknownRegistering a lone .safetensors file scans its parent directory: if that folder
is a real HuggingFace model (config plus weights and tokenizer), the folder is
registered; otherwise the file is rejected with an "incomplete model" message
rather than added as a half-model. The exception is an image or video model file
(a diffusion model, text encoder, VAE or LoRA recognised from its tensor layout,
or named with --type), which registers on its own as that type.
A reranker scores each of several documents against a query, so a search result list can be
reordered by relevance. A GGUF cross-encoder such as bge-reranker-v2-m3, or a decoder reranker
such as Qwen3-Reranker, registers as type embedding and is recognised as a reranker from the
classification head in its own header. Rank documents with it from the command line, the
server's POST /v1/rerank or the MCP rerank tool; /v1/embeddings refuses it.
localm add bge-reranker-v2-m3-Q8_0.gguf -n bge-reranker
localm rerank "what is a panda?" "The giant panda is a bear." "Paris is a city." --model bge-reranker
localm rerank "what is a panda?" --file documents.txt --top-n 5 --json--model can be left out when exactly one reranker is registered. A higher score is more
relevant; the scale depends on the model (bge returns an unbounded score, Qwen3-Reranker the
probability of "yes"). Only the best --top-n are shown. The model runs in this process; a
document longer than the model's window is cut to fit and marked.
A text-to-speech GGUF (Qwen3-TTS) registers as type tts and needs its mmproj, which
localm pull fetches from the same repository. localm speak writes a WAV file:
localm pull ggml-org/Qwen3-TTS-12Hz-1.7B-Base-GGUF:Qwen3-TTS-12Hz-1.7B-Base-Q4_K_M.gguf
localm speak "Hello there." -o hello.wav
localm speak --file chapter.txt -o chapter.wav --seed 7 --language en
localm speak "Hello there." -o hello.wav --voice-file my-voice.wav # imitate a recording
localm speak --list-voices-o/--output is required (except with --list-voices). --model can be left out when exactly one speech model is registered. A named --voice
is a WAV recording saved as <name>.wav in the voices folder of the data directory;
--voice-file takes a WAV recording of at most 30 seconds instead (not together with a named --voice). The
model runs in this process; a status line shows how much audio has been made, and Ctrl+C
stops it. The seed is printed so a result can be reproduced. The server's
POST /v1/audio/speech does the same.
A GGUF LoRA adapter (a .gguf whose header says general.type = adapter, as made by
llama.cpp's convert_lora_to_gguf.py) registers as type lora and cannot be run on its
own. Attach it to a registered GGUF chat model and it is applied every time that model loads:
localm add my-lora.gguf -n my-lora
localm adapter attach my-lora qwen3-0.6b --scale 0.8 # refused if the architectures differ
localm run qwen3-0.6b # runs with the adapter applied
localm adapter list # adapters and what they are attached to
localm adapter detach my-loraAn adapter belongs to one base; attaching it again moves it. Several adapters can be attached
to one base and are applied together, each at its own scale (a negative scale subtracts it).
A change applies the next time the base loads, so unload a model that is already running
(localm unload BASE). Adapters need a llama runtime that exports the LoRA functions and a GGUF
base model; they are not supported for HuggingFace-format models.
localm list [--type TYPE] # registered models, optionally filtered by type
localm models # available shortcuts
localm rm MODEL [--yes] # alias-aware removal
localm relocate MODEL NEW_PATH # re-point a registered model after you moved its file
localm unload [MODEL] # free VRAM on the running server: all models, or just onelocalm rm only deletes the file when the last alias pointing at it is removed and the file lives in <data dir>/models; a model registered in place is only unregistered. The confirmation prompt states exactly what will happen. It also refuses when a running localm server (this directory's or another one's) still has the model's file loaded - checked regardless of --yes, before the confirmation prompt, since this one-shot process shares no memory with a server and has to ask over HTTP; a server it cannot reach counts as "cannot rule it out", not as a green light. localm unload talks to the server serving the current directory (or LOCALM_URL); with no argument it unloads every model, and a named model that is not loaded is a no-op.
These are core CLI commands, not plugin installs. The GUI Media pages and the /generate-* chat commands belong to the media plugins. See docs/flux-setup.md and docs/video.md for ComfyUI model setup.
localm image "A cat on a sunny beach"
localm image "a lighthouse at dusk" --size 768x512
localm music "lofi, jazzy, mellow" --lyrics song.txt -d 180
localm video "a fox runs through snow" --duration 5Options (all optional): localm image takes --negative, --guidance, --cfg, --seed, --image PATH (image-to-image) with --denoise, --lora, --size WIDTHxHEIGHT and -o/--out (default ./image_<timestamp>.png). localm music takes --lyrics FILE, -d/--duration seconds (default 120), -o/--out (default ./music_<timestamp>.wav natively, .flac with ComfyUI), --seed, --steps and --cfg. localm video takes --negative, -d/--duration seconds (default 5), --fps (default 24), --width, --height, --image PATH (image-to-video), -o/--out (default ./video_<timestamp>.mp4), --seed, --steps (default 30) and --cfg. See localm <command> --help for each default.
localm image, localm video and localm music need no ComfyUI: with nothing set up
they use the built-in native backends (stable-diffusion.cpp for images and video, ACE-Step
1.5 on KoboldCpp for music), which install their runtimes on first use
(docs/video.md). localm setup-sdcpp and localm setup-music (under Setup and
diagnostics) install them ahead of time; localm setup-music also downloads the default
music models, which a generation never downloads by itself. Full guides:
docs/native-image.md, docs/native-music.md.
localm can run its own managed ComfyUI instead of depending on your install, so it can pin a known-good version and carry fixes. Off by default; your own ComfyUI is never modified. Full guide: docs/managed-comfyui.md.
localm comfy setup # provision it (copies your ComfyUI, or a fresh hardware-matched install)
# media routes to it right away (comfy_target defaults to "own")
localm comfy status # is one installed, which ComfyUI is targeted, and is it running
localm comfy update # advance to the shipped pinned version, re-apply localm's patches
localm comfy remove [--models] [-y] # delete it (keeps the managed models unless --models; -y skips the confirmation)localm comfy setup takes --copy-custom-nodes / --no-custom-nodes (copy path
only; you are asked when custom nodes are present). localm comfy update takes
--reinstall-requirements and, for testing, --commit <sha>.
These drive whichever ComfyUI localm targets - the managed one or your own.
localm comfy status # ...including whether it is running, and whether localm launched it
localm comfy status --no-ping # skip the liveness check (offline and instant)
localm comfy start # start it without running a generation
localm comfy start --media music # start it with the music plugin's own ComfyUI settings
localm comfy stop # abort the render, clear the queue, free its VRAM
localm comfy restart # stop it, then launch a fresh onestart, stop and restart need a running localm server (localm gui or localm serve; they exit 1 without one), because the
handle on a ComfyUI localm launched belongs to the process that launched it -
only that process can end it. localm comfy stop never kills a ComfyUI you
started yourself: it aborts the render and frees the VRAM, and says so rather
than implying the process is gone. A cold start compiles GPU kernels and can take
minutes, so start and restart wait for the configured comfy_launch_timeout. localm comfy status also works without a server, but then reports whether localm launched the running ComfyUI as unknown.
Pressing Ctrl-C during localm image / localm music / localm video tells
ComfyUI to abort that render and free its VRAM.
Whether localm targets the managed instance is decided by one setting,
comfy_target (own by default, or user to force your own ComfyUI) - localm
uses the managed instance only when it is own AND an instance is installed;
otherwise it uses your own ComfyUI.
Each media plugin can generate with an uploaded ComfyUI workflow (in ComfyUI:
Save > API format) instead of the shipped default - the same picker the GUI's
Image/Music/Video pages expose. This governs localm image/music/video
too, not just the GUI, and works fully offline (no running server needed).
localm comfy workflow list image # uploaded workflows, and which is active
localm comfy workflow add image my_flux.json --use # upload, and select it
localm comfy workflow use image my_flux.json # select an already-uploaded one
localm comfy workflow use image --clear # back to the shipped default
localm comfy workflow rm image my_flux.json # delete (refuses the active one; -y skips the confirmation)
localm comfy workflow add image my_flux.json --name flux2.json # store it under another filenameThe media argument is image, music or video.
localm plugin config <name> workflow <file> reaches the same selection - it
is what add --use/use write to - but only workflow list shows what is
actually uploaded.
localm rag add NAME PATH... [--embed] [--force] # index files/folders into a collection
localm rag list # collections with doc/chunk counts
localm rag docs NAME # list a collection's documents: path, chunks, status
localm rag query NAME "text" [--embed] [-k N] [--relevant-only] [--context "previous message"] [--rerank|--no-rerank] # show the top matching excerpts (-k: how many, default 4)
# (--relevant-only: only those over the chat's relevance floor;
# --context: the previous chat message, searched together with a
# "text" that refers back to it, with --relevant-only;
# --rerank/--no-rerank: re-score the best hits with an installed
# reranker; default is the rag_rerank setting)
localm rag resync NAME [--embed] [--prune-missing] # re-walk the indexed folders: pick up new and
# changed files, flag ones that have vanished
localm rag repair NAME [--embed] [-y] # re-index every known document from scratch
localm rag reembed NAME [-y] # recompute vectors with the current embedding model, without re-reading source files
localm rag rm-doc NAME PATH # remove one document from the index (file kept)
localm rag rm NAME [--yes] # delete a collection (index only, files kept)CLI indexing is lexical-only (BM25) by default, with no engine involved; pass
--embed to add/query/resync/repair to also compute embeddings via a
running localm server (--url to point at a non-default one, also on reembed),
matching the GUI's hybrid retrieval; add and query fall back to lexical-only
when no server is reachable. repair without --embed on a collection that has embeddings drops
them for every re-indexed document, so it asks first (-y accepts the drop); with
nobody to answer (a script, cron) it keeps the embeddings by recomputing them.
resync is the incremental one to run regularly (--prune-missing to also drop
entries whose file is gone; off by default so an unplugged drive cannot delete
your index). Put it on a schedule with
localm job add sync-docs --rag --collection NAME --cron "0 3 * * *" - see
docs/jobs.md.
A named API key's whole RAG reach - indexing, querying, and every other
collection route - can be confined to specific folders with localm key create NAME --scope rag --rag-root DIR (repeatable) - see
API keys and docs/rag.md.
Enable the rag plugin to use Knowledge; PDF parsing is built in. See docs/rag.md for retrieval design.
localm job add NAME --prompt "..." [--cron "0 9 * * 1-5" | --every SECONDS] # neither: every 3600 seconds
localm job add NAME --prompt "..." --disabled # create it disabled until `job enable`
localm job add NAME --prompt "..." --coder --cwd DIR --scope "tests/**"
localm job add NAME --memory --every 21600 # synthesise memory facts, no prompt needed
localm job add NAME --rag --collection COLL --cron "0 3 * * *" # keep a Knowledge collection current
localm job list # id, name, schedule, state, last status
localm job show JOB_ID # full definition: schedule, prompt, cwd/scope, allow_shell
localm job run JOB_ID # run once now, record the result
localm job results JOB_ID [--limit N] [--offset N] # past run results, newest first
localm job enable JOB_ID
localm job disable JOB_ID
localm job remove JOB_ID # delete the job and its results--cron and --every are mutually exclusive, as are --coder, --memory and --rag; --rag needs --collection. A job's --model NAME picks a specific registered model to run it with (chat
and coder jobs; otherwise the server's active model, unless the job needs
something it lacks, in which case an installed model that has it runs it
instead), and a coder job needs --allow-shell to run unrestricted (off by
default: read plus confined edits, no shell, no network).
The localm job CLI, the Jobs GUI tab, and the plugin's /api/jobs routes share one on-disk store. The scheduler only ticks while a localm gui/localm serve (with the jobs plugin active) is up. See docs/jobs.md.
localm memory list [--all] [--json] # what localm has remembered about you
localm memory show ID # one fact in full, with its provenance
localm memory add "fact" [--kind semantic|episodic] [--importance F]
localm memory forget ID [-y] # delete one fact (not recoverable)
localm memory forgotten # facts localm archived on its own
localm memory restore ID # bring an archived fact back
localm memory corrections [--json] # proposals consolidation left for review
localm memory accept ID | reject ID # resolve one proposal
localm memory clear [-y] # erase everything, archive included (not recoverable)Reads and writes the same store the app and the memory plugin's chat recall
use, and works whether or not that plugin is installed - the plugin only adds
the automatic recall-on-chat and background consolidation hooks. add,
restore, accept and reject write to the store, so they refuse in the
default privacy mode (set mode or chat_mode to log or full first), and
corrections lists nothing there (it prints why and exits 0). forgotten lists
the archive, which is filled when the record cap evicts a fact or an accepted
correction replaces one; forget is a hard delete that never reaches it. See
docs/memory.md.
localm config temperature 0.7
localm config n_gpu_layers 99
localm config n_ctx 8192
localm config port 8650
localm config confirm_remove false
localm config comfy_launch_cmd "D:\path\to\comfyui.bat"
localm config autoprune_missing_models true
localm config language de # interface language: en (default) or delocalm config KEY VALUE always sets a value; localm info prints the current ones. Config lives at <data dir>/config.json and only known keys are settable (both the CLI and the GUI validate against the schema). Only the settings you actually changed are stored in the file. Set require_auth true (or LOCALM_REQUIRE_AUTH=1) to fail closed and refuse requests until a key exists; localm gui and localm serve refuse to bind past loopback unless an API key of at least 8 characters is set (exit 2; --insecure overrides it, and a bind address set in Settings falls back to loopback with a warning instead); cors_origins widens CORS (locked to localhost by default). See the API keys section and SECURITY.md for the auth and scope model, and docs/tls.md for LAN serving.
The context window starts at n_ctx (default 4096) and grows automatically when a conversation outgrows it, in n_ctx_grow steps (default 4096), up to n_ctx_max (default 16384). Small windows load fast; long chats get room when they need it; the ceiling keeps VRAM use predictable.
localm config n_ctx_max 32768 # raise the ceiling
localm config n_ctx_grow 8192 # grow in bigger steps (fewer rebuilds)
localm config ctx_auto false # use the fixed n_ctx_max ceiling instead of VRAM sizingctx_auto is on by default: it sizes the ceiling from free VRAM at load time (clamped to 4k-64k; n_ctx_max 0 lifts the 64k clamp), overriding a non-zero n_ctx_max. When a conversation reaches the ceiling, replies shorten to fit; when even that is impossible you get a clear error instead of an out-of-memory crash. An explicit -c/--ctx larger than the ceiling always wins.
When free VRAM cannot be measured (for example on a CPU-only machine), ctx_auto falls back to a fixed 16384-token ceiling (set ctx_auto false and raise n_ctx_max to change it).
Long chats compact automatically before they collide with the ceiling. See docs/architecture.md for the compaction and VRAM-sizing details.
On a multi-GPU system, localm loads models onto device 0 by default. localm gpus lists every detected device (index, name, VRAM) and marks the configured one:
localm gpus # list detected GPUs
localm config main_gpu_index 1 # load models onto device 1 insteadThe GUI has the same control: Settings > Live tuning shows a "Main GPU" dropdown once more than one GPU is detected. An index that no longer matches a currently-detected device falls back to device 0 with a logged warning rather than silently loading onto the wrong card.
localm gpus omits the free-VRAM figure (printing a note instead) rather than show a number it cannot stand behind, when the reading is process-scoped or otherwise untrusted for the platform - notably AMD ROCm/HIP on Windows.
When a Mixture-of-Experts model does not fit in VRAM and GPU layers are
auto-sized (n_gpu_layers_auto, with n_gpu_layers left at 99, the
defaults), localm keeps the routed experts of as few layers as needed in system
RAM with every layer on the GPU, before it moves any whole layer to the CPU
(on several GPUs, checking each card's own share; not with a configured
gpu_split_indices split). The load output names the choice and how much
expert data each generated token reads from RAM, which bounds the speed:
gpu layers auto: every layer on the GPU, with the routed experts of 18/48 layers in system RAM (Mixture-of-Experts) - ...
moe speed: each generated token reads about 0.41 GB of expert weights from system RAM, ...
n_cpu_moe sets it yourself: the expert weights of the first N layers stay in
system RAM while the rest runs on the GPU.
localm config n_cpu_moe 16 # keep 16 layers' worth of experts on CPU
localm config n_cpu_moe 0 # automatic, only when the model does not fit - the defaultA value above 0, or an explicit n_gpu_layers, is used as given. No effect on
a normal (dense) model. The Settings page has the same field ("MoE expert
layers on CPU"). See
docs/gpu-setup.md
for measured numbers.
use_mmap controls whether the model file is memory-mapped, so only the pages a
run touches are resident instead of the whole model being read into RAM first.
localm config use_mmap auto # localm decides - the default
localm config use_mmap on # always memory-map
localm config use_mmap off # always read the whole model into memory firstWith auto and every layer on the GPU, localm reads the weights that stay in
system RAM (the token embeddings, and any MoE experts kept off the GPU) into
memory when they fit available RAM with 2 GiB to spare (inside a container,
its memory limit counts). When they do not, the model is memory-mapped and the
load output says so:
mmap on: model may not fit in available RAM, running from disk-backed memory, first tokens slower
Reads then come from disk until the pages are cached, which is why the first
tokens are slower. A model split between GPU and CPU, a load on a machine with
no GPU, and a load where available RAM cannot be read use llama.cpp's own
default instead, which memory-maps the file wherever the device supports it.
When the weights such a load keeps in system RAM (its CPU layers, plus a draft
model placed on the CPU) do not fit available RAM with 2 GiB to spare, the load
output says the CPU layers read them from disk-backed memory and every token is
slower. on and off are used as given and the load output names
them (mmap on / mmap off); with off, a load whose weights do not fit
available RAM warns before it starts that it may fail or swap. The setting applies to the loaded model on its
next load; the Settings page has the same field ("Memory-map model files").
A model too large for any single card's VRAM can load using the combined VRAM of 2 or more GPUs, instead of picking just one:
localm gpus # (split) marks any device in the split
localm config gpu_split_indices 0,1 # split the model across devices 0 and 1
localm config gpu_split_ratios 3,1 # optional: PIN device 0 to three times device 1's share
localm config gpu_split_indices 1 # GGUF chat model: load on device 1 only
localm config gpu_split_indices "" # clear it - llama.cpp spreads a GGUF model over every GPU againHow much of the model lands on each card is figured out automatically: at load time localm reads every split device's free VRAM and sizes each card's share proportionally, so a card that is half-occupied gets a half-sized share instead of an equal one that would not fit. Set gpu_split_ratios only to pin exact weights (that disables the automatic distribution); when free VRAM cannot be measured per device, the split falls back to even shares, and the decision is logged either way.
GGUF models use llama.cpp's native layer-split; HF (transformers) models use accelerate's device_map="auto" restricted to just the listed devices. A single entry loads a GGUF chat model on that device alone, when localm can match the device to llama.cpp's own device list (otherwise llama.cpp's default split is kept and the reason is logged), and loads an HF model on that device with any overflow on the CPU. A longer list with fewer than 2 currently-detected devices (a stale index, or only one still present) drops the split with a logged warning - it never crashes a load. On a CUDA or ROCm build with an integrated GPU beside a discrete one, the integrated GPU is listed, and llama.cpp usually does not use it: for a GGUF load localm checks llama.cpp's own device list and renumbers the split and main_gpu_index into it (when the runtime keeps the integrated GPU, the numbers already match and nothing changes; when localm cannot match the two lists, llama.cpp's default split is kept, device 0 is the primary, and the reason is logged). A split or single entry that names an integrated GPU llama.cpp leaves out refuses the GGUF load with a message saying so. On the vulkan or sycl runtime build the indices are passed to the native loader as-is (torch and nvidia-smi cannot see or number Vulkan-only or SYCL-only devices, so there is nothing to cross-check them against); there the numbers mean that backend's own device order, which is exactly what the GUI's selectors list on that build. The GUI has the same control: Settings > Live tuning shows "Split across GPUs" checkboxes next to the Main GPU dropdown (one ticked GPU loads a GGUF model on that GPU only, none ticked keeps automatic placement), and the model search results hint when a model would fit split across your GPUs but not on the largest one alone.
localm already keeps several models resident at once when they fit: loading a
second model does not evict the first if a live free-VRAM reading shows it
fits alongside (the model's estimated need plus a 1 GB headroom, and, with a
split configured, enough room on every split device). Only when it does not fit
is a resident model evicted, least-recently-used first, and never one that is
currently generating. When free VRAM cannot be measured, or the reading is
inconclusive, localm deliberately stays single-resident rather than stacking
models until the driver runs out. This applies to the HTTP server (localm serve / localm gui) and the MCP server (localm mcp) alike.
Two optional knobs override that arithmetic when you would rather decide yourself:
localm config max_resident_models 2 # keep at most 2 models loaded at once
localm config max_resident_models 1 # strict single-resident (evict on every switch)
localm config pinned_models tiny-a,tiny-b # never evict these to make room
localm config max_resident_models "" # clear the cap - back to free-VRAM arithmetic
localm config pinned_models "" # clear every pinBoth are off by default, so behavior is unchanged unless you set them. The cap bounds how many models stay loaded regardless of how much headroom there is; pinning protects named models from being chosen as the eviction victim (it never loads a model on its own). If pins leave nothing that can be evicted, the load still goes ahead and the missed policy is logged rather than silently dropped.
Note: the native 2-device split load path is verified end to end (real device enumeration, a lopsided configured ratio honored in the per-layer placement, coherent inference across the split) against two genuinely distinct Vulkan devices, and the ratio/index validation and parameter wiring are unit-tested. Not yet verified on real multi-GPU hardware: VRAM pressure and out-of-memory behavior across cards (the second test device is a software one backed by system RAM), and the amd-rocm (HIP) multi-device path. Report an issue if a split load misbehaves.
localm's HTTP surface is protected by a bearer key. Manage the owner key and mint named, scope-limited keys from the CLI:
localm key show [--reveal] # show the active owner key (masked, or full with --reveal) or "open mode"
localm key generate # generate a random owner key, persist it, print it once
localm key set KEY # persist a specific owner key you provide (8+ characters: letters, digits, - and _)
localm key clear [-y] # remove the owner key, return to open mode (-y skips the confirmation)
localm key create NAME --scope chat --scope rag # mint a named key limited to those scopes (--scope/-s is required)
localm key create NAME -s rag --fs-access host --rag-root D:\docs --expires-in 86400
localm key list # list named keys (metadata only, never the secret)
localm key rm KEY_ID [-y] # revoke a named key by ID (-y skips the confirmation)
localm key recover # recover owner access after a lockout (run locally on the server machine): mints a new owner key, signs out browser sessions, leaves named keys workingThe owner key can also be set outside these commands: the LOCALM_API_KEY env var, or a <data dir>/auth.key file.
key create takes three optional confinements beyond --scope/-s, each narrowing what the key can do below what the owner can:
--fs-access [none|host]- host filesystem reach for the coder/file tools. Defaults tonone(device-upload-only);hostgrants the whole server disk, same as the owner.--rag-root DIR(repeatable) - confines the key's whole RAG reach (indexing and every other collection route) to exactly these folders instead of the global folder policy. Omit for no per-key restriction. See docs/rag.md.--expires-in SECONDS- the key stops working this many seconds after creation. Omitted means it never expires.
Privileged scopes (config:write, plugins:admin, keys:admin, admin, coder:full) are refused by key create unless you pass --allow-privileged; an owner-authenticated POST /v1/keys API call can mint them too. See SECURITY.md for the auth and scope model, and docs/tls.md for serving over a LAN.
localm completion powershell # also: bash, zsh, fishIn bash/zsh/fish, model names complete everywhere a model argument is expected. In PowerShell, model-name completion only covers run, serve, rm, and alias; other commands that take a model argument (relocate, set-type, unload, rename, benchmark, bench-mtp, bench-spec, gui) complete only the command name, not the model.
localm plugin status # what is installed and which installs are active
localm plugin install NAME # copy NAME from the store and enable it (or a path to a plugin folder; --force overwrites an existing install from a folder)
localm plugin enable NAME # enable an already-installed plugin
localm plugin disable NAME # disable but keep it installed
localm plugin uninstall NAME # remove it (add --delete-data to drop its data)
localm plugin refresh [NAME] # re-sync installed first-party plugin(s) with the bundled store
localm plugin setup # pick a starter set interactively
localm plugin setup --defaults # coder, rag, web and tts, no prompt (also: --all, or --plugins a,b)
localm plugin install-deps NAME # install a plugin's pip extras on this host
localm plugin install-deps --all # fill in missing extras for every enabled plugin
localm plugin install-deps # no NAME: only list what is missing
localm plugin config NAME # show one plugin's own settings and their values
localm plugin config NAME KEY # show one setting
localm plugin config NAME KEY VALUE # set it (a blank VALUE clears the override)plugin config edits the per-plugin settings blocks the GUI edits under
Settings. localm config cannot reach them: it writes top-level keys, while
these live under a plugin of their own.
localm plugin config image workdir /srv/comfy # for image only, not music/video
localm plugin config video float_type fp16
localm plugin config music use_config_from image # reuse image's backend settings
localm plugin config image workflow mine.json # pick an uploaded workflow
localm plugin config tts voice af_heartimage, music, video and tts work offline, and each can hold its own
value for a field instead of sharing the global comfy_* default. Any other
plugin declares its settings as it loads, so listing or setting those needs a
running localm (found the way localm status finds it, or set LOCALM_URL).
The store names are coder, browser, image, music, video, rag, web, memory, voice, tts, jobs, and mcp (plus the protected chat). Plugins with heavy Python dependencies carry them in a pip extra, installed on the host by default (the auto_install_plugin_deps setting; --no-deps to skip, --with-deps to force, on install, enable and setup, or localm plugin install-deps later). Installing from the CLI changes configuration only: a running GUI server picks up the plugin's HTTP routes and tabs on its next start; stdio plugins like mcp take effect on the next localm mcp. See docs/plugins.md.
Third-party plugins are folders containing a plugin.toml manifest and Python files. Install from a local path with localm plugin install <path> (the same command takes a store name or a directory); installation is a local directory copy, fully offline. See docs/plugins.md for the full authoring contract.
localm coder --model mymodel # interactive session in the current repo
localm coder "fix the failing test" # single task
localcoder --model mymodel # same thing, standalone entry point
localm coder --model mymodel --pin-model # always answer with mymodel
localm coder --system "always run pytest before finishing" # custom instructions for this run
localm coder "make the suite pass" --until "pytest -x" # one-shot, verified by exit code
localm coder --model mymodel --verify "pytest -x" # interactive, same check per turn
localm coder --model mymodel --seed 1234 # reproducible sampling
localm coder "add type hints" --cwd D:\path\to\repo --scope "src/**/*.py" # other directory, confined file access
localm coder "review this" --online --model gpt-4o # OpenAI (--anthropic for Anthropic, via ANTHROPIC_API_KEY)
localm coder --url http://localhost:11434/v1 --model llama3.2 --no-server # any OpenAI-compatible server
localm coder "fix the bug" --ci --output-format json # CI: auto-approve, no colors; exit 0 done, 1 incomplete (max turns), 2 startup errorlocalm coder and localcoder refuse to run (exit 1) until the coder plugin is installed and enabled: localm plugin install coder. The rest of the options:
-m/--model(orLOCALCODER_MODEL),-u/--url(orLOCALCODER_URL),-k/--api-key(defaultlocalm, orLOCALM_API_KEY; arequire_authserver needs the real key),-p/--portfor the auto-started server (first free in 8642-8741),-c/--cwd.--no-serverstarts no server;--newstarts a dedicated one instead of attaching to the one already running for the project.--max-turns(default 40) and--max-tokens(default 2048) may also come from.localcoder/config.toml;--temperature,--verbose.-y/--yesauto-approves destructive tool calls,--interactive-confirmauto-approves file writes but still asks before shell commands,--dry-runruns without executing destructive tools.--estimateplans only and exits;--patch-mode FILEcaptures all file writes as a unified diff written to FILE (-for stdout);--native-toolsuses the OpenAI-compatible tools API (automatic for--onlineand--anthropic).--mode privacy|log|full(defaultprivacy);--output-format text|jsonfor non-interactive runs;-r/--resume [ID]resumes the last saved session or a checkpoint.
Every request the agent makes needs structured tool calls. When --model
names a model whose chat template cannot format them and an installed model
can, localm answers with that one instead; --pin-model keeps the named
model. In the GUI coder, a session started without choosing a model follows
the model selected in the sidebar the same way, while a session given a
model is pinned to it.
The agent auto-starts localm serve when needed and plans with tool calls: reading and searching the project, writing and patching files, running the shell and the test suite, git, web fetch and search, image generation, Knowledge-collection search, background jobs, and delegating to sub-agents. Plus any MCP server tools, plugin-exported tools, and Agent Skills available in that project. The full list is in Built-in tools below. It asks before destructive actions, tracks a turn budget so it asks for help instead of guessing forever, and verifies its own code changes before answering. Privacy mode is the default: nothing is persisted unless you opt into --mode log or --mode full.
The agent ships 43 built-in tools. "Confirms" means the agent stops and asks before running it by default; "Restricted" means a shared, non-owner session may use it at all. The GUI coder has the same set (see gui.md).
| Tool | What it does | Confirms | Restricted |
|---|---|---|---|
read_file |
Read a file, truncating large ones (re-read a region with offset) | no | yes |
list_dir |
List a directory | no | yes |
tree |
Recursive tree with sizes, skipping noise dirs | no | yes |
search_files |
Find files matching a glob | no | yes |
grep |
Regex search over file contents, skipping noise dirs | no | yes |
find_references |
Find call sites of a symbol across the indexed project (best-effort, regex-based) | no | yes |
git_status |
Working-tree status | no | yes |
git_diff |
Unstaged diff, or staged with staged=true |
no | yes |
git_log |
Recent commits, oneline | no | yes |
read_todos |
Read back the task list written with set_todos |
no | yes |
set_todos |
Record the session task list (replaces the previous one) | no | yes |
write_file |
Write or overwrite a file | yes | yes |
edit_file |
Replace the first occurrence of exact text | yes | yes |
edit_files |
Apply the same exact-string edit across several files, all-or-nothing | yes | yes |
edit_notebook_cell |
Replace one cell's source in a .ipynb |
yes | yes |
patch_file |
Apply a unified diff, more reliable than edit_file for multi-hunk |
yes | yes |
search_replace |
Regex search and replace across many files | yes | yes |
read_env |
Read .env and environment, with secret-looking values masked |
no | no |
run_tests |
Run the detected suite (pytest, cargo, go, npm/yarn) | no | no |
run_shell |
Execute a shell command | yes | no |
run_shell_background |
Start a shell command in the background, returning a job id | yes | no |
check_shell_job |
Check a background shell job's state and output | no | no |
kill_shell_job |
Stop a background job and its process tree | yes | no |
git_commit |
Stage and commit | yes | no |
git_create_branch |
Create a branch, optionally checking it out | yes | no |
git_push |
Push the current branch | yes | no |
spawn_agent |
Spawn a sub-agent for a sub-task and return its result | yes | no |
spawn_agent_background |
Start a sub-agent in the background, returning a job id | yes | no |
check_agent_job |
Check a background sub-agent's state and result | no | no |
dispatch_parallel |
Run up to 2 sub-tasks at once, each in its own git worktree | yes | no |
fetch_url |
Fetch a URL and return its text, HTML stripped | see below | no |
web_search |
Search the web, returning titles, URLs and snippets | see below | no |
generate_image |
Generate or refine an image with the local pipeline | no | no |
rag_list_collections |
List indexed Knowledge collections and their stats | no | no |
rag_search |
Search a named Knowledge collection for excerpts | yes | no |
browser_navigate |
Open a URL in the automated browser (browser plugin) | see below | no |
browser_click |
Click a CSS selector | see below | no |
browser_fill |
Type into a form field | see below | no |
browser_read |
Read the visible page text | no | no |
browser_screenshot |
Save a PNG of the current page | no | no |
browser_console |
Read the page's console messages | no | no |
browser_network |
List requests the page made and any the network policy refused | no | no |
browser_close |
Close the browser session | no | no |
The eight browser_* tools appear only when the browser plugin is
installed and enabled, and are always unavailable to a restricted session -
"a restricted session never browses" is a deliberate exclusion, not an
oversight. See network.md.
Five things the table cannot express, and each of them matters:
fetch_url,web_search, andbrowser_navigate/browser_click/browser_fillfollow the network policy, not this column. They confirm whennet_modeisask(the default) and run without asking when it isallow. See network.md.- "Confirms: no" is not "harmless".
run_testsandgenerate_imageboth have real side effects and neither asks by default.run_testsruns your project's own test command, which can do anything that command does. - Restricted sessions are allowlisted, not denylisted. A newly added tool is unavailable to a shared session until it is explicitly added, so this column fails closed rather than open.
- A restricted session leaves the project's coder configuration alone. It
starts no MCP server, loads no plugin tools or skills, and its write tools refuse
any path inside a
.localcoderdirectory, at any depth. Asearch_replacesweep skips matching files there and lists them in its result. - The
--scopeglob confines file tools only.run_shellandrun_testsstart a process, which a path check cannot bound, so a command can still reach outside the scope. Disable those tools for a hard boundary.
Verification by exit code. The agent's own "I am done" is not evidence, so localm
judges a change by running a command and reading its exit code - the harness runs it,
not the model, which is what makes it un-gameable. For a one-shot task that is
--until "pytest -x": the task is retried (up to --goal-max-iters, default 5) until
the command exits 0, and a run that never gets there exits non-zero rather than
claiming success. Interactive sessions (the REPL and the GUI coder) run the same check
at the moment the agent would otherwise finish a turn that changed files. The command
defaults to the project's obvious one - cargo test, go test ./..., npm test when
package.json defines a test script, or pytest when the project has a pytest setup -
and only when that runner is actually installed: a Rust project on a machine without
cargo gets no check rather than one that can only fail. A project with no detectable
check simply runs without one. If the command cannot be started at all, that is
reported as "could not run - nothing was actually verified", which is neither a pass
nor a failure charged to the agent; a command that runs and fails is retried as
normal, including when it fails because something it calls is missing. Override it with
--verify COMMAND, a verify = "..." key in .localcoder/config.toml, or /verify
mid-session; turn it off with --no-verify or /verify off. When the check keeps
failing, the agent is told (and told not to edit the check to force a pass); when the
attempts run out, the turn is reported as NOT verified rather than as done. Sessions
opened with a shared, scoped key never run a verify command - those sessions have no
process execution at all. In the GUI the same three controls sit in the coder setup
form: a verification command, a fix-attempt cap, and a skip-verification toggle.
Self-review. An optional reviewer model reads the cumulative diff before the agent
declares a task done and looks for blocking problems - correctness bugs, security holes,
broken or missing functionality, or a check weakened just to make it pass. Off by
default; turn it on with coder_review in Settings and it runs automatically, once per
task, feeding any blocking issue back for one more fix pass. The reviewer can be the
agent's own model (the default, same-model self-review), a second small model loaded on
CPU (coder_reviewer = "local"), a cloud model ("openai"/"anthropic"), or a second
OpenAI-compatible server (a URL) - set with coder_reviewer / coder_reviewer_model. A
network reviewer (cloud, or a non-loopback URL) is skipped in privacy mode, or when the
network policy refuses it (net_mode off, net_deny / net_allow, or a LAN address while
net_allow_private is off), falling back to the same-model reviewer with a warning; a restricted session runs no reviewer at all,
regardless of coder_reviewer. Ask for a second opinion on demand, at any point in a
REPL session and independent of the coder_review setting, with /review.
Reproducible runs. --seed N pins the sampler's RNG, so the same seed with the same
model, prompt and settings repeats the same random choices. Measured bit-for-bit on one AMD
gfx1030 box with the bundled llama.cpp runtime and Qwen2.5-Coder-7B Q6_K: 5/5 identical
responses at temperature 0.8 with a seed, 5/5 different without one, and identical
again after a full model reload. That is one hardware and software combination, not a
guarantee: different GPUs, backends, llama.cpp builds, or concurrent load were not
measured, a GGUF reply can also depend on the requests the model answered before it
(see the prompt cache note in server-api.md), and
--anthropic ignores the flag because the Anthropic API has no seed parameter.
Episodic memory. The agent keeps a per-project log of lessons learned across sessions. Manage it without starting a session:
localm coder --episodes # list stored lessons and exit
localm coder --episodes-archive # list dropped (merged/evicted/forgotten) lessons and exit
localm coder --forget-episode ID # drop one lesson (archived, recoverable) and exit
localm coder --forget-episodes # erase ALL episodic memory for this project and exit
localm coder --restore-episode ID # bring an archived lesson back into recall and exit
localm coder --consolidate-episodes # ask the model to merge related lessons (opt-in, manual only)The GUI offers all of this under lessons in the coder setup panel: a stored and a
dropped tab, per-lesson forget and restore, an erase-everything button behind a
confirmation, and consolidate - ids included, so what you read there stays actionable
from a terminal. The GUI also carries web forms of --estimate (the estimate button under the
composer), --patch-mode (a setup toggle plus a patch download), --native-tools (a
setup toggle, which reports back when the server cannot honour it) and
--output-format json (the export dialog's result-JSON option).
Give the agent standing guidance (conventions, style, constraints) with a .localcoder/system.md file in the repo - it is injected into the system prompt under "## User Instructions" for every session in that project. The --system TEXT flag overrides the file for a single run. This is separate from LOCALCODER.md, the project-memory file, which holds facts you add with /remember and drop with /forget; the agent does not write it itself (its own close-time reflection is stored in the localm data dir, not in your repo).
Both files are injected into every system prompt, so both are capped at 3000 characters each to leave room for the repo map and the conversation. Going over is not silent: the agent prints which file was over budget and by how much, and the prompt itself carries a note saying the file was cut. Normal-sized files are injected verbatim.
localm mcp --print-config # JSON block for Claude Desktop and friends
localm mcp # run as an MCP server over stdio (launched by the client)
localm mcp --no-images # do not expose generate_image
localm mcp --no-coder # do not expose run_coder_task
localm mcp --no-memory # do not expose memory_recall
localm mcp --memory-write # also expose memory_append (off by default; both memory tools refuse in privacy mode)
localm mcp -m mymodel # default model for chat/embed tools (default: LOCALM_MODEL env, else first registered)
localm mcp --share-loaded-models # answer chat with a model another localm instance here has loaded, instead of loading a second copyExposes your local models and localm management (chat, model and plugin management, diagnostics, and more) to Claude Desktop and other MCP clients, with tool annotations so a client can confirm destructive calls. See docs/mcp.md for the full tool list and both directions: localm as an MCP server, and the coder consuming external MCP tool servers.
localm setup-llama # auto-detect the GPU, fetch the right backend
localm setup-llama --backend vulkan # any GPU (AMD/NVIDIA/Intel), no vendor toolkit
localm setup-llama --backend cuda # NVIDIA / --backend amd-rocm (AMD) / --backend cpu / also: hip, sycl, metal
localm setup-llama --from <build-dir> # or copy your own llama.cpp build
localm setup-llama --url <archive-url> --sha256 <hex> # explicit prebuilt archive, optionally pinned to a digest
localm setup-llama --tag b10355 # install and pin an exact llama.cpp release (--tag latest: upstream's newest, untested here; --tag default: the confirmed build)
localm setup-llama --rollback # back to the previous llama.cpp build
localm setup-llama --force -y # re-provision even if present; -y accepts the recommended action at every prompt
localm setup-llama --backend cuda --cuda-line cuda-12 # Linux: CUDA runtime without a GPU, for building images
localm setup-sdcpp # install the native image runtime (stable-diffusion.cpp), auto-picking the build
localm setup-sdcpp --backend vulkan # or cpu / cuda (Windows) / rocm / metal
localm setup-sdcpp --status # which builds are installed, and their devices (--force reinstalls)
localm setup-music # install native music: the KoboldCpp runtime, the default ACE-Step 1.5 models, a test track
localm setup-music --backend vulkan # or cpu / cuda / metal
localm setup-music --status # installed builds, which backends worked, the default models
localm setup-music --no-models --no-test # runtime only, no default models, no test track (--force reinstalls)
localm setup-embeddings # install the on-device embedding model (semantic memory + RAG)
localm setup-browser # download Chromium for the automated browser (coder tool)
localm setup-browser --force # reinstall even if already present
localm make-launcher # build the native LocaLM app launcher (see docs/native-app.md)
localm make-launcher --force # rebuild it (use after a Python upgrade); --quiet reports only problems
localm doctor # check Python, llama.dll, GPU driver, VRAM, packages
localm info # models dir, registry file, config file, native binaries dir, install mode, temp dir, and the full config
localm memory list # what localm has remembered about you (see docs/memory.md)
localm status # show the localm server serving this directory, and what it is doing
localm status --project D:\path\to\dir # check that directory instead of the current one
localm ps # list running localm servers (per-directory instances)
localm cancel <id> # cancel one operation that server is running (id from `status`)
localm stop # stop the server serving this directory
localm stop <id> # stop one instance by id (or an id prefix, as shown by `ps`)
localm stop --all # stop every running localm instance--cuda-line cuda-12|cuda-13 (Linux, with --backend cuda) fetches the CUDA build and runtime libraries of that line on a machine with no NVIDIA GPU, which is how the cuda and cuda13 Docker images are built (see docs/docker.md). The driver check and the load test are skipped, the runtime is recorded as not load-tested, and localm doctor tests it on the machine it runs on. A failed fetch exits with an error; it never falls back to another backend.
localm run (when no server is serving the directory) and localm coder start a background server that keeps running after the command exits; localm gui and localm serve run in the foreground until Ctrl+C. localm stop ends any of them - it asks the server to shut down cleanly (model unloaded, same as the GUI's Settings page), and force-ends the process if it does not confirm within --timeout seconds (default 10).
localm status lists what that server is working on right now - a model pull, a RAG re-embed, a media generation - with each operation's id. localm cancel <id> stops one of them (a unique id prefix is enough); a pull's download is ended, and an in-process job stops at its next checkpoint. Scheduled jobs are a separate thing under their own ids - use localm job for those.
localm setup-embeddings fetches a small on-device embedding model (default bge-small-en-v1.5) so semantic memory and RAG retrieval work without a lexical-only fallback; pass --model to choose a known key, a registered model, or a GGUF path. Switching to a different model than the one currently configured reports which existing Knowledge collections have embeddings and asks you to confirm before it happens (-y/--yes skips the confirmation) - see docs/rag.md.
localm setup-browser downloads the Chromium build that the automated browser tool drives (the coder's browser tool, and anything else built on localm.browser). The browser pip extra installs the playwright driver only; this fetches the separate, version-pinned Chromium binary it needs. Respects the network policy and is refused under net_mode=off unless net_allow_model_downloads exempts it, same as any other explicit download; does nothing on the network when Chromium is already installed. The GUI offers the same download as a Download browser button on the Browser tab and under Settings > Server & network. --force reinstalls even if present - note that playwright removes the existing build before redownloading, so a failed --force run can leave no Chromium installed at all.
See docs/gpu-setup.md for the full GPU setup guide.
localm update # check for and apply a newer localm build (you always initiate it)
localm update --check # only report whether an update is available; do not apply
localm update -y # apply without the confirmation prompt
localm update --rollback # restore the previous build from the last update backup
localm bug-report -m "..." # generate an editable bug report and offer to send it to the maintainer
localm bug-report -m "what I did" -e "what I expected" -w "what happened" --send # non-interactive, send immediately
localm issues [NUMBER] # list the project's issues, or show one by number
localm issues --state open # open | closed | all (default all)bug-report asks three questions (what you were doing, what you expected, what actually happened; Enter skips one) when run in a terminal without -m/-e/-w, and needs at least -m or -w. It attaches the tail of this run's debug log when one exists (--no-log to leave it out), never chat content. issues is read-only and needs the bug-report proxy to be configured.
Updates are signed: localm verifies an Ed25519 signature from its release key before applying anything, and refuses a build that is not newer. The keys are pinned in its own source and can be replaced by a signed update. See SECURITY.md for the update trust model. The GUI Models page has an "Update now" button for the same flow.
localm bug-report needs a working localm. When localm will not start at all (a
failed install, a broken venv, setup itself failing), use the standalone reporter
instead: double-click report-issue.bat (Windows) or run bash report-issue.sh
(Linux/macOS) from the clone. It shows you exactly what will be sent, files an
account-less GitHub issue via the same proxy (no GitHub login), and works with no
Python or a broken install. The setup.bat / setup.sh failure paths and the
launcher's "Report a problem" button both open it for you. This standalone
reporter needs a git clone of the repo; if you installed via pip install localm
and it will not start at all, there is no bundled recovery script - file an
Issue directly instead.
Updates are always user-initiated: localm never updates itself in the background.