Sandbox Adapter API
A sandbox adapter wraps an execution environment — a provider SDK, a container, the host machine, an in-memory emulation — into the factory contract that useSandbox(...) accepts. This page documents that contract: the SandboxFactory interface, the Sandbox surface an adapter must produce, the helpers that produce it from simpler shapes, the adapter tool factory, and the built-in factories. For choosing and using sandboxes, see the Sandboxes guide; for the catalog of supported providers, see Sandboxes in the Ecosystem.
The model never calls this surface. An agent’s model-facing file and shell capabilities are the built-in tools — read with offset/limit paging, edit string replacement, grep, glob — built on top of it and documented in Agent Behavior. This page is for the two audiences underneath: adapter authors implementing a provider, and application code scripting the environment through harness.sandbox.
All symbols on this page are exported from @flue/runtime, except local() (from @flue/runtime/node) and cloudflareSandbox() (from @flue/runtime/cloudflare). The former names — SessionEnv, SandboxApi, SessionToolFactory, createSandboxSessionEnv, and the factory method createSessionEnv — remain available as deprecated aliases, so existing adapters keep compiling and running unchanged.
SandboxFactory
interface SandboxFactory {
createSandbox(options: { id: string }): Promise<Sandbox>;
tools?: SandboxToolFactory;
}
The value passed to useSandbox(...) or composed into an agent’s sandbox: config. The factory object itself is cheap to construct — agents build a fresh one on every render. All expensive work belongs inside createSandbox().
createSandbox(options)— builds the environment. Called once per initialized harness — one call perinit()— and every session and task session of that harness shares the returned sandbox. Re-renders never rebuild the environment. A rejection fails the agent’s initialization.options.id— the agent instance id (ctx.id). Multiple harnesses initialized in the same context receive the sameid, so an adapter that keys provider resources onidmust tolerate repeated calls with the same value. Keying a provider workspace onidis how a conversation gets a durable filesystem across messages and restarts.tools— optional. When present, replaces the framework’s default model-facing tool set for this sandbox. SeeSandboxToolFactory.
A minimal adapter over a provider SDK, using sandboxFromDriver to supply the generic path and abort plumbing:
import { sandboxFromDriver, type SandboxDriver, type SandboxFactory } from '@flue/runtime';
export function myProvider(client: MyProviderClient): SandboxFactory {
return {
async createSandbox({ id }) {
const sandbox = await client.findOrCreate(id);
const driver: SandboxDriver = {/* map each SandboxDriver method to the provider SDK */};
return sandboxFromDriver(driver, '/workspace');
},
};
}
What the contract deliberately does not include:
- No teardown verb. There is no
dispose()or lifecycle callback. Flue connects to what the factory hands it and never creates, reuses, or destroys provider infrastructure on its own — provisioning and deletion belong to the application (typically inside the factory, or in application code around it). An adapter must not call the provider’sdelete()/terminate()/kill()on the application’s behalf. - No per-message rebuild. The environment is resolved once per initialized harness. An adapter cannot observe individual messages or turns.
- Legacy method name. Factories implementing the pre-rename
createSessionEnvstill work: the runtime calls it whencreateSandboxis absent (with a one-time deprecation warning). New adapters should implementcreateSandbox. - No identity beyond
id. The factory receives the instance id and nothing else — no conversation content, no request data. Anything else an adapter needs must be captured in the closure that built the factory.
useSandbox cwd scoping
When the agent passes useSandbox(factory, { cwd }), the runtime wraps the adapter’s sandbox in a scoping layer after createSandbox() resolves. The adapter is not involved and must not apply an agent’s cwd itself:
- The
cwdvalue is resolved through the adapter env’s ownresolvePath(so a relative value resolves against the adapter’s base directory), then POSIX-normalized. - The wrapper resolves all relative file paths against the scoped
cwd, defaultsexec’s working directory to it, and resolves a relative per-callexeccwdagainst it. - The wrapper exposes only the standard
Sandboxmembers. Extra properties an adapter attached to its sandbox (a native surface) are not forwarded — agents that need the native surface must not set acwdoverride onuseSandbox.
Sandbox
interface Sandbox {
exec(
command: string,
options?: {
cwd?: string;
env?: Record<string, string>;
timeoutMs?: number;
signal?: AbortSignal;
},
): Promise<ShellResult>;
readFile(path: string): Promise<string>;
readFileBuffer(path: string): Promise<Uint8Array>;
writeFile(path: string, content: string | Uint8Array): Promise<void>;
stat(path: string): Promise<FileStat>;
readdir(path: string): Promise<string[]>;
exists(path: string): Promise<boolean>;
mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;
cwd: string;
resolvePath(p: string): string;
}
The agent’s live sandbox: the universal environment interface. Every sandbox mode — virtual, local, remote — implements it, so core logic never branches on mode. The same object is exposed to application code as harness.sandbox, and the standard model-facing tools operate through it. Operations on it are never recorded in the conversation.
Most adapters should not implement this interface by hand: sandboxFromDriver (over a provider SDK) and bash() (over a just-bash instance) produce conforming sandboxes from smaller surfaces. The contract below is what those wrappers guarantee, and what a hand-written implementation must reproduce.
Path semantics
- Paths are POSIX-style,
/-separated. (local()on Windows uses host path semantics.) - Every file method accepts both absolute and relative paths. Relative paths resolve against
cwd. cwd— the environment’s working directory, as an absolute path. Workspace discovery (the directory listing,AGENTS.md,.agents/skills/) and default command execution happen here.resolvePath(p)— resolves a relative path againstcwdwithout touching the filesystem; absolute paths pass through. File methods resolve internally — callers needresolvePathonly when their own logic wants the absolute path. The standardwrite/edittools also use it to key per-file mutation locks, so two spellings of the same path must resolve to the same string.
exec
Runs a shell command and resolves with its output.
- Resolves with a
ShellResultfor any completed command, non-zero exit codes included. Rejections are reserved for transport failures and aborts. options.cwd— working directory for this command. A relative value resolves againstenv.cwd; when omitted, the command runs inenv.cwd.options.env— environment variables supplied to the command, layered on top of whatever base environment the adapter defines.options.timeoutMs— wall-clock deadline hint in milliseconds, and the primary cancellation contract. Forward it to the provider’s native timeout option (E2BtimeoutMs, Daytonatimeout, Modaltimeout, and so on) so signal-blind providers still observe the deadline. Providers with coarser granularity may round the value up, never down.options.signal— cancellation. Aborting rejects the returned promise promptly with anAbortError(DOMException) carrying the signal’s reason ascause— never gated on the remote command’s settlement. An adapter whose provider can cancel mid-flight does so, so the rejection is exact; one that can’t leaves the command running as an orphan that keeps executing (and mutating the workspace) after the rejection, its eventual result discarded rather than surfacing later. TheAbortErrormessage says so. SeesandboxFromDriverfor how the wrapper implements this and how to observe an orphan’s settlement.timeoutMsandsignalare independent. Callers with a deadline that also want ad-hoc cancellation pass both; adapters that support both should observe whichever fires first. The standardbashtool passes both whenever the model requests a timeout.
File verbs
readFile(path)— reads a UTF-8 file. Throws if the path does not exist or is not a file.readFileBuffer(path)— reads raw bytes.writeFile(path, content)— creates or replaces a file. Must create missing parent directories — this is a cross-mode guarantee (fs.writeFile('out/nested/report.md', …)never requires a priormkdir).sandboxFromDriver,bash(), andlocal()all implement it by retrying a failed write once aftermkdir -pon the parent; a hand-written sandbox must provide the same guarantee.stat(path)— file metadata. Throws if the path does not exist.readdir(path)— directory entry names (names only, no paths). Throws if the path is not a directory.exists(path)—trueif a file or directory exists. Never throws.mkdir(path, options)— creates a directory;recursivecreates missing parents and tolerates an existing directory.rm(path, options)— removes a file or directory;recursiveremoves directory contents,forcesuppresses the missing-path error. An adapter whose provider cannot honor a requested option must throwSandboxOperationUnsupportedErrorbefore modifying anything — never silently ignore an option or leave its behavior provider-defined.
Errors thrown by file verbs surface to the model as tool errors, so messages should be factual and self-contained (the standard tools pass them through).
ShellResult
interface ShellResult {
stdout: string;
stderr: string;
exitCode: number;
}
FileStat
interface FileStat {
isFile: boolean;
isDirectory: boolean;
isSymbolicLink?: boolean;
size?: number;
mtime?: Date;
}
isSymbolicLink,size, andmtimeare omitted when the provider does not expose them. Adapters must never fabricate placeholder values (new Date(),0,false) — callers cannot distinguish them from real metadata.- For symlinks,
isFile/isDirectory/size/mtimedescribe the target andisSymbolicLinkdescribes the path itself (the semantics ofstat -Lplus a non-following check;local()and the Cloudflare Sandbox adapter both implement this).
Extending Sandbox
An adapter may return a sandbox with additional properties — a native surface beyond the generic verbs. harness.sandbox exposes the object exactly as returned, so an adapter package can ship a runtime-checked accessor that narrows to it (the Cloudflare Computer adapter’s computerWorkspace(harness.sandbox) returns its Workspace this way). Two constraints:
- A
cwdoverride onuseSandboxwraps the sandbox and drops extra properties (above). - A sandbox that cannot execute commands should still ship all file verbs and throw from
exec— and pair the sandbox with atoolslist that omits the exec-backed standard tools.
sandboxFromDriver(driver, cwd, options?)
function sandboxFromDriver(
driver: SandboxDriver,
cwd: string,
options?: { onOrphanSettled?: (settlement: OrphanedExecSettlement) => void },
): Sandbox;
Wraps a SandboxDriver — the minimal interface a remote provider adapter implements — into a conforming Sandbox. The wrapper supplies:
- Path resolution: relative file paths and relative/absent
execworking directories resolve againstcwd, POSIX-normalized. Thedrivermethods always receive absolute paths. - The
writeFileparent-creation guarantee: a failed write is retried once afterdriver.mkdir(parent, { recursive: true }); when the retry still fails, the retried write’s error propagates. - The
execabort race: an already-aborted signal rejects withAbortErrorbeforedriver.execis called. An abort that fires mid-flight rejects promptly too — the wrapper never waits ondriver.exec’s own settlement to decide the caller’s outcome, whether or not the adapter wiredsignalinto its SDK. The adapter only needs to forwardsignalwhen its SDK has a real cancellation primitive; the abort race and the promise-consumption below apply either way.
Orphaned commands
When an abort fires before driver.exec’s promise has settled, that promise becomes an orphaned command: the caller has already been released with an AbortError, but the provider call keeps running until it settles on its own. A cancel-capable adapter that forwards signal still produces one of these — the window just shrinks from the command’s remaining duration down to the SDK’s cancellation latency, since the wrapper’s rejection always races ahead of that confirmation.
An orphan’s eventual settlement — fulfillment or rejection — is never appended to the conversation; the abort already stands as the command’s terminal result, and a second outcome arriving later would violate reducer invariants. It’s consumed here so it can’t surface as an unhandled rejection, and reported only through options.onOrphanSettled:
interface OrphanedExecSettlement {
command: string;
startedAt: Date;
abortedAt: Date;
settledAt: Date;
result?: ShellResult;
error?: unknown;
}
error carries whatever the orphaned call eventually rejected with — a late SandboxDiedError included. Without onOrphanSettled, the settlement is simply discarded; adapters that want to log, bill, or reap an orphaned remote process out-of-band use the callback to do so.
SandboxDriver
interface SandboxDriver {
readFile(path: string): Promise<string>;
readFileBuffer(path: string): Promise<Uint8Array>;
writeFile(path: string, content: string | Uint8Array): Promise<void>;
stat(path: string): Promise<FileStat>;
readdir(path: string): Promise<string[]>;
exists(path: string): Promise<boolean>;
mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;
exec(
command: string,
options?: {
cwd?: string;
env?: Record<string, string>;
timeoutMs?: number;
signal?: AbortSignal;
},
): Promise<ShellResult>;
}
Identical to the corresponding Sandbox members except that paths arrive pre-resolved (absolute) and the writeFile parent guarantee is handled by the wrapper.
File-verb implementation notes:
writeFile— accept bothstringandUint8Array; convert strings to UTF-8 bytes for a provider that only accepts buffers. Let a missing-parent error propagate — the wrapper retries aftermkdir(parent, { recursive: true }), so adapter-side parent creation is redundant.readFileBuffer— return aUint8Array; wrap a NodeBufferwithnew Uint8Array(buffer).exists— must not throw. Most provider SDKs throw for a missing path; catch and returnfalse.mkdir— a provider SDK that only supports single-level creation may implementrecursivewithexec('mkdir -p …').rm— implementrecursiveandforceexactly, or throwSandboxOperationUnsupportedErrorbefore any mutation. A direct filesystem adapter must not shell out solely to emulate unsupported removal flags; an adapter that already runs other verbs through the shell implements the flags withrmthere too — shell semantics match Node’sfs.rmexactly (-fresolves on a missing path,-rwithout-ffails on one,-fon a directory still errors).
exec implementation contract:
- Honor
timeoutMsby forwarding it to the provider SDK’s native timeout option, converting units and rounding up — never down — when the provider is coarser (a whole-seconds provider forwardsMath.ceil(timeoutMs / 1000)). It stays the provider-primary deadline regardless ofsignal: it’s what protects a signal-blind caller, and a caller that never aborts at all. - An adapter that enforces the deadline itself resolves an expired command as a
ShellResultwithexitCode: 124and the timeout details onstderr— thetimeout(1)convention the shipped adapters follow. Rejection stays reserved forsignalaborts. - Forward
signalwhen the SDK has a real cancellation primitive (anAbortSignaloption, a process kill, a cancel token) — doing so shrinks the orphan window from the command’s remaining duration down to the SDK’s cancellation latency. Confirm the cancellation actually takes effect; asignalthat’s accepted but not honored is worse than not forwarding it, since it advertises a kill the command never receives. Don’t implement a second abort race around the call (a localPromise.race, or the adapter’s own pre/postsignal.abortedchecks) —sandboxFromDriveralready racessignalagainstdriver.exec’s promise and owns the caller-facing rejection; a second race only duplicates it while leaving the orphan bookkeeping unable to tell which one fired. - When the provider does not expose
stderrseparately, return''for it. ReportexitCode: 0only for a clearly successful call.
Liveness contract (all SandboxDriver methods):
- An adapter should ensure in-flight operations settle when the sandbox dies, by whatever mechanism its provider SDK supports — native rejection of in-flight calls, or polling a cheap control-plane status read while a call is pending. The first-party Cloudflare adapter implements the polling shape internally.
- An adapter with no such mechanism carries an accepted limitation: when the provider transport never settles a call after the sandbox dies, that call may hang until the surrounding operation is aborted.
- There is deliberately no per-command deadline in this contract. Agent commands are legitimately unbounded;
timeoutMsis the command’s own deadline, not an infrastructure liveness bound. - An adapter that detects sandbox death should reject with
SandboxDiedError(type: 'sandbox_died', exported from@flue/runtime), so shell classification reports an infrastructure failure rather than caller cancellation. - Liveness detection and caller abort are separate concerns implemented at different layers, and a death detector must not blur them: it races the sandbox’s liveness signal against the in-flight provider call and nothing else.
sandboxFromDriveralready racessignalone layer up and consumes the provider promise’s eventual settlement once the caller has been released, so a death detector that also listens forsignalproduces two rejections competing for the same promise. The first-party Cloudflare adapter’s death detector follows this split — liveness-only, with the caller-abort race left entirely to the wrapper it builds on.
bash(factory)
function bash(factory: BashFactory): SandboxFactory;
type BashFactory = () => BashLike | Promise<BashLike>;
Wraps a just-bash Bash instance into a SandboxFactory — the in-memory virtual sandbox (seeded files, a network allowlist, custom commands).
- The factory function is called once, when the runtime initializes the agent.
- The returned value is duck-type checked (
exec,getCwd, and anfsobject). A wrong value throwsError('[flue] BashFactory must return a Bash-like object.'). - The sandbox’s
cwdis the instance’sgetCwd()(just-bash defaults to/home/userwhen constructed withoutcwdorfiles). - just-bash has no native timeout option, so the wrapper translates
exec’stimeoutMsinto anAbortSignaland merges it with the caller’s signal. Pre- and post-call abort checks apply as insandboxFromDriver. - The
writeFileparent-creation guarantee is applied over the instance’sfs.
BashLike is a structural type (no just-bash import in @flue/runtime), exported for adapter authors who construct compatible runtimes:
interface BashLike {
exec(
command: string,
options?: { cwd?: string; env?: Record<string, string>; signal?: AbortSignal },
): Promise<ShellResult>;
getCwd(): string;
fs: {
readFile(path: string, options?: any): Promise<string>;
readFileBuffer(path: string): Promise<Uint8Array>;
writeFile(path: string, content: string | Uint8Array, options?: any): Promise<void>;
stat(path: string): Promise<any>;
readdir(path: string): Promise<string[]>;
exists(path: string): Promise<boolean>;
mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;
resolvePath(base: string, path: string): string;
};
}
SandboxToolFactory
type SandboxToolFactory = (sandbox: Sandbox, options: SandboxToolFactoryOptions) => AgentTool<any>[];
interface SandboxToolFactoryOptions {
subagents: Record<string, SubagentDefinition>;
}
An optional tools function on a SandboxFactory. When present, its return value replaces the framework’s default six-tool set (read, write, edit, bash, grep, glob) for agents on this sandbox. Compose the replacement from the standard tool factories plus the sandbox’s own native tools rather than rebuilding from scratch — an exec-less sandbox, for example, lists the three file tools and its own executor tool.
- Must be synchronous and return a fresh array on every call. It is invoked each time the runtime assembles the model’s tool list — at initialization and again at every turn boundary — not once.
sandbox— the live sandbox, with the packaged-skill overlay layered ontoreadFile. This is not the identical objectharness.sandboxexposes; tools that hold the sandbox in a closure read packaged-skill paths transparently.options.subagents— the agent’s current subagent roster, keyed by name. Provided for adapters whose tools describe or constrain delegation.
The replacement covers only the framework’s built-in group. Unaffected by it:
- The framework group —
task(always present),activate_skill(when any skill is mounted), andread_skill_resource(when a mounted packaged skill carries supporting files) — is appended separately. - Custom tools from
useTool(...)/defineTool(...)and per-call result tools are added separately.
Tool names must be unique across all groups, and the names task, activate_skill, read_skill_resource, finish, and give_up are framework-reserved. A collision throws ToolNameConflictError when the tool list is assembled.
The element type is AgentTool from @earendil-works/pi-agent-core (a dependency of @flue/runtime; the type is not re-exported). Structurally:
interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any> {
name: string;
label: string;
description: string;
parameters: TParameters; // TypeBox schema
execute(
toolCallId: string,
params: Static<TParameters>,
signal?: AbortSignal,
onUpdate?: (partial: AgentToolResult<TDetails>) => void,
): Promise<AgentToolResult<TDetails>>; // { content, details, terminate? }
}
execute throws on failure rather than encoding errors in content. The standard factories return values of this type; typing a factory as SandboxToolFactory checks a hand-written tool against it.
The standard tool factories
function createReadTool(sandbox: Sandbox): AgentTool;
function createWriteTool(sandbox: Sandbox): AgentTool;
function createEditTool(sandbox: Sandbox): AgentTool;
function createBashTool(sandbox: Sandbox): AgentTool;
function createGrepTool(sandbox: Sandbox): AgentTool;
function createGlobTool(sandbox: Sandbox): AgentTool;
One factory per standard model-facing tool, each closing over a Sandbox. These are exactly the tools the framework installs when a sandbox has no tools function; exporting them per-tool lets an adapter’s SandboxToolFactory add, drop, or swap members without rebuilding the set. The tools’ model-facing behavior — parameters, truncation limits, error shapes, continuation markers — is documented in Agent Behavior. What matters when composing them:
createReadTool,createWriteTool, andcreateEditToolneed only the file verbs;createBashTool,createGrepTool, andcreateGlobToolrequire a workingexec— leave them out for exec-less sandboxes.readfetches throughreadFileand slices in the runtime;editis a whole read → replace → write transaction. Same-file mutations fromwrite/editwithin one parallel tool batch are serialized through a per-path lock keyed onresolvePath, so two spellings of the same path must resolve to the same string. Abashcommand mutating the same file concurrently is not synchronized.createBashToolconverts the model’stimeout(seconds) totimeoutMsfor the sandbox and additionally composes it into the abort signal as a backstop for sandboxes that ignore both cancellation fields; a pure timeout surfaces as a recoverableexitCode: 124result while a host abort rethrows.createGrepToolprobes forrgonce per environment (rg --version, 10-second deadline, cached) and falls back togrep -rnH;createGlobToolshells out tofind -name.
Packaged-skill overlays
Supporting files of a packaged skill live in the application bundle, not the sandbox. The runtime serves them at virtual paths under /.flue/packaged-skills/<skill-id>/…, and it does so by layering an overlay onto the env it hands to tool factories — never by writing into the adapter’s filesystem.
- The env passed to every tool factory (standard and adapter alike) has
readFilewrapped: paths under/.flue/packaged-skills/resolve from the in-memory skill catalog, everything else delegates to the adapter. Adapters need no special-casing; any tool that reads through its env resolves skill paths transparently. - An unknown path under that root throws
Error('[flue] Packaged skill file not found: <path>')instead of reaching the adapter. - Binary skill files are served as base64 text, wrapped to 76-character lines.
- The overlay is session-internal.
harness.sandboxanduseToolhandlers see the adapter’s real env; the virtual root is not visible there. - Only
readFileis overlaid.exec,exists,stat, and the other verbs pass straight through, so shell commands cannot see the virtual root — the standardreadtool (or the framework’sread_skill_resourcetool) is the access path.
Built-in factories
local(options?)
import { local } from '@flue/runtime/node';
function local(options?: LocalSandboxOptions): SandboxFactory;
interface LocalSandboxOptions {
cwd?: string;
env?: Record<string, string | undefined>;
}
Node target only. Binds the agent directly to the host: file verbs call node:fs/promises, and exec spawns real processes. There is no isolation — see the Node target guide for when that is appropriate.
cwd— working directory. Defaults toprocess.cwd(); resolved to an absolute host path.env— variables layered on top of the default allowlist. Set a key toundefinedto drop a default. A non-record value (an array,true) throws aTypeErrorat construction. Per-callexecenvlayers on top of the result.
Environment allowlist: the model’s shell does not inherit process.env. Only PATH, HOME, USER, LOGNAME, HOSTNAME, SHELL, LANG, LC_ALL, LC_CTYPE, TZ, TERM, TMPDIR, TMP, and TEMP pass through by default; everything else is a per-variable opt-in via options.env. The snapshot is taken once at construction — later mutations of process.env are not picked up. env: { ...process.env } inherits everything, host secrets included.
exec behavior:
- Commands run through real
bashwhen present (probed once per process, resolved to an absolute path), falling back to the platform default shell (/bin/shor, on Windows, the system shell) when it is not. - On POSIX the child leads its own process group; abort and timeout signal the whole group —
SIGTERM, escalating toSIGKILLafter a 2-second grace — so compound commands cannot orphan grandchildren. The kill is real, solocal()has no orphaned-command window beyond that grace period. - Non-zero exits and spawn failures resolve as
ShellResult(spawn failures asexitCode: 1with the error message on stderr). AtimeoutMsexpiry also resolves as aShellResult, withexitCode: 124— thetimeout(1)convention. A caller-initiatedsignalabort instead rejects withAbortError, even though the kill takes the same process-group path and produces that same 124 exit internally — the rejection wins and the caller never observes theShellResult. A signal deathlocal()did not itself initiate keeps the genericexitCode: 1. - Captured output is capped at 64 MiB; exceeding it kills the process tree and resolves with
exitCode: 1and a truncation note on stderr. timeoutMsis composed into the caller’ssignal(there is no separate native timeout), so a pure deadline expiry and a caller abort are both delivered through the same kill path and only diverge at the point above.
stat reports isFile/isDirectory/size/mtime for the symlink target and isSymbolicLink for the path itself. All FileStat fields are populated.
cloudflareSandbox(sandbox, options?)
import { cloudflareSandbox } from '@flue/runtime/cloudflare';
function cloudflareSandbox(
sandbox: CloudflareSandboxStub,
options?: CloudflareSandboxOptions,
): SandboxFactory;
interface CloudflareSandboxOptions {
cwd?: string;
}
Cloudflare target. Wraps a @cloudflare/sandbox Durable Object stub (the value getSandbox() returns) into a SandboxFactory. CloudflareSandboxStub is structural, so @flue/runtime does not depend on @cloudflare/sandbox.
cwd— working directory inside the container. Defaults to/workspace.
See Cloudflare Sandbox in the target guide and the ecosystem entry.
SandboxOperationUnsupportedError
class SandboxOperationUnsupportedError extends FlueError {
constructor(input: { operation: string; provider: string; options: readonly string[] });
}
The error an adapter throws when a caller requests an operation with options the provider cannot honor (type: 'sandbox_operation_unsupported'). Throw it before modifying the filesystem, so the rejection guarantees nothing changed. operation names the verb, provider the sandbox product, and options the specific option names that could not be honored; all three are preserved on the error’s meta. See Errors — SandboxOperationUnsupportedError.