Skip to main content
This FAQ is grounded in current code behavior (src/, src/types.ts, and schema/isol8.config.schema.json).

Core behavior and defaults

Defaults are conservative:
  • timeoutMs: 30000
  • memoryLimit: "512m"
  • cpuLimit: 1
  • network: "none"
  • sandboxSize: "512m"
  • tmpSize: "256m"
  • maxConcurrent: 10
First match wins:
  1. ./isol8.config.json in current working directory
  2. ~/.isol8/config.json
  3. built-in defaults
No. User config is deep-merged with defaults. You can override only the keys you need.
Use:
isol8 config --json
This is the best way to confirm what values are actually active.
Request/CLI values override config defaults for that execution. Config remains the baseline.
Not always. The built CLI can run under Node, and isol8 serve in built mode downloads a standalone server binary that embeds Bun.

Setup and build behavior

It checks Docker connectivity, builds base runtime images, and can build custom images with configured dependencies.
Use --force after Dockerfile/runtime dependency changes, or when troubleshooting stale image behavior.
Built CLI checks standalone server binary version against CLI version. If mismatched, it prompts to update.
Yes:
isol8 serve --update
CLI fails with an unsupported platform error for unknown OS/arch combinations.

Execution modes, lifecycle, and persistence

  • --persistent: selects persistent execution mode (reuse one container state for that engine/session).
  • --persist: keep container(s) running after execution for inspection/debugging. They control different concerns and can be combined.
Not by default. Each CLI invocation creates a new process and a new engine lifecycle, then stops it in finally. For true cross-call persistence, use remote API/library with a stable sessionId.
No. Persistent containers are runtime-bound. Switching runtime in the same persistent engine throws an error.
  • explicit DELETE /session/:id
  • auto-prune if enabled and session is idle past cleanup.maxContainerAgeMs
No. Active sessions are skipped while executing (isActive check).

Streaming and output behavior

Yes. isol8 run streams output by default. Use --no-stream to wait for final result.
stdout, stderr, exit, error.
--out writing is part of non-streaming result handling path. If you need predictable captured output file, use --no-stream.
Output is capped by maxOutputSize (default 1MB). If exceeded, output is truncated and marked.
Yes. Secret value masking is applied in both collected output and streaming output pipelines.
No. Masking is text-output masking. Retrieved file contents are returned as-is.

Networking and security

  • none: outbound network blocked (default, safest)
  • filtered: proxy + hostname policy + iptables enforcement
  • host: unrestricted host networking (use only for trusted workloads)
Denylist/blacklist wins. Matching blocked hosts are denied even if also allowed by whitelist.
Common causes:
  • regex mismatch against actual hostname
  • blacklist also matches
  • request host differs from what you expected
No. It also applies in-container iptables rules so uid 100 traffic is restricted to proxy path.
  • strict: apply the default built-in seccomp profile
  • unconfined: no seccomp filter
  • custom: use profile from security.customProfilePath
Execution fails instead of running without seccomp. In standalone server binary mode, isol8 uses an embedded default profile when on-disk profile files are unavailable.
No direct run seccomp flag currently. Use config (security.*) or API/library options.security.
Network logs require filtered mode. --log-network only works when network mode is filtered.
CLI auto-selects filtered networking for that run and adds runtime-default package registry hosts to the allowlist (for example PyPI or npm registry hosts).
No. Explicit --net is preserved. Only the allowlist is merged when effective mode is filtered.
Yes. The timeout now applies to both package installation and code execution, so blocked or stalled installs fail instead of hanging indefinitely.

Runtimes, files, and package installs

Runtime registry maps extensions to adapters. Examples:
  • .py -> python
  • .mjs / .js / .cjs -> node
  • .ts -> bun
  • .mts -> deno
  • .sh -> bash
Bun is mapped to .ts. Deno uses .mts to avoid extension collisions.
Deno adapter currently requires a file path and does not support inline command path.
Use fileExtension (library/API) or file suffix in CLI input:
  • .mjs for ESM
  • .cjs for CJS Node adapter supports both.
Package installs are placed under /sandbox user directories (e.g. Python user base, npm/bun globals), not /tmp.
Yes in API/library via files and outputPaths. CLI currently does not expose full generic files/outputPaths request fields.
Local file APIs require persistent mode and at least one execution to create/activate the container.
/tmp is mounted noexec. Native extensions often require executable paths, so /sandbox is used.
install package names are validated to reduce injection risk. Invalid characters are rejected.

Resource limits and performance

One full CPU core worth of quota (NanoCpus mapping inside Docker host config).
Command is wrapped with timeout enforcement and will be terminated when limit is exceeded.
Formats like 512m, 1g, 256k, or raw bytes are accepted. Invalid format throws a parse error.
  • increase sandboxSize for larger user files/package footprints
  • keep tmpSize sufficient for temporary build/runtime caches
  • poolStrategy: "fast" (default): clean/dirty pools with background cleanup
  • poolStrategy: "secure": cleanup in acquire path
  • poolSize: warm pool capacity
  • maxConcurrent limits total parallel executions (semaphore).
  • poolSize controls warm container availability per runtime image.
  • If concurrency exceeds warm capacity for a runtime, requests can still run but may pay cold create/start latency.
Usually not much. One-shot CLI exits and calls engine.stop(), which drains/removes pool containers. Background cleaning is most useful for long-lived processes (serve, long-running app instance).

Remote server and API

  • 401: missing Authorization header
  • 403: header present but API key invalid
No. /health is intentionally unauthenticated for liveness checks.
Yes. File operations are tied to persistent sessions. Without sessionId, they fail.
Not currently. Server streaming path is forced to ephemeral mode.
Yes. Send options in request envelope; they are merged over server defaults for that execution.
It performs a health check against /health to verify remote server reachability.
If sessionId is configured, it calls DELETE /session/{id}. Without sessionId it is effectively a no-op cleanup.

Audit logging and observability

Only when audit.enabled is true.
filesystem (or file) and stdout are implemented.
Yes. Use:
  • audit.includeCode: false
  • audit.includeOutput: false and keep metadata/codeHash/duration-level provenance.
Yes. audit.postLogScript executes after writes and receives audit file path.
Only when both are true:
  • network mode is filtered
  • logNetwork is enabled
Keep audit.includeCode=false and audit.includeOutput=false, and set reasonable retentionDays.

Troubleshooting quick map

  • Runtime detection errors: see /runtimes and pass explicit runtime.
  • Session/file 404s: verify stable sessionId and that session was created.
  • Unexpected network blocks: verify allow/deny regex and network mode.
  • Missing logs/metrics: verify feature flags (audit.enabled, logNetwork, etc).