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

# Fork a sandbox and let a model try three fixes

A sandbox with failing tests forks into three copies; each asks the node's model for a fix at its own temperature and runs the tests on it.

Best-of-N without paying for N setups: the source sandbox gets `slug.py` (a `slugify` with four bugs),
`test_slug.py` (seven tests, five of which fail) and `fix.py`, then forks into three copies that start from its
memory and disk. Each fork asks the node's model for a fix at its own temperature (0, 0.6 and 1.0), runs the tests on
the answer and, if they still fail, sends the new output back once. The lowest temperature whose fix passes wins.

Verified 2026-11-06: this recipe's last run passed against `https://beta-api.b3os.org`, label `live-recorded` (recorded from production), from commit `9fd4273e`. The recipe harness runs it again, and a failed run takes this page out of the cookbook.

## Run it

Each tab uploads the three files from this recipe's folder, forks once into three copies and runs `fix.py` in each
at its own temperature.

**curl**

```bash
API=https://beta-api.b3os.org
AUTH="Authorization: Bearer $B3OS_API_KEY"
post() { curl -s "$API$1" -H "$AUTH" -H "Content-Type: application/json" -d @-; }

SRC=$(echo '{"template": "base", "timeout_s": 300, "forkable": true, "egress": {"mode": "deny"},
  "api": {"scopes": ["infer:run"], "spend_cap_usd": 1}}' | post /v1/sandboxes | jq -r .id)
for f in slug.py test_slug.py fix.py; do
  curl -s -X PUT "$API/v1/sandboxes/$SRC/files?path=/workspace/$f" -H "$AUTH" \
    -H "Content-Type: application/octet-stream" --data-binary @"$f" > /dev/null
done
echo '{"cmd": ["python3", "/workspace/fix.py", "--tests-only"]}' | post "/v1/sandboxes/$SRC/exec" | jq -r .stdout

# Three copies of the source's memory and disk, then one try per temperature, at once
FORKS=$(echo '{"count": 3}' | post "/v1/sandboxes/$SRC/fork" | jq -r '.data[].id')
i=0
for id in $FORKS; do
  i=$((i + 1))
  t=$(echo "0 0.6 1.0" | cut -d' ' -f$i)
  jq -n --arg t "$t" '{cmd: ["python3", "/workspace/fix.py"], env: {TEMPERATURE: $t}, timeout_ms: 58000}' \
    | post "/v1/sandboxes/$id/exec" | jq -r '.stdout | split("\n") | map(select(. != "")) | last' &
done
wait
for id in $SRC $FORKS; do curl -s -X DELETE "$API/v1/sandboxes/$id" -H "$AUTH" > /dev/null; done
```
**TypeScript**

```ts
import { readFileSync } from "node:fs";

const API = "https://beta-api.b3os.org";
const auth = { authorization: `Bearer ${process.env.B3OS_API_KEY}` };
const call = async (method: string, path: string, body?: unknown): Promise<any> =>
  (
    await fetch(`${API}${path}`, {
      method,
      headers: { ...auth, "content-type": "application/json" },
      body: body === undefined ? undefined : JSON.stringify(body),
    })
  ).json();
const last = (r: { stdout: string }) => JSON.parse(r.stdout.trim().split("\n").at(-1) ?? "{}");

const src = await call("POST", "/v1/sandboxes", {
  template: "base",
  timeout_s: 300,
  forkable: true,
  api: { scopes: ["infer:run"], spend_cap_usd: 1 },
  egress: { mode: "deny" },
});
for (const f of ["slug.py", "test_slug.py", "fix.py"])
  await fetch(`${API}/v1/sandboxes/${src.id}/files?path=/workspace/${f}`, {
    method: "PUT",
    headers: { ...auth, "content-type": "application/octet-stream" },
    body: readFileSync(f, "utf8"),
  });
console.log(last(await call("POST", `/v1/sandboxes/${src.id}/exec`, { cmd: ["python3", "/workspace/fix.py", "--tests-only"] })));

const temperatures = [0, 0.6, 1.0];
const fork = await call("POST", `/v1/sandboxes/${src.id}/fork`, { count: temperatures.length });
const tries = await Promise.all(
  fork.data.map(async (c: { id: string }, i: number) => {
    const r = await call("POST", `/v1/sandboxes/${c.id}/exec`, {
      cmd: ["python3", "/workspace/fix.py"],
      env: { TEMPERATURE: String(temperatures[i]) },
      timeout_ms: 58000,
    });
    return { temperature: temperatures[i], ...(r.exit_code === 0 ? last(r) : { error: r.stderr }) };
  }),
);
console.log(tries);
for (const id of [src.id, ...fork.data.map((c: { id: string }) => c.id)])
  await call("DELETE", `/v1/sandboxes/${id}`);
```
**Python**

