> ## Documentation Index
> Fetch the complete documentation index at: https://instabox.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Parallel forks

> Set up one machine, copy it into several, try an approach in each, and keep one.

At the end of this page, you have tried several approaches to the same task at once and kept the
best one. You set up one machine with the repo, tools, and sign-ins, and copy it into a few machines.
An agent or a script works in each copy, and you compare the results. Every copy starts with the same
disks, so nobody repeats the setup.

**1. Set up one machine**

`my-repo`, `npm ci`, and `npm test` on this page stand for your own repo and its commands.

```bash theme={null}
instabox create --name base
cd my-repo && instabox push base .         # into /data/home/my-repo
instabox exec base --cwd /data/home/my-repo -- npm ci
```

`exec` prints the command's output when the command exits.

**2. Fork it**

```bash theme={null}
instabox fork base --name try --count 3 --json
```

This command makes `try-1`, `try-2`, and `try-3` with the same template and size, and waits until
they run. One command makes up to 5 copies. With `--json`, it prints the new machines under
`machines`. Without it, it prints their rows and the time the fork took.

The disks are copied on the machine's host in a few seconds, without a snapshot. Memory and
running programs are not copied. The source machine is not changed. Copies of one source wait for
each other only while their disks are copied, then boot in parallel.

**3. Run one approach in each**

`approach-a.sh` to `approach-c.sh` stand for your own scripts.

```bash theme={null}
instabox exec --background try-1 --cwd /data/home/my-repo -- ./approach-a.sh
instabox exec --background try-2 --cwd /data/home/my-repo -- ./approach-b.sh
instabox exec --background try-3 --cwd /data/home/my-repo -- ./approach-c.sh
instabox jobs ls try-1
```

Each `exec --background` prints the ID of the job it started. `jobs ls` lists the jobs of a
machine. With a coding agent, run `instabox agent prompt try-1 -f "..."` in each copy. See
[Coding agents](https://instabox.sh/docs/use-cases/coding-agents.md).

**4. Compare the copies and keep one**

```bash theme={null}
instabox exec try-2 --cwd /data/home/my-repo -- 'git diff --stat && npm test'
instabox pull try-2 /data/home/my-repo/dist ./dist-b
instabox rm try-1 --yes
instabox rm try-3 --yes
```

`pull` copies the copy's `dist` folder to `./dist-b` on your computer. The `rm` commands delete
the copies you do not keep.

> [!NOTE]
>
> Each copy is a machine. It counts toward your plan's machines and machine starts a minute, and
> `fork` waits out the start limit. Each copy also runs: when your workspace cannot run `--count`
> more machines, `fork` creates none and says how many fit. See [Limits](https://instabox.sh/docs/account/limits.md).

## Start copies from a snapshot instead

A snapshot keeps the setup for later. It starts any number of machines, at any time, on any host:

```bash theme={null}
instabox snapshot save base --name base-setup
instabox create --name try-4 --snapshot base-setup
```

From the TypeScript SDK:

```ts theme={null}
import { Sandbox } from '@insforge/instabox-sdk'

const base = await Sandbox.create('agent-browser')
// ... set it up ...
const snap = await base.createSnapshot({ name: 'base-setup' })
const tries = await Promise.all([1, 2, 3].map(() => Sandbox.create(snap.id)))
```

> [accordion] A paused machine cannot be forked
>
> `fork` copies a running or stopped machine. The server refuses to fork a paused machine, one with
> no host, or one on an older host, with `409 fork_unavailable`, and creates nothing. Resume a
> paused machine first (it cannot be stopped while paused); otherwise save a snapshot and create from it.
>
> A fork is made only on the source's host. When that host is under maintenance or full, the
> answer is the same code but retryable, with `reason` `source_host_unavailable` (maintenance) or
> `source_host_full` (no room), and nothing is created. Stop and start the machine to move it to
> another host, then fork it.
>
> With an older server that has no native fork, with a source host that is under maintenance or full, or
> with `--keep-snapshot`, the CLI saves a
> snapshot and creates the copies from it. It then deletes the snapshot, unless you passed
> `--keep-snapshot`.

> [accordion] Size, Secrets, and variables of the copies
>
> `fork` keeps the source's size, environment variables, and Secret selection. It also keeps the
> source's auto-pause, max runtime, labels, and delete time (the same moment, so a source deleted
> in 2h gives copies deleted in 2h) unless you pass `--auto-suspend`, `--max-run-minutes`, `--meta`,
> or `--delete-after`. Your plan's limits apply to these as they do on `create`: a kept value your
> plan does not allow is refused, and the error names the flag to pass. A machine created
> from a snapshot gets the plan's default size unless you pass one. It also gets only the variables
> and Secrets in its own create request.

> [accordion] Over the API
>
> `POST /v1/machines/{id}/fork` answers the create operation. Its `machineId` is the new machine,
> and the new machine's `instabox-fork-of` label names the source.

> [card] [Snapshots](https://instabox.sh/docs/machines/snapshots.md)
>
> Save, fork, restore in place, and what a snapshot holds.

> [card] [Errors](https://instabox.sh/docs/reference/errors.md)
>
> `fork_unavailable` and every other error code.
