ivar

What is ivar

The idea behind ivar — a hall of real git worktrees, one view directory per feature, and one agent session across every repo a change touches.

Your team already works in a monorepo. It just isn't one repo.

The problem

A contract lives in api. Its client lives in web. It is one change — but git sees two repositories, and your agent sees one of them.

So the work splits. You describe the contract change to an agent in one repo, then describe it again, from memory, in the other. The half that knows what changed cannot see the half that has to follow. Every review, every rebase and every rollback then has to reconstruct a connection that was never written down.

ivar closes that gap without merging the repos: it mounts every repo the change touches into a single directory, on a single branch, and opens one agent session over all of them.

The hall

A hall is a directory that owns a set of repos, described by a committed ivar.json:

ivar.json
{
  "name": "acme",
  "providers": {
    "available": ["claude-code", "opencode"],
    "default": "claude-code"
  },
  "repos": [
    { "name": "api", "url": "https://github.com/acme/api", "default_branch": "main" },
    { "name": "web", "url": "https://github.com/acme/web", "default_branch": "main" }
  ],
  "version": 1
}

That file is the whole contract. Clone the hall, run ivar sync, and you have the same repos on the same branches as everyone else — the command clones what is missing, materialises harness config, and runs each repo's setup script.

git clone git@github.com:acme/hall.git && cd hall
ivar sync

Onboarding stops being a document that drifts out of date, because it is the manifest the tool actually reads.

On disk

Each repo gets exactly one bare clone. Every working copy — the default branch included — is a git worktree cut from that clone.

ivar.json
.bare
main
feat--billing-currency

No copies, no sync step

A change under the hall is a change in that repository — these are real worktrees, not mirrors. Nothing is duplicated, and there is no second command to remember before your edit counts.

The feature

A feature is a name, a branch, and the set of repos that branch exists in. Creating one records the name and the branch, and claims no repos yet:

ivar feature create billing-currency

Repos join it one at a time. Each promotion cuts the feature's branch in that repo and materialises its worktree; a branch that already exists is adopted as it is, one that does not is created off the repo's base.

ivar feature promote billing-currency api
ivar feature promote billing-currency web

Everything you did not promote stays on its default branch. Scope is rarely right the first time, and that is the point: promote the repo you turn out to need, demote the one that turned out not to belong.

ivar feature demote billing-currency infra

The view directory

Starting a session materialises a view directory: the feature's repos mounted at its root, all on the same branch, plus the agent config for the harness you opened it in.

openapi.json
src/api/billing.ts

The agent edits api/openapi.json and then web/src/api/billing.ts in the same session, reading the first to write the second. No handoff, no re-explaining.

The guard

Repos you have not promoted have their write bits cleared — mode & ~0o222, applied recursively. The kernel refuses the write.

That is the point: a prompt asking an agent not to touch shared works until it does not. A cleared write bit does not depend on the model's cooperation. The harness hook only explains how to promote the repo if you decide it belongs in the feature after all.

Skills and context

Repo skills keep their origin in their name, so two repos can each ship an openapi-contract skill without one silently shadowing the other:

api--openapi-contract
web--openapi-contract

Hall skills mount flat and apply to the whole session. ivar skill installs them from git, updates them to a tracked ref, and materialises them into each harness's native location — so the same skill set follows you across harnesses instead of being re-installed per tool.

Delivery

ivar feature deliver pushes each promoted worktree and opens a pull request in its own repo, then links them to each other — the URLs only exist once the pull requests do. --preview prints the whole side-effect-free summary first and pushes nothing.

The link reads part of, not depends on. ivar models co-belonging, not dependency: it will not sequence your merges or decide whether the client can land before the contract. Reviewers make that call; they just stop having to reconstruct which changes belonged together.

Sessions are not owned by one vendor

Nothing in the view directory belongs to a particular agent. The worktrees are git, the manifest is JSON, the skills are folders of Markdown. A session relays to another harness with the same branch and the same context, and nothing is uploaded to do it.

ivar session relay billing-currency --provider opencode

Every command also takes --json, printing exactly the value it computed — the human-readable output is a rendering of that same value, so a script and a person can never be told different things.

What ivar is not

  • Not a monorepo migration. Your repos stay separate, with their own history, CI and pull requests.
  • Not a build system. It does not model a task graph or cache builds; Nx and Turborepo do that, and they do it better.
  • Not a service. A single Rust binary, local-only — it never talks to a server, and nothing is uploaded. That is a property of the architecture, not a policy.
  • Not tied to one agent. Nothing in the view directory belongs to a vendor; the same worktrees, branch and context relay to another harness.
  • Not a merge queue. It records that changes belong together and stops there.

Where next

On this page