@pai/sandbox-local
Trusted local-process SandboxProvider implementation for local coding agents and demos.
Package: @pai/sandbox-local
Implements the SandboxProvider contract against a local directory and, when
explicitly enabled, the host shell. It is for local coding agents, demos, and
development workflows where the agent is meant to work in a real checkout. It
is not a security sandbox.
Quick start
import { createAgentRuntime } from "@pai/core";
import { sandboxCapability } from "@pai/sandbox";
import { createLocalSandboxProvider } from "@pai/sandbox-local";
const runtime = createAgentRuntime({
agent, // tools: { ...sandboxTools() }
capabilities: {
sandbox: sandboxCapability({
provider: createLocalSandboxProvider({
rootDir: process.cwd(),
unsafeAllowHostCommands: true,
}),
}),
},
});Options
type LocalSandboxProviderOptions = {
/** Host directory exposed as /workspace. Defaults to a temp directory. */
rootDir?: string;
/** Working directory when `runCommand.cwd` is omitted. Defaults to /workspace. */
defaultCwd?: string;
/** Idle lifetime for sandboxes created without `ttlMs`. Defaults to 5 minutes. */
defaultTtlMs?: number;
/** Required before `runCommand` will execute anything. */
unsafeAllowHostCommands?: boolean;
/** Inherit `process.env` for commands. Defaults to true. */
inheritEnv?: boolean;
/** Applied to every command. */
env?: Record<string, string>;
/** Provider-owned state. Defaults to `.pai/sandboxes/local` under the root. */
stateDir?: string;
/** Shell for commands. Defaults to `$SHELL`, then Node's default. */
shell?: string;
now?: () => number;
generateId?: () => string;
};Behaviour notes
- Commands are opt-in. Without
unsafeAllowHostCommands: true,runCommandthrows aTypeErrorrather than running anything. The flag is named to stop a caller mistaking this for isolated execution. - Files map onto
rootDir. It is exposed as/workspace, and absolute host paths under it also resolve, which is what a local coding agent needs./tmpis a provider-owned per-sandbox directory. kill()removes provider-owned temp state and never deletes workspace files.connect()andlist()rediscover live sandboxes from a registry file understateDir, so a restarted process finds them again.- Only
{ access: "full" }is accepted. Host execution cannot enforce egress control, socreaterejects any other explicit network policy rather than pretending to honour it. probe()checksrootDir, and creates nothing. That directory is all a local sandbox depends on, so a root that is missing, is not a directory, or cannot be written into isSandboxUnavailableError. With norootDirconfigured there is nothing to check, becausecreatemints a fresh temporary one.resourcesis rejected, for the same reason.bindingKeyis ignored, so concurrent creates for one key can produce two sandboxes.
Security contract
Commands run on the host as the current user, with the same files, network,
credentials, tools, and environment the process has. The provider constrains
readFile, writeFile, and listDir to the configured workspace and rejects
symlink and traversal escapes, but that containment does not extend to
arbitrary shell commands. For untrusted code or customer data use an isolated
provider: @pai/sandbox-e2b,
@pai/sandbox-gke, or
@pai/sandbox-docker.