Skip to content

Docker Sandbox

Objective: use DockerSandbox when a host needs stronger isolation than local shell execution.

Install Docker, enable virtualization, and install Docker Sandboxes (sbx) on the host. On Linux, KVM must be available to the user running the Harness process.

Terminal window
docker version
lsmod | grep '^kvm'
groups

Install the sbx package from Docker’s package repository, then start and authenticate the daemon:

Terminal window
sbx daemon start
sbx login
sbx policy set-default balanced
sbx diagnose

For long-running hosts, run the daemon under your process manager instead of starting it manually in a terminal. The Harness runtime expects sbx to be installed, authenticated, and reachable before tool execution begins.

Install the sandbox package with the Node tools that will use it:

Terminal window
pnpm add @harness-kernel/sandbox-docker @harness-kernel/tools-node

Attach DockerSandbox in the runtime host:

import { createHarnessSessionStore } from "@harness-kernel/core/runner";
import { DockerSandbox } from "@harness-kernel/sandbox-docker";
import { OpenAIProvider } from "@harness-kernel/provider-openai";
import { agent } from "./agent.js";
const store = await createHarnessSessionStore({
agent: { definition: agent },
providers: [new OpenAIProvider()],
defaultModel: "openai/gpt-5.1",
sandbox: new DockerSandbox({
workspace: { hostPath: process.cwd() },
persistence: "workspace",
namePrefix: "support-prod",
defaultTimeoutMs: 30_000,
}),
});

Modes still own the tools:

import { HarnessMode } from "@harness-kernel/core/agent/mode";
import { createCoreTools } from "@harness-kernel/tools-node";
class OperatorMode extends HarnessMode {
prompt = "Use the shell and files only when needed.";
tools = createCoreTools();
toolApproval = "ask" as const;
}

Each Harness sessionId maps to one deterministic sbx sandbox name, and all tools in that Harness session share the same sandbox. The package does not persist an extra sandbox handle in storage. In production, set namePrefix to an app, environment, and tenant scoped prefix such as support-prod-acme.

Use the default workspace persistence when project files are the only state that should survive:

new DockerSandbox({
workspace: { hostPath: process.cwd() },
persistence: "workspace",
namePrefix: "support-prod",
});

Use sandbox persistence when installed packages, caches, Docker daemon state inside the sandbox, or files outside the workspace should survive store.close(sessionId):

new DockerSandbox({
workspace: { hostPath: process.cwd() },
persistence: "sandbox",
namePrefix: "support-prod",
});

Lifecycle behavior:

Store callworkspace persistencesandbox persistence
store.close(sessionId)Removes the sbx sandbox.Stops the sbx sandbox.
store.delete(sessionId)Removes the sbx sandbox.Removes the sbx sandbox.

store.delete(sessionId) also removes a stopped sandbox for an inactive persisted session when the sandbox provider implements destroy({ sessionId }).

Mount host-owned files into the sandbox with extraWorkspaces. A dynamic function can route uploads, PDFs, datasets, or other attachments by sessionId:

import { DockerSandbox, dockerSandboxSessionSegment } from "@harness-kernel/sandbox-docker";
const sandbox = new DockerSandbox({
workspace: { hostPath: process.cwd() },
extraWorkspaces: ({ sessionId }) => [
{
hostPath: `.harness-kernel/sessions/${dockerSandboxSessionSegment(sessionId)}/files`,
readOnly: true,
envName: "HARNESS_FILES_DIR",
},
],
});

Relative paths are resolved from the main workspace, cannot escape with .., and are created by the host before sbx create shell. Absolute paths are allowed as explicit trusted host configuration. Every command receives HARNESS_FILES_DIR pointing at the mounted directory.

Sandbox activity is operational logging, not agent timeline events.

  • ToolStartEvent and ToolEndEvent describe the tool call in the session timeline.
  • Sandbox logs describe the underlying command execution: open, close, start, completion, timeout, and failure.

Use a log sink for host diagnostics:

import { ConsoleLogSink } from "@harness-kernel/core/runner/logging";
const store = await createHarnessSessionStore({
agent: { definition: agent },
providers: [new OpenAIProvider()],
defaultModel: "openai/gpt-5.1",
sandbox,
logging: {
sinks: [new ConsoleLogSink({ level: "debug" })],
},
});

Useful checks while developing:

Terminal window
sbx version
sbx diagnose
sbx ls -q

Stop a leftover sandbox by name:

Terminal window
sbx stop <sandbox-name>

Remove a leftover sandbox:

Terminal window
sbx rm --force <sandbox-name>

Boundary note: the host owns sbx, daemon lifecycle, login, policy, quotas, and cleanup. Agent packages should only depend on tool and mode contracts.

API: Sandbox, Logging, Events, and Sandbox Docker.