Metadata-Version: 2.5
Name: omm-model
Version: 0.3.105
Summary: Open source Model Manager - a package manager for local LLMs (GGUF)
License-Expression: MIT
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: cryptography>=43
Requires-Dist: filelock>=3.16
Requires-Dist: psutil>=5.9
Requires-Dist: questionary>=2.0
Requires-Dist: requests>=2.31
Requires-Dist: rich>=13
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: fastapi>=0.115; extra == 'dev'
Requires-Dist: httpx2>=2.12; extra == 'dev'
Requires-Dist: plyer>=2.1; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: scikit-learn>=1.4; extra == 'dev'
Requires-Dist: uvicorn>=0.30; extra == 'dev'
Requires-Dist: watchdog>=4; extra == 'dev'
Provides-Extra: nvidia
Requires-Dist: nvidia-ml-py>=12; extra == 'nvidia'
Provides-Extra: server
Requires-Dist: fastapi>=0.115; extra == 'server'
Requires-Dist: pydantic>=2.9; extra == 'server'
Requires-Dist: uvicorn>=0.30; extra == 'server'
Provides-Extra: watch
Requires-Dist: plyer>=2.1; extra == 'watch'
Requires-Dist: watchdog>=4; extra == 'watch'
Description-Content-Type: text/markdown

# omm — Open source Model Manager

