# ivar hall
> Commands that create a hall and keep a checkout in line with ivar.json — init, sync, status, doctor, repo and provider.
Source: https://ivar.run/docs/reference/hall

import { Callout } from 'fumadocs-ui/components/callout';
import { File, Files, Folder } from 'fumadocs-ui/components/files';

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

```sh
mkdir acme-hall && cd acme-hall
git init
ivar init
```

`ivar 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`.

<Callout title="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.
</Callout>

## Add repos

```sh
ivar repo add api https://github.com/acme/api
ivar repo add web https://github.com/acme/web --default-branch develop
```

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.

```json title="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": "develop" }
  ],
  "version": 1
}
```

## The layout on disk

One bare clone per repo. Every working copy — including the default branch — is
a worktree cut from it.

<Files>
  <Folder name="acme-hall" defaultOpen>
    <File name="ivar.json" />
    <Folder name=".ivar" defaultOpen>
      <Folder name="repos" defaultOpen>
        <Folder name="api" defaultOpen>
          <File name=".bare" />
          <File name="main" />
          <File name="billing-currency" />
        </Folder>
        <Folder name="web" />
      </Folder>
      <Folder name="features" />
      <Folder name="sessions" />
      <Folder name="skills" />
      <Folder name="setups" />
    </Folder>
  </Folder>
</Files>

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

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

`ivar 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

```sh
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 state
```

`ivar 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.

## When something looks wrong

```sh
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.

## Providers

```sh
ivar provider list
ivar provider add opencode
```

The 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.
