ivar feature
The feature lifecycle on the command line — create, promote, execute, deliver, integrate, close and prune.
A feature is a name, a branch, and the set of repos that branch exists in.
It is the unit ivar uses to decide what an agent may write to and what gets
delivered together.
Create a feature
ivar feature create billing-currencyThe name is one path segment, unique in the hall, and becomes the branch name.
When the branch has to be spelled differently than the feature — feat/login,
say — pass --branch:
ivar feature create login --branch feat/login--base sets the branch new promotions start from, per repo. Left off, each
repo starts from its own default branch.
A new feature owns no repos yet
create records the feature and nothing else. Repos join it one at a time
through promote, which is what makes scope an explicit decision rather than
a guess made up front.
Promote the repos it touches
ivar feature promote billing-currency api
ivar feature promote billing-currency webPromotion 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 effective base. --base overrides that start point for a single
repo.
If the repo has a setup script,
promotion runs it in the new worktree. A failing script leaves the repo
promoted in a failed state, logs its output to
.ivar/features/<feature>/setup-<repo>.log, and ivar feature status shows
the reason. Run the same ivar feature promote again to retry.
Inside a feature session, commands that take a feature name default to
$IVAR_FEATURE, so ivar feature promote web promotes web into the
session's feature.
Everything you did not promote stays on its default branch — and, inside a session, stays read-only. That is the mechanism described in the guard.
When scope moves
Scope is rarely right the first time. It is normal to find, halfway through, that the change reaches one repo further:
Promote the repo. Add it to the feature before editing it.
ivar feature promote billing-currency sharedUpdate the approved Plan. A Run Receipt records its Plan fingerprint at
start. If the Plan changes during execution, review and approve the revision,
then use ivar feature execute accept-revision and explicitly resume. Execution
modes (default or goal) are retained on resume or switched with --mode. See
Execution and
Execution modes.
Open a multi-root workspace
ivar feature workspace billing-currency
ivar feature workspace billing-currency api web
ivar feature workspace billing-currency --jsonivar feature workspace writes a multi-root VS Code workspace file at
.ivar/features/<feature>/<feature>.code-workspace and launches the editor.
Access model
The workspace mirrors the guard directly into your editor:
- Promoted repositories: Folder entries point at the worktree on the feature branch and remain writable.
- Non-promoted (context) repositories: Folder entries point at the worktree
on the repo's default branch. The workspace's
settingsmap includes"files.readonlyInclude"with"<absolute-worktree-path>/**": true, causing the editor to refuse edits inside those folders.
When all included repositories are promoted, files.readonlyInclude is
omitted entirely.
By default, every repository declared in ivar.json is included. Passing a list
of repositories (ivar feature workspace billing-currency api web) restricts
the workspace to that subset. Folder entries are always emitted in manifest
declaration order, filtered but never reordered, so regenerating produces a
deterministic file.
Editor launch
On a normal interactive run, the workspace file is written to disk first, then
code <path> is spawned detached. If the code binary is not found or fails to
launch, the command still succeeds and prints a note explaining that the file
was written but could not be opened.
Passing --json writes the workspace file and outputs structured metadata
without launching an editor.
{
"root": "/home/mnzs/personal/valhalla-hall",
"path": "/home/mnzs/personal/valhalla-hall/.ivar/features/docs-usage-examples/docs-usage-examples.code-workspace",
"feature": "docs-usage-examples",
"folders": [
{
"repo": "ivar",
"branch": "docs-usage-examples",
"path": "/home/mnzs/personal/valhalla-hall/.ivar/repos/ivar/docs-usage-examples",
"readonly": false
},
{
"repo": "valhalla",
"branch": "docs-usage-examples",
"path": "/home/mnzs/personal/valhalla-hall/.ivar/repos/valhalla/docs-usage-examples",
"readonly": false
},
{
"repo": "orca",
"branch": "main",
"path": "/home/mnzs/personal/valhalla-hall/.ivar/repos/orca/main",
"readonly": true
},
{
"repo": "ivar-orca",
"branch": "main",
"path": "/home/mnzs/personal/valhalla-hall/.ivar/repos/ivar-orca/main",
"readonly": true
}
]
}Failure codes and fixes
feature.not_found: The specified feature does not exist or has nofeature.json. Fix: Create the feature first:ivar feature create <feature>.repo.not_in_manifest: A named repository is not declared inivar.json. Fix: Declare the repository withivar repo add <repo> <url>before adding it to the workspace.
Rebase
ivar feature rebase billing-currencyEvery promoted worktree is rebased onto its effective base. A dirty worktree is
skipped rather than stashed, and a conflict is aborted and reported — ivar
will not leave you inside a half-finished rebase.
Deliver
ivar feature deliver billing-currency --preview
ivar feature deliver billing-currency --fingerprint <fp>
ivar feature deliver billing-currency --preview --land
ivar feature deliver billing-currency --land --fingerprint <fp>Delivery moves a root feature's work to real remotes.
Roots deliver, children integrate
deliver operates on root features only. If you try to deliver a child
feature, ivar refuses with integration.root_refused and points you at
ivar feature integrate.
Delivery supports two modes:
- Push mode (default): Pushes each promoted repo's branch to its remote and creates or updates its pull request.
- Land mode (
--land): Merges each promoted repo's feature branch into its default branch locally (fast-forward only), then pushes each default.
Land failure codes and fixes
When using --land, ivar runs an all-or-nothing preflight before writing to
any worktree. Here are the failure codes you may encounter:
deliver.declare_default_branch: A promoted repository has no default branch declared inivar.json. Fix: Declare a default branch for the repository inivar.jsonbefore landing.deliver.land_rebase_in_progress: A default branch worktree has an active rebase in progress. Fix: Complete or abort the in-progress rebase before landing.deliver.land_dirty_worktree: A default branch worktree has uncommitted changes. Fix: Commit or stash your changes in the default worktree before landing.deliver.land_not_fast_forward: The default branch has diverged or cannot fast-forward to the feature tip. Fix: Rebase the feature onto default first:ivar feature rebase <feature>.deliver.land_no_repos: The feature promotes no repositories to land. Fix: Promote at least one repository before delivering.deliver.land_remote_moved(warning): A remote default branch tip moved, disappeared, was absent at preview, or could not be verified since the preview was generated. The land batch is skipped. Fix: Runivar feature deliver <feature> --preview --landagain to preview with the updated remote state.deliver.land_push_failed(warning): Local fast-forward merges succeeded, but pushing a default branch to its remote failed. Fix: Rerunivar feature deliver <feature> --land --fingerprint <fp>to retry the push; fast-forward merge is a safe no-op on already-merged branches.
Subfeatures
A feature can be created under another one, deriving its base from the parent's branch instead of a repo default:
ivar feature create billing-currency-ui --parent billing-currencyPromote the parent into a repo before the child. A child promoted first asks
to promote the parent, or, without a terminal, fails with
feature.parent_promotion_required naming ivar feature promote <parent> <repo>;
nothing is created until the parent has the repo.
integrate requires the child's plan gate to be approved. Write the child's
plan before approving it; an approved empty scaffold leaves the child's
session with nothing to execute:
ivar plan create billing-currency-ui plan
ivar plan approve billing-currency-ui planivar feature integrate lands a child into its immediate parent, leaves first,
one promoted repo at a time — durable and resumable. The integration policy
(--via pr or local, --strategy squash, merge or rebase) is persisted
when the feature is created; after the first receipt it is frozen.
ivar feature reparent moves a still-pristine child under a different parent.
It is refused the moment anything real exists under the feature — a promotion, a
plan, a session, a receipt or a descendant.
Finish up
ivar feature close billing-currency
ivar feature delete billing-currency
ivar feature pruneclose is idempotent — closing a closed feature does nothing. It refuses while
a Run Receipt is active, blocked, or diverged; finish, restart, or resolve
that receipt first. Terminal receipt history is preserved when the feature
closes.
delete refuses while the feature has a live session or a promoted worktree
with uncommitted or untracked changes. --force deletes anyway and discards
that work. It also refuses if anything under the feature directory cannot be
removed, and keeps the feature record so you can retry.
prune deletes features whose branches carried commits that landed on their
base. It keeps a feature with no commits of its own, one with a live session,
and one with a dirty worktree.