Mentu

Transfer Modes & VM Isolation

Transfer Modes & VM Isolation

mentu provides two orthogonal isolation axes: transfer modes control where files live during execution, and VM isolation controls where code runs. They compose independently, so you can use either, both, or neither.

Transfer Modes

A transfer mode determines how mentu creates an isolated copy of your project before running a recipe. Four modes are available:

Mode What it does When to use
none Runs in-place on the working directory Quick tasks, trusted recipes
worktree Creates a git worktree, runs there, merges back via canary Default for pipelines, any multi-step work
mirror Pushes to a bare repo clone, works there, fetches back Remote targets or when worktrees are unavailable
rsync Rsync-based copy with standard excludes (.git, .build, node_modules) Large repos where worktree is slow, or non-git projects

CLI usage

All three execution commands accept --transfer:

mentu sequence my-recipe --transfer worktree
mentu pipeline my-pipeline --transfer mirror
mentu compound my-compound --transfer rsync

The --worktree flag is shorthand for --transfer worktree:

mentu sequence my-recipe --worktree

Recipe-level

Set the transfer mode in the recipe JSON so it always runs isolated:

{
  "name": "my-recipe",
  "transfer_mode": "worktree",
  "steps": [...]
}

Resolution order

  1. --transfer on the CLI (highest priority)
  2. --worktree on the CLI (shorthand for --transfer worktree)
  3. transfer_mode in the recipe JSON
  4. none if nothing else is set (in-place execution)

If the CLI passes --transfer, it wins. Otherwise the recipe's transfer_mode field is used. If neither is set, execution runs in-place.

VM Isolation

The --vm flag sends each step's tool execution to a VM sandbox via mentu-runtime. The agent (Claude) runs on the host, but all tool calls (file reads, writes, bash commands) execute inside the VM. Recipe orchestration stays on the host.

mentu sequence my-recipe --vm

If the mentu-runtime daemon is not running, mentu starts it automatically. If the daemon is unavailable, the step runs without VM sandboxing and prints a warning.

Recipe-level and step-level

VM isolation can be set at the recipe level, overridden per step:

{
  "name": "my-recipe",
  "vm": true,
  "steps": [
    { "label": "trusted-step", "vm": false },
    { "label": "untrusted-step", "vm": true }
  ]
}

Resolution order

  1. --vm on the CLI (highest priority, applies to all steps)
  2. vm field on a step (per-step override)
  3. vm field on the recipe (recipe-level default)
  4. false if nothing else is set (no VM)

The CLI flag is a global override. If not set, each step checks its own vm field, then falls back to the recipe-level vm field, then defaults to false.

Composition

Both axes compose. --transfer worktree --vm creates a git worktree AND runs each step in a VM sandbox. They are independent:

mentu sequence audit-pipeline --transfer worktree --vm

The two axes form a 2x4 grid. Rows are VM isolation, columns are transfer mode.

none worktree mirror rsync
VM off in-place isolated copy bare-repo copy rsync copy
VM on VM only VM + isolated VM + bare-repo VM + rsync

Every cell is a valid mode. Pick the row that matches your trust in the tool calls and the column that matches your filesystem needs.

Pick each axis based on what you need:

  • Filesystem isolation only (--transfer worktree): protect your working tree from multi-step recipes that create, modify, or delete files. Changes merge back only if the canary passes.
  • Process isolation only (--vm): run untrusted tool calls in a sandbox while keeping files in-place.
  • Both (--transfer worktree --vm): full isolation. The recipe operates on an isolated copy, and tool execution is sandboxed.

Canary Checks

When using worktree, mirror, or rsync, mentu runs a canary before merging changes back to your working tree. The canary runs these checks in order:

  1. Build (swift build -c release). Only runs if Swift files changed. Skipped for recipes that only produce docs or reports.
  2. Tests (swift test). Only runs if a test target exists and Swift files changed.
  3. CIR contradiction check. Fails if unresolved contradictions exist in the CIR store.
  4. Ratchet check. If ratchets.json exists, verifies quality metrics have not regressed.
  5. Plugin before_merge hook. Any registered plugin can abort the merge.
  6. Git conflict check. Attempts direct merge, falls back to rebase-then-fast-forward if the base branch moved.

If any check fails, changes stay in the isolated branch. Nothing merges to your working tree.

⚠️

When a canary fails during a sequence, mentu automatically re-runs the last step up to 3 times with the canary error injected as MENTU_CANARY_ERROR so the agent can attempt a fix. If all 3 attempts fail, the branch is preserved for manual resolution.

Manual recovery

If a canary blocks the merge, the worktree branch is preserved:

# See what the agent produced
git log mentu/<recipe-name>
 
# Merge manually after fixing
git merge mentu/<recipe-name>
 
# Or discard
git branch -d mentu/<recipe-name>

Workspace Locking

When running in none mode (in-place), mentu acquires an exclusive workspace lock. A second sequence targeting the same directory will fail with an error. Transfer modes avoid this because each sequence gets its own isolated copy, so multiple sequences can run concurrently.

# These can run simultaneously. Each gets its own worktree.
mentu sequence recipe-a --transfer worktree &
mentu sequence recipe-b --transfer worktree &

In Scripts

mentu.sequence.run('my-recipe', {
  transfer: 'worktree',
  vm: true,
  vars: { TARGET: 'production' },
});

See SDK Reference for the full SequenceRunOptions type.

© 2026 Mentu.