The repo is copied into every sandbox for you. Use the files API for everything else: fixtures, data, logs, or the build output you want to keep.
Fig. 1 Data transfer Replay
Data transfer
A large block of data moves in chunks along six parallel streams to a destination, which fills as the source drains, while a throughput reading climbs, holds and finishes.
= 0.0 && r < 6.0 && rc < 3.0) {
float mid = abs(rc - 1.0) < 0.5 ? 1.0 : 0.0;
// the source: full until its chunk leaves (lifting just before), empty ticks after, refilled by the sweep
if (col >= 5.0 && col < 29.0 && mod(col - 5.0, 4.0) < 3.0) {
float j = floor((col - 5.0) / 4.0);
float d = dep(r, 5.0 - j);
float R = resetAt(j);
float lift = sm(d - 0.14, d, t) * step(t, d);
float back = step(R, t) * (1.0 - sm(0.0, 0.16, t - R));
v = t < d || t >= R ? grain(col, cell) + 0.35 * lift + 0.4 * back : 0.19;
}
// the destination: empty ticks until its chunk lands (with a flash), full after, cleared by the sweep
if (col >= 74.0 && col < 98.0 && mod(col - 74.0, 4.0) < 3.0) {
float j = floor((col - 74.0) / 4.0);
float a = dep(r, 5.0 - j) + TRAVEL;
float flash = step(a, t) * (1.0 - sm(0.0, 0.22, t - a));
v = t >= a && t < resetAt(j) ? grain(col - 69.0, cell) + 0.5 * flash : 0.19;
}
// the lane across the gap: faint ticks, a flow running right while the transfer runs
if (col >= 29.0 && col < 74.0 && mid > 0.5) {
float act = sm(0.2, 0.5, t) * (1.0 - sm(3.3, 3.7, t));
v = max(v, 0.13 + act * (0.1 + 0.24 * pow(0.5 + 0.5 * sin(col * 0.9 - TAU * 8.0 * t / T), 4.0)));
}
// chunks in flight on this lane: a dense head, the stream behind it thinning
for (int ki = 0; ki < 6; ki++) {
float k = float(ki);
float c0 = 5.0 + 4.0 * (5.0 - k);
float d = dep(r, k);
if (t >= d && t < d + TRAVEL) {
float u = (t - d) / TRAVEL;
float xc = floor(c0 + 69.0 * mix(u, ease(u), 0.6) + 0.5);
float lc = col - xc;
if (lc >= 0.0 && lc < 3.0) v = max(v, grain(c0 + lc, cell) + 0.12);
else if (lc < 0.0) v = max(v, (mid > 0.5 ? 0.9 * exp(lc / 7.0) : 0.55 * exp(lc / 4.5)) * step(c0, col));
}
}
}
// the strip chart: one column per 0.1 s, drawn up to now, its newest column hot; cleared as the reset starts
if (col >= 33.0 && col <= 68.0 && cell >= 37.0 && cell <= 42.0) {
float s = (col - 33.0) / 35.0 * 3.6;
float h = floor(q(s) / 1.2 * 6.0 + 0.5);
float up = 42.0 - cell;
if (s <= t && t <= 3.85 && up < h) v = t - s < 0.103 ? 0.98 : up > h - 1.5 ? 0.72 : 0.42;
if (cell > 41.5) v = max(v, 0.13);
}
return v;
}]]>
Large files move in chunks over six streams at once. The destination fills as the source drains, so a 2 GB fixture lands in seconds.
await sandbox.files. write ( "fixtures/orders.json" , JSON . stringify (orders)); sandbox.files.write( "fixtures/orders.json" , json.dumps(orders)) Paths are relative to the repo root. Folders are made as needed.
const log = await sandbox.files. read ( "logs/test.log" ); log = sandbox.files.read( "logs/test.log" )
For anything over a few megabytes, stream it. Uploads and downloads are split into chunks that travel in parallel, and resume where they stopped if the connection drops.
import { createReadStream, createWriteStream } from "node:fs" ;
await sandbox.files. upload ( "data/events.parquet" , createReadStream ( "./events.parquet" ));
await sandbox.files. download ( "dist/app.tar.gz" , createWriteStream ( "./app.tar.gz" )); with open ( "events.parquet" , "rb" ) as f:
sandbox.files.upload( "data/events.parquet" , f)
with open ( "app.tar.gz" , "wb" ) as f:
sandbox.files.download( "dist/app.tar.gz" , f) Limit Value Largest single file 5 GB Sandbox disk 20 GB on Hobby, 100 GB on Team Parallel streams per transfer 6
Note Files you write are part of the sandbox, not the repo. They never appear in a pull request unless the agent adds them to the diff itself.