One logical change
The change spans api, web, and shared contracts.
Change an API contract in api, regenerate its client in web, and update the shared types that bind them. It is one change. Git sees three.
So the work splits. You describe the 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.
ivar feature create billing-currencyFeature billing-currency · branch createdivar feature promote billing-currency apiapi writable / billing-currencyivar feature promote billing-currency webweb writable / billing-currencyshared read-only / mainivar session start billing-currencyview dir ready · .ivar/sessions/…/view

Shared contract
currency.tsAPI
contract updatedWeb
client regenerated01The fair objection
Why not a monorepo?
A monorepo is valid when its ownership and release boundaries allow it. It makes one repository the right unit for the work.

Monorepo
apiwebshared
Independent repositories
apiwebshared
When one repo is not the unit
Some organisations need independent repositories, ownership, permissions, and release schedules.
The change still spans them
The contract in
api, the client inweb, and the shared types change together.ivarkeeps those repositories separate while giving that change one working context.
02The working boundary
A Hall makes the repositories visible. Promoting one makes it writable.
A Hall is a committed ivar.json that defines the repositories for a team, product, or initiative. It gives the Session a shared map without merging those repositories.

ivar feature promote billing-currency apiapi writable / billing-currencyivar feature promote billing-currency webweb writable / billing-currencyshared read-only / maininfra read-only / main
One branch, several repos
A Feature is one branch across the repositories a change needs, carrying the same name in each of them.
Scope you opt into
Promote only the repositories that belong in that Feature: their worktrees become writable on its branch.
03One agent context
A Session opens one view dir for the Feature.
A Session binds an agent to a Feature. Its view dir contains one symlink per repository: promoted repositories point to the Feature worktree; the rest point to the shared, read-only default worktree.

ivar session start billing-currencyapi → repos/api/billing-currencyweb → repos/web/billing-currencyshared → repos/shared/main read-onlyinfra → repos/infra/main read-only.claude/ · CLAUDE.md · plans/ materialisedclaude/ivar-planplans/billing-currency/plan.md
Provider-native config
The Session materialises the configuration your agent already reads:
.claude/for Claude Code,.opencode/for OpenCode.The whole change in view
The agent sees the contract, client, and implementation together while the writable boundary stays explicit.
04Code graph
One graph of the Hall, seen from each Feature branch.
ivar graph indexes every repository into a local SQLite graph: symbols, calls, routes, and the edges between repositories. Agents ask it for source, callers and blast radius over MCP instead of grepping and reading file by file.

ivar graph explore formatAmountformatAmount [api] (fn) in src/billing.ts:1-31 export function formatAmount(cents, currency)renderInvoice [api:src/billing.ts] depth 1checkout [api:src/checkout.ts] depth 2Impact: 2 callers across 2 files
Across repositories
An HTTP route links to the client request in another repository that calls it.
Per Feature
Sessions share one base index; each Feature adds a layer holding only the files it changed.
Fresh on every call
Changed files are reindexed before each query, in tens of milliseconds.
Fewer reads
In a two-repo benchmark, discovery used a median 460k tokens against 738k.
05Local by construction
Real worktrees, one Feature branch, no hosted control plane.
Inspect the worktrees, Feature branches, generated view dir configuration, and source files directly on disk; that is the complete local state.

ivar feature status billing-currencyWorktrees repos/api/billing-currencyFeature branch billing-currencyview dir .ivar/sessions/…/viewServer state none
Real worktrees
Each repository is a real git worktree, not a copied checkout.
One branch name
Every promoted repository uses the Feature branch of the same name.
Plain symlinks
The view dir is local symlinks and materialised configuration.
No server
There is no server, account, or sync step between the repositories.
06From the blog
What we are working out in the open.
Notes on coordinating one change across repositories, and on the parts of the problem that do not have a tidy answer yet.
One feature, three repos: a walkthrough
Promote the API and web app, discover the shared types need a change too, and deliver all three pull requests from one feature.
One repo, many agents: parallel features from a Figma prototype
Split a large prototype into subfeatures, run one agent per slice on its own branch with Figma MCP ready, and ship it as one pull request.
A code graph for agents that spans repos and parallel features
Why ivar indexes the hall once and layers each feature on top, what the agent gets back from one query, and what that did to token use in a benchmark.
The context problem nobody solved: AI agents across multiple repos
An agent is good inside one repo and blind between them. Five workarounds, and where all of them stop.
Start locally
Install ivar when the working boundary is clear.
curl -fsSL ivar.run/install | sh