omh

Your agent gets a sandbox. You get a branch to read.

omh runs Claude Code in a container with your rules, skills and MCP servers already inside it, on a git worktree of its own. Your checkout is never mounted. When the agent is done you are on the host, looking at a diff.

brew install mindsers/tap/omh

macOS and Linux, arm64 and x86_64. Needs Docker and git. Source on GitHub.

~/code/your-project omh s
$ omh s
  s01  omh/s01  stopped  2 uncommitted
  s02  omh/s02  stopped  2 uncommitted

  s01 and s02 both change shared.rs

Your checkout is never mounted

A session is a container, a git worktree and a branch. The agent works on its side of that line and cannot reach across it. Nothing arrives in your working tree until you put it there.

On your host, while it works

~/code/your-project untouched
$ git status
On branch main
nothing to commit, working tree clean

$ git stash list
(nothing — yours is where you left it)
omh s01 commit

Inside the session, meanwhile

/work omh/s01
$ omh s01 log
a4f21c8  add the parser, and its guard
7e0b3d1  reset --hard, second attempt
c19f4a2  wire it into the CLI

its own repo, one commit deep

What running omh buys you

  • Several sessions, and the collision before you hit it

    omh s is every session with its state, how far it has drifted from trunk, and the files two of them are both about to change — the merge conflict you would otherwise meet on Friday.

  • Your setup, declared once

    Rules, skills, MCP servers, commands, subagents and hooks live in one place. omh renders them into the shape the harness reads, and omh eject hands the raw config back whenever you want out.

  • A code graph the agent actually uses

    Indexed per session and refreshed after every turn in about a seventh of a second, with hooks that point the agent at it when it is about to grep or read a whole file.

  • Your editor, inside the sandbox

    omh s01 attach opens VS Code, Zed, Cursor or Neovim over SSH into the container — one dependency tree, shared with the agent, instead of a second one on your host that quietly drifts.

  • The agent gets git too

    Its own repository, holding one commit and none of your history, so stash and reset --hard are its to use. Bring its commits over with the messages it wrote, all of them or the ones you name.

Getting the work back

Three commands, in the order you would guess. Nothing here touches your checkout — the work sits on omh/s01 until you merge it, and one command throws the whole session away.

  1. Read it. omh s01 diff, or -p for the patch.
  2. Land it. omh s01 commit — one commit, or replant the agent's own.
  3. Share it. omh s01 push, named for a reviewer.
~/code/your-project the loop
$ omh s01 diff
 README.md   | 2 +-
 src/main.rs | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

$ omh s01 commit -m "Add a greeting"
committed to omh/s01 (1 commit on the branch)

$ omh s
  s01  omh/s01  up  1 to push

It decides, and tells you what it decided

omh init asks nothing. Your manifests name the stack, git log names what you work on, the README names the project — so it reads those, picks, and prints the result. Every entry it adds can be traced with omh why: what it costs, and what was considered instead.

~/code/your-project omh init
$ omh init
omh init — decided, asked nothing

  harness    claude  (found on your host)
  stack      rust  (from Cargo.toml)
  hooks      2 selected  (4 more in your catalogue)
  provision  rust/toolchain
  memory     2 notes written
  graph      indexing in background

  omh why <name>  what it costs, what was
  considered instead, how to remove it

Install

Homebrew

brew install mindsers/tap/omh

brew upgrade keeps it current, which is the part the script cannot do.

Without Homebrew

curl -fsSL https://ohmyharness.sh/install.sh | sh

Redirects to the script in the repo, so there is one copy of it. It picks the build for your machine, checks it against the published SHA256SUMS, and runs it once before installing. A failed install never replaces a working omh.

Requires Docker and git. Also builds from source with Rust 1.85+.