Skip to main content

om-harness

Ship better code. Spend less context.
A context-efficient AI coding-agent harness for real git repositories.

CI Release Coverage Package version PyPI Downloads Supported Python versions License

See it in action · Install · Contribute · Discuss

om-harness is a local-first coding agent for real git repositories. It inspects the repo, plans the work, edits files, runs tests, and reports what it did — while keeping context usage, latency, cost, and tool permissions under control.

Why use it?

Common coding-agent problem om-harness approach
Context grows on every turn Bounded repository indexes and history
Agent behavior is hard to inspect Typed plans, task results, and events
Tools can make unsafe changes Permission levels and approval policies
Interrupted work has to start over Durable sessions, checkpoints, and resume
Trying the project requires API keys Deterministic offline demos and tests

See it in action

The complete offline flow goes from repository inspection to edits and tests:

om-harness inspecting a repository, editing a file, and running tests

Easy installation using uv

$ uv tool install om-harness

Easy installation using pip

$ pip install om-harness

Using harness

$ cd your-project
$ om-harness init
$ om-harness run "fix the failing test in test_worker.py"

Open an interactive shell using below command

$ om-harness

/setup walks you through provider configuration in interactive shell


Why om-harness exists

Most coding-agent demos are a thin loop around a chat model: they resend the whole conversation, the entire system prompt, and every file the agent ever saw — on every single turn. That wastes tokens, adds latency, and makes multi-step and multi-agent work needlessly expensive and unpredictable.

om-harness is built around three ideas that address this directly:

  1. Context is a budget, not a dump. Repository context comes from a cached, bounded file index (paths + sizes, not contents). System prompts are small and role-scoped. Agents exchange compact structured TaskResults, never conversation transcripts. Old history is summarized, not resent. Everything sent to the model is itemized in a token report.
  2. Orchestration is a plan, not vibes. A planner picks the simplest strategy that can complete the goal — usually a single agent. When it doesn't, work is expressed as an inspectable task graph (sequential pipeline, parallel fan-out/fan-in, or implement→review) executed by a coordinator with bounded concurrency, timeouts, retries, and cancellation.
  3. Reliability and safety are structural. Every meaningful operation is a typed event on one bus (UIs, logs, and persistence all subscribe to the same stream). State is durable and resumable. Tools carry permission levels (read-only / mutating / destructive) gated by a configurable approval policy that fails safe in non-interactive contexts.

It is not an agent framework you build products on top of — it is a working coding assistant, plus a small, readable codebase where every design decision is visible.

Feature highlights

  • CLI-first: init, run, chat, agent, providers, doctor, status, resume, config, update — each with --json output for automation. update upgrades om-harness from PyPI via the auto-detected install channel.
  • Multi-provider via PydanticAI: OpenAI, Anthropic, Google/Gemini plus any OpenAI-compatible endpoint through one interface; your selected model always wins, with per-task routing and clear errors when a provider is unavailable. An offline echo model exists only for explicit mock: configuration in demos and tests — it is never auto-selected.
  • Async orchestration: parallel fan-out/fan-in with deterministic aggregation, per-task timeouts, retries with backoff, and cancellation.
  • Repository tools: file list/read/search/write/edit, find files by glob, count lines/words/characters, safe shell execution (with native pipe and redirection support — no shell process involved), git status/diff/log/show/add/commit/restore, branch management, stash, blame, remote management, log graph, test-runner detection and execution, auto-detect formatter/linter, web content fetching (single URL + explicit batch URL fetching), parallel task dispatch (dispatch_parallel — fan-out independent sub-tasks with full tool access, supports map-reduce), repo info — all schema'd, timeout-bounded, and output-capped.
  • Durable sessions: state in .om-harness/ (gitignored), atomic writes, checkpoints, and resume for interrupted work.
  • Project-level memory: facts discovered during one session persist across sessions. The remember and recall tools (plus /memory REPL command) let agents store and retrieve knowledge about the repository — file locations, bugs found, decisions made, configuration details. Keyword-based retrieval, no vector DB, no model calls. When context grows too large, mechanical fact extraction preserves important findings into memory before compressing conversation history (configurable threshold via context.max_context_tokens; strategy via memory.compression_strategy).
  • Observability: every run, agent call, tool call, approval, retry, and usage figure is a typed event; --verbose/--debug expose them.
  • Web reference client: the same runtime, consumed over HTTP/SSE — proving the UI/runtime split.

Install

Requires Python 3.11+. The recommended installer is uv:

uv tool install om-harness                    # latest from PyPI

or directly from GitHub:

uv tool install git+https://github.com/omkumar01/om-harness

From a clone (for development):

git clone https://github.com/omkumar01/om-harness
cd om-harness
uv sync
uv tool install . --force                    # force reinstall after making changes to source
uv run om-harness --version

