A3S Docs
A3S Box

Configuration

BoxConfig, resource limits, caching, warm pool, and logging options

Configuration

A3S Box uses BoxConfig as the central configuration struct, controlling resources, networking, caching, warm pool, TEE, and logging.

BoxConfig

pub struct BoxConfig {
    pub agent: AgentType,
    pub business: BusinessType,
    pub workspace: PathBuf,
    pub skills: Vec<PathBuf>,
    pub resources: ResourceConfig,
    pub log_level: LogLevel,
    pub tee: TeeConfig,
    pub cmd: Vec<String>,
    pub entrypoint_override: Option<Vec<String>>,
    pub volumes: Vec<String>,
    pub extra_env: Vec<(String, String)>,
    pub cache: CacheConfig,
    pub pool: PoolConfig,
    pub port_map: Vec<String>,
    pub dns: Vec<String>,
    pub network: NetworkMode,
    pub tmpfs: Vec<String>,
    pub resource_limits: ResourceLimits,
}

Resource Configuration

Control CPU, memory, disk, and lifetime for each VM:

pub struct ResourceConfig {
    pub vcpus: u32,       // Default: 2
    pub memory_mb: u32,   // Default: 1024
    pub disk_mb: u32,     // Default: 4096
    pub timeout: u64,     // Lifetime in seconds (0 = unlimited, default: 3600)
}

CLI usage:

a3s-box run --cpus 4 --memory 2048 --timeout 7200 alpine:latest

Resource Limits

Fine-grained control via cgroup v2 and rlimits:

pub struct ResourceLimits {
    pub pids_limit: Option<u64>,
    pub cpuset_cpus: Option<String>,
    pub ulimits: Vec<String>,
    pub cpu_shares: Option<u64>,
    pub cpu_quota: Option<i64>,
    pub cpu_period: Option<u64>,
    pub memory_reservation: Option<u64>,
    pub memory_swap: Option<i64>,
}

Prop

Type

a3s-box run --pids-limit 500 --cpuset-cpus "0,1" alpine:latest

Agent Type

Controls how the coding agent is loaded into the VM:

pub enum AgentType {
    A3sCode,                                        // Built-in (default)
    OciImage { path: PathBuf },                     // Local OCI image
    LocalBinary { path: PathBuf, args: Vec<String> },
    RemoteBinary { url: String, checksum: String },
    OciRegistry { reference: String },              // Registry image
}

Business Type

Controls how user code is loaded:

pub enum BusinessType {
    None,                           // No business code (default)
    OciImage { path: PathBuf },     // Packaged OCI image
    Directory { path: PathBuf },    // Mount directory as workspace
}

Cache Configuration

OCI image and rootfs caching settings:

pub struct CacheConfig {
    pub enabled: bool,              // Default: true
    pub cache_dir: Option<PathBuf>, // Default: ~/.a3s/cache
    pub max_rootfs_entries: usize,  // Default: 10
    pub max_cache_bytes: u64,       // Default: 10 GB
}

The caching pipeline:

Registry → Layer Cache (compressed blobs) → Rootfs Cache (composed filesystem)
  • Layer cache: Content-addressable by compressed layer digest
  • Rootfs cache: Content-addressable by combined layer digest (SHA256)
  • Eviction: LRU when max_rootfs_entries or max_cache_bytes exceeded
  • Override: Set A3S_IMAGE_CACHE_SIZE environment variable

Warm Pool Configuration

Pre-boot VMs for instant allocation:

pub struct PoolConfig {
    pub enabled: bool,          // Default: false
    pub min_idle: usize,        // Pre-warmed VMs to keep (default: 1)
    pub max_size: usize,        // Pool capacity limit (default: 5)
    pub idle_ttl_secs: u64,     // Idle VM time-to-live (default: 300s)
}

How it works:

  1. WarmPool::start() spawns min_idle VMs in background
  2. Replenishment loop runs every second, keeping idle count at min_idle
  3. pool.acquire() pops an idle VM instantly (no boot latency)
  4. pool.release(vm) returns VM to pool or destroys if at capacity
  5. VMs exceeding idle_ttl_secs are evicted automatically
pub struct PoolStats {
    pub idle_count: usize,
    pub total_created: u64,
    pub total_acquired: u64,
    pub total_released: u64,
    pub total_evicted: u64,
}

Pool activity is also tracked via Prometheus metrics: warm_pool_size (current idle count) and warm_pool_capacity (configured max_size), plus warm_pool_hits and warm_pool_misses counters.

Log Configuration

Docker-compatible JSON file logging with gzip-compressed rotation, plus syslog:

pub struct LogConfig {
    pub driver: LogDriver,
    pub options: HashMap<String, String>,
}

pub enum LogDriver {
    JsonFile,   // Docker-compatible JSON lines with gzip rotation (default)
    Syslog,     // Forward to syslog daemon (UDP or TCP)
    None,       // Disable logging
}

Log format (json-file):

{"log":"hello\n","stream":"stdout","time":"2026-02-12T06:00:00.000000000Z"}

json-file options:

Prop

Type

a3s-box run --log-driver json-file \
  --log-opt max-size=50m \
  --log-opt max-file=5 \
  my-image:latest

syslog options:

Prop

Type

a3s-box run --log-driver syslog \
  --log-opt syslog-address=udp://10.0.0.1:514 \
  --log-opt tag=my-app \
  my-image:latest

State Persistence

All box state is persisted to ~/.a3s/boxes.json:

pub struct BoxRecord {
    pub id: String,             // Full UUID
    pub short_id: String,       // 12-char hex
    pub name: String,
    pub image: String,
    pub status: String,         // "created", "running", "stopped", "dead"
    pub pid: Option<u32>,       // Shim process PID
    pub created_at: DateTime<Utc>,
    pub started_at: Option<DateTime<Utc>>,
    // ... 30+ additional fields
}

Boxes can be referenced by full ID, short ID (12-char prefix), or name.

Environment Variables

Prop

Type

On this page