Skip to content

think: make createSandboxTools actually work #1319

Open

Description

@threepointone

Parent roadmap: #1439

Summary

@cloudflare/think/tools/sandbox currently exports createSandboxTools(), but the implementation is intentionally a no-op: it logs a warning once and returns {}.

That means the blog/docs-level execution ladder says Think can wire in Cloudflare Sandbox as Tier 4, but the package export does not yet provide any usable tools.

This issue tracks turning createSandboxTools() into a real integration with the Cloudflare Sandbox SDK, or narrowing/removing the public promise until the integration exists.

Current behavior

Current implementation in packages/think/src/tools/sandbox.ts:

export function createSandboxTools(
  _binding?: unknown,
  _options?: CreateSandboxToolsOptions
): ToolSet {
  if (!warned) {
    warned = true;
    console.warn(
      "[@cloudflare/think] createSandboxTools is not yet implemented. " +
        "No tools will be registered."
    );
  }

  return {};
}

The export exists in packages/think/package.json as @cloudflare/think/tools/sandbox, so users can import and spread it, but they get no tools.

Why this matters

Project Think's execution ladder is meant to be additive:

  • Tier 0: Think Workspace / @cloudflare/shell
  • Tier 1: Dynamic Worker / codemode execution
  • Tier 2: npm/runtime dependency loading
  • Tier 3: browser automation
  • Tier 4: full Sandbox for OS-level toolchains, repos, test runners, compilers, and long-running processes

Tier 4 is the escape hatch for tasks that cannot fit in a Workers isolate: git clone, npm test, cargo build, real CLIs, shell scripts, code review bots, and heavyweight project work.

Right now Think has a named Sandbox tool export, but no actual Sandbox bridge. That creates a confusing gap for users and for the roadmap.

Sandbox SDK capabilities to target

The Sandbox SDK already exposes useful primitives:

  • getSandbox(env.Sandbox, id) to create/reuse a sandbox instance
  • exec() for command execution with complete stdout/stderr/exit code
  • execStream() for long-running commands with streamed output
  • startProcess() / process log streaming for services
  • file operations: readFile, writeFile, mkdir, exists, delete/move/rename
  • code interpreter contexts for Python/JavaScript/TypeScript
  • preview URLs / port exposure for web servers
  • terminal and WebSocket connections
  • request-proxy patterns so real credentials stay in the Worker, not inside sandbox code

For Think v1, we should probably start with a small subset instead of exposing the whole SDK.

Proposed first milestone

Implement a minimal createSandboxTools(binding, options) that exposes a conservative tool set for Think agents:

  1. sandbox_exec

    • Run a shell command in a named sandbox.
    • Inputs: command, optional sandboxId, optional cwd, optional timeout.
    • Output: stdout, stderr, exitCode, success, maybe truncated output metadata.
  2. sandbox_write_file

    • Write a file into /workspace or another allowlisted path.
    • Inputs: path, content, optional encoding.
  3. sandbox_read_file

    • Read a file back from the sandbox.
    • Inputs: path, optional encoding / max bytes.
  4. Optional later: sandbox_exec_stream

    • Stream long-running output into Think chunks or a retained run/event model.
    • This is probably not required for the first PR unless the API shape is obvious.
  5. Optional later: sandbox_expose_port / preview URL helpers.

Keep the first implementation boring and testable: command execution + file transfer.

Workspace sync question

The important design question is how Think's DO-local Workspace interacts with the Sandbox filesystem.

Possible approaches:

A. Explicit file transfer tools

The model calls read / find / grep against Think Workspace, then calls sandbox_write_file for files it wants in the Sandbox. After commands run, it calls sandbox_read_file to pull results back.

Pros: simple, no hidden sync, minimal API.
Cons: tedious for whole repos / many files.

B. Helper methods for push/pull workspace snapshots

Expose tools like:

  • sandbox_push_workspace({ paths, sandboxPath })
  • sandbox_pull_workspace({ sandboxPath, paths })