```python
import json
import os
from concurrent.futures import ThreadPoolExecutor

import requests

API = "https://beta-api.b3os.org"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['B3OS_API_KEY']}"


def last(r):
    return json.loads(r["stdout"].strip().split("\n")[-1])


src = s.post(f"{API}/v1/sandboxes", json={
    "template": "base", "timeout_s": 300, "forkable": True, "egress": {"mode": "deny"},
    "api": {"scopes": ["infer:run"], "spend_cap_usd": 1},
}).json()["id"]
for f in ["slug.py", "test_slug.py", "fix.py"]:
    with open(f, "rb") as fh:
        s.put(f"{API}/v1/sandboxes/{src}/files", params={"path": f"/workspace/{f}"}, data=fh.read(),
              headers={"Content-Type": "application/octet-stream"})
print(last(s.post(f"{API}/v1/sandboxes/{src}/exec",
                  json={"cmd": ["python3", "/workspace/fix.py", "--tests-only"]}).json()))

temperatures = [0, 0.6, 1.0]
forks = [c["id"] for c in s.post(f"{API}/v1/sandboxes/{src}/fork", json={"count": 3}).json()["data"]]


def attempt(pair):
    sbx, t = pair
    r = s.post(f"{API}/v1/sandboxes/{sbx}/exec", json={
        "cmd": ["python3", "/workspace/fix.py"], "env": {"TEMPERATURE": str(t)}, "timeout_ms": 58000,
    }).json()
    return {"temperature": t, **(last(r) if r["exit_code"] == 0 else {"error": r["stderr"]})}


with ThreadPoolExecutor(3) as pool:
    print(list(pool.map(attempt, zip(forks, temperatures))))
for sbx in [src, *forks]:
    s.delete(f"{API}/v1/sandboxes/{sbx}")
```
**MCP**

The MCP `sandbox_create` tool takes neither `forkable` nor an `api` grant, so create the source sandbox with the API,
with the same `B3OS_API_KEY` your MCP client sends:

```bash
curl -s https://beta-api.b3os.org/v1/sandboxes -H "Authorization: Bearer $B3OS_API_KEY" \
  -H "Content-Type: application/json" -d '{"template": "base", "timeout_s": 600, "forkable": true,
  "egress": {"mode": "deny"}, "api": {"scopes": ["infer:run"], "spend_cap_usd": 1}}' | jq -r .id
```

`sandbox_fork` is in the `sandboxes` toolset, so connect to the remote [B3OS MCP server](/sdks/mcp) as
`https://beta-api.b3os.org/mcp?toolsets=sandboxes`. Then, with the three files' contents in the conversation, ask
your agent:

```text
In sandbox <id>, write slug.py, test_slug.py and fix.py to /workspace and run
python3 /workspace/fix.py --tests-only. Then fork it into three copies and in each run python3 /workspace/fix.py
with TEMPERATURE set to 0, 0.6 and 1.0 and a 58 second timeout. Tell me which temperatures pass all seven tests,
then delete all four sandboxes.
```

The agent calls `sandbox_write_file` three times, `sandbox_exec`, `sandbox_fork`, `sandbox_exec` once per fork and
`sandbox_delete` four times.

The forks inherit the source's grant (`infer:run` with its $1 spend cap, so `OPENAI_BASE_URL` points at the node's
model) and its egress (`deny`). Each fork changes only its own copy of `slug.py`; the source and the other forks never see it. Which
temperatures pass changes from run to run: the recipe asserts the setup (seven tests, five failing, three forks that
each ran), not the model's answers. `fork_ms` and `fork_restore_ms` are the fork's server-side total and restore phase
from its `Server-Timing` header; `model_ms` and `tests_ms` are measured inside each fork. All four sandboxes are
deleted at the end.

Files: `run.mjs` (the client), `slug.py`, `test_slug.py` and `fix.py` (uploaded to the source sandbox).

Owner: Sandboxes. Products: Sandboxes, Infer.

## Output of the last green run

**Outputs**

```json
{
  "tests_total": 7,
  "failing_before": 5,
  "forks": 3,
  "fork_ms": 52.118,
  "fork_restore_ms": 27.921,
  "passing": 2,
  "winner_temperature": 0,
  "tries": [
    {
      "temperature": 0,
      "passed": true,
      "tests_passed": 7,
      "rounds": 2,
      "model_ms": 3197.7,
      "tests_ms": 37.7,
      "lines": 27,
      "failing": []
    },
    {
      "temperature": 0.6,
      "passed": true,
      "tests_passed": 7,
      "rounds": 2,
      "model_ms": 2734,
      "tests_ms": 73.5,
      "lines": 26,
      "failing": []
    },
    {
      "temperature": 1,
      "passed": false,
      "tests_passed": 6,
      "rounds": 2,
      "model_ms": 4240.6,
      "tests_ms": 28.6,
      "lines": 34,
      "failing": [
        "test_accents"
      ]
    }
  ]
}
```
**Command**

```bash
$ node run.mjs
# exit 0
```

The outputs this recipe publishes (the `publish.outputs` list in its recipe.json), with workspace identifiers redacted. The run's stdout, stderr and other outputs are not published.

Captured 2026-11-06 from commit `9fd4273e`, label `live-recorded` (recorded from production). Case `recipes/sandbox-fork-best-of-n-fixes`.