cwsandbox) and shows the sync and async form of each common operation.
The SDK has a single async implementation internally. The sync/async flexibility comes from how you consume results: use .result() for sync and await for async.
Choose authentication
These examples run on serverless capacity unless a section specifies CKS. Choose the credential for the account that owns your sandboxes. See Choose and get credentials to obtain a key or token. Run the installation commands in an active Python virtual environment. Save the Python code from your credential tab assandbox_auth.py beside the Python scripts you run from this page. It stores the authentication choice, not your credential. The examples import AUTH from that file and pass it explicitly to each new sandbox or session.
- Forge API key
- CoreWeave API access token
Use your Forge API key through the SDK’s W&B authentication strategy:
sandbox_auth.py
placement_mode="cks" on sandbox creation or in SandboxDefaults. Creating a session with auth=AUTH also authenticates the sandboxes it owns. Keep the same credential when reconnecting, listing, or cleaning up sandboxes.
Quick decision guide
Rule of thumb: Use sync patterns (
.result()) for simplicity. Switch to await only when you’re already
in an async codebase.
Core concept: OperationRef
Most SDK methods returnOperationRef[T], a wrapper that is both .result()-able and awaitable.
Both paths raise the same exceptions.
Sandbox.exec() returns Process, which extends OperationRef[ProcessResult] with streaming
and stdin.
Auto-start behavior
session.sandbox() returns an unstarted sandbox. The sandbox auto-starts on the first operation
that requires it:
Triggers auto-start: exec(), read_file(), write_file(), wait(), wait_until_complete()
Does not auto-start: get_status() (raises SandboxNotRunningError), stop() (no-op if never started)
Operations
Create sandboxes
- Sync
- Async
Sandbox.run() calls start().result() internally, which blocks the event loop.
In async code, construct with Sandbox(...) and use async with to start the sandbox.
exec() waits for RUNNING before executing. To wait for startup separately, use
await sandbox and check its status before operations.
start()
- Sync
- Async
exec()
- Sync
- Async
read_file()
- Sync
- Async
write_file()
- Sync
- Async
stop()
- Sync
- Async
wait()
wait() waits for startup status. For example, it can return when the sandbox is
RUNNING or TERMINATING, or after it completes successfully. It’s sync-only. In async code,
await sandbox uses the same startup wait without blocking the event loop.
A normal return doesn’t guarantee RUNNING. Check status before operations that require a
running sandbox. For terminal-state and error handling, see
Wait for a sandbox.
wait_until_complete()
- Sync
- Async
get_status()
get_status() is sync-only. It fetches the current status from the API.
Sandbox.list()
- Sync
- Async
Sandbox.from_id()
- Sync
- Async
Sandbox.delete()
- Sync
- Async
session.list()
- Sync
- Async
session.from_id()
- Sync
- Async
Stream stdout
- Sync
- Async
Stream stdin
Enable stdin withstdin=True. Use write() for raw bytes, writeline() for text lines,
and close() to signal EOF.
- Sync
- Async
cwsandbox.results()
cwsandbox.results() is a sync-only batch helper. It calls .result() on one or more OperationRef objects.
cwsandbox.wait()
cwsandbox.wait() is sync-only. It waits for a sequence of Sandbox, OperationRef, or Process
objects and returns (done, pending). For sandboxes, it uses the same startup wait as
Sandbox.wait(), rather than waiting for the main command to finish. A sandbox in done
isn’t guaranteed to be RUNNING. For example, it may already be completed or terminating. Check
each sandbox’s status before operations that require it to be running.
@session.function()
- Sync
- Async
Parallel execution
The sync API supports parallel execution because operations are non-blocking by design. Methods likeexec(), read_file(), and write_file() return immediately. You only block when you call
.result().
Sandbox.run() blocks until the backend accepts the start request (it calls start().result()
internally). For parallel startup, use session.sandbox() (auto-starts on first operation) or
collect start() refs:
Jupyter notebooks
The sync API works in Jupyter withoutnest_asyncio because the SDK runs its own background event
loop in a daemon thread:
await works directly since Jupyter has a built-in event loop:
Error handling
Both sync and async paths raise the same exceptions..result() re-raises any exception
from the underlying operation, and await does the same. See What do common sandbox SDK error messages mean?
for the full exception hierarchy and recovery patterns.