zidane/ contexts
Execution contexts, the environments where an agent runs shell commands and reads and writes files.
import { … } from 'zidane/contexts'src/contexts/index.ts
Use this entry point to choose or build the place where tool calls run. It holds the ExecutionContext interface that every backend implements, the in-process createProcessContext, and the helpers for the optional OS sandbox. Docker, E2B and Daytona have their own subpaths, so their SDKs load only when you import them. See Execution contexts for the guide.
import { createProcessContext } from 'zidane/contexts'
const context = createProcessContext({ cwd: process.cwd() })
const handle = await context.spawn()
const result = await context.exec(handle, 'echo hello')
console.log(result.stdout, result.exitCode)
await context.destroy(handle)Functions#
createProcessContextFunction#
Creates an execution context that runs commands and file operations in the current process.
No isolation unless config.isolation asks for an OS sandbox. This is the default context.
function createProcessContext(config?: SpawnConfig): ExecutionContextParameters
| Name | Type | Description |
|---|---|---|
| config? | SpawnConfig | Default spawn settings, such as |
Returns
Example
import { createAgent } from 'zidane'
import { createProcessContext } from 'zidane/contexts'
import { basic } from 'zidane/presets'
import { anthropic } from 'zidane/providers/anthropic'
const agent = createAgent({
...basic,
provider: anthropic(),
execution: createProcessContext({ cwd: process.cwd() }),
})entryPortOfFunction#
The context's own entry port for handle, else one over its commands.
function entryPortOf(context: ExecutionContext, handle: ExecutionHandle): EntryPortParameters
| Name | Type | Description |
|---|---|---|
| context | ExecutionContext | The execution context. |
| handle | ExecutionHandle | The handle the operations run in. |
Returns
execEntryPortFunction#
An EntryPort over a context's exec (POSIX sh), its files written with the context's writeFile.
function execEntryPort(
context: Pick<ExecutionContext, 'exec' | 'writeFile'>,
handle: ExecutionHandle,
): EntryPortParameters
| Name | Type | Description |
|---|---|---|
| context | Pick<ExecutionContext, 'exec' | 'writeFile'> | The context: its commands and its file write. |
| handle | ExecutionHandle | The handle to run them in. |
Returns
isolationAvailabilityFunction#
Whether the sandbox can actually be enforced on this host. Callers that
requested isolation and get ok: false MUST fail closed (refuse to run
the command) — silently running unsandboxed would turn a security
setting into a placebo.
function isolationAvailability(
platform?: Platform,
env?: ProcessEnv,
): IsolationAvailabilityParameters
| Name | Type | Default | Description |
|---|---|---|---|
| platform? | Platform | process.platform | Platform to check. |
| env? | ProcessEnv | process.env | Environment used to look up |
Returns
IsolationAvailabilitylistOwnedProcessesFunction#
The processes registered now.
function listOwnedProcesses(): OwnedProcess[]Returns
listSessionProcessesFunction#
The processes registered now.
function listSessionProcesses(): SessionProcess[]Returns
nodeEntryPortFunction#
An EntryPort on this machine's filesystem.
function nodeEntryPort(options: NodeEntryPortOptions): EntryPortParameters
| Name | Type | Description |
|---|---|---|
| options | NodeEntryPortOptions | How paths resolve, what may change, and where removed entries go. |
Returns
parseAllowWriteSettingFunction#
Parse the user-facing "extra writable paths" setting: comma- or
newline-separated, ~ expanded, relative entries resolved against cwd,
blanks dropped.
function parseAllowWriteSetting(raw: string, cwd: string, home?: string): string[]Parameters
| Name | Type | Description |
|---|---|---|
| raw | string | Comma- or newline-separated paths. |
| cwd | string | Base for relative entries. |
| home? | string | Home directory that |
Returns
string[]registerSessionProcessFunction#
Records pid as started for sessionId.
function registerSessionProcess(pid: number, sessionId: string): () => voidParameters
| Name | Type | Description |
|---|---|---|
| pid | number | The child's pid. |
| sessionId | string | The session's id on this host. |
Returns
() => voidRemoves the record; idempotent, and a no-op once the pid was registered again.
resolveDetachedTasksCapabilityFunction#
Effective DetachedTasksCapability of a context, with the
backward-compatible inference for contexts that predate the field.
function resolveDetachedTasksCapability(
context: ExecutionContext,
): DetachedTasksCapabilityParameters
| Name | Type | Description |
|---|---|---|
| context | ExecutionContext | Execution context to inspect. |
Returns
resolveWritableRootsFunction#
The set of directories a sandboxed command may write to: the workspace
(cwd), the system temp dirs, git's common dir when cwd is a linked
worktree, plus any user-configured extras. All canonicalized.
function resolveWritableRoots(
cwd: string,
options?: ResolveWritableRootsOptions,
): string[]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| cwd | string | Workspace directory. | |
| options? | ResolveWritableRootsOptions | {} | Extra roots and overrides for the environment, platform and git lookup. |
Returns
string[]resolveWritableRootsAsyncFunction#
Async twin of resolveWritableRoots for hosts that must not block (the daemon).
function resolveWritableRootsAsync(
cwd: string,
options?: Omit<ResolveWritableRootsOptions, 'gitCommonDir'> & { gitCommonDir?: (cwd: string) => Promise<string | null> },
): Promise<string[]>Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| cwd | string | Workspace directory. | |
| options? | Omit<ResolveWritableRootsOptions, 'gitCommonDir'> & { gitCommonDir?: (cwd: string) => Promise<string | null> } | {} | Extra roots and overrides for the environment and platform, with an async git lookup. |
Returns
Promise<string[]>Interfaces#
ContextCapabilitiesInterface#
Features an execution context supports. Consumers check these before relying on a feature.
interface ContextCapabilitiesProperties
| Name | Type | Description |
|---|---|---|
| detachedTasks? | DetachedTasksCapability | Background-task lifetime guarantee. Optional for backward
compatibility — when absent, callers infer |
| filesystem | boolean | Can read/write files in a workspace |
| glob? | boolean | Can enumerate glob matches through |
| gpu | boolean | Has GPU access |
| isolated? | boolean | Shell commands run under an ENFORCED OS-level sandbox (macOS Seatbelt /
Linux bwrap) — see |
| network | boolean | Can make outbound network requests |
| shell | boolean | Can execute shell commands |
| stream? | boolean | Can open a bidirectional byte stream to a long-lived process through
Consumers that NEED live stdin (stdio MCP servers routed into the context) must check this before calling; the seam is optional so contexts backed by a request/response-only API stay valid. |
ContextHardeningInterface#
Opt-in container hardening for the docker context. Every field defaults to
"unset" so an omitted hardening (or omitted field) leaves the container
unrestricted.
interface ContextHardeningProperties
| Name | Type | Description |
|---|---|---|
| dropAllCapabilities? | boolean | Drop all Linux capabilities ( |
| noNewPrivileges? | boolean | Set |
| pidsLimit? | number | Max number of processes ( |
| readonlyRootfs? | boolean | Mount the container root filesystem read-only. Pair with writable mounts
for scratch space. Default: |
ContextMountInterface#
A host directory bind-mounted into an execution context.
interface ContextMountProperties
| Name | Type | Description |
|---|---|---|
| readonly? | boolean | Mount read-only. Defaults to false for Docker's native bind behavior. |
| shared? | boolean | Apply the SELinux shared label ( |
| source | string | Absolute host path to mount. |
| target | string | Absolute path inside the execution context. |
EntryPortInterface#
The few file operations every entry action is built from
(createEntryOps, zidane/chat), paths resolved like the context's
other file methods. None of them overwrites: a target is checked missing
first, and the operations refuse one that appeared since.
interface EntryPortProperties
| Name | Type | Description |
|---|---|---|
| copy | (from: string, to: string) => Promise<void> | Copies |
| emptyDirs | (path: string, limit: number) => Promise<string[]> | Empty folders under folder |
| list | (path: string) => Promise<string[]> | The names in folder |
| mkdir | (path: string) => Promise<void> | Creates folder |
| move | (from: string, to: string) => Promise<void> | Renames |
| remove | (path: string) => Promise<void> | Removes |
| stat | (path: string) => Promise<EntryKind | null> | What |
| write | (path: string, bytes: Uint8Array) => Promise<void> | Writes a new file (its folder exists). |
ExecOptionsInterface#
Options of ExecutionContext.exec.
interface ExecOptionsProperties
| Name | Type | Description |
|---|---|---|
| cwd? | string | Folder to run in, resolved against the handle's. Default: the handle's folder. |
| env? | Record<string, string> | Variables added to the command's environment. |
| onOutput? | (stream: 'stdout' | 'stderr', text: string) => void | Output as it arrives, decoded per stream. A chunk can end mid-line. |
| signal? | AbortSignal | Kills the command (its whole process group, in the process context) when aborted. |
| timeout? | number | Seconds. Default 30. |
ExecResultInterface#
Result of a buffered command.
interface ExecResultProperties
| Name | Type | Description |
|---|---|---|
| exitCode | number | Process exit code. |
| stderr | string | Captured standard error. |
| stdout | string | Captured standard output. |
ExecutionContextInterface#
An environment where an agent runs commands and reads and writes files: the host process, a Docker container or a remote sandbox.
interface ExecutionContextProperties
| Name | Type | Description |
|---|---|---|
| capabilitiesreadonly | ContextCapabilities | What this context supports |
| destroy | (handle: ExecutionHandle) => Promise<void> | Destroy the execution environment and clean up resources |
| entries? | (handle: ExecutionHandle) => EntryPort | The context's own entry operations (create, move, copy, remove) for
|
| exec | (handle: ExecutionHandle, command: string, options?: ExecOptions) => Promise<ExecResult> | Execute a shell command in the context.
Implementations are free to ignore
|
| execBackground? | (handle: ExecutionHandle, command: string, options: { cwd?: string; env?: Record<string, string>; maxOutputBytes?: number; onExit?: (info: TaskExitInfo) => void; onStall?: (info: TaskStallInfo) => void; outputDir: string; stallTimeoutMs?: number; terminal?: BackgroundTerminalOptions }) => Promise<TaskHandle> | Start a process in the background. Settles as soon as Optional — contexts without background support (some remote sandboxes) just don't implement it. The shell tool surfaces a clean "background mode is not supported in this execution context" error when this is undefined.
See |
| execStream? | (handle: ExecutionHandle, command: string, options?: { cwd?: string; env?: Record<string, string>; signal?: AbortSignal }) => Promise<StreamHandle> | Open a LIVE bidirectional byte stream to a long-lived process in the
context. The third execution mode, alongside the buffered Motivating consumer: stdio MCP servers. An MCP server is an ordinary
process doing Optional — a context backed by a request/response-only API can't
implement it. Advertise support via IMPLEMENTOR CONTRACT — the shape is deliberately the SUPERSET of what the backing APIs can do, because they do not agree:
|
| fileSize? | (handle: ExecutionHandle, path: string) => Promise<number | null> | Cheap size probe for a file in the context's filesystem, in bytes.
Exists because
KNOWN RESIDUAL (sandbox providers): this guards the |
| getMappedPort? | (handle: ExecutionHandle, containerPort: number) => Promise<number | null> | Resolve the host-side port that a container port was published on
(docker context only, and only when the matching entry was created
with Resolves to |
| killBackground? | (handle: ExecutionHandle, taskId: string) => Promise<TaskExitInfo | null> | SIGTERM the whole process group of a running background task.
Idempotent — second call returns
|
| listBackground? | (handle: ExecutionHandle) => Promise<readonly TaskEntry[]> | Snapshot of every task in the context's registry — running AND terminated (entries remain until the next context destroy, so the model can still read output of exited tasks). |
| listFiles | (handle: ExecutionHandle, path: string, options?: ListFilesOptions) => Promise<ListFilesEntry[]> | List files in the context filesystem. Plain paths list immediate directory entries. Paths that
contain glob metacharacters ( |
| openTerminal? | (handle: ExecutionHandle, options: TerminalOptions) => Promise<TerminalProcess> | Open an interactive terminal (a PTY running the user's login shell) in
the context: on the host, in the container, in the sandbox. For people,
not protocols: the opposite of Optional: a context without a PTY primitive (or a runtime without one: the local contexts need Bun) leaves it undefined, and callers offer no terminal rather than falling back to a host shell. |
| readFile | (handle: ExecutionHandle, path: string) => Promise<string> | Read a file from the context's filesystem |
| readFileBinary? | (handle: ExecutionHandle, path: string) => Promise<Uint8Array<ArrayBufferLike>> | Read a file from the context's filesystem as raw bytes. Used by |
| reassignBackgroundTasks? | (fromHandle: ExecutionHandle, toHandle: ExecutionHandle, newOnExit?: (info: TaskExitInfo) => void, newOnStall?: (info: TaskStallInfo) => void) => Promise<readonly TaskEntry[]> | Transfer ownership of every still-running task from With Side effects:
Returns the entries that were actually reassigned (running tasks only; terminated ones stay where they are). Implementations that don't support reassignment can leave this undefined; the caller (spawn.ts) falls back to the current behavior of killing child tasks at subagent shutdown. |
| reconnectTerminal? | (handle: ExecutionHandle, id: string, options: TerminalOptions) => Promise<TerminalProcess | null> | Re-attach to a terminal opened earlier, by its |
| spawn | (config?: SpawnConfig) => Promise<ExecutionHandle> | Spawn a new execution environment |
| typereadonly | ContextType | Context type identifier |
| waitBackground? | (handle: ExecutionHandle, taskId: string, options?: { signal?: AbortSignal; timeoutMs?: number }) => Promise<TaskExitInfo | null> | Block until a background task terminates, then resolve with its exit info. Resolves immediately for already-terminated tasks. Returns
Callers that need to distinguish "unknown" from "still running"
should consult This is the injectable wait seam for the |
| writeFile | (handle: ExecutionHandle, path: string, content: string | Buffer<ArrayBufferLike>, encoding?: BufferEncoding) => Promise<void> | Write a file to the context's filesystem.
|
ExecutionHandleInterface#
Opaque handle to a running execution context instance
interface ExecutionHandleProperties
| Name | Type | Description |
|---|---|---|
| cwd | string | Working directory within the context |
| id | string | Identifier of the spawned instance, unique within its context. |
| type | ContextType | Type of the context that created the handle. |
IsolationPolicyInterface#
Policy for an OS-level sandbox around shell commands.
interface IsolationPolicyProperties
| Name | Type | Description |
|---|---|---|
| network | 'allow' | 'deny' |
|
| unreadableDirs? | string[] | Directories hidden from the sandboxed command (read AND write denied).
Defaults to |
| writableRoots | string[] | Directories the sandboxed command may write to (create, modify,
delete). Absolute paths; callers should pass them through
|
ListFileMetadataInterface#
A listed file with optional metadata.
interface ListFileMetadataProperties
| Name | Type | Description |
|---|---|---|
| mtimeMs? | number | Last modification time, in milliseconds since the epoch. |
| path | string | Path of the file. |
| size? | number | Size in bytes. |
ListFilesOptionsInterface#
Options for ExecutionContext.listFiles.
interface ListFilesOptionsProperties
| Name | Type | Description |
|---|---|---|
| gitignore? | boolean | Skip git-ignored files when globbing. Default |
| glob? | boolean | Treat |
| limit? | number | Maximum number of entries to return. |
| metadata? | boolean | Return |
| signal? | AbortSignal | Abort the listing early — forwarded from the calling tool's |
NodeEntryPortOptionsInterface#
Options of nodeEntryPort.
interface NodeEntryPortOptionsProperties
| Name | Type | Description |
|---|---|---|
| entry? | (path: string) => Promise<string> | Same, for the entry itself, its own link never followed (stat, move, remove, a target to create). Default: |
| resolve | (path: string) => Promise<string> | A path as the caller names it → the absolute path to act on; throws when it is out of bounds. |
| trash? | (absolute: string) => Promise<void> | Removes |
| writable? | (absolute: string, path: string) => Promise<void> | Throws when the caller may not change |
OwnedProcessInterface#
One process the app started for itself.
interface OwnedProcessProperties
| Name | Type | Description |
|---|---|---|
| pid | number | The child's pid. |
| role | OwnedProcessRole | What the app started it for. |
SessionProcessInterface#
One process a session started.
interface SessionProcessProperties
| Name | Type | Description |
|---|---|---|
| pid | number | The child's pid. |
| sessionId | string | The session it runs for, by its id on this host. |
SpawnConfigInterface#
Configuration for ExecutionContext.spawn. Not every context honors every field.
interface SpawnConfigProperties
| Name | Type | Description |
|---|---|---|
| cwd? | string | Working directory (created if it doesn't exist) |
| destroyGraceMs? | number | How long Default: |
| env? | Record<string, string> | Environment variables |
| hardening? | ContextHardening | Container hardening options (docker context only). All fields are opt-in and OFF by default to preserve existing behavior
(containers run with the image's default user/capabilities). Enable them
for untrusted workloads. |
| image? | string | Docker image (only for 'docker' context) |
| inheritEnv? | boolean | Whether spawned shells inherit the parent Default |
| isolation? | IsolationPolicy | OS-level sandboxing of shell commands (process context only). When set,
every Fails closed: when the backend is unavailable on the host, every command returns exit 127 with the reason instead of running unsandboxed. Build the policy with |
| labels? | Record<string, string> | Docker labels to attach to the container (docker context only). Useful for ownership tracking — callers can sweep abandoned
containers (e.g. from a crashed parent process) by filtering on
a label they own: |
| limits? | { cpu?: string; memory?: number; timeout?: number } | Resource limits |
| mounts? | ContextMount[] | Host paths mounted into the context (only for 'docker' context today) |
| name? | string | Docker container name prefix (only for 'docker' context) |
| network? | string | User-defined Docker network to join (docker context only). Defaults to Docker's default bridge. Use a user network when you need multiple sibling containers (e.g. agent + database + dev server) to discover each other by name. |
| ports? | { container: number; host?: number; proto?: 'tcp' | 'udp' }[] | Publish container ports on the host (docker context only). Each entry maps a container port to either an explicit host port or
(when |
| sandbox? | { [key: string]: unknown; apiKey?: string; provider: string; sandboxId?: string } | Sandbox provider config (only for 'sandbox' context) |
| sessionId? | string | The session this context runs commands for (process context only): each
command it starts ( |
| user? | string | UID/GID the container should run as (docker context only). Accepts the same forms Docker's |
| workspaceRoot? | string | Optional workspace-containment root for the file methods ( When set, a resolved path that escapes this root (via absolute path,
|
StreamHandleInterface#
A live bidirectional stream to a process in the context. Returned by
ExecutionContext.execStream; see that method for the full
implementor contract (why the streams are bytes, why stderr is
optional, what PTY-backed contexts must do before the first byte).
Ownership: the caller owns the lifetime. Nothing reaps this handle
automatically, so kill() belongs in the consumer's teardown path —
for MCP that is the transport's close(), reached via the agent's
mcpConnection.close() during destroy().
interface StreamHandleProperties
| Name | Type | Description |
|---|---|---|
| exited | Promise<number> | Resolves with the exit code when the child terminates, including
termination via |
| kill | () => Promise<void> | Terminate the child. Idempotent — killing a dead child is a no-op. |
| pid | number | Process id inside the context — NOT meaningful on the host. |
| stderr? | AsyncIterable<Uint8Array<ArrayBufferLike>, any, any> | Child's stderr, when the implementation can provide it separately. Present on pipe-backed contexts. A PTY-backed context cannot split it from the terminal stream, so it redirects stderr to a file and either surfaces it here out-of-band or leaves this unset — expect a lower latency guarantee there than on stdout. |
| stdout | AsyncIterable<Uint8Array<ArrayBufferLike>> | Child's stdout as raw byte chunks, in emit order. CONSUMER OBLIGATION: drain this (and
|
| write | (data: Uint8Array) => Promise<void> | Write to the child's stdin. Resolves once the bytes are handed off. |
TaskEntryInterface#
One row in listBackground's snapshot. Living entries (status 'running')
have exitCode / signal / endedAt unset; terminated entries carry the
same data TaskExitInfo returned at exit time.
interface TaskEntryProperties
| Name | Type | Description |
|---|---|---|
| bytesWritten | number | Total bytes written to the output file so far — useful for "task X has produced N KB" UX hints. |
| command | string | Command the task runs. |
| cwd | string | Working directory of the task. |
| endedAt? | number | Set when the task terminated. Lets pull-based consumers (the agent's
run-boundary reconcile) derive |
| exitCode? | number | Exit code. Set once the task terminated. |
| outputPath | string | Absolute path of the log file holding the task output. |
| pid | number | Process id. |
| signal? | Signals | Signal that terminated the process, when there was one. |
| startedAt | number | Start time, in milliseconds since the epoch. |
| status | BackgroundTaskStatus | Current state of the task. |
| taskId | string | Id of the task, as in |
TaskExitInfoInterface#
Fired exactly once per task when the child process terminates, via
execBackground's onExit callback. The agent layer translates this
into a queued <task-notification> for the next turn.
signal is set when the child was terminated by a signal (e.g.
SIGTERM from our own kill-tree, SIGKILL from oom-killer); absent on
natural exit. exitCode is 128 + signal-number on signal-killed
children, matching POSIX shell conventions — 143 for SIGTERM, etc.
interface TaskExitInfoProperties
| Name | Type | Description |
|---|---|---|
| command | string | The original command string the model invoked — useful for telemetry / banner summary. |
| durationMs | number |
|
| exitCode | number | Exit code of the process. |
| outputPath | string | Absolute path of the log file holding the task output. |
| signal? | Signals | Signal that terminated the process, when there was one. |
| status | 'exited' | 'killed' | How the task ended. |
| taskId | string | Id of the task, as in |
TaskHandleInterface#
Returned by execBackground once the process has spawned — the handle the model and
the framework use to refer to the task until it terminates.
outputPath is an absolute path to the log file the context is
appending stdout + stderr to (interleaved by emit order). The model
reads it via the normal read_file tool; no special tool is required.
interface TaskHandleProperties
| Name | Type | Description |
|---|---|---|
| outputPath | string | Absolute path to the log file the context is streaming output into. |
| pid | number | OS pid of the spawned shell wrapper (process-group leader on POSIX). |
| taskId | string | Stable id minted by the context — typically |
| terminal? | boolean | True when the task runs in a terminal ( |
TaskStallInfoInterface#
Fired by the optional stall watchdog (see execBackground's
stallTimeoutMs) when a running task has produced no output for the
configured window. The process is still alive — this is a signal, not
a state transition.
interface TaskStallInfoProperties
| Name | Type | Description |
|---|---|---|
| bytesWritten | number | Total bytes the task has written so far. |
| command | string | Command the task runs. |
| outputPath | string | Absolute path of the log file holding the task output. |
| stalledForMs | number | Milliseconds since the last output chunk (>= the configured window). |
| taskId | string | Id of the stalled task. |
Types#
BackgroundTaskStatusType#
Lifecycle status of a background task.
'running'— process is still live;exitCode/signalunset.'exited'— process terminated on its own (clean or non-zero exit).'killed'— the host issuedkillBackground(SIGTERM to the group).
The status is a coarse-grained signal; the exit code carries the
fine-grained detail (e.g. 143 = SIGTERM for 'killed').
type BackgroundTaskStatus = 'running' | 'exited' | 'killed'ContextTypeType#
Kind of execution context: process, docker or sandbox.
type ContextType = 'process' | 'docker' | 'sandbox'DetachedTasksCapabilityType#
Lifetime guarantee of background tasks started through
ExecutionContext.execBackground.
'none'— the context cannot detach tasks at all.'process-lifetime'— tasks live as long as the HOST process; a crash/restart of the host orphans or kills them (ProcessContext).'durable'— tasks live on a remote runner and survive host process death (remote execution contexts driven by durable runtimes).
Durable-execution runtimes consult this to decide whether backgrounding
is safe to expose (disableBackgroundTasks: 'non-durable', the default
in replay mode): a 'durable' context keeps its tasks across worker
crashes, so there is no reason to strip the capability from the model.
type DetachedTasksCapability = 'none' | 'process-lifetime' | 'durable'EntryKindType#
What a path is: a file (a symlink counts as one, never followed) or a folder.
type EntryKind = 'file' | 'dir'IsolationBackendType#
Sandbox backend: macOS Seatbelt or Linux bubblewrap.
type IsolationBackend = 'seatbelt' | 'bwrap'ListFilesEntryType#
One listing entry: a plain path, or a ListFileMetadata object when metadata was requested.
type ListFilesEntry = string | ListFileMetadataOwnedProcessRoleType#
Why the app started the process.
type OwnedProcessRole = 'mcp' | 'tool'Re-exports#
These names are documented on the entry point that owns them.