To run the web reference client from a clone, install the optional web dependencies and start the server:

# web reference client (needs the `web` extra):
uv sync --extra web
uv run python -m om_harness.ui.web.server

Then, inside any git repository:

om-harness                 # starts an interactive chat session

The first launch creates your user config at ~/.om-harness/ and prints a short setup hint. That's the whole onboarding.

Updating

om-harness can upgrade itself from PyPI:

om-harness update            # upgrade to the latest release
om-harness update --json     # machine-readable output

The command auto-detects how om-harness was installed (uv tool, pipx, or pip) and runs the matching upgrade, then prints the new version's release notes under a "What's new" heading. Installations from a local editable or git source print manual upgrade instructions instead. --json emits current, latest, channel, command, upgraded, and notes.

On every invocation, om-harness also checks PyPI for a newer release (cached for 24 hours). If one is available, it prints a single dim line to stderr:

Update available: 1.4.0 (you have 1.3.0) — run: om-harness update

The notice is skipped for --version, --help/-h, --json, and the update command itself, and is silent on any network failure. To disable it entirely:

export OM_HARNESS_NO_UPDATE_CHECK=1

The interactive shell

Running bare om-harness (or om-harness chat) opens a coding shell in the current repository:

╭─ om · openai:gpt-4o · ⏵⏵ auto · ◑ thinking:med ──────╮
│ ❯ fix the sign bug in calc.py
╰──────╯
⚙ tool read_file(path='calc.py')
⚙ tool edit_file(path='calc.py', old_string='…', new_string='…')
⚙ tool run_tests()
✔ run completed
om Fixed add() in calc.py — tests pass.
◇ wrote calc.py · ran run_tests · 115+2 tok
  • Always-on status: the input header and the persistent status bar show the approval mode, the active provider and model (what the next turn will actually use), the thinking level, and a live context gauge (context ▮▮▮▯▯… 32k/200k) at all times — plus the Alt+M model selector shortcut. The gauge shows the current context size (the latest model call's input tokens), updates live while the model streams, and its ceiling is the active model's real context window (from models.json contextWindow or a built-in lookup).
  • Live activity: tool calls, commands, and approvals stream as they happen — every tool call is visible in all verbosity modes; per-turn summaries show files read, files modified, commands run, and tokens spent. Replies stream token-by-token from streaming models.
  • Live thinking & file changes: the model's reasoning streams as it thinks, and every file the agent writes or edits renders a real-time diff (✎ path with +/− lines, or a new-file marker). /thinking (no args) cycles the display: inline stream → minimized (◐ thinking… with a per-turn token summary) → off; /thinking inline restores the full stream. When a provider doesn't stream reasoning, thinking recovered from the completed run is still shown inline.
  • Never lose your session: when a run finishes or you exit the shell, a resume command is printed (om-harness --resume --session <id>) so interrupted or completed work can always be continued.

Keybindings

Keys Action
Enter send
\ + Enter or Alt+Enter newline (multi-line input)
Shift+Tab cycle approval mode: ask → auto → deny
Alt+M model selector (arrow keys, all configured providers)
Ctrl+T cycle thinking level: off → low → medium → high
Ctrl+O cycle verbosity: compact → verbose → debug
Ctrl+G help (commands + keys)
Ctrl+L clear screen
Ctrl+C clear input · double-press quits · interrupts a running turn
Ctrl+D quit
Up/Down input history

Slash commands

/model [name] (no args: arrow-key selector) · /thinking [inline|minimized|off|low|medium|high] (no args: cycle display inline → minimized → off; inline/minimized set the display, off|low|medium|high set the model level) · /config · /config set <key> <value> · /timeout [agent|tool] <seconds|off> · /providers · /tools · /skills · /skill <name> [args] · /plugins · /status · /sessions · /checkpoint [label] · /resume · /memory [list [tag] | recall <query> | clear] · /setup · /verbose · /help · /exit.

/setup walks you through provider configuration (including adding a custom OpenAI-compatible endpoint to ~/.om-harness/config/models.json), model selection, approval mode, verbosity, and thinking level — everything persists to ~/.om-harness/.

/plan [on|off] toggles plan mode: the agent researches the repository with read-only tools only (edits, shell commands, and commits are blocked) and proposes an implementation plan instead of making changes. While plan mode is active the status bar shows ⏸ plan, and /mode / Shift+Tab are disabled until you leave it. When the plan looks right, reply approve (or go ahead, implement, …) — plan mode exits, your previous approval mode is restored, and the same message is sent to the agent to implement.

/timeout shows the current agent (whole-turn) and tool (per-call) timeouts; /timeout agent 300, /timeout tool off, or /timeout off (disable both) change them live and persist to ~/.om-harness/config/config.toml. /config set agent_timeout|tool_timeout <seconds|off> does the same.

refer docs/slash-commands.md for detailed guide.

Skills and plugins

Skills are small instruction packs (SKILL.md with a name / description frontmatter) that the agent loads on demand. They are discovered from ~/.agents/skills, the repo's .agents/skills (repo wins on name conflicts), extra dirs from [skills].extra_dirs in config, and from installed plugins. Only names and one-line descriptions go into the system prompt; the full instructions are fetched through the read-only skill tool when a task matches — keeping context small by default.

Plugins are git repositories installed with:

om-harness install git:github.com/obra/superpowers   # or a local path
om-harness plugins                                   # list what's installed
om-harness uninstall superpowers                     # remove

A plugin may carry an optional plugin.json manifest (name, description) and skills in skills/*/SKILL.md or .agents/skills/*/SKILL.md. Plugin skills are fully active in every flow (chat, run, agent): they appear in /skills and the system prompt under their namespaced name (<plugin>:<skill>, plain name when unique), and the agent can load them with the skill tool. In the shell, /skill <name> [args] runs a turn that follows a skill. Disable everything with [skills] enabled = false in om-harness.toml. For a comprehensive guide to using tools, skills, and plugins in the interactive shell, see docs/interactive-shell-extensions.md.

Thinking levels

off / low / medium / high map to each provider's native reasoning controls (Anthropic thinking budgets, Gemini thinking config, OpenAI reasoning effort — reasoning models only). Unsupported providers simply run without thinking settings.

User-level configuration lives in ~/.om-harness/:

~/.om-harness/
├── config/
│   ├── config.toml     # user-level harness settings
│   └── models.json     # custom providers (local gateways, private endpoints)
└── cache/
    └── repo-index/     # repository index caches

Repo-level om-harness.toml / models.json override the user-level files; environment variables override everything. Sessions and checkpoints stay in the repository (.om-harness/, gitignored).

Configure providers

API keys are read from the environment (never from config files, never stored, never logged):

export OPENAI_API_KEY=...        # or ANTHROPIC_API_KEY / GOOGLE_API_KEY

With no keys configured, model requests fail with a clear "provider unavailable" error — om-harness never silently substitutes a different model. For offline demos and tests you can explicitly set mock:echo as your model (an echo stub, never auto-selected).

Optional file configuration in om-harness.toml (or [tool.om-harness] in pyproject.toml):

[routing]
default_model = "openai:gpt-4o-mini"

[routing.task_models]
explore = "openai:gpt-4o-mini"
implement = "anthropic:claude-sonnet-4-5"

[approval]
policy = "auto"          # ask | auto | allowlist | deny
allowlist = ["write_file", "edit_file"]

[context]
max_context_tokens = 8000   # auto-compress when context exceeds this; None disables

[memory]
enabled = true                           # project-level memory master switch
compression_strategy = "mechanical"        # "mechanical" | "llm"
fact_ttl_days = 7                        # auto-extracted facts expire; 0/none disables

Environment variables override the file: OM_HARNESS_DEFAULT_MODEL, OM_HARNESS_APPROVAL_POLICY, OM_HARNESS_MAX_CONCURRENCY, OM_HARNESS_VERBOSITY, OM_HARNESS_MAX_REQUESTS. See docs/configuration.md.

Custom & local model providers

Any OpenAI-compatible endpoint (LM Studio, Ollama, NVIDIA NIM, private deployments) can be registered through a models.json file — no code changes:

{
  "providers": {
    "lm-studio": {
      "baseUrl": "http://127.0.0.1:8080/v1",
      "api": "openai-completions",
      "allowLocal": true,
      "models": [{ "id": "qwen3-32b", "contextWindow": 256000 }]
    }
  }
}

Then use it like any built-in provider:

om-harness run "fix the parser bug" --model lm-studio:qwen3-32b

Keys are read from the environment via apiKeyEnv (inline apiKey is supported for local gateways and is auto-registered with the secret redactor). Loopback/private endpoints require the explicit allowLocal opt-in. Full field reference: docs/configuration.md.

First run

om-harness                       # interactive chat (auto-creates ~/.om-harness/)
om-harness doctor                # checks git, config, state dir, providers
om-harness run "explain the module layout in src/"          # read-only task
om-harness run "add input validation to parser.py and test it"
om-harness status                # sessions, checkpoints, providers
om-harness resume                # inspect and continue the latest session

No keys at all? Watch a complete coding flow (inspect → edit → test) run offline through a scripted model:

uv run python scripts/demo.py

Automation (exit code reflects run status):

om-harness run "fix lint errors in src/" --json --approval-policy auto

Verbosity: default output is compact (plan, key activity, summary); --verbose adds tool calls, agent handoffs, and usage; --debug prints everything.

How it works

flowchart LR
    CLI[CLI / Web UI] --> H[Harness facade]
    H --> SM[SessionManager + Store]
    H --> P[Planner]
    P -->|Plan| C[Coordinator]
    C -->|tasks| R[AgentRunner]
    R --> A[PydanticAI Agent]
    A -->|tool calls| T[GuardedToolExecutor]
    T -->|approval gate| TL[Tool registry]
    R --> RT[ModelRouter]
    RT --> PR[ProviderRegistry<br/>openai / anthropic / google / mock]
    R -.events.-> BUS((EventBus))
    T -.events.-> BUS
    BUS -.-> UI[Terminal renderer / SSE]
    BUS -.-> ST[Event log JSONL]

One request flows roughly like this: the Harness resolves or creates a Session, the Planner produces a Plan (usually one task), the Coordinator executes the task graph through AgentRunner, each task becomes one PydanticAI agent invocation with scoped context and tools, and every step publishes Events. Results are persisted, a Checkpoint is saved, and the CLI renders a summary. Details in docs/architecture.md.

What makes it context-efficient

Waste in a naive loop om-harness behavior
Repo contents re-sent each turn Cached RepoIndex summary (paths + sizes, capped)
One giant system prompt Small role-scoped prompts (planner/explorer/implementer/reviewer/chat)
Full transcripts passed between agents Structured TaskResult (summary, findings, files, errors)
Unbounded history growth History trimmed to a window; the dropped tail becomes a one-line summary (or, when max_context_tokens is set, facts are extracted to memory before the one-line summary so nothing important is lost)
Repetitive reasoning across sessions Project-level memory: remember/recall tools persist and retrieve facts; relevant facts are injected into context automatically
Invisible cost Per-component token ledger; status shows the effective model and usage

These properties are enforced by tests (see tests/unit/test_context.py and the tests/unit/test_memory_*.py suite), not just by convention.

Testing strategy

The default suite is fully deterministic and needs no API keys — provider calls go through PydanticAI's FunctionModel scripting, which exercises the real agent loop. Race-prone parallelism is tested with sentinel synchronization that would deadlock if work were serialized.

make check               # format + lint + types + tests (coverage-gated)
uv run pytest            # fast: unit + e2e
uv run pytest -m integration   # live provider round-trips (needs keys)

Contributing

om-harness is intentionally small and readable, so contributions are very welcome. The loop is:

git clone https://github.com/omkumar01/om-harness
cd om-harness
uv sync
make check            # ruff format + ruff check + mypy + pytest with a coverage gate

Good places to dig in: src/om_harness/models/ (Pydantic contracts — the system's spine), src/om_harness/ui/ (terminal renderer, REPL, web), and src/om_harness/tools/ (permission levels, the approval engine). Please read the CONTRIBUTING.md workflow, and open an issue or PR for anything that looks off — including the docs.

Documentation

Project layout

src/om_harness/
├── models/          # Pydantic contracts: events, tasks, plans, sessions
├── config/          # TOML + env configuration, secret redaction
├── providers/       # provider registry, task-type router, mock models
├── context/         # repo index, token budgeting, scoped assembly, compression
├── memory/          # project-level fact store, keyword index, fact extraction
├── tools/           # repo tools + permission levels + approval engine + memory tools
├── runtime/         # event bus, session/checkpoint manager, agent runner
├── orchestration/   # planner, coordinator (waves/concurrency)
├── ui/              # shared components, terminal renderer, REPL, web/
└── cli/             # Typer application

License

MIT — see LICENSE.

Metadata

Release files for om-harness 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for om-harness 1.3.0
File Size Uploaded Provenance Actions
om_harness-1.3.0.tar.gz 16.0 MB With provenance Details for om_harness-1.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for om-harness 1.3.0
File Interpreter ABI Platform Actions
om_harness-1.3.0-py3-none-any.whl Python 3 none any Details for om_harness-1.3.0-py3-none-any.whl

Total release size: 16.1 MB

Release files / om_harness-1.3.0.tar.gz

Download URL om_harness-1.3.0.tar.gz
Size 16.0 MB
Tags Source
SHA-256 checksum
How to use checksums
a86877ab310f2447ef3f7254f2d0a22c55acc684e32f206cdf3b6c6ef6dabda7
BLAKE2b-256 checksum
How to use checksums
98449f5630d5f3dbbe25d4b18123b83a77e7ba0b7ddb5910132f32dd83c7721d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / om_harness-1.3.0-py3-none-any.whl

Download URL om_harness-1.3.0-py3-none-any.whl
Size 152.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2c43a1c96fd5dc843922b9d8f28e4b5e9464ca48dbf36b0b1f748b7f11eba97c
BLAKE2b-256 checksum
How to use checksums
3eb6f546813106f8bc7cfa0c3e4f3d5f3714c94a62906c694c8b5bdd7e51d377
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Security for om-harness 1.3.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for om_harness-1.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page