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

# Fork

> Snapshot a running sandbox, spawn N copies, each starts from the parent's current state.

## What fork actually does

```python theme={null}
with Sandbox() as parent:
    parent.run_code("x = 42; import json")
    children = parent.fork(n=5)
    # Each child can access `x` and `json` immediately.
```

Conceptually, `parent.fork(n=5)` does this:

1. **Pause parent** for a few milliseconds.
2. **Take a diff snapshot** of parent's memory — only dirty pages are
   captured.
3. **Resume parent** immediately. The pause window is tiny.
4. **Prepare child memory** from the shared base + the diff.
5. **Spawn N children** in parallel. Each child gets a per-child
   rootfs clone (copy-on-write) and shares memory pages with its
   siblings until they diverge.

## Timing

| n | total    |
| - | -------- |
| 1 | \~90 ms  |
| 2 | \~100 ms |
| 5 | \~100 ms |

<Note>
  Spawn cost is nearly flat in N because children boot in parallel.
</Note>

## What each child inherits

From the parent's moment of snapshot:

* **Python REPL state**: variables, imported modules, open file handles, any
  in-memory objects.
* **Filesystem state**: everything written to the parent's rootfs so far.
* **Process tree**: every running process in the VM. (Yes, including the
  Podflare agent + REPL.)

What children do *not* share after fork:

* Subsequent writes to memory — isolated between siblings.
* Subsequent writes to the rootfs — isolated between siblings.
* Their control channel — each child is independently addressable by its
  own sandbox id.

## Tree-search pattern

<CodeGroup>
  ```python Python theme={null}
  with Sandbox() as parent:
      parent.run_code("""
          import pandas as pd
          df = pd.read_csv('/data/medium.csv')
      """)

      # 5 different hypotheses
      plans = [
          "print(df['col_a'].mean())",
          "print(df['col_b'].mean())",
          "print(df[df.col_a > 0].shape)",
          "print(df.describe().loc['mean'])",
          "print(df.corr().iloc[0])",
      ]

      children = parent.fork(n=len(plans))
      try:
          results = [c.run_code(p) for c, p in zip(children, plans)]
          winner = children[pick_best_index(results)]
          parent.merge_into(winner)
      finally:
          for c in children:
              c.close()
  ```

  ```ts TypeScript theme={null}
  const parent = await Sandbox.create();
  try {
    await parent.runCode(`
      import pandas as pd
      df = pd.read_csv('/data/medium.csv')
    `);

    const plans = [/* ... */];
    const children = await parent.fork(plans.length);

    try {
      const results = await Promise.all(
        children.map((c, i) => c.runCode(plans[i]))
      );
      const winner = children[pickBestIndex(results)];
      await parent.mergeInto(winner);
    } finally {
      for (const c of children) await c.close();
    }
  } finally {
    await parent.close();
  }
  ```
</CodeGroup>

## diff(other)

Compare filesystem state between two sandboxes (typically two forks of the
same parent):

```python theme={null}
a, b = parent.fork(n=2)
a.run_code("with open('/root/a.txt','w') as f: f.write('from a')")
b.run_code("with open('/root/b.txt','w') as f: f.write('from b')")

d = a.diff(b)
# { "added": ["/root/b.txt"], "removed": ["/root/a.txt"], "modified": [] }
```

Default compares `/root` and `/tmp`; pass `paths=[...]` to compare elsewhere.
Implemented as two parallel `sha256sum | sort` invocations inside the two
sandboxes, diffed SDK-side.

## merge\_into(winner)

Commit one fork's state as the new state of the parent:

```python theme={null}
parent.merge_into(winner)
# parent.id is still valid; it now drives winner's VM.
# winner.close() becomes a no-op (marked defunct internally).
# Siblings you don't need: call close() explicitly.
```

Under the hood: the parent sandbox is destroyed and the winner takes
over the parent's id.

## Limits

* `fork(n)` with `1 <= n <= 32`. Larger fanouts are deferred until we
  prove memory pressure at scale.
* `fork()` requires a pool-warm parent. Sandboxes created with custom
  RAM or rootfs skip the pool and can't be forked.