[![Cross-platform validation](https://github.com/omm-hippo/omm/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/omm-hippo/omm/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/omm-model)](https://pypi.org/project/omm-model/)
[![npm](https://img.shields.io/npm/v/@omm-hippo/omm)](https://www.npmjs.com/package/@omm-hippo/omm)
[![Python](https://img.shields.io/pypi/pyversions/omm-model)](https://pypi.org/project/omm-model/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-3.0-4baaaa.svg)](CODE_OF_CONDUCT.md)

`omm` is an apt/brew-style package manager for local GGUF models. It keeps one
model hub, exposes models to supported local AI runners, checks whether a model
fits the current hardware, and can verify real local generation before you rely
on it.

> [!NOTE]
> The `main` branch documents the current development version. For the latest
> published build, use the [GitHub Releases](https://github.com/omm-hippo/omm/releases)
> page or the version shown by your package manager.

**Project guides:** [Contributing](CONTRIBUTING.md) ·
[Code of Conduct](CODE_OF_CONDUCT.md) · [Security](SECURITY.md) ·
[Privacy](PRIVACY.md) · [MIT License](LICENSE)

## What omm does

- Installs GGUF models into a central, configurable model hub.
- Links or imports models across Ollama, LM Studio, Jan, AnythingLLM, Msty,
  text-generation-webui, and KoboldCpp without silently duplicating large files.
- Ranks models against live RAM, VRAM, operating-system, and runner state.
- Verifies load and generation through local Ollama or LM Studio APIs.
- Keeps benchmark uploads, anonymous usage stats, and crash reports opt-in,
  with a separate setting for each. Searches, downloads, and update checks
  also use the network; see [PRIVACY.md](PRIVACY.md).

## Quick start

After [installing omm](#install), run these commands in order:

```sh
omm setup       # Scan hardware and choose a local AI runner
omm recommend   # Review compatible models and choose one to install
omm list        # Find the installed model's name
```

Use that name with `omm verify <name>` to check local load and generation,
then `omm run <name>` to use it. If setup or a runner is not working, start
with `omm doctor` and `omm log --lines 5`. A recommendation estimates fit;
verification checks the selected model on your machine.

## Table of contents

- [What omm does](#what-omm-does)
- [Quick start](#quick-start)
- [Install](#install)
  - [Windows](#windows)
  - [macOS](#macos)
  - [Linux](#linux)
  - [Any OS via PyPI or pipx](#any-os-via-pypi-or-pipx)
  - [npm](#npm)
  - [Troubleshooting](#troubleshooting)
  - [Windows portable and Winget status](#windows-portable-and-winget-status)
  - [Supported platforms](#supported-platforms)
  - [Local AI runners](#local-ai-runners)
  - [Storage location](#storage-location)
- [Usage](#usage)
  - [Setup & discovery](#setup--discovery)
  - [Install & manage models](#install--manage-models)
  - [Verify & benchmark](#verify--benchmark)
  - [Update & configuration](#update--configuration)
  - [Local logs and automatic import](#local-logs-and-automatic-import)
  - [Scripting](#scripting)
- [Self-hosted benchmark data](#self-hosted-benchmark-data)
- [Signed recommendation data](#signed-recommendation-data)
- [Development](#development)
- [Contributing](#contributing)
- [Security](#security)
- [License](#license)

## Install

Pick your OS and follow one path from top to bottom:

- [Windows](#windows) — PowerShell one-liner (verified Git-source installer)
- [macOS](#macos) — Terminal one-liner, or the Homebrew Tap
- [Linux](#linux) — shell one-liner
- [Any OS via PyPI or pipx](#any-os-via-pypi-or-pipx) — `pip` / `pipx`, no signature verification
- [npm](#npm) — standalone native command distributed through npm
- [Troubleshooting](#troubleshooting) — what you see, why, and how to fix it

### Windows

**1. Open this app.** Open **PowerShell** — either Windows PowerShell 5.1 (Start menu → "Windows PowerShell") or PowerShell 7 (`pwsh`). Windows Terminal is fine as long as the active tab is a PowerShell tab. Do **not** use Command Prompt (`cmd.exe`), and do not paste the one-liner into Git Bash or WSL; those are Unix shells and need the [Linux](#linux) path instead.

**2. Requirements.** Python 3.10+. Windows 10 22H2/11 is the supported baseline. The installer bootstraps Python and git via [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/) if they are missing (winget is built into Windows 10 2004+ and Windows 11 — on older Windows, install [Python 3.10+](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads) manually first), then installs `omm` through that exact validated Python interpreter. The optional NVIDIA detector is installed only when `nvidia-smi` indicates an NVIDIA driver.

**3. Run the installer.** Both lines are one command; paste them together.

```powershell
# This must run before irm: script-internal TLS settings are too late for its first download.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; irm https://omm.run/install.ps1 | iex
```

**4. After install.** Open a new PowerShell window so your `PATH` picks up `omm`, then run:

```powershell
omm        # first run: setup wizard (hardware scan + engine checklist)
omm scan   # memory, runner, and model summary
```

**5. Windows notes.** Model exposure tries an unprivileged same-volume hard link first, then a symbolic link (Developer Mode or Administrator), then an owned copy. Before copying, omm checks destination free space and reports that the model now consumes additional bytes. File junctions do not apply because model targets are files, not directories.

Set `OMM_HOME` before installation and on later runs to put the model hub on another volume. Runners omm installs itself (KoboldCpp, text-generation-webui, AnythingLLM, Msty) go to `OMM_HOME\apps` and installer downloads to `OMM_HOME\tmp`, so nothing large lands on the system drive. (AnythingLLM still keeps its bundled Ollama and starter model, ~5 GB, under `%APPDATA%` - its installer offers no way to move that.)

```powershell
[Environment]::SetEnvironmentVariable("OMM_HOME", "D:\omm", "User")
$env:OMM_HOME = "D:\omm"
```

Install native shell completion once, then restart the shell:

```powershell
omm --install-completion powershell
```

Remove a Git-source installation while preserving downloaded models and settings:

```powershell
irm https://omm.run/uninstall.ps1 | iex
```

Download that script and run it with `-Purge` to remove the model hub and settings too.

Runner note: AnythingLLM and Msty currently require manual installation on Windows; the checklist prints guidance instead of guessing an installer or package ID.

Detailed walkthrough: <https://omm.run/install/windows>

### macOS

**1. Open this app.** Open **Terminal** (Applications → Utilities → Terminal), or any terminal emulator you already use. The command runs under `sh`/`zsh`/`bash`.

**2. Requirements.** Python 3.10+ and git. The installer uses Homebrew when either is missing: if Homebrew itself is not installed, it bootstraps Homebrew with Homebrew's official installer first (Homebrew requires a supported macOS and Apple's Xcode Command Line Tools). To require a pre-existing Homebrew installation instead of letting the installer bootstrap it, export `OMM_AUTO_INSTALL_HOMEBREW=0` before running the command. `pipx` is bootstrapped with `pip` if missing (Homebrew and other PEP-668 "externally-managed" Pythons are handled with `--break-system-packages`), and `omm` is then installed as an isolated CLI via `pipx`. The installer also persists pipx's executable directory in `~/.zprofile`, so a newly opened zsh finds `omm` automatically. The optional NVIDIA detector is installed only when `nvidia-smi` indicates an NVIDIA driver.

**3. Run the installer.**

```sh
curl -fsSL https://omm.run/install.sh | sh
```

**4. After install.** Open a new shell afterward so your `PATH` picks up `omm`, then run:

```sh
omm        # first run: setup wizard (hardware scan + engine checklist)
omm scan   # memory, runner, and model summary
```

**5. Homebrew Tap (alternative).**

```sh
brew install omm-hippo/omm/omm
```

Upgrade or remove the formula with Homebrew. Removing the formula preserves
downloaded models and settings under `OMM_HOME`:

```sh
brew upgrade omm-hippo/omm/omm
brew uninstall omm-hippo/omm/omm
```

After a tagged PyPI release passes its public install checks, GitHub notifies
the Homebrew Tap. Homebrew intentionally applies its upstream release cooldown
before opening an automated Formula update PR, so the Tap can temporarily lag
behind PyPI. Use `brew info omm-hippo/omm/omm` to see the version currently
provided by the Tap. `omm update` does not modify a Homebrew installation and
instead prints the matching `brew upgrade` command.

**6. macOS notes.** Set `OMM_HOME` before installation and on later runs to put the model hub elsewhere:

```sh
export OMM_HOME=/mnt/models/omm
```

Install native shell completion once, then restart the shell:

```sh
omm --install-completion bash  # or zsh/fish
```

Remove a Git-source installation while preserving downloaded models and settings:

```sh
curl -fsSL https://omm.run/uninstall.sh | sh
```

Download that script and run it with `--purge` to remove the model hub and settings too.

Detailed walkthrough: <https://omm.run/install/macos>

### Linux

**1. Open this app.** Any terminal emulator. The command runs under `sh`/`bash`.

**2. Requirements.** Python 3.10+. The installer bootstraps `python3`, `python3-venv`/equivalent, and `git` via whichever supported package manager is present — `apt-get`, `dnf`, `yum`, `pacman`, or `apk` — when the current user can install system packages; on an unsupported distribution, install Python 3.10+ and git yourself first or the installer exits with `Python 3.10+ not found` or `git not found. Install git first`. `pipx` is bootstrapped with `pip` if missing (PEP-668 "externally-managed" Pythons are handled with `--break-system-packages`), and `omm` is then installed as an isolated CLI via `pipx`. The optional NVIDIA detector is installed only when `nvidia-smi` indicates an NVIDIA driver.

**3. Run the installer.**

```sh
curl -fsSL https://omm.run/install.sh | sh
```

**4. After install.** Open a new shell afterward so your `PATH` picks up `omm`, then run:

```sh
omm        # first run: setup wizard (hardware scan + engine checklist)
omm scan   # memory, runner, and model summary
```

**5. Linux notes.** Set `OMM_HOME` before installation and on later runs to put the model hub on another volume:

```sh
export OMM_HOME=/mnt/models/omm
```

Install native shell completion once, then restart the shell:

```sh
omm --install-completion bash  # or zsh/fish
```

Remove a Git-source installation while preserving downloaded models and settings:

```sh
curl -fsSL https://omm.run/uninstall.sh | sh
```

Download that script and run it with `--purge` to remove the model hub and settings too.

Runner note: omm installs Jan on Linux through Flatpak, so `flatpak` must be present for that entry in the runner checklist.

Detailed walkthrough: <https://omm.run/install/linux>

### Any OS via PyPI or pipx

Works on macOS, Linux, and Windows:

```sh
# macOS / Linux (Python 3.10+ and pip must already be installed)
python3 -m pip install omm-model

# Windows (Python 3.10+ and pip must already be installed)
py -m pip install omm-model
```

This does not go through the signed-commit verification described below; it
relies on PyPI's own account security and TLS, the same trust model as
installing any other PyPI package. It is a package-manager path, not a
zero-prerequisite installer: install Python and pip first on a clean computer.

For an isolated command-line installation, `pipx` is recommended:

```sh
# If pipx is not installed yet, install it with the same Python first.
python3 -m pip install --user pipx
python3 -m pipx ensurepath
python3 -m pipx install omm-model
```

On Windows, use `py -m pip`, `py -m pipx`, and `py -m pipx ensurepath` instead.
If the operating system marks Python as externally managed, install pipx from
the operating system package manager or use the Git-source installer above.

The distribution name is `omm-model`; the installed command and Python import
remain `omm`. Upgrade and remove it with the same tool that installed it:

```sh
# macOS / Linux
python3 -m pip install --upgrade omm-model
python3 -m pip uninstall omm-model

# Windows
py -m pip install --upgrade omm-model
py -m pip uninstall omm-model

# Or, for pipx:
pipx upgrade omm-model
pipx uninstall omm-model
```

Both commands preserve downloaded models and settings under `OMM_HOME`.

### npm

The public npm launcher installs a platform-specific standalone `omm` binary,
so Python is not required for this path. It requires Node.js 22.14 or newer:

```sh
npm install --global @omm-hippo/omm
omm --version
```

Published npm binaries cover macOS on Apple Silicon and Intel, glibc-based
Linux on ARM64 and x86_64, and Windows x64. Other operating-system,
architecture, and libc combinations should use the Python-based installer or
PyPI path instead.

Upgrade or remove the npm installation with:

```sh
npm update --global @omm-hippo/omm
npm uninstall --global @omm-hippo/omm
```

The npm launcher verifies the selected native package name, version, platform
metadata, and binary containment before executing it. Release CI separately
checks package integrity and registry signatures. Removal preserves models and
settings under `OMM_HOME`.

### Troubleshooting

Match the message you see, not the step you think you are on.

| What you see | Why | Fix |
|---|---|---|
| PowerShell says `sh` is not recognized, or `curl` rejects `-fsSL` | The macOS/Linux `curl … \| sh` line was pasted into PowerShell, where `curl` is an alias for `Invoke-WebRequest` and there is no `sh` | Use the [Windows](#windows) command instead |
| `irm` or `iex` is not recognized | You are in Command Prompt (`cmd.exe`), not PowerShell | Open PowerShell (or switch the Windows Terminal tab to PowerShell) and rerun |
| `Windows detected. Run the native PowerShell installer instead:` | The `install.sh` one-liner was run under Git Bash/MSYS/Cygwin, which the script refuses | Run the [Windows](#windows) PowerShell command |
| The download fails, times out, or reports a TLS/SSL error on Windows | The default security protocol negotiated an older TLS version | Run the `[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;` pre-line in the same command, before `irm`. Behind a corporate proxy, configure the proxy for PowerShell first |
| `Python not found. Install Python 3.10+ first` (Windows) or `Python 3.10+ not found` (macOS/Linux) | No runnable Python 3.10+ was found, and the winget/Homebrew/package-manager bootstrap could not supply one | Install [Python 3.10+](https://www.python.org/downloads/), open a new shell, and rerun |
| `git not found. Install git first (needed to fetch omm from GitHub)` | git is missing and could not be bootstrapped | Install [git](https://git-scm.com/downloads), open a new shell, and rerun |
| `git 2.34+ is required to verify SSH commit signatures` | Older git cannot check SSH commit signatures, and the installer fails closed rather than trusting an unverified checkout | Upgrade git to 2.34 or newer and rerun |
| `merge commit ... can only be verified with git 2.38+` | `omm update` needs `git merge-tree --write-tree` (git 2.38+) to authenticate an unsigned merge commit's result tree, and fails closed instead of trusting it unverified | Upgrade git to 2.38+ and rerun `omm update` |
| `Signature verification failed - refusing to install untrusted code.` | The fetched commit is not signed by the expected trust anchor | Do not bypass it. Stop and report the failure at <https://github.com/omm-hippo/omm/issues> |
| `Refusing to replace unrelated pipx environment 'omm'.` | A different tool already owns a pipx environment named `omm` | Remove or rename that environment manually, then rerun |
| `Refusing to replace an unverified omm-model pipx environment.` | An existing `omm-model` pipx environment could not be confirmed as OMM's | Inspect it with `pipx list`, remove it if it is safe to remove, then rerun |
| `Could not inspect existing pipx environments; refusing an unsafe migration.` | pipx metadata could not be read | Repair the pipx installation (`python -m pip install --user --upgrade pipx`) and rerun |
| `Refusing to remove unsafe pipx shared directory` | pipx reported a shared-environment path outside its own `PIPX_HOME/shared` directory, or that path is a symlink/reparse point | Do not delete the reported path. Repair or reinstall pipx, confirm `pipx environment --value PIPX_HOME` and `PIPX_SHARED_LIBS`, then rerun the installer |
| `git clone failed.` | The staging clone could not be fetched | Check network/proxy access to `github.com` and rerun |
| `omm` is not found after a successful install | The new `PATH` entry is not in the shell that ran the installer | Open a new terminal window and try again |
| `Could not remove <model>; the registry entry was kept` | Another program, antivirus scanner, or indexing service still has the model file open | Close local AI runners that use the model and retry `omm uninstall <model>`; OMM keeps the registry entry so the retry remains safe |
| winget is unavailable (older Windows) | winget ships with Windows 10 2004+ and Windows 11 only | Install [Python 3.10+](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads) manually first, then rerun the installer |
| Homebrew bootstrap fails or is refused on macOS | `curl`/`/bin/bash` are unavailable, or `OMM_AUTO_INSTALL_HOMEBREW=0` was set without Homebrew already installed | Install [Homebrew](https://brew.sh) yourself, or unset `OMM_AUTO_INSTALL_HOMEBREW`, then rerun |
| pipx fails with `ensurepip is not available`, or `python3`/`git` are missing on an unsupported Linux distribution | The Linux bootstrap only automates `apt-get`, `dnf`, `yum`, `pacman`, and `apk` | Install `python3` (3.10+), the venv package for it, and `git` with your distribution's package manager, then rerun |
| Jan cannot be installed from the runner checklist on Linux | omm installs Jan on Linux via Flatpak | Install `flatpak` (and the Flathub remote), then rerun `omm setup` |
| `Refusing unsafe OMM_HOME`, `Refusing non-absolute OMM_HOME`, or `Refusing OMM_HOME that contains the current directory` | `OMM_HOME` points at `/`, your home directory, a relative path, or the directory you are running from | Set `OMM_HOME` to a dedicated absolute path and rerun from outside it |
| `Refusing unrecognized custom OMM_HOME (missing .omm-managed)` during uninstall | The uninstaller only removes homes that an omm installer marked as its own | Remove the directory yourself if it really is your model hub |

### Windows portable and Winget status

The Windows x64 portable ZIP and checksum are published as CI-verified GitHub
Release assets. The community Winget submission is not yet merged, so there is
no supported `winget install` command to document at this time.

### Supported platforms

`omm` is tested in CI on Windows, macOS, and Linux. Python-based installation
paths require Python 3.10 or newer; the npm path requires Node.js 22.14 or
newer and one of the published native targets listed above. Windows 10
22H2/11 is the supported Windows baseline because that matches Ollama's native
Windows requirements. Hardware scan, install, linking, benchmark, update, and
contribution flows are cross-platform. Benchmarking selects an available
local Ollama or LM Studio runtime; runner- and model-specific capabilities can
still differ.

### Updates and verification

Both installers clone to a versioned staging directory, verify the signed commit against a bootstrap trust anchor, and only then switch pipx to it. Do not replace this with an unverified `git clone` plus `pipx install` if commit authenticity matters.

`omm update` updates only a canonical OMM Git-source installation. For a
package-managed installation, it leaves files unchanged and prints the
matching package-manager upgrade command. The Git-only beta channel is
likewise unavailable to package-managed installations. Git-source updates
parse the new release's declared dependencies, honor `python_version` markers,
and refresh the pipx environment when an applicable dependency is missing or
older than the declared minimum.

### Package-channel verification

| Installation path | Highest verified level | Remaining limitation |
|---|---|---|
| PyPI / pipx | Simulator-verified on GitHub-hosted Windows, macOS, and Ubuntu runners using the public package | **Physical-device-verified: Not verified**; a real upgrade from the first public release is also unverified |
| npm | Simulator-verified by building, installing, running, checking update guidance, and uninstalling all five published native targets | **Physical-device-verified: Not verified** |
| Homebrew Tap | Physical-device-verified on an Apple Silicon Mac for public Tap install, `omm --version`, `brew test`, upgrade guidance, and uninstall | Intel Mac installation is not yet physical-device-verified |

Additional package-manager commands are added here only after their public
registry path has been installed and verified.

### Local AI runners

The first bare `omm` run on a fresh install (or `omm setup` any time after) shows a hardware summary and a checklist of local AI runners. Checking one that omm knows how to install runs its official installer with live progress in the terminal; checking one it doesn't yet automate on your platform prints a link instead. Automation coverage today:

| Runner | Automated on | Manual elsewhere |
|---|---|---|
| Ollama | macOS (Homebrew), Windows (WinGet) | Linux |
| LM Studio | macOS (Homebrew), Windows (WinGet) | Linux |
| Jan | macOS (Homebrew), Windows (winget), Linux (Flatpak) | wherever that package manager isn't installed |
| AnythingLLM | macOS (Homebrew) | Linux, Windows |
| Msty | macOS (Homebrew) | Linux, Windows |
| KoboldCpp | — | All platforms; automatic artifacts lack a pinned checksum |
| text-generation-webui | — | All platforms; install manually from the official releases |

Every currently-installed runner is also listed (marked as already installed, not selectable) rather than hidden, so the checklist always reflects what omm actually detects on the machine.

See [engine management](docs/engine-management.md) for operation previews,
package ownership checks, and verification limits.

### Storage location

The model hub and omm state default to `~/.omm`. Set `OMM_HOME` before installation and on later runs to put them on another volume (see the snippet in your OS section above).

Ollama's own model location follows `OLLAMA_MODELS`. LM Studio follows its home pointer; set `OMM_LMSTUDIO_MODELS_DIR` when LM Studio uses a custom directory that omm cannot discover automatically.

### Completion and uninstall

Each OS section above carries the completion and uninstall commands for that shell. For a PyPI installation, use `python -m pip uninstall omm-model`; for pipx,
use `pipx uninstall omm-model`. Both commands preserve downloaded models and
settings under `OMM_HOME`.

Purge (`-Purge` on PowerShell, `--purge` on sh) removes only known omm-owned paths and leaves unrelated files in a custom `OMM_HOME` untouched. Installers mark custom homes so uninstallers can refuse ambiguous or unsafe locations; shell profiles are never rewritten during uninstall.

## Usage

### Setup & discovery

```sh
omm setup  # First-run setup wizard: hardware scan + engine checklist (re-runnable any time)
omm engine install [ENGINE]  # Install one supported local runner, or choose interactively
omm engine status [ENGINE] [--json]  # Separate application, package version, and local API state
omm engine doctor [ENGINE]  # Read-only diagnostics and next steps
omm engine update ENGINE [--dry-run] [--yes]  # Use the identified package manager
omm engine uninstall ENGINE [--dry-run] [--yes]  # Remove the engine package, keep OMM models
omm scan [--json]  # Memory, storage, installed runners, and models
omm doctor [--json]  # Read-only diagnostics for the installation and Ollama reachability/links
omm recommend [--json]  # Rank compatible models, mark installed ones, and offer a new one to install
omm compare <name> <name>... [--for TASK] [--profile PROFILE] [--json]  # Read-only comparison of 2-5 catalog packages
omm tune <name> [--json]  # Recommend context, GPU offload, threads, and batch size
omm tune <name> --apply --save --engine ollama --yes  # Verify proposed settings locally, then save
omm search <query> [--json] [--skip-unfit] [--skip-ms] [--limit N] [--provider curated|huggingface|modelscope]  # Search curated, Hugging Face, and ModelScope sources
omm help [command]  # Show help, same as --help
```

`omm recommend` keeps compatible models visible when they are already present,
marks whether OMM or another supported local runner owns them, and never
reinstalls a selected installed model. In JSON output, `installed`,
`managed_by_omm`, `installed_engines`, and `installation_match` expose the same
state. `installation_match` distinguishes an exact artifact from the same
model-and-parameter-size identity in a manifest-based runner, whose local
quantization may differ. With `--yes`, the highest-ranked model that is not
installed is selected; if every displayed recommendation is already present,
the command exits without downloading.

### Install & manage models

```sh
omm install <name> [--skip-unfit] [--upload/--no-upload] [--force] [--verify-runtime|--no-verify-runtime]  # Download, link, and optionally verify a model (--force re-checks the source and only re-downloads when it actually changed)
omm fit <name>  # Memory card: does this model (installed or not) fit next to what is running right now?
omm run [name] [--engine NAME]  # Chat with an installed model: Ollama in the terminal, KoboldCpp/text-generation-webui with the model loaded, GUI apps opened
omm import [directory] [--yes]  # Adopt GGUF files found across supported runners (and an optional directory) into the hub
omm uninstall <name> [--dry-run]  # Uninstall a model and clean up its symlinks/manifests (alias: rm)
omm uninstall all [--yes] [--dry-run]  # Uninstall every model installed via omm
omm list [--json] [--engine NAME]  # Show models installed via omm and their linked status (alias: ls)
omm info <name> [--json]  # What a model is: source repo, version, size and run commands once installed; author, downloads, license and architecture for a search result
omm upgrade <name> [--dry-run]  # Look for a better model than this one - a curated successor, or a higher quantization from the same repo that still fits (alias: up)
omm upgrade [--yes] [--dry-run]  # Scan every installed model for a better alternative
omm link [models] [--engine NAME]  # Re-verify and repair installed-model links across supported runners; `models` is a comma-separated name/index list (omit for every model)
omm link [models] --to <directory>  # Reuse central GGUF files; Windows warns if a real copy is required
omm unlink <models> [--runner NAME]  # Remove models' links from one runner (--runner all for every runner), keeping the hub file
omm export <name> <destination> [--force]  # Copy a hub model out for deployment or backup (hard link when possible)
omm pin <name>  # Archive this model's current version before its next forced reinstall
omm unpin <name>  # Stop archiving this model and delete any version already archived for it
omm rollback <name>  # Restore a pinned model's archived version in place of the installed one
omm cleanup  # Remove orphaned partial downloads and broken runner symlinks
```

`install`, `uninstall`, `info`, and `upgrade` accept either a model name/reference or the numeric index shown by the last `omm search` or `omm list` run in that terminal. `omm info` and `omm fit` both work on a model that is not installed yet, so a search result can be inspected before downloading several GB; `omm info` describes the model, `omm fit` answers whether it runs on this machine. `search`/`install` mark models predicted not to run on this machine's hardware in red.

Interrupted installs keep checkpoints under `OMM_HOME/install-journal`. Re-run
the original install command to recheck the file and repair links; `omm doctor`
lists incomplete attempts. See [install recovery](docs/install-recovery.md).

`omm install --skip-unfit` is a scripting-friendly skip, not a successful
installation: it prints `Skipped` and leaves the model hub unchanged. If an
uninstall cannot remove the managed model file, OMM exits with status 1 and
keeps the registry and any still-live links so the same command can be retried.

`omm upgrade` no longer re-downloads a model against its own source. To
re-check an installed file and replace it only if the source actually
changed, use `omm install <name> --force`.

### Verify & benchmark

```sh
omm verify <name> [--engine ollama|lmstudio] [--yes] [--keep-loaded]  # Prove local load + generation works
omm benchmark <name>... [--output PATH]  # Local quality + speed evidence for selected installed models
omm benchmark all [--output PATH]  # Benchmark every installed model in the selected runtime
omm evaluate <ollama-tag> [--pack PATH] [--output PATH]  # Run local Python coding tasks in Docker/Podman
omm contribute [--yes]  # Repeatedly install/benchmark/upload hardware-fit models to grow the dataset
omm contribute --max-minutes 30 --max-download-gb 10 --max-models 3
```

`omm verify` checks more than a link: it asks before starting a stopped local
runtime or loading an unloaded model, sends one short deterministic prompt,
requires a non-empty answer, and stops or unloads only what OMM started for
the check. It never deletes the model or stores the generated answer. Use
`--yes` for unattended confirmation and `--keep-loaded` to preserve a model
OMM loaded for the check. LM Studio API authentication reads
`LM_API_TOKEN` from the process environment and never writes it to
`config.json`. Compatibility status is stored locally in `models.json` and is
shown by `omm info`.

`omm compare` resolves two to five exact packages from the signed recommendation
catalog and compares predicted speed, estimated memory, install state, declared
purpose, and any locally cached signed quality evidence. It never downloads,
installs, or runs a model. `BEST FOR` remains provider-declared metadata;
`MEASURED` is shown separately and missing evidence is `Not measured`, never a
zero score.

`omm evaluate` currently supports installed Ollama models and the versioned
Python coding smoke pack. Model-generated source runs only through Docker or
Podman with no network, a read-only workspace, bounded resources, dropped
capabilities, and a timeout. Generated source is neither stored nor uploaded;
`--output` contains only task outcomes and exact model/pack identity. This pack
is a small reproducibility check, not a leaderboard. OMM never pulls the
container image implicitly; if it is absent, the error prints the exact
digest-pinned `docker pull`/`podman pull` command for the user to run explicitly.

### Update & configuration

```sh
omm update  # Update a canonical OMM Git-source install; package installs print their manager command
omm setting  # Interactive menu for outbound data, version, theme, calibration, and catalog trust
omm setting version [--stable|--beta]  # Show or switch the update channel `omm update` pulls from
omm setting telemetry --endpoint <url>  # Configure where benchmark telemetry is sent
omm setting upload  # Show all three outbound-data policies (benchmark / usage / crash); see PRIVACY.md
omm setting upload benchmark --enable|--disable|--ask  # Benchmark-result upload policy
omm setting upload usage --enable|--disable  # Anonymous daily usage stats (off by default)
omm setting upload crash --enable|--disable|--ask  # Opt-in crash-report policy
omm setting memory-guard --policy ask|block|observe  # Protect local runtime loads from live memory pressure
omm setting theme [--set NAME]  # Show or change omm's output color theme
omm setting calibrate <name>  # Locally correct predicted speed with an installed Ollama model
omm setting runtime-profile <name> [--engine ollama|lmstudio] [--restore] [--json]  # Inspect or undo saved settings
omm setting catalog-trust --manifest-url <url> --public-key <key>  # Require signed recommendation downloads
omm setting catalog-status [--json]  # Show trust, rollback snapshots, and per-check evaluation evidence
omm setting catalog-rollback  # Restore the most recent different recommendation snapshot
```

### Local logs and automatic import

```sh
omm log --lines 5                 # Read the last five command summaries
omm log --grep install            # Filter the local history by text
omm setting auto-import status   # Inspect the setting and OS service registration
omm setting auto-import enable   # Register background import of models from local runners
omm setting auto-import disable  # Stop and unregister background import
```

Logs live under `OMM_HOME/logs/` and are not uploaded by the data-sharing
channels. Review and redact a log before attaching it to an issue.

Automatic import is off by default. Enabling it registers a per-user
background service that adopts newly discovered models without a prompt.
It requires the optional `watch` dependencies (`watchdog` and `plyer`);
for a pip installation, use `python -m pip install "omm-model[watch]"` in
that installation's environment. The status command reports configuration
and service registration; it does not prove that a particular file has
been imported. Check `omm list` after the file has finished downloading.

Saved runtime profiles are tied to the exact model file and engine. `omm verify`
and supported `omm run` paths use them on the next owned load; running models
keep their current settings. See [runtime profiles](docs/runtime-profiles.md)
for engine capabilities, memory checks, cleanup, and verification limits.

### Scripting

All errors, warnings, and confirmation prompts print to stderr. For `search`,
`list`, `info`, `tune`, `scan`, `doctor`, `recommend`, `compare`, and `evaluate`, `--json` makes
stdout a single structured document that is safe to pipe (for example,
`omm list --json | jq .`). `benchmark --json` also writes a single JSON report to stdout; `--output` saves
the same evidence as a file. Supported commands emit a structured error document
when their command body fails before producing a result, and use exit status 130
with `status: "cancelled"` when interrupted. Argument-parser errors use a JSON
error document when `--json` was requested, and stderr otherwise, with exit
status 2. Successful data shapes remain unchanged.

For commands that document `--yes`/`-y`, pass it to skip their confirmation
prompts, or use the command-specific flag (`install --skip-unfit`, `install
--upload`/`--no-upload`). Benchmark upload consent remains governed by
`omm setting upload`; for non-interactive benchmarks, start the selected local
runtime before invoking the command.

These common flags are available on most top-level commands. Where supported,
they may be accepted before or after the subcommand name (`omm --json search
foo` and `omm search foo --json` are equivalent). Use `omm COMMAND --help` for
the exact flags and placement of a specific command:

- `--json` — structured output, where supported (see above)
- `--yes` / `-y` — skip confirmation prompts
- `--quiet` / `-q` — suppress progress bars and background status/hint lines (e.g. download progress, "Verifying checksum...", scan's "Run: omm link" nudge); errors, warnings, and the result of what you asked for still print
- `--no-color` — disable ANSI colors on omm's own console output and its download progress bar; the `NO_COLOR` environment variable does the same

Unsupported `--json` combinations return a single `unsupported_json` error
document and exit 2 before command actions or startup prompts run. JSON mode
never opens the first-run setup/import dialogs, including on a terminal.
`omm --json --version` returns a version document; explicit `--help` still
shows normal help. The shared flag wrapper warns when `--yes` has no effect.
Exit codes are consistent across commands: `0` success, `1` failure, and `2`
usage error (bad flag or argument).

`rm`, `ls`, and `up` are short aliases for `uninstall`, `list`, and `upgrade`.

Set `OMM_HOME` to store everything (models, config, catalog history) under a different directory instead of `~/.omm` — useful when `$HOME`'s filesystem doesn't have room for GGUF models, e.g. `OMM_HOME=/mnt/data/omm omm contribute --yes`.

`omm contribute` keeps models and partial downloads already on your computer;
it removes only the temporary models created by that session. Choose an optional
time, model-data download, or new-model count limit, or combine them as above.
The download limit is in GiB and includes retries; metadata and HTTP/TLS overhead
are excluded. A time limit requests cancellation and then allows safe cleanup
to finish. Without these flags, the loop continues until Esc or candidate exhaustion.
The startup notice explains what is sent and whether the configured collector is
public. The final summary separates successful measurements, accepted uploads,
failed sends saved for retry, and the files kept or removed. The
[recommendation data contribution guide](docs/contribution-sessions.md) gives a
one-model starting point, cross-computer instructions, and the current quality-data
limits.

`omm contribute` performs a 10 GiB startup free-space preflight. Before each
download it separately budgets the central GGUF, a worst-case full runner copy,
any required Windows cross-volume copies, and safety headroom. Each model
evaluation prints a heartbeat every 30 seconds and is terminated after an
absolute 10-minute deadline instead of hanging an unattended session
indefinitely.

Localfit does not assume all installed memory belongs to the model. A live
scan subtracts memory currently used by other applications, keeps at least
2 GB (or 10% of RAM) for the OS and newly opened apps, and applies total-memory
caps. Recommendation fit and `omm tune` use this safe budget, so rerunning a
command adapts after memory-heavy applications are opened or closed.

`omm benchmark` runs a versioned eight-item bilingual arithmetic smoke pack
against models already installed in the selected Ollama or LM Studio runtime.
It stores parsed answers,
correctness, pinned model metadata, and fixed-length timings under
`OMM_HOME/evaluations/` (default `~/.omm/evaluations/`); it stores no generated text. Opt-in telemetry sends a locally
computed CPU chip score (and GPU chip score, when a GPU is present) plus
architecture and core counts — never the raw CPU/GPU model name — so speed
predictions can distinguish otherwise identical Linux `x86_64` machines.
Results are uploaded only after explicit opt-in. The pack is intentionally
small and is not a leaderboard.

On Windows, Ollama is detected by its HTTP API first, so a freshly installed
tray app works even before the current terminal receives the new `PATH`.
When the daemon is stopped, omm also checks Ollama's documented
`%LOCALAPPDATA%\Programs\Ollama` location. It only stops daemon processes it
started itself. Before deleting a contribution model, omm requests an Ollama
unload, waits for `/api/ps` to confirm handle release, and uses bounded retries
for Windows file locks. Real-time antivirus can still delay a first load; the
benchmark uses repeated samples and reports their median. Do not disable your
antivirus for omm.

## Self-hosted benchmark data

Benchmark results are never uploaded without explicit per-run consent or an
`always` policy. New installations use the hosted proof-of-work gateway as the
default destination, while existing local-only configurations stay local. To
run the bundled FastAPI + SQLite collector instead:

```sh
pip install -e ".[server]"
export LOCALFIT_DB_PATH="$PWD/localfit.db"
export LOCALFIT_ADMIN_TOKEN="replace-with-a-long-random-token"
localfit-server
```

Explicitly configure the endpoint and opt in before uploading:

```sh
omm setting telemetry --endpoint http://127.0.0.1:8000/v1/benchmarks
omm setting upload benchmark --enable
```

Loopback ingestion needs no token. Once `LOCALFIT_INGEST_TOKEN` is set, every
request needs it — including loopback ones, so export the same value for the
omm client on that machine. A same-host reverse proxy makes remote requests
look like loopback, so peer address alone is not treated as authentication.
If the collector listens on a non-loopback interface, set the same
`LOCALFIT_INGEST_TOKEN` on both the server and the omm client; remote
ingestion fails closed when it is missing. The client only attaches
`LOCALFIT_INGEST_TOKEN` to an `https` endpoint, so a loopback
(`http://127.0.0.1:…`) collector never receives it.

Training can consume the authenticated export directly:

```sh
export LOCALFIT_ADMIN_TOKEN="replace-with-a-long-random-token"
python scripts/train_model.py \
  --telemetry-url http://127.0.0.1:8000/v1/benchmarks/export
```

Firebase Realtime Database JSON endpoints remain supported. An official
`*.firebaseio.com` or
`*.firebasedatabase.app` `.json` URL can be read without an admin token;
self-hosted raw export requires `LOCALFIT_ADMIN_TOKEN`. Exact duplicate events
are ignored.

Automated retraining is fail-closed. Configure
`LOCALFIT_TELEMETRY_EXPORT_URL`; configure `LOCALFIT_ADMIN_TOKEN` as well for a
self-hosted export (it is optional for an official Firebase JSON URL). The
scheduled job otherwise stops without changing the published artifact. It
requires at least 100 distinct valid v6/v7 configurations with explicit
runtime and CPU metadata (legacy rows do not satisfy this minimum), rejects datasets with more
than 25% invalid rows, and reserves a deterministic 20% holdout. A 64-tree v4
candidate replaces the incumbent only when both holdout RMSLE and P90 absolute
percentage error stay within the configured regression limits. Selection is
evaluated on whole hardware/request contexts, so sibling model variants never
leak across training and holdout sets. Publishing requires at least three multi-model selection groups and complete
selection metrics. Fit-regression checks are only applied once the minimum
known-unfit sample count is met. A passed publication gate therefore does not
mean every check was evaluated: per-check `evaluation_details` and
`omm setting catalog-status` distinguish passed, failed, and insufficient data.
See [evaluation evidence](docs/evaluation-evidence.md). The artifact records
the candidate/baseline evaluation report.

The same gate can validate an exported local dataset without contacting the
collector:

```sh
python scripts/train_model.py --offline \
  --telemetry-file benchmarks.jsonl \
  --quality-gate --minimum-real-configurations 100 \
  --baseline published/localfit-recommend-model.json \
  --output candidate.json --quality-report quality-report.json
```

Synthetic bootstrap training remains available for local development, but the
scheduled publishing workflow never uses it as a substitute for missing real
benchmark data.

## Signed recommendation data

`omm setting catalog-trust --manifest-url <https-url> --public-key <base64-key>`
enables Ed25519 verification for future recommendation downloads. Existing
artifacts are snapshotted before replacement and `omm setting catalog-rollback`
restores the most recent different snapshot.

## Development

```sh
python -m venv .venv
source .venv/bin/activate  # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]" -r requirements-train.txt
```

Run tests with the disposable home and model-hub setup in
[CONTRIBUTING.md](CONTRIBUTING.md#development-setup). That guide also covers
platform-specific setup, scoped checks, signed-head requirements, and
pull-request conventions.

## Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup,
testing, and PR conventions, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for
community expectations. Report security issues per [SECURITY.md](SECURITY.md)
rather than as a public issue.

## Security

Do not open a public issue for a suspected vulnerability. Follow the private
reporting instructions and supported-version policy in
[SECURITY.md](SECURITY.md).

## License

The omm source code is available under the [MIT License](LICENSE). Third-party
dependency notices are listed in
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). Models and local runner
applications installed or linked by omm keep their own upstream licenses and
terms; the project MIT license does not replace them.
