Skip to content

agentkernel.toml

Complete reference for the agentkernel configuration file.

[sandbox]

Basic sandbox settings.

[sandbox]
name = "my-project"           # Sandbox name
base_image = "python:3.12"    # Base Docker image (if not using build)
Field Type Description
name string Sandbox name (alphanumeric, hyphens, underscores)
base_image string Docker image to use (ignored if [build] is present)

[build]

Build a custom Docker image.

[build]
dockerfile = "Dockerfile"     # Path to Dockerfile (relative to config)
context = "."                 # Build context directory
target = "runtime"            # Multi-stage build target
no_cache = false              # Disable build cache

[build.args]
NODE_VERSION = "22"           # Build arguments
Field Type Description
dockerfile string Path to Dockerfile
context string Build context (default: Dockerfile's directory)
target string Multi-stage build target
no_cache bool Force rebuild without cache
args table Build arguments passed to docker build

When dockerfile is specified, agentkernel sandbox create automatically builds the image.

[git]

Configure per-sandbox host-side Git checkout isolation.

[git]
worktree = true              # Same behavior as --git-worktree

When enabled, sandbox create creates a dedicated branch and checkout under ~/.local/share/agentkernel/worktrees, then mounts that checkout at /workspace. The checkout is removed only when it is clean; uncommitted, untracked, or ignored agent changes are preserved and reported for explicit cleanup. The generated branch is retained so agent commits remain recoverable.

[agent]

AI agent settings.

[agent]
preferred = "claude"          # Agent type
compatibility_mode = "claude" # Compatibility adjustments
git_name = "AgentKernel Agent" # Git author/committer name inside the sandbox
git_email = "agent@agentkernel.dev" # Git author/committer email
Field Type Values
preferred string claude, codex, gemini, opencode
compatibility_mode string Same as preferred
git_name string Git author and committer name inside the sandbox
git_email string Git author and committer email inside the sandbox

Set both Git identity fields together. AgentKernel injects them as process-scoped Git configuration on sandbox start, so agent commits are distinguishable without overwriting a mounted user's global Git configuration.

[resources]

Resource limits.

[resources]
vcpus = 2                     # Virtual CPUs
memory_mb = 1024              # Memory in MB
Field Type Default Description
vcpus int 1 Number of virtual CPUs
memory_mb int 512 Memory limit in megabytes

[security]

Security and isolation settings.

[security]
profile = "moderate"          # Security profile preset
network = true                # Allow network access
mount_cwd = true              # Mount current directory
mount_home = false            # Mount home directory
pass_env = false              # Pass host environment variables
read_only = false             # Read-only root filesystem
Field Type Default Description
profile string moderate Preset: permissive, moderate, restrictive
network bool varies Allow network access
mount_cwd bool varies Mount current working directory to /workspace
mount_home bool varies Mount $HOME to /home/user (read-only)
pass_env bool varies Pass through host environment variables
read_only bool varies Make root filesystem read-only

Individual settings override the profile defaults.

[network]

Advanced network settings.

[network]
vsock_cid = 3                 # Vsock CID (Firecracker only)
ports = ["8080:80", "3000"]   # Port mappings (host:container or container-only)
# Optional managed bridge (Docker/Podman only)
name = "agentkernel-dev"
subnet = "172.30.0.0/24"
gateway = "172.30.0.1"
dns = ["1.1.1.1"]
static_ip = "172.30.0.9"
Field Type Default Description
vsock_cid int auto Vsock CID (Firecracker only)
ports array [] Port mappings. Format: "host:container", "container", or "host:container/udp"
name string unset AgentKernel-managed bridge name (Docker/Podman only)
subnet string 172.30.0.0/24 Managed bridge IPv4 CIDR
gateway string runtime-selected Managed bridge gateway IPv4 address
dns array [] Managed bridge DNS IPv4 addresses
static_ip string runtime-assigned Fixed sandbox IPv4 address on the managed bridge

Port mappings have no effect when network access is disabled ([security] network = false or --no-network). Managed bridge values are validated before creation. Address ownership is persisted and locked across processes; bridges that existed without AgentKernel's ownership label are treated as external and are never removed.

[api]

HTTP API server security settings.

[api]
api_key = "my-secret-key"
api_key_env = "AGENTKERNEL_API_KEY"
allow_sudo_exec = false
# control_socket = "/absolute/private/path/api.sock"
Field Type Default Description
api_key string - Static API key for HTTP Bearer authentication.
api_key_env string - Environment variable name to read the API key from (used if set).
control_socket path - Private Unix-domain socket for local CLI/MCP delegation. Clients set AGENTKERNEL_CONTROL_SOCKET to the same absolute path.
allow_sudo_exec bool false Allow /exec and /sandboxes/{name}/exec to run with sudo: true when explicitly requested.

HTTP API authentication uses the Authorization: Bearer <api_key> header when enabled.

[scheduling]

Workspace lifecycle scheduling is enforced by the long-running agentkernel serve daemon. The scheduler is disabled until at least one policy is configured. Cron expressions use five UTC fields: minute, hour, day of month, month, and day of week. A matching cron minute starts each stopped, non-dormant sandbox once.

[scheduling]
enabled = true
autostop_after_minutes = 30       # Stop running sandboxes after 30 idle minutes
autostart_cron = "0 9 * * 1-5"    # Start workspaces at 09:00 UTC on weekdays
dormant_after_days = 14           # Mark stopped, unused workspaces dormant
remove_dormant_after_days = 30    # Reclaim dormant workspaces after 30 days
check_interval_seconds = 60       # Enforcement poll interval

[[schedule]]

User job schedules are daemon-level automation and are independent of [scheduling] workspace lifecycle rules. Each entry has a stable id, a five-field UTC cron expression, an optional enabled flag (default true), and exactly one target. Invalid IDs, cron expressions, or targets stop daemon startup with the schedule ID in the error.

The tagged target form is recommended:

[[schedule]]
id = "refresh-index"
cron = "*/15 * * * *"
enabled = true
target = { type = "sandbox_command", sandbox = "worker", command = ["python", "refresh.py"] }

[[schedule]]
id = "nightly-orchestration"
cron = "0 2 * * *"
target = { type = "orchestration", name = "nightly", input = { source = "cron" } }

[[schedule]]
id = "hourly-counter"
cron = "0 * * * *"
target = { type = "object_method", class = "Counter", object_id = "main", method = "increment", args = { amount = 1 } }

For simple files, target fields may be flattened (type, sandbox, command; or orchestration; or object_class, object_id, and method). The daemon claims each matching cron minute atomically in its durable SQLite store, so loop ticks and restarts do not duplicate a minute. A failed job is recorded and does not prevent other jobs from running.

Dormant workspaces are not autostarted. A manual start clears the dormant mark and records fresh activity. The daemon performs the checks continuously while the API server is running; existing per-sandbox lifecycle policies are also reconciled during the same pass. Use enabled = false to pause enforcement.

[ssh]

SSH access configuration. When enabled, an OpenSSH server is injected into the sandbox with certificate-only authentication.

[ssh]
enabled = true                          # Enable SSH server in sandbox
port = 22                               # sshd port inside container
user = "sandbox"                        # SSH login user
cert_ttl = "30m"                        # Client certificate validity
# vault_addr = "https://vault:8200"     # Vault address for CA signing
# vault_ssh_mount = "ssh"               # Vault SSH secrets engine mount
# vault_ssh_role = "agentkernel-client" # Vault signing role
Field Type Default Description
enabled bool false Inject sshd into sandbox (same as --ssh flag)
port int 22 sshd listen port inside the container
user string sandbox Username for SSH login
cert_ttl string 30m Client certificate time-to-live (e.g. 1h, 30m, 3600)
vault_addr string none HashiCorp Vault address for certificate signing
vault_ssh_mount string ssh Vault SSH secrets engine mount path
vault_ssh_role string agentkernel-client Vault SSH signing role

Without Vault, a per-sandbox CA keypair is generated locally. Client certs are signed on each agentkernel ssh connect invocation and stored in ~/.agentkernel/ssh/<name>/.

[[files]]

Inject files into the sandbox at startup.

[[files]]
source = ".env"               # Local file path
dest = "/app/.env"            # Path inside sandbox

[[files]]
source = "config/settings.json"
dest = "/etc/app/settings.json"
Field Type Description
source string Local file path (relative to config file)
dest string Absolute path inside sandbox

[orchestrator]

Configuration for Kubernetes and Nomad orchestration backends. Only needed when using --backend kubernetes or --backend nomad.

[orchestrator]
provider = "kubernetes"              # "kubernetes" or "nomad"
namespace = "agentkernel"            # Namespace for sandbox resources

# Kubernetes-specific
kubeconfig = "~/.kube/config"        # Optional, auto-detected
context = "my-cluster"               # Optional kubeconfig context
runtime_class = "gvisor"             # Optional: "gvisor", "kata"
service_account = "agentkernel-sa"   # Optional service account

# Nomad-specific
nomad_addr = "http://127.0.0.1:4646"  # Nomad API address
nomad_driver = "docker"                 # "docker", "exec", "raw_exec"
nomad_datacenter = "dc1"               # Target datacenter

# Pool settings
warm_pool_size = 10                  # Pre-warmed instances
max_pool_size = 50                   # Maximum concurrent sandboxes
max_sandboxes = 200                  # Hard cap on total sandboxes
Field Type Default Description
provider string none kubernetes or nomad
namespace string agentkernel Namespace for sandbox resources
kubeconfig string auto-detected Path to kubeconfig file
context string current Kubeconfig context
runtime_class string none K8s RuntimeClass (gvisor, kata)
service_account string none K8s service account
nomad_addr string NOMAD_ADDR env Nomad API address
nomad_token string NOMAD_TOKEN env Nomad ACL token
nomad_driver string docker Nomad task driver
nomad_datacenter string dc1 Nomad datacenter
warm_pool_size int 10 Pre-warmed idle instances
max_pool_size int 50 Maximum pool capacity
max_sandboxes int 200 Hard cap on total sandboxes

See the Orchestration Guide for detailed usage and deployment instructions.

[remote]

Configuration for hosted remote backends (daytona, runloop, e2b, modal, agentcomputer).

Current note: daytona, runloop, e2b, and modal are the shipped live adapters today. The bundled bridge reads provider credentials and routing from [remote.<provider>], or from exported provider environment variables when you prefer env-based setup.

[remote]
default_profile = "node-dev"
bridge = "./scripts/remote-bridge.mjs"
sync_mode = "managed"

[remote.daytona]
api_key_env = "DAYTONA_API_KEY"
base_url = "https://app.daytona.io/api"
organization = "acme"
region = "us"

[remote.runloop]
api_key_env = "RUNLOOP_API_KEY"

[remote.e2b]
api_key_env = "E2B_API_KEY"

[remote.modal]
token_id_env = "MODAL_TOKEN_ID"
token_secret_env = "MODAL_TOKEN_SECRET"
project = "agentkernel"

[remote.agentcomputer]
api_key_env = "AGENTCOMPUTER_API_KEY"

[remote.profiles.node-dev]
image = "node:22"
workspace_dir = "/workspace"
bootstrap = "npm install"

[remote.profiles.node-dev.env]
NODE_ENV = "development"
Field Type Default Description
default_profile string none Remote runtime profile used when no profile is selected
bridge string scripts/remote-bridge.mjs Custom remote bridge executable or script; set this when running outside the repo root and still using the bundled bridge
sync_mode string managed Remote workspace sync mode

[remote.]

Supported providers: daytona, runloop, e2b, modal, agentcomputer.

Field Type Default Description
api_key string none Inline provider API key
api_key_env string none Environment variable containing the API key
token_id string none Inline provider token ID
token_id_env string none Environment variable containing the provider token ID
token_secret string none Inline provider token secret
token_secret_env string none Environment variable containing the provider token secret
base_url string provider default Override API base URL
environment string provider default Provider environment or workspace environment name
organization string none Provider organization or team
project string none Provider project/workspace name
region string none Default provider region
profile string none Provider-specific default runtime profile

For the bundled live adapters today:

  • daytona uses api_key, api_key_env, base_url, organization, and region
  • runloop uses api_key / api_key_env and optionally base_url
  • e2b uses api_key / api_key_env and optionally base_url
  • modal uses token_id, token_id_env, token_secret, token_secret_env, and optionally base_url, environment, project, and region
  • agentcomputer config can be declared now, but the bundled bridge does not ship its live adapter yet

[remote.profiles.]

Field Type Default Description
image string none Provider-neutral runtime hint used by the bridge
workspace_dir string /workspace Workspace root inside the remote sandbox
bootstrap string none Startup/bootstrap command for the remote runtime
env table {} Environment variables injected into the remote runtime

Enterprise resource quotas

When the enterprise feature is enabled, resource quotas can limit each authenticated user and organization independently. Quota checks are performed atomically with sandbox create/start/resize operations. Cedar still decides whether the action is authorized; quotas enforce mutable resource counts.

[enterprise]
enabled = true
org_id = "acme"

[enterprise.quotas]
enabled = true

# Fallback limits for users without an explicit entry. Omitted values are unlimited.
[enterprise.quotas.default]
max_running_sandboxes = 4
max_total_sandboxes = 12
max_total_vcpus = 16
max_total_memory_mb = 16384

[enterprise.quotas.users.alice]
max_running_sandboxes = 8

[enterprise.quotas.organizations.acme]
max_total_sandboxes = 100
max_total_vcpus = 128
max_total_memory_mb = 131072

max_total_* includes stopped sandboxes because their allocations remain reserved. A limit of 0 is valid and denies that resource. Existing sandboxes created before ownership metadata was introduced are accounted to the anonymous/default tenant; remove or recreate them if they should belong to a specific tenant.

JWT users are addressed by their token sub. API-key users are addressed by api-key:<sha256>, where the digest is computed over the complete API key; the raw key is never persisted, returned by /quotas, or written to quota audit events. To configure an API-key override, compute that SHA-256 digest offline and use the resulting identifier as the key under [enterprise.quotas.users].

Full Example

[sandbox]
name = "my-fullstack-app"

[build]
dockerfile = "Dockerfile.dev"
context = "."

[build.args]
NODE_VERSION = "22"

[agent]
preferred = "claude"

[resources]
vcpus = 4
memory_mb = 2048

[security]
profile = "moderate"
network = true
mount_cwd = true

[network]
ports = ["3000:3000", "8080:80"]

[ssh]
enabled = true
cert_ttl = "1h"

[[files]]
source = ".env.development"
dest = "/app/.env"