Skip to content

[sandbox-cli] Add read, write, and recursive copy for agent-friendly file I/O - #380

Draft
roboeve[bot] wants to merge 1 commit into
mainfrom
sandbox-cli/read-write-recursive-copy
Draft

roboeve[bot] wants to merge 1 commit into
mainfrom
sandbox-cli/read-write-recursive-copy

Conversation

@roboeve

@roboeve roboeve Bot commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Adds sandbox read, sandbox write, and sandbox copy --recursive so a coding agent can drive a sandbox's filesystem from the CLI without shell workarounds.

Why

Agents like Claude Code can already run commands through sandbox exec, but file I/O is awkward:

  • sandbox copy moves one file per call, so pushing a project means tarring it locally, copying the tarball, and extracting it with exec.
  • There is no direct way to read or write a file. Agents fall back to exec -- cat and shell heredocs, which brings quoting bugs (zsh globs, nested quotes) and mixes file contents with command output.
  • A failed copy printed an error but still exited 0, so scripts and agents could not detect it.

Approach

Add the three missing primitives on top of existing SDK calls, with no API changes:

  • sandbox read <name>:<path> (alias cat) streams the file's raw bytes to stdout via sandbox.readFile. Errors go to stderr with a non-zero exit, so output is safe to pipe.
  • sandbox write <name>:<path> [--mode 755] reads stdin and writes it with sandbox.writeFiles. If stdin is a TTY it exits with a hint instead of hanging.
  • sandbox copy -r <src> <dst> copies directories in both directions. The contents of src land inside dst.
    • Upload: walks the local tree, keeps file modes, and sends files in tarball batches of up to 32 MiB through writeFiles.
    • Download: lists files with find <dir> -type f -printf '%P\0' (NUL-separated, so odd filenames are safe), then reads them with up to 8 in flight.
    • -r on a single file falls back to a normal file copy. Copying a local directory without -r fails with a hint.
  • Copy failures now set exit code 1.

Paths use the same SANDBOX_NAME:PATH syntax as copy, so there is one convention to learn.

Validation

  • pnpm typecheck passes.
  • pnpm vitest run: 28 files, 235 tests pass.
  • New test/commands/file-commands.test.ts runs the real command handlers against a fake sandbox backed by a temp directory (real find). It covers a copy -r round trip with modes kept, the no--r directory error, -r on a single file, read writing exact bytes to stdout, read exiting non-zero on a missing file, and write from stdin with --mode.
  • New unit tests cover file listing, size batching, find output parsing, mode parsing, and the concurrency limit.
  • Not yet run against a live sandbox. Worth a manual check before merging: write to a path whose parent directory doesn't exist yet, and a large copy -r upload.

Relevant context

  • Shared helpers live in src/util/file-transfer.ts.
  • docs/index.md was regenerated, and scripts/print-usage.ts now includes the new commands.
  • The sandbox skill's CLI section documents the new commands.
  • A changeset marks this as a minor bump of sandbox.

Adds sandbox read, sandbox write, and sandbox copy --recursive so coding agents can work with sandbox files without shell workarounds. Failed copies now exit non-zero.
@vercel

vercel Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
sandbox Ready Ready Preview, v0 Oct 11, 2026 3:48pm UTC
sandbox-cli Ready Ready Preview, v0 Oct 11, 2026 3:48pm UTC
sandbox-sdk-ai-example Ready Ready Preview, v0 Oct 11, 2026 3:48pm UTC
workflow-code-runner Ready Ready Preview, v0 Oct 11, 2026 3:48pm UTC

@vercel-security-reviewer

Copy link
Copy Markdown

Security review details

})),
);
await sandbox.writeFiles(contents);
done += batch.length;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unbounded concurrent fs.readFile in uploadDirectory can exhaust file descriptors (EMFILE) when uploading a directory containing many small files.

Fix on Vercel

This branch was successfully deployed

4 active deployments
Preview – sandbox — 6ebec9ca Deployed Oct 11, 2026 by vercel[bot]
Preview – sandbox-sdk-ai-example — 6ebec9ca Deployed Oct 11, 2026 by vercel[bot]
Preview – workflow-code-runner — 6ebec9ca Deployed Oct 11, 2026 by vercel[bot]
Preview – sandbox-cli — 6ebec9ca Deployed Oct 11, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants