Skip to content
ivralo
Sections

Docs / Developer mode

Parallel coders and worktrees

When a plan's wave holds several coding steps, ivralo runs them at once, each Code Engineer in its own git worktree. This page covers how many coders there are, where their worktrees live, how each one's change comes back as a three-way patch, and how a conflict is resolved.

How many coders

In a repository, the team carries several Code Engineers, the specialist for code. IVRALO_CODERS sets how many; the default is 3.

CoderWorks in
Code EngineerYour workspace, as always
Code Engineer 2, Code Engineer 3, ...A git worktree of its own under the ivralo home

A git worktree is a second checkout of the same repository in another directory, sharing its history. The coding steps of a wave are handed out in step order: the first to the Code Engineer, the second to Code Engineer 2, and so on. Past the last coder, steps queue on the coders in order. A wave with one coding step cuts no worktree, and IVRALO_CODERS=1 keeps every coding step in your workspace, one after the other.

Parallel coders only exist inside a plan (Plan mode). Outside a plan, a long coding side job is an instance, which also gets its own worktree (Instances).

Where the worktrees live

<home>/worktrees/<slug>-<hash>/2
<home>/worktrees/<slug>-<hash>/3

<slug> is your repository's directory name and <hash> comes from its full path, so two checkouts both called app never share a directory. Each worktree is cut, detached, from your HEAD when its coder's first step of the wave starts.

A worktree is cut from HEAD, so it cannot see what you have not committed. When a wave with two or more coding steps is about to run on a workspace with uncommitted changes, the plan screen says so before you approve it:

the workspace has uncommitted changes; Code Engineer 2.. start from the last commit

A worktree holds only what git tracks: no virtual environment, no installed packages, no build output. Each coder is told so, and that the project's own install command brings them up. Which command that is comes from your # Commands section in IVRALO.md; ivralo provisions nothing itself.

Telling the coders apart

Each coder's shell and Python worker carry IVRALO_CODER: 2 for Code Engineer 2, 3 for Code Engineer 3. The Code Engineer in your workspace has none, so a setup that reads a missing value as 1 covers it. Use it in your own test setup so two coders running the suite at once do not share a test database, and say how in IVRALO.md, which every coder reads:

# Conventions

- Tests use the database `shop_test_${IVRALO_CODER:-1}`; `make test-db` creates it.

Each coder step's prompt also carries a short brief of the repository, built once per wave without a model call, and one line per coding step of the plan that already finished: its files and the first sentence of its report. A coder still working hears of a sibling that finished with its next tool result. A coder in a worktree is told not to run git worktree, checkout, stash or commit there: ivralo integrates.

Every edit a coder makes asks as any edit does. The dialog adds a where row naming the worktree, and the transcript prefixes its lines with the step and the coder, such as step 3 · Code Engineer 2 ›.

Integration: a three-way patch

When every coder of the wave is done, each worktree is integrated in step order. Code Engineer 1's steps are already in your workspace.

  1. The worktree's whole difference from where it was cut, committed and uncommitted alike, is taken as one patch. .ivralo/ is never part of it.
  2. Every file the patch touches is copied into ivralo's history first, so it can be restored.
  3. The patch is applied with git apply --3way against a temporary index under .ivralo/. Your own staging area is left exactly as it was, and nothing is committed: git diff shows what landed.

A three-way apply lands hunks wherever they do not overlap with what changed in your workspace since the cut, including an earlier coder's integration or your own uncommitted edit. A real overlap is a conflict, the same rule a merge applies.

Before applying, the integration dialog shows the step, the coder and every file with its lines added and removed (Editing and approvals). Accept edits for the session, or edit_file in allow_tools, lifts that dialog. Unattended, ivralo ask --plan integrates only under allow_tools; otherwise the step fails as not integrated - allow edit_file in permissions.json and its worktree is kept. A line follows each integration, such as step 3: 4 files integrated.

Conflicts and the resolve step

A conflict is fixed, not undone. git's conflict markers stay in the files, and ivralo inserts a resolve step right after the conflicted one, marked (resolve):

step 2: conflict in src/db.py - resolving (step 3)
⇄ 3. (resolve) Code Engineer: Resolve conflicts in src/db.py

The Code Engineer in your workspace is told which files, which step's changes collided with what the workspace already held, and to remove every marker and run the project's checks. The resolve step starts at once, with no plan approval, and its edits ask like every edit. The next worktree waits for it. It counts as delivered only when no marker is left, and then the conflicted step's worktree is dropped.

If the resolve step fails, the failure screen names the files with markers left and the path of the kept worktree. b there rolls the wave back through history, returning every integrated file to the bytes it had before the patch came in, and drops the wave's worktrees. Unattended with no allow_tools for edits, a conflict is the step's failure, with the markers left in place.

Stopping and resuming

Esc while the coders work stops the wave: finished steps keep their verdicts, nothing is integrated, and a line names the worktrees left behind. /plan resume runs their steps again in fresh worktrees, which replaces the kept ones, so copy anything you want out of them first. Esc during a resolve step keeps what was already integrated, markers included, and /plan resume runs the resolve step next.

A kept worktree stays until the next cut of that coder replaces it. You can remove one by hand and run git worktree prune afterwards. ivralo only ever removes the worktree slots under its own worktrees/<slug>-<hash>/ directory.