ivar hall
Commands that create a hall and keep a checkout in line with ivar.json — init, sync, status, doctor, repo and provider.
A hall is a directory that owns a set of repos. It is itself a git repo, and
the file it commits — ivar.json — is the only thing a teammate needs to end up
with the same checkout you have.
Create one
mkdir acme-hall && cd acme-hall
git init
ivar initivar init writes ivar.json, the .ivar/ working area, and the hall's
gitignore lines. It takes the hall's name from the directory unless you pass
--name, and records claude-code as the sole available provider unless you
pass --provider.
Commit ivar.json, ignore .ivar/
ivar.json is the manifest and belongs in the repo. .ivar/ is local working
state — clones, worktrees, sessions — and init adds the ignore lines for
you.
One hall per tree
ivar init refuses to run inside an existing hall (hall.nested): every
ivar command run from inside it would act on the enclosing hall. For a
scratch or throwaway hall — a demo, a test, a reproduction — start in a
directory outside any hall:
cd "$(mktemp -d)"
ivar initAdd repos
ivar repo add api https://github.com/acme/api
ivar repo add web https://github.com/acme/web --default-branch developStart a repo from scratch instead of cloning one:
ivar repo create notes --local # stored in the hall's origin under repos/notes/
ivar repo create notes --remote # created on GitHub with gh (private; --public to share)A --local repo travels with the hall: anyone who clones the hall and runs
ivar sync gets it. It delivers by push and local merge, never a pull request.
Each call declares the repo in ivar.json, clones it bare, and materialises its
default-branch worktree. The name is one path segment and must be unique in the
hall; the default branch is main unless you say otherwise.
{
"$schema": "https://ivar.run/schema/4.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": "develop" }
],
"version": 4
}The manifest also carries the hall's MCP servers, under an mcp key — see
MCP servers.
Editor validation
The $schema property is what makes an editor validate ivar.json, complete
every field and enum value, and flag a typo before ivar sees the file.
The URL carries the manifest version because the schema pins version with
const: one document describes exactly one version, and an editor that
fetched the wrong one would report an error on a file that is correct. You do
not maintain this line — ivar stamps the URL for the version it writes, so a
hall created before the property existed, or carrying an older URL, is
corrected by the next command that touches its manifest.
Documents start at version 4, the first version whose schema was published. Once released, a document is frozen: halls on that version resolve against the copy that shipped, so a correction arrives as a new manifest version rather than as an edit to a released one.
The layout on disk
One bare clone per repo. Every working copy — including the default branch — is a worktree cut from it.
Because these are worktrees and not copies, editing a file under .ivar/repos/
edits that repository. There is no export step and nothing to keep in sync.
Onboarding a teammate
git clone git@github.com:acme/hall.git && cd hall
ivar syncivar sync brings the local hall in line with ivar.json: it clones repos that
are missing, materialises harness config, and runs each repo's setup script.
Setup scripts are receipted, so a second sync does not re-run work that has
already been done — --force-setup overrides that for when a script's effect
was undone outside ivar, like a deleted node_modules.
Keeping it current
ivar repo pull # fetch every repo's default branch
ivar repo pull api # or just one
ivar repo setup api # re-run one repo's setup script
ivar repo list # what is declared, and its stateivar repo remove takes a repo out of the manifest and tears its files down. It
refuses while the repo is promoted in a feature or referenced by a live session;
--force lifts both gates and cascades.
Upgrading ivar
ivar upgrade # install the latest release the way this one was installed
ivar upgrade --check # report current and latest; install nothing| binary in | channel | what runs |
|---|---|---|
$IVAR_INSTALL_DIR or ~/.local/bin | installer | the install script, into the same directory |
~/.cargo/bin | cargo | cargo install ivar --locked |
/usr/bin | system (AUR) | nothing — prints paru -S ivar-bin |
| anywhere else | unknown | nothing — prints every supported command |
It prints the command before running it, does nothing when you are already on the latest release, and exits non-zero if the command fails or the latest release cannot be found.
At most once per 20 hours an interactive ivar asks GitHub which tag
releases/latest points at, caches it under ~/.cache/ivar/, and — when a
newer release is cached — ends the next command with one stderr line. It never
touches stdout or the exit code, and it is off with IVAR_NO_UPDATE_CHECK=1,
under CI, with --json, when stderr is not a terminal, and for the verbs
hooks and MCP clients call.
When something looks wrong
ivar status # hall health, and each repo's state
ivar doctor # diagnose problems and suggest fixes
ivar cleanup # reconcile stale state (asks before deleting)Every command accepts --json, which prints exactly the value the command
computed — the human-readable output is a rendering of that same value, so a
script and a person can never be told different things.
"For AI Agents" block
When ivar sync materialises HALL.md, it appends a directive block addressed
to AI agents:
## For AI Agents
This directory is an `ivar` orchestration hall. You are fully authorized to
run `ivar` commands (e.g., `ivar feature create`, `ivar session start`, `ivar sync`)
on behalf of the user to manage features, repos, and sessions.
If you are unsure of the exact CLI syntax or how `ivar` works, DO NOT GUESS.
First, fetch and read the documentation from:
https://ivar.run/llms.txtThe block lives inside the managed markers and is overwritten on every sync. Content you write above the managed block survives; content below it is not touched either. Only the block between the markers is ivar's.
The block is opt-in by presence
If you remove the managed markers from HALL.md, ivar sync will prepend the
block at the top of the file instead. This is the "markers absent" case — it
preserves everything already in the file.
Providers
ivar provider list
ivar provider add opencode
ivar provider remove opencodeThe hall's providers decide which harnesses a session can be opened in, and
which one ivar session start uses when you do not name one.
ivar provider remove drops a provider from ivar.json and removes the
config ivar materialised for it: its MCP entry, hook settings, ivar-*
commands, and shipped skills. Files you wrote yourself stay. Removing the
default provider needs a replacement named in the same command:
ivar provider remove claude-code --default opencodeThe hall must keep at least one provider. A session still running under the
removed provider is not stopped, but it loses its ivar guard hooks, and the
command warns about each one.