Skip to main content
sandbox.files manages files inside one sandbox. /workspace is the default mutable work tree, but general filesystem APIs also accept valid sandbox-scoped absolute paths such as /tmp/result.txt, /context/input.json, and /srv/app/config.json.

Read and write

from nullspace import Sandbox

with Sandbox.create() as sandbox:
    sandbox.files.write("/workspace/hello.txt", "hello\n")
    sandbox.files.write_files([
        ("/workspace/a.txt", "a\n"),
        ("/workspace/b.txt", "b\n"),
    ])
    print(sandbox.files.read("/workspace/hello.txt"))
    print(sandbox.files.read("/workspace/hello.txt", format="bytes"))
    print(sandbox.files.list("/workspace"))
Use format="stream" for large downloads:
for chunk in sandbox.files.read("/workspace/large.log", format="stream"):
    process_chunk(chunk)
Migration note: No breaking change: /workspace is still the default mutable work tree. General filesystem APIs also accept valid sandbox-scoped absolute paths such as /srv/app/...; reserved runtime paths under /workspace/.nullspace are rejected.

Upload and download

sandbox.files.upload("./local.txt", "/workspace/local.txt")
sandbox.files.upload_dir("./src", "/workspace/src", max_concurrency=4)
sandbox.files.upload_file(
    "./large.bin",
    "/data/large.bin",
    resumable=True,
    checksum="auto",
    spool_to_disk="auto",
)
url = sandbox.files.download_url("/workspace/local.txt")
print(url)
info = sandbox.files.info("/workspace/local.txt")
exists = sandbox.files.exists("/workspace/local.txt")
matches = sandbox.files.search_files("/workspace", "*.txt")
print(info.path, exists, matches)
Other management helpers include make_dir(), rename(), remove(), set_permissions(), and get_info() as an alias for info().

Replace and watch

paths = sandbox.files.search_files("/workspace", "*.py")
count = sandbox.files.replace_in_files(paths, "old_name", "new_name")
print(count)

def on_event(event):
    print(event.type, event.path)

with sandbox.files.watch_dir("/workspace", on_event, recursive=True, timeout=30):
    sandbox.files.write("/workspace/changed.txt", "changed\n")
Most file helpers accept user= when paths should be resolved for a specific sandbox user.

Async API

from nullspace import AsyncSandbox

async with await AsyncSandbox.create(template="base") as sandbox:
    await sandbox.files.write("/workspace/hello.txt", "hello\n")
    text = await sandbox.files.read("/workspace/hello.txt")
    matches = await sandbox.files.search_files("/workspace", "*.txt")
    print(text, matches)
Async file uploads, signed URLs, replace, and watch helpers mirror the synchronous sandbox.files API. Concept: Exec. API reference: listDir, readFile, writeFile, uploadUrl, and downloadUrl.