Pros: better UX for project work.
Cons: needs careful path filtering, binary handling, limits, and conflict behavior.

C. Git/Artifacts handoff

Use Git/Artifacts as the handoff boundary: Think commits workspace state to an Artifacts repo, Sandbox clones/mounts it, pushes results, and Think imports/reviews the diff.

Pros: clean versioned boundary, aligns with #1440.
Cons: larger integration; should not block the minimal createSandboxTools() milestone.

Recommendation: start with A, design B after using it, and keep C linked to #1440.

API shape questions

  • Should createSandboxTools() accept a Sandbox Durable Object namespace directly, or a factory function like (id) => getSandbox(binding, id)?
  • How should the sandbox id be chosen by default: Think agent name, chat/session id, caller-provided id, or a generated per-run id?
  • Should tools reuse a long-lived sandbox per Think agent/session, or create per-run sandboxes?
  • How should timeouts work, given Sandbox command timeout behavior does not necessarily kill the underlying process?
  • Should path access be restricted to /workspace by default?
  • Should network/proxy setup be part of createSandboxTools() or left to application code?
  • How do we surface preview URLs / running background processes without turning v1 into a full IDE API?

Security constraints

  • Do not pass durable secrets directly into sandbox commands by default.
  • Prefer Worker-side proxy patterns for external APIs so the sandbox gets short-lived scoped credentials, not real API keys.
  • Require explicit opt-in for network credentials, repo write tokens, or access to user data.
  • Default path access should be scoped, probably to /workspace.
  • Tool outputs must be truncated/structured to avoid blowing up model context.
  • Commands should have explicit timeouts and clear behavior for non-zero exit codes.
  • Avoid logging secrets in command strings, outputs, or chat history.

Relationship to existing Think tools

  • createExecuteTool() remains the default for small JavaScript programs in Dynamic Worker isolates.
  • createSandboxTools() is for full OS/toolchain work that cannot run in codemode: real shell commands, package managers, compilers, tests, CLI agents, and services.
  • Browser tools remain separate; Sandbox should not replace createBrowserTools().
  • Artifacts integration (Think + Artifacts: versioned workspaces, forks, and handoff #1440) may become the preferred handoff mechanism for large repo workflows, but this issue should make the Sandbox export useful on its own first.

Acceptance criteria

  • createSandboxTools() returns at least one real AI SDK tool instead of {} when passed a valid Sandbox binding/factory.
  • The minimal tools can run a command in a sandbox and return structured result data.
  • The minimal tools can write a file into the sandbox and read it back.
  • Tool outputs are bounded/truncated and include enough metadata for the model to continue.
  • Timeouts and non-zero exit codes have documented behavior.
  • The implementation has worker tests or a focused example covering command execution and file round trip.
  • Docs explain when to use createExecuteTool() versus createSandboxTools().
  • Docs show the required Wrangler binding/configuration.
  • The no-op warning is removed, or retained only when the function is called without a usable binding.

Nice-to-have follow-ups

  • Streaming command output into Think events.
  • Background process and preview URL tools.
  • Workspace push/pull helpers.
  • Artifacts-backed clone/push handoff with Think + Artifacts: versioned workspaces, forks, and handoff #1440.
  • Sandbox request proxy helpers for GitHub, package registries, model providers, or R2.
  • A Think example that runs tests/builds in Sandbox and reports results back into chat.

Useful files

  • packages/think/src/tools/sandbox.ts
  • packages/think/src/tools/execute.ts
  • docs/think/tools.md
  • examples/assistant/src/server.ts
  • experimental/gadgets-sandbox/README.md

References

Activity

  1. added
    bugSomething isn't working
    on the roadmapFeature accepted and planned for implementation
    on May 5, 2026
  2. threepointone commented on Jun 17, 2026

    @threepointone
    ContributorAuthor

    this is probably going to be @cloudflare/workspace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingon the roadmapFeature accepted and planned for implementationthink

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions