LocalHarness
Run AI agents on the models you already run locally.
LocalHarness is an open-source, self-hosted agent harness for local LLMs. It connects to a model you serve over an OpenAI-compatible API (vLLM, llama.cpp, Ollama or LM Studio), or starts one for you, and gives it agents, defined in YAML, with tools, MCP servers, a permission gate in front of every tool call, and helper agents that each work in a fresh context with only the tools they are allowed. A small core runs the agent loop; memory, the phone app, Discord, image generation, the self-improvement loop and a headless browser for JavaScript-rendered pages are plugins that you turn on or off with one command. Use it as a coding and research agent on your own machine, with no account and no telemetry.
Why an agent harness for local models
- Local models. The harness sizes a launch from the model's own files. It reads the served, trained and fitted context windows, prices a llama.cpp launch from the GGUF tensor table, keeps an MoE's experts in RAM when the GPU cannot hold them, and refuses a model that fits nowhere. It will not launch below the window the agent loop needs. A model without native tool calling gets an XML fallback.
/effort off|low|high|maxcaps how much a model may think per request. - The model server.
localharness startfinds a model on your machine or offers one to fetch, writes it a preset (KV cache type, drafting and parsers are chosen at launch), serves it, and remembers your last choice./modellists every launch this box can make, each with its runtime, weight placement and window, and switches in place.localharness model --autostart onstarts the server with the harness, andlocalharness model --scriptprints the launch as a shell script. A turn survives a server restart. - Private by default. Memory is SQLite in your home directory, config is YAML, and the event stream, logs and bench results stay on your disk. Plugins, tool hooks and the phone app use the same event bus and public plugin API as the bundled plugins. No account, no telemetry (what
startcontacts); web search runs over DuckDuckGo with no key. MIT licensed. - Permissions. One permission gate stands in front of every tool call, helper agents included. An agent that reads untrusted content, a web page or an MCP result, is not given tools that change your machine; the check runs when an agent's tools resolve and fails closed. The endpoint, credential and allowed senders are set in machine-level config, and a cloned repository cannot change them. Threat model: SECURITY.md.
Quick start
Python 3.12 or later and uv. You do not need a running model server: the first localharness start finds a model on your machine or offers one to fetch.
uv tool install 'localharness[embeddings,mobile]' # memory's CPU model + the phone app's dependencies (`plugins enable mobile` turns it on)
localharness start # finds a model (or offers one), sets up, opens a session
localharness plugins list # every plugin and whether it is on
localharness plugins disable autoresearch
localharness plugins enable image --set comfyui_url=http://127.0.0.1:8188
localharness update # the latest release from PyPI
plugins enable and plugins disable write overrides.yaml and leave your config.yaml alone; --workspace changes a bundled plugin for one project only. Inside a session, /plugins enable <name> asks what the plugin needs, checks it, and restarts with your conversation kept. Keyboard shortcuts and multi-line input: docs/terminal-keys.md.
What agents can do
Agents are YAML. A project's agents live in its .localharness/agents/ and yours in ~/.localharness/agents/, the project's file winning a shared name; the model is told about both and sees a new one as soon as it is used or created, and localharness agent list shows where each comes from. The built-in tools are read, write, edit, glob, grep, bash, python, web search and fetch, delegation to helper agents, and MCP servers, so a session works as a coding agent or a research agent. Drive it from the terminal, from Zed (localharness acp), from your phone on your own network (localharness mobile) or from Discord (--channel discord). With a vision model, drop a screenshot on the terminal, paste one into Zed or the phone page, or attach one on Discord.
Supported runtimes
Point it at vLLM, llama.cpp, Ollama or LM Studio; the agents, tools, permission gate and plugins are the same on all four. Every runtime is reached through one OpenAI-compatible client, and init can attach to an endpoint that is already running. Live-validated means run on the DGX Spark reference machine; recorded bench runs exist for vLLM only.
| Runtime | Harness starts the server | Tool calling | Token counting | Live-validated |
|---|---|---|---|---|
| vLLM | docker or binary | native | exact | reference machine and bench |
| llama.cpp | spawns llama-server |
XML / Hermes fallback | exact | reference machine |
| Ollama | spawns ollama serve |
native | exact with the exact-tokenizer extra, else estimated |
CPU round-trip |
| LM Studio | drives headless lms |
native | exact with the exact-tokenizer extra, else estimated |
CPU round-trip |
A session with no temperature set sends none, so the server's sampling defaults apply; pin one on the server (llama-server's --temp, vLLM's --generation-config). Setup: llama.cpp, Ollama, LM Studio, vLLM (reference architectures); the code is the provider layer.
Plugins
| Name | What it does | Default | How to switch |
|---|---|---|---|
image |
makes pictures with ComfyUI | off | localharness plugins enable image --set comfyui_url=<url> |
mobile |
Mobile: the phone page, served with its event API by localharness mobile |
off; needs localharness[mobile] |
uv tool install 'localharness[mobile]' (name the other extras you use too: a reinstall keeps only the ones it names), then localharness plugins enable mobile --set public_url=<url> |
memory |
persistent memory: facts recalled into each turn, memory tools, background consolidation | on | localharness plugins disable memory |
dispatch |
chat: Discord | off; needs localharness[dispatch] |
uv tool install 'localharness[dispatch]' (name the other extras you use too: a reinstall keeps only the ones it names), then localharness plugins enable dispatch --set discord.token=… --set discord.allow=<your user id> |
autoresearch |
experiment loop | on | localharness plugins disable autoresearch |
browser |
reads JavaScript-rendered pages through a sandboxed headless Chromium | off; needs localharness[browser] |
uv tool install 'localharness[browser]' (name the other extras you use too: a reinstall keeps only the ones it names), then localharness plugins enable browser |
Pages: image · mobile · memory · dispatch · autoresearch · browser, and on the site: image · mobile · memory · dispatch · autoresearch · browser.
Installed plugins live on your machine, not inside a project: a Python package with a localharness.plugins entry point beside LocalHarness, or a folder ~/.localharness/plugins/<name>/. None of its code is imported until localharness plugins enable <name>, which only your machine-level config can do. A plugin you turn on is trusted code that runs with your privileges: read SECURITY.md before you enable one.
Write a plugin
Copy the example plugin: one tool, one command, one slash command, one doctor check and two settings, tested in CI. The API is plugins/api.py; its version is "1", and changes since its first release have only added optional fields. Plugins written for the previous plugin API no longer load; the example plugin says how to port one.
Skills
A skill is a folder holding a SKILL.md in the open Agent Skills format: a name, a one-line description of when to use it, and a procedure. LocalHarness reads a project's .localharness/skills/ and .agents/skills/, ~/.localharness/skills/ and the bundled set. The model sees one line per skill and loads the procedure with its skill tool when a request matches. The model may not pick a skill up on its own; /<name> asks it to.
localharness skills lists what was found and why anything was skipped, and /skill-creator writes a new one with you, one approval per file. A skill is text: it grants no tool and installs nothing. A project's skills load with its config, so read them in a repository you did not write: SECURITY.md.
Status
Early stage (v0.22.1, pre-1.0). Interfaces and config schema may change without notice. Each release's known limitations are listed in the CHANGELOG.
Links
- SECURITY.md: trust boundaries, the permission gate, the prompt-injection threat model
- src/localharness/: the source, one package per component; the CLI is
cli/ - docs/task-context.md: how a session keeps a working record for substantive work, with an example workflow
- docs/reference-architectures/: tested hardware and setup notes
- docs/running-agents-locally.md: where LocalHarness fits among local agent tools, and where it is behind
- LocalShift: the companion project that moves a headless Claude Code job onto LocalHarness once a local model proves good enough
- localharness.dev
License
Metadata
Release files for localharness 0.22.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| localharness-0.22.1.tar.gz | 1.8 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| localharness-0.22.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.5 MB
Release files / localharness-0.22.1.tar.gz
| Download URL | localharness-0.22.1.tar.gz |
|---|---|
| Size | 1.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
18fe7e8cf0049779899188eade38f2af276a420f79476a10a10cbc885f61c30c
|
|
BLAKE2b-256 checksum How to use checksums |
7c0ae4a8bf40fc867329637e165b49d335762ec35595296a937584a188e6940a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / localharness-0.22.1-py3-none-any.whl
| Download URL | localharness-0.22.1-py3-none-any.whl |
|---|---|
| Size | 1.8 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ca2a567e353aa435b5415df17662efcae5253d25776bcab80c8710843d374160
|
|
BLAKE2b-256 checksum How to use checksums |
8cf37c0d5aa99533eae3ca34012c6fe9dfd1233dbe648b2745da54cdf9824d39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for localharness 0.22.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.