Skip to main content
The sbx.files.write() API accepts both strings and raw bytes. When you pass bytes (Python) or Uint8Array (TypeScript), the SDK automatically routes the payload to the binary-safe PUT /files/raw endpoint (Content-Type: application/octet-stream, 500 MiB cap) instead of the text-only JSON endpoint. Callers pass whatever type they have — no manual base64 dance required.

What You’ll Learn

  • Writing raw bytes with sbx.files.write(path, b"...")
  • Reading bytes back with format="bytes" and verifying byte-identical round-trip
  • Writing real binary formats (a PNG) and proving the sandbox can decode them
  • The base64.b64decode(...)files.write(...) pattern common in LLM tool-use pipelines
  • Mixed batch writes — WriteEntry entries with str and bytes data in a single write_files() call

Prerequisites

export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="your-declaw-instance.example.com:8080"

Code Walkthrough

import base64
import os
from declaw import Sandbox, WriteEntry

# 1x1 transparent PNG — 67 bytes.
PNG_B64 = (
    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwC"
    "AAAAC0lEQVR42mNgYAAAAAMAASsJTYQAAAAASUVORK5CYII="
)

sbx = Sandbox.create(template="base", timeout=300)
Random binary blob — the classic round-trip test:
blob = os.urandom(4096)
sbx.files.write("/tmp/blob.bin", blob)
got = sbx.files.read("/tmp/blob.bin", format="bytes")
assert bytes(got) == blob
Real PNG — write it, then let the sandbox decode it:
png_bytes = base64.b64decode(PNG_B64)
sbx.files.write("/tmp/pixel.png", png_bytes)

result = sbx.commands.run("file /tmp/pixel.png")
print(result.stdout.strip())
# /tmp/pixel.png: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
Base64-decoded payload — the LLM tool-use pattern:
payload_b64 = base64.b64encode(b"\x00\x01\xff\xfe\x80\x81").decode()
decoded = base64.b64decode(payload_b64)
sbx.files.write("/tmp/decoded.bin", decoded)
Mixed batch — str and bytes entries in a single call. The SDK partitions entries internally (str → JSON batch, bytes → raw PUT) and returns results in the original input order:
results = sbx.files.write_files([
    WriteEntry(path="/tmp/readme.txt", data="Hello from a mixed batch."),
    WriteEntry(path="/tmp/config.bin", data=os.urandom(256)),
])
for r in results:
    print(r.path, r.size)

When to use the URL helpers instead

/files/raw caps request bodies at 500 MiB, but the JSON gateway in front caps the text endpoint at 10 MiB. For very large uploads (hundreds of MB or GB-class), prefer sbx.upload_url(path) and sbx.download_url(path) — they return URLs your client can PUT/GET streams against directly.
url = sbx.upload_url("/data/huge.tar.gz")
# Use `requests`, `httpx`, or curl to PUT a large stream at this URL.

Expected Output (Python)

Sandbox created: sbx_abc123

--- Section 1: Random binary blob ---
Wrote and read back 4096 random bytes, sha=<hex>

--- Section 2: Real PNG ---
`file` output: /tmp/pixel.png: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced

--- Section 3: Base64-decoded payload ---
Wrote 8 decoded bytes, round-trip OK

--- Section 4: Mixed batch write ---
  wrote /tmp/readme.txt (25 bytes)
  wrote /tmp/config.bin (256 bytes)
Both entries round-tripped cleanly.