Filesystem
Read, write, search, and watch files inside a sandbox over HTTP.
The filesystem API reads, writes, searches, and watches files inside a sandbox. It works over HTTP — no SSH, no network setup. Use it to move code and data in and out of a running sandbox.
All paths are absolute paths inside the sandbox.
Read and write
The API caps writes at 16 MiB and reads at 256 MiB. See Limits for larger files.
await sbx.files.write("/workspace/app.py", "print('hello')");
const buf = await sbx.files.read("/workspace/app.py");sbx.files.write("/workspace/app.py", b"print('hello')")
data = sbx.files.read("/workspace/app.py")pt sandbox cp ./app.py $ID:/workspace/app.py
pt sandbox cp $ID:/workspace/app.py ./app.pycurl -X PUT "$PT_API_URL/v1/sandboxes/$ID/files?path=/workspace/app.py&mode=0755" \
-H "Authorization: Bearer $PT_TOKEN" --data-binary @app.py
curl "$PT_API_URL/v1/sandboxes/$ID/files?path=/workspace/app.py" \
-H "Authorization: Bearer $PT_TOKEN" -o app.pyWrites create parent directories automatically. There is no batch upload — send one file per call.
List, stat, mkdir
const entries = await sbx.files.list("/workspace");
const st = await sbx.files.stat("/workspace/app.py");
const there = await sbx.files.exists("/workspace/app.py");
await sbx.files.mkdir("/workspace/data");entries = sbx.files.list("/workspace")
st = sbx.files.stat("/workspace/app.py")
there = sbx.files.exists("/workspace/app.py")
sbx.files.mkdir("/workspace/data")pt sandbox fs ls $ID /workspace
pt sandbox fs stat $ID /workspace/app.py
pt sandbox fs mkdir $ID /workspace/datacurl "$PT_API_URL/v1/sandboxes/$ID/files/list?path=/workspace" -H "Authorization: Bearer $PT_TOKEN"
curl "$PT_API_URL/v1/sandboxes/$ID/files/stat?path=/workspace/app.py" -H "Authorization: Bearer $PT_TOKEN"
curl -X POST "$PT_API_URL/v1/sandboxes/$ID/files/mkdir?path=/workspace/data" -H "Authorization: Bearer $PT_TOKEN"exists returns a boolean and does not throw. Over REST, use stat — a 404 means the path does not exist.
Delete
Non-empty directories need recurse. The API refuses to delete /.
await sbx.files.delete("/tmp/junk");
await sbx.files.delete("/tmp/junkdir", { recurse: true });sbx.files.delete("/tmp/junk")
sbx.files.delete("/tmp/junkdir", recurse=True)pt sandbox fs rm $ID /tmp/junk
pt sandbox fs rm $ID /tmp/junkdir -rcurl -X DELETE "$PT_API_URL/v1/sandboxes/$ID/files?path=/tmp/junkdir&recurse=true" \
-H "Authorization: Bearer $PT_TOKEN"Search and replace
In replace, find is a regular expression. Escape metacharacters to match them literally.
const files = await sbx.files.find("/workspace", "*.py");
const hits = await sbx.files.grep("/workspace", "TODO");
await sbx.files.replace("/workspace", "TODO", "DONE", { glob: "*.py" });files = sbx.files.find("/workspace", "*.py")
hits = sbx.files.grep("/workspace", "TODO")
sbx.files.replace("/workspace", "TODO", "DONE", glob="*.py")pt sandbox fs find $ID '*.py' --path /workspace
pt sandbox fs grep $ID TODO --path /workspace
pt sandbox fs replace $ID TODO DONE --path /workspace --glob '*.py'curl "$PT_API_URL/v1/sandboxes/$ID/files/find?path=/workspace&pattern=*.py&max=500" -H "Authorization: Bearer $PT_TOKEN"
curl "$PT_API_URL/v1/sandboxes/$ID/files/grep?path=/workspace&pattern=TODO&max=500" -H "Authorization: Bearer $PT_TOKEN"
curl -X POST "$PT_API_URL/v1/sandboxes/$ID/files/replace" -H "Authorization: Bearer $PT_TOKEN" \
-H "Content-Type: application/json" -d '{"path": "/workspace", "find": "TODO", "replace": "DONE", "glob": "*.py"}'find matches filename globs — anything find -name accepts. grep returns one file:line:content line per match. For large trees, run ripgrep via exec if your template ships it.
Watch for changes
watch streams file-change events under a path as Server-Sent Events.
The stream is best-effort. It does not report deletions. A change in the same second as a poll can slip by. Consume it server-side — a browser EventSource cannot send the auth header.
for await (const ev of sbx.files.watch("/workspace", { maxSeconds: 300 })) {
if (ev.event === "change") console.log(ev.data.path);
}for ev in sbx.files.watch("/workspace", max_seconds=300):
if ev["event"] == "change":
print(ev["data"]["path"])pt sandbox fs watch $ID /workspace --max-seconds 300curl -N "$PT_API_URL/v1/sandboxes/$ID/files/watch?path=/workspace&interval_ms=1000&max_seconds=300" \
-H "Authorization: Bearer $PT_TOKEN"ready fires once, after the watcher arms the baseline. The stream reports only changes after that point. The stream ends after max_seconds — reconnect to keep watching.
Limits
| Limit | Value |
|---|---|
Upload (PUT /files) | 16 MiB per request |
Download (GET /files) | 256 MiB per request |
| RPC replies (stat, list, find, grep) | 16 MiB per call |
Every write replaces the whole file. There is no append, so one path cannot be uploaded in chunks. For files past the upload limit, fetch them from inside the sandbox with wget/curl via exec. Or stage them on a volume.
File calls reset the auto-stop idle timer. Steady traffic keeps an ephemeral sandbox alive.
Behavior details
The async Python client (AsyncPlatinum) mirrors sbx.files with awaited calls.
| Detail | Behavior |
|---|---|
| Sandbox state | Must be running, else 409 sandbox_not_running |
| Paths | .. segments and NUL bytes → 400 |
Non-empty delete without recurse | 500 "directory not empty" |
| Write response | { ok, size, mode } |
| Read response | Bytes; octal mode in x-pt-mode header |
mode on PUT / mkdir | Octal, HTTP-only, default 0644; SDKs never set it |
stat response | { ok, size, mode, mtime } — decimal permission bits (493 = 0755), mtime unix ms, is_dir only when true |
max on find / grep | Result cap — default 500, max 5000 |
| Search timeouts | find 15 s, grep 30 s, replace 60 s |
replace response | { ok, stdout, stderr }, no per-file change count |
watch tunables | path default /workspace; interval_ms 500–10000 (default 1000); max_seconds 5–3600 (default 300) |
change payload | { ts, type, path } — ts unix seconds; type: file, dir, link, other |
Exact request and response schemas are in the API reference.
Browse from the dashboard
The sandbox detail view in the dashboard has a Files tab — browse, upload, download.
See also
- Exec — run commands and code, redirect large output to files
- Volumes — persistent storage that survives sandbox deletion
- API reference — exact request/response schemas