Skip to main content

Code Interpreter

The Code Interpreter (codeapi) runs IntelliAsk's Run Code feature in hardened sandboxes. Its architecture (six services + bundled Redis), how the app authenticates with a signed JWT, the language-runtime package tree, and the full CODEAPI_* reference in config/.env.

The Code Interpreter — codeapi — powers IntelliAsk's Run Code feature. It runs user code in hardened sandboxes, brokers tool calls, gates all sandbox network egress through an allow-listed proxy, and stores generated files in an S3-compatible bucket (the bundled Garage service by default).

Full reference lives in Services

This page is just what you need to run codeapi in the stack. For the complete per-service environment surface, architecture, and security model, see Services → Code Interpreter.

Architecture

codeapi is six services plus a dedicated redis, all defined in config/codeapi.compose.yml. They share the stack network and reuse the bundled garage (S3) service.

ServicePortRole
codeapi-api3112Public entry point — the IntelliAsk app sends /v1/* requests here.
codeapi-service-worker3113 (health)Pulls jobs from Redis, drives the sandbox, signs execution manifests.
codeapi-sandbox-runner2000Runs untrusted user code. Privileged.
codeapi-egress-gateway3190Allow-listed outbound proxy; the sandbox may only reach the network through here.
codeapi-tool-call-server3033Brokers tool calls back to the caller.
codeapi-file-server3000S3/object I/O, backed by the bundled Garage.
redis6379Cache/queue backend shared by the codeapi services.

Privileged sandbox + host requirements

codeapi-sandbox-runner runs privileged because it executes untrusted code, isolating via unshare --mount + NsJail user namespaces (KVM_ENABLED=false, no libkrun MicroVM). This path needs host cgroup v2 (unified hierarchy). Keep the service on the internal network only — never publish its port.

How the app talks to codeapi

The IntelliAsk app (the intelliask service) reaches the API at http://codeapi-api:3112/v1 and authenticates with a short-lived Ed25519 JWT it mints per request. There is no reverse proxy and no X-API-Key in this path.

intelliask ──(Bearer EdDSA JWT)──▶ codeapi-api:3112/v1
                                      │
        ┌─────────────────────────────┼───────────────────────────┐
        ▼            ▼                 ▼            ▼               ▼
   service-worker  file-server   tool-call-server  egress-gateway  redis
        │                                              ▲
        ▼                                              │
   sandbox-runner ──(all egress via signed grant)──────┘

The signing key is a pair: the IntelliAsk app holds the private half (CODEAPI_JWT_PRIVATE_KEY_BASE64) and codeapi-api verifies with the public half (CODEAPI_JWT_PUBLIC_KEY). Both are auto-provisioned.

Prerequisite: the language-runtime package tree

Build the package tree before first use

The sandbox loads its runtimes from a prebuilt package tree bind-mounted read-only at /host-packages (from ${STORAGE_ROOT}/code-interpreter-packages on the host). An empty tree makes every run fail with runtime is unknown. Populate it before first use — provisioning only creates the empty directory.

Configuration

Every codeapi variable lives in config/.env and is read by the containers under the same name — see Services → Code Interpreter → Configuration for the full per-service reference. The defaults are production-ready and the sandbox is hardened by default (CODEAPI_HARDENED_SANDBOX_MODE=true). The only secrets are auto-provisioned during intelliask provision — leave them blank on a fresh install and never edit one half of a pair by hand:

SecretUsed by
CODEAPI_JWT_PRIVATE_KEY_BASE64 ⇄ CODEAPI_JWT_PUBLIC_KEYApp signs request JWTs / codeapi-api verifies them.
CODEAPI_EXECUTION_MANIFEST_PRIVATE_KEY ⇄ SANDBOX_EXECUTION_MANIFEST_PUBLIC_KEYservice-worker signs execution manifests / sandbox-runner verifies them.
CODEAPI_INTERNAL_SERVICE_TOKENService-to-service auth between the codeapi components.
CODEAPI_EGRESS_GRANT_SECRETHMAC secret for signed egress grants.

Resource limits

Each service has its own CODEAPI_*_CPUS / CODEAPI_*_MEMORY ceiling in config/.env. The sandbox-runner is the heavy one — it launches user code — so its defaults are the largest:

ServiceCPUsMemory
codeapi-apiCODEAPI_API_CPUS (1.0)CODEAPI_API_MEMORY (1024m)
codeapi-service-workerCODEAPI_WORKER_CPUS (1.0)CODEAPI_WORKER_MEMORY (1024m)
codeapi-sandbox-runnerCODEAPI_SANDBOX_CPUS (2.0)CODEAPI_SANDBOX_MEMORY (3072m)
codeapi-file-serverCODEAPI_FILE_CPUS (0.5)CODEAPI_FILE_MEMORY (512m)
codeapi-tool-call-serverCODEAPI_TOOLCALL_CPUS (0.3)CODEAPI_TOOLCALL_MEMORY (384m)
codeapi-egress-gatewayCODEAPI_EGRESS_CPUS (0.3)CODEAPI_EGRESS_MEMORY (384m)

codeapi needs a bigger host than LCI

These ceilings sum to well over the 4 GiB / 2 vCPU reference host. The sandbox in particular runs untrusted, memory-hungry code — size the VM accordingly (give the sandbox its own headroom).

Applying changes

After editing any CODEAPI_* value, recreate the affected service(s):

intelliask up codeapi-api             # one service
intelliask up codeapi-sandbox-runner codeapi-service-worker

Updating the Code Interpreter

codeapi ships as six images, each with its own CODEAPI_*_IMAGE variable, so you can update the whole code interpreter or a single service independently:

CODEAPI_API_IMAGE
CODEAPI_WORKER_IMAGE
CODEAPI_FILE_SERVER_IMAGE
CODEAPI_TOOL_CALL_SERVER_IMAGE
CODEAPI_EGRESS_GATEWAY_IMAGE
CODEAPI_SANDBOX_RUNNER_IMAGE
# 1. Publish new builds under new tags, then bump the matching CODEAPI_*_IMAGE in
#    config/.env, e.g. CODEAPI_API_IMAGE=codeapi-api:2
 
# 2. Pull + recreate only the changed services
intelliask update codeapi-api

To roll back, restore the previous tag(s) and re-run the update. Use immutable tags so rollbacks stay unambiguous.

Last updated on