Files

1 line
67 KiB
JSON

{"repo": "chekusu/sandbank", "files": {"docs/sandbank-agent-configuration.md": {"5cbad62d6eafc0c9b13dcc9658b9ca7c50b5cd0f": {"t": 1785746399.4688766, "n": 10581, "h": "6b236b35dabe4142", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank is a workspace-native agent harness: the durable agent state lives in a `WorkspaceAdapter`, while concrete work is dispatched to the best available execution backend for that task. The lower-level sandbox SDK remains part of the stack, but the product-level contract is the harness that keeps workspace state portable across providers.\n\nThe main execution roles are:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state, memory, artifacts, and audit data in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- Tool Use and code mode expose host-registered capabilities to the agent through policy-checked bindings.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers and syncs their outputs back into the same Workspace.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, Tool Use handlers, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider. In both cases, the Workspace remains the durable source of truth; provider-local files and volumes are temporary execution state unless synced back.\n\nFor general-purpose sandbox execution, prefer Sandbank Cloud first. Sandbank Cloud is the hosted BoxLite provider operated by Sandbank; use the other providers when you need a specific external backend, a self-hosted BoxLite deployment, or provider-specific capabilities.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, memory, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state. The harness materializes Workspace files into a sandbox when needed, then syncs or merges the result back so later tasks can continue on another backend.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Tool Registration And Code Mode\n\nTool registration is controlled by the host application, not by arbitrary end users. A third-party caller creates a `ToolUseRegistry`, registers definitions such as `createCloudflareResourceTool`, `createSearchCodeRunTool`, and `createSandboxPythonTool`, then enables the exact tools/resources for each agent run through `toolUse.policy`.\n\n`search.code.run` is the Dynamic Worker code mode tool. It runs a JavaScript function body and exposes controlled bindings as `ctx.search`, `ctx.workspace`, and `ctx.runtime`. Enable it only when the agent policy grants the required resources:\n\n- `dynamic_worker.execution:execute`\n- `runtime.javascript:execute`\n- `external.search:{provider}:query`\n- `http.egress:{host}:fetch` for each allowed outbound host\n- `workspace.path:{artifactRoot}:write` for generated artifacts\n\nThe tool denies raw outbound access by default and expects search/fetch behavior to come from the registered host-side search provider.\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The scheduler is the bridge between the durable Workspace and interchangeable execution backends. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { SandbankCloudAdapter } from '@sandbank.dev/cloud'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new SandbankCloudAdapter({ apiToken: process.env.SANDBANK_API_TOKEN })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 30,\n },\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n 'sandbank-cloud': 'python:3.12-slim',\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Sandbank Cloud | `SANDBANK_API_TOKEN` for authenticated access, or `WALLET_PRIVATE_KEY` for x402 pay-per-use; optional `SANDBANK_CLOUD_URL` |\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | official `@boxlite-ai/boxlite` Node.js SDK; optional `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "ef040c5aad8399dd955f983df10f7c35534a2df9": {"t": 1785763377.6443453, "n": 10581, "h": "6b236b35dabe4142", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank is a workspace-native agent harness: the durable agent state lives in a `WorkspaceAdapter`, while concrete work is dispatched to the best available execution backend for that task. The lower-level sandbox SDK remains part of the stack, but the product-level contract is the harness that keeps workspace state portable across providers.\n\nThe main execution roles are:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state, memory, artifacts, and audit data in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- Tool Use and code mode expose host-registered capabilities to the agent through policy-checked bindings.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers and syncs their outputs back into the same Workspace.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, Tool Use handlers, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider. In both cases, the Workspace remains the durable source of truth; provider-local files and volumes are temporary execution state unless synced back.\n\nFor general-purpose sandbox execution, prefer Sandbank Cloud first. Sandbank Cloud is the hosted BoxLite provider operated by Sandbank; use the other providers when you need a specific external backend, a self-hosted BoxLite deployment, or provider-specific capabilities.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, memory, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state. The harness materializes Workspace files into a sandbox when needed, then syncs or merges the result back so later tasks can continue on another backend.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Tool Registration And Code Mode\n\nTool registration is controlled by the host application, not by arbitrary end users. A third-party caller creates a `ToolUseRegistry`, registers definitions such as `createCloudflareResourceTool`, `createSearchCodeRunTool`, and `createSandboxPythonTool`, then enables the exact tools/resources for each agent run through `toolUse.policy`.\n\n`search.code.run` is the Dynamic Worker code mode tool. It runs a JavaScript function body and exposes controlled bindings as `ctx.search`, `ctx.workspace`, and `ctx.runtime`. Enable it only when the agent policy grants the required resources:\n\n- `dynamic_worker.execution:execute`\n- `runtime.javascript:execute`\n- `external.search:{provider}:query`\n- `http.egress:{host}:fetch` for each allowed outbound host\n- `workspace.path:{artifactRoot}:write` for generated artifacts\n\nThe tool denies raw outbound access by default and expects search/fetch behavior to come from the registered host-side search provider.\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The scheduler is the bridge between the durable Workspace and interchangeable execution backends. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { SandbankCloudAdapter } from '@sandbank.dev/cloud'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new SandbankCloudAdapter({ apiToken: process.env.SANDBANK_API_TOKEN })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 30,\n },\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n 'sandbank-cloud': 'python:3.12-slim',\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Sandbank Cloud | `SANDBANK_API_TOKEN` for authenticated access, or `WALLET_PRIVATE_KEY` for x402 pay-per-use; optional `SANDBANK_CLOUD_URL` |\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | official `@boxlite-ai/boxlite` Node.js SDK; optional `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "6c9a1f44fa279689111cdad86b1318383c91ff5b": {"t": 1785763384.3926096, "n": 10586, "h": "a9927e2e792d23af", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank is a workspace-native agent harness: the durable agent state lives in a `WorkspaceAdapter`, while concrete work is dispatched to the best available execution backend for that task. The lower-level sandbox SDK remains part of the stack, but the product-level contract is the harness that keeps workspace state portable across providers.\n\nThe main execution roles are:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state, memory, artifacts, and audit data in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- Tool Use and code mode expose host-registered capabilities to the agent through policy-checked bindings.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers and syncs their outputs back into the same Workspace.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, Tool Use handlers, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider. In both cases, the Workspace remains the durable source of truth; provider-local files and volumes are temporary execution state unless synced back.\n\nFor general-purpose sandbox execution, prefer Sandbank Cloud first. Sandbank Cloud is the hosted BoxLite provider operated by Sandbank; use the other providers when you need a specific external backend, a self-hosted BoxLite deployment, or provider-specific capabilities.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, memory, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state. The harness materializes Workspace files into a sandbox when needed, then syncs or merges the result back so later tasks can continue on another backend.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Tool Registration And Code Mode\n\nTool registration is controlled by the host application, not by arbitrary end users. A third-party caller creates a `ToolUseRegistry`, registers definitions such as `createCloudflareResourceTool`, `createSearchCodeRunTool`, and `createSandboxPythonTool`, then enables the exact tools/resources for each agent run through `toolUse.policy`.\n\n`search.code.run` is the Dynamic Worker code mode tool. It runs a JavaScript function body and exposes controlled bindings as `ctx.search`, `ctx.workspace`, and `ctx.runtime`. Enable it only when the agent policy grants the required resources:\n\n- `dynamic_worker.execution:execute`\n- `runtime.javascript:execute`\n- `external.search:{provider}:query`\n- `http.egress:{host}:fetch` for each allowed outbound host\n- `workspace.path:{artifactRoot}:write` for generated artifacts\n\nThe tool denies raw outbound access by default and expects search/fetch behavior to come from the registered host-side search provider.\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The scheduler is the bridge between the durable Workspace and interchangeable execution backends. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { SandbankCloudAdapter } from '@sandbank.dev/cloud'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new SandbankCloudAdapter({ apiToken: process.env.SANDBANK_API_TOKEN })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 30,\n },\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n 'sandbank-cloud': 'python:3.12-slim',\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Sandbank Cloud | `SANDBANK_API_TOKEN` for authenticated access, or `WALLET_PRIVATE_KEY` for x402 pay-per-use; optional `SANDBANK_CLOUD_URL` |\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | local `boxlite` Python package; optional `pythonPath` and `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "3754af93b1974dccf4fc880cc870eb14087ecfff": {"t": 1785763388.6522388, "n": 9854, "h": "dbbb1c1b2f81a9ab", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank is a workspace-native agent harness: the durable agent state lives in a `WorkspaceAdapter`, while concrete work is dispatched to the best available execution backend for that task. The lower-level sandbox SDK remains part of the stack, but the product-level contract is the harness that keeps workspace state portable across providers.\n\nThe main execution roles are:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state, memory, artifacts, and audit data in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- Tool Use and code mode expose host-registered capabilities to the agent through policy-checked bindings.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers and syncs their outputs back into the same Workspace.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, Tool Use handlers, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider. In both cases, the Workspace remains the durable source of truth; provider-local files and volumes are temporary execution state unless synced back.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, memory, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state. The harness materializes Workspace files into a sandbox when needed, then syncs or merges the result back so later tasks can continue on another backend.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Tool Registration And Code Mode\n\nTool registration is controlled by the host application, not by arbitrary end users. A third-party caller creates a `ToolUseRegistry`, registers definitions such as `createCloudflareResourceTool`, `createSearchCodeRunTool`, and `createSandboxPythonTool`, then enables the exact tools/resources for each agent run through `toolUse.policy`.\n\n`search.code.run` is the Dynamic Worker code mode tool. It runs a JavaScript function body and exposes controlled bindings as `ctx.search`, `ctx.workspace`, and `ctx.runtime`. Enable it only when the agent policy grants the required resources:\n\n- `dynamic_worker.execution:execute`\n- `runtime.javascript:execute`\n- `external.search:{provider}:query`\n- `http.egress:{host}:fetch` for each allowed outbound host\n- `workspace.path:{artifactRoot}:write` for generated artifacts\n\nThe tool denies raw outbound access by default and expects search/fetch behavior to come from the registered host-side search provider.\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The scheduler is the bridge between the durable Workspace and interchangeable execution backends. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | local `boxlite` Python package; optional `pythonPath` and `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "47f94e178aaf3e7da5fd7a3876a07c8eb4037965": {"t": 1785763390.0508587, "n": 8898, "h": "16304b5b265c1048", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank has two related execution layers:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Tool Registration And Code Mode\n\nTool registration is controlled by the host application, not by arbitrary end users. A third-party caller creates a `ToolUseRegistry`, registers definitions such as `createCloudflareResourceTool`, `createSearchCodeRunTool`, and `createSandboxPythonTool`, then enables the exact tools/resources for each agent run through `toolUse.policy`.\n\n`search.code.run` is the Dynamic Worker code mode tool. It runs a JavaScript function body and exposes controlled bindings as `ctx.search`, `ctx.workspace`, and `ctx.runtime`. Enable it only when the agent policy grants the required resources:\n\n- `dynamic_worker.execution:execute`\n- `runtime.javascript:execute`\n- `external.search:{provider}:query`\n- `http.egress:{host}:fetch` for each allowed outbound host\n- `workspace.path:{artifactRoot}:write` for generated artifacts\n\nThe tool denies raw outbound access by default and expects search/fetch behavior to come from the registered host-side search provider.\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | local `boxlite` Python package; optional `pythonPath` and `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "6bdba93d75e3feec17c9691b99178afec173cc97": {"t": 1785763395.0537715, "n": 7910, "h": "6534500ee7d79844", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank has two related execution layers:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `SANDBANK_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DEEPSEEK_API_KEY` | One key required | — | Preferred Sandbank harness model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `SANDBANK_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `SANDBANK_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `SANDBANK_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | local `boxlite` Python package; optional `pythonPath` and `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}, "832f771bc3273ccabb9b4165d329519576be6d45": {"t": 1785763397.8215404, "n": 7956, "h": "ccc11d1ab32ed7fc", "c": "# Sandbank Agent Configuration\n\n[English](./sandbank-agent-configuration.md) | [中文](./sandbank-agent-configuration.zh-CN.md) | [日本語](./sandbank-agent-configuration.ja.md)\n\nThis guide covers the configuration developers need before running a Sandbank Agent. Sandbank has two related execution layers:\n\n- The DB-native agent harness (`sandbank harness-api`) calls a model, persists run state in a Workspace, and can invoke bounded Dynamic Worker capsules.\n- The provider scheduler (`runWorkspaceSandboxTask`) dispatches concrete compute tasks, such as generated Python or Codex runs, into configured sandbox providers.\n\n## Required Configuration\n\n| Area | Required for | Required settings |\n|------|--------------|-------------------|\n| Model | DB-native harness model calls | `CHATW_DEEPSEEK_API_KEY` or `DEEPSEEK_API_KEY` |\n| Workspace | Durable agent state, run files, checkpoints, memory, artifacts | `DB9_DATABASE_ID` and `DB9_TOKEN`, unless `createWorkspace` is injected |\n| Provider | Sandbox compute tasks outside Dynamic Worker | At least one configured `SandboxProviderCandidate` whose capabilities match the task |\n| Image/runtime | Provider-dispatched tasks | A logical image mapping or direct image that contains the required tools |\n\nProvider configuration is not required for the basic DB-native harness if the agent only uses the model, Workspace, and Dynamic Worker bindings. It is required when the agent needs to execute Python, Codex, or other commands in a sandbox provider.\n\n## Model Configuration\n\nThe harness currently uses a DeepSeek-compatible chat completions API.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `CHATW_DEEPSEEK_API_KEY` | One key required | — | Preferred ChatW-specific model key |\n| `DEEPSEEK_API_KEY` | One key required | — | Fallback model key |\n| `OPENAI_API_KEY` | Conditional | — | Used only when `CHATW_DEEPSEEK_USE_OPENAI_ENV=1` or `OPENAI_BASE_URL` points at a DeepSeek/OpenRouter/gateway endpoint |\n| `CHATW_DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Preferred model override |\n| `DEEPSEEK_MODEL` | No | `deepseek-v4-pro` | Fallback model override |\n| `CHATW_DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Preferred compatible API base URL |\n| `DEEPSEEK_BASE_URL` | No | `https://api.deepseek.com` | Fallback compatible API base URL |\n| `OPENAI_BASE_URL` | Conditional | — | Used only under the same OpenAI-env condition as `OPENAI_API_KEY` |\n\nThe `model` object in an incoming chat request is preserved as UI metadata; the actual backend model used by the harness is selected from these environment variables.\n\n## Workspace Configuration\n\nThe Workspace is the durable state boundary. It stores run inputs/outputs, audit logs, checkpoints, artifacts, and agent state. Provider-local files and volumes are not treated as canonical cross-provider state.\n\n| Setting | Required | Notes |\n|---------|:--------:|-------|\n| `DB9_DATABASE_ID` | Yes | db9 workspace database id |\n| `DB9_TOKEN` | Yes | db9 API token |\n| `DB9_BASE_URL` | No | Overrides the db9 API base URL |\n\nFor tests or custom deployments, pass `createWorkspace` to the harness dependencies instead of using db9 environment variables.\n\n## Harness Server Configuration\n\n```bash\nDB9_DATABASE_ID=...\nDB9_TOKEN=...\nDEEPSEEK_API_KEY=...\nDEEPSEEK_MODEL=deepseek-v4-pro \\\n sandbank harness-api --host 0.0.0.0 --port 8789\n```\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_HARNESS_HOST` | No | `0.0.0.0` | CLI `--host` overrides it |\n| `SANDBANK_HARNESS_PORT` | No | `8789` | CLI `--port` overrides it; `PORT` is also accepted |\n| `SANDBANK_HARNESS_API_KEY` | No | — | Enables bearer-token auth |\n| `CHATW_HARNESS_API_KEY` | No | — | Alternate auth env name |\n\n## Dynamic Worker Configuration\n\nDynamic Worker capsules are optional. They run bounded JavaScript code and receive scoped `SANDBANK_WORKSPACE` and `SANDBANK_RUNTIME` bindings. They are not a full VM, shell, Python runtime, or Codex runtime.\n\n| Setting | Required | Default | Notes |\n|---------|:--------:|---------|-------|\n| `SANDBANK_DYNAMIC_WORKER_TIMEOUT_MS` | No | `15000` | Capsule timeout |\n| `SANDBANK_DYNAMIC_WORKER_CPU_MS` | No | Provider default | CPU budget when supported |\n| `SANDBANK_DYNAMIC_WORKER_SUBREQUESTS` | No | Provider default | Subrequest budget when supported |\n\n## Provider Scheduler Configuration\n\nUse provider scheduling when a task needs a sandbox provider. The required input is:\n\n- `workspace`: a `WorkspaceAdapter`\n- `providers`: one or more `SandboxProviderCandidate`\n- `task`: a `command`, `python`, `codex.exec`, or `codex.goal` task\n- `imageCatalog`: optional logical-image mappings\n- `consistency`: optional workspace consistency policy\n- `preflight`: optional runtime probe settings\n\n```typescript\nimport { createProvider } from '@sandbank.dev/core'\nimport { E2BAdapter } from '@sandbank.dev/e2b'\nimport { DaytonaAdapter } from '@sandbank.dev/daytona'\nimport { MemoryWorkspaceAdapter } from '@sandbank.dev/workspace'\nimport {\n preflightWorkspaceSandboxTask,\n runWorkspaceSandboxTask,\n} from 'sandbank'\n\nconst workspace = new MemoryWorkspaceAdapter()\n\nconst providers = [\n {\n provider: createProvider(new E2BAdapter({ apiKey: process.env.E2B_API_KEY })),\n capabilities: ['runtime.python'],\n priority: 20,\n },\n {\n provider: createProvider(new DaytonaAdapter({ apiKey: process.env.DAYTONA_API_KEY! })),\n capabilities: ['runtime.python', 'runtime.codex', 'codex.exec', 'codex.goal'],\n priority: 10,\n },\n]\n\nconst imageCatalog = {\n 'python-agent': {\n default: 'ghcr.io/acme/python-agent:2026.06',\n providers: {\n e2b: 'python-agent-e2b-template',\n },\n },\n 'codex-agent': {\n default: 'ghcr.io/acme/codex-agent:2026.06',\n },\n}\n\nconst task = {\n kind: 'python' as const,\n path: '/workspace/generated/task.py',\n image: 'python-agent',\n}\n\nconst preflight = await preflightWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n preflight: { runtime: true },\n})\n\nif (!preflight.ok) throw new Error(preflight.errors.join('; '))\n\nawait runWorkspaceSandboxTask({\n workspace,\n providers,\n task,\n imageCatalog,\n consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },\n preflight: { runtime: true },\n})\n```\n\n## Provider Credentials\n\n| Provider | Typical required configuration |\n|----------|--------------------------------|\n| Daytona | `DAYTONA_API_KEY`; optional `DAYTONA_API_URL` |\n| Fly.io | `FLY_API_TOKEN`, `FLY_APP_NAME`; optional `FLY_REGION` |\n| Cloudflare | Worker Durable Object binding such as `env.SANDBOX`; optional storage config for volumes |\n| BoxLite remote | `BOXLITE_API_URL` plus `BOXLITE_API_TOKEN` or OAuth2 client credentials |\n| BoxLite local | local `boxlite` Python package; optional `pythonPath` and `boxliteHome` |\n| E2B | `E2B_API_KEY`; logical images map to E2B templates |\n\n## Image Requirements\n\nFor snapshot workspace sync, images should have `tar` and `gzip`. Runtime tasks need the corresponding toolchain:\n\n- Python tasks: `python`\n- Codex exec: `codex`, `git`, `tar`, `gzip`\n- Codex goal: `codex`, `tmux`, `bash`, `git`, `gh`, `tar`, `gzip`\n- Live workspace mounts: a Sandbank workspace client, daemon, or equivalent filesystem bridge\n\n`preflight: { runtime: true }` creates a temporary sandbox and probes these tools before the real task materializes the Workspace.\n\n## Required vs Optional Summary\n\nRequired for a live DB-native harness:\n\n- Model API key\n- Workspace backend or injected Workspace adapter\n\nRequired for provider-dispatched execution:\n\n- At least one provider adapter with credentials\n- Task-compatible provider capabilities\n- Task-compatible image/runtime\n- Workspace capabilities required by the selected consistency mode\n\nOptional:\n\n- Harness bearer auth\n- Custom model name and base URL\n- Dynamic Worker limits\n- Provider image catalog\n- Runtime preflight probes\n- Provider-native volumes as cache or provider-local persistence\n"}}}}