sandbox-libkrun
v0.2.2libkrun sandbox adapter - serves the iii sandbox router's sandbox::* calls as sandbox-libkrun::* in libkrun microVMs, and boots Compose's worker VMs.
Install
iii trigger compose::add worker=sandbox-libkrunRun in your project with the iii engine running. Exact versions are immutable and digest-pinned.
Full markdown
/registry/workers/sandbox-libkrun.md. Paste it into an LLM prompt or pipe it through curl from a worker.Install
iii trigger compose::add worker=sandbox-libkrun@0.2.2Configuration
- auto_install: true
default_cpus: 1
default_idle_timeout_secs: 300
default_memory_mb: 512
image_allowlist:
- python
- node
max_concurrent_sandboxes: 32Dependencies
Readme
sandbox-libkrun
The libkrun sandbox adapter: it runs sandboxes and worker VMs as libkrun
microVMs on the engine's host. The engine's sandbox::* router forwards each
sandbox call to it as sandbox-libkrun::<operation>, and Compose boots
package:// and path:// VM workers through its sandbox-libkrun::worker::*
functions. You rarely call it directly: callers use sandbox::*, and Compose
installs this adapter when a project needs it.
Install
Compose adds it on its own when a project needs sandboxes or VM workers. To
add it by hand on iii 0.26 or later, use the iii-sandbox alias, which pins
the adapter to the sandbox contract major the engine supports:
iii trigger compose::add worker=iii-sandboxOlder Compose has no such alias, so pin the range yourself (0.2.x implements sandbox contract 1):
iii trigger compose::add worker=sandbox-libkrun@^0.2Calling sandbox::* through the router needs iii 0.26 or later; the
sandbox-libkrun::* ids work on iii 0.24 and later.
Quickstart
Run code in a fresh VM through the router, which forwards to this adapter:
iii trigger sandbox::run --timeout-ms 300000 \
--json '{"image":"python","code":"print(6*7)","lang":"python"}'The reply carries stdout (42), stderr and exit_code; the VM stops
when the call returns. The first call pulls the image, so it is slower. sandbox-libkrun::run takes the same payload directly.
What it serves
| Functions | Purpose |
|---|---|
create, exec, stop, list, catalog::list, run |
Sandbox lifecycle and one-call runs |
fs::ls, fs::stat, fs::mkdir, fs::rm, fs::chmod, fs::mv, fs::grep, fs::sed, fs::write, fs::read |
Files inside a live sandbox |
adapter::info |
Adapter name, version and the sandbox contract version it implements |
worker::prepare, worker::start, worker::status, worker::logs, worker::stop, worker::destroy |
Compose's worker VMs (see below) |
Every id is prefixed with sandbox-libkrun::.
Configuration
The adapter reads its configuration entry once at startup with
configuration::get (III_CONFIG_NAME, else sandbox-libkrun). A change
applies when the adapter restarts. A config that does not parse, or a failed
read, stops the adapter with exit code 2 instead of falling back to defaults.
auto_install: true # pull a missing image on first create
image_allowlist: [python, node] # bootable images; empty denies every create
default_idle_timeout_secs: 300 # idle sandboxes are reaped after this
max_concurrent_sandboxes: 32
max_concurrent_exec_per_sandbox: 4 # 0 means 1, not unlimited
max_exec_timeout_ms: 300000 # ceiling on any exec's timeout_ms
default_cpus: 1
default_memory_mb: 512
per_image_caps: # optional per-image ceilings
python: { max_cpus: 4, max_memory_mb: 2048 }
custom_images: # extra images: name -> OCI ref
my-app: ghcr.io/acme/my-app:1.2.3 # must also be in image_allowlistA custom_images key may not reuse a preset name (python, node), and the
old wrapped shape (sandbox: {...}) is rejected.
VM tuning stays in four environment variables the adapter passes to each worker VM (sandboxes ignore them):
| Variable | Effect |
|---|---|
III_VM_HYPERTHREADING=1 |
Enable SMT (hyperthreading) in the guest |
III_VM_NESTED_VIRT=1 |
Enable nested virtualization |
III_VM_VIRTIOFS_SHM_SIZE_MIB=<n> |
virtiofs shared-memory window; 0 skips it |
III_VM_NOFILE_LIMIT=<n> |
Guest open-file limit; 0 leaves it to the guest init |
Host prerequisites
- macOS, Apple Silicon only. The released binary is ad-hoc signed with
the
com.apple.security.hypervisorandcom.apple.security.cs.disable-library-validationentitlements. An unsigned dev build signs itself in place on first run. - Linux, glibc. The Compose user needs read/write access to
/dev/kvm. - Any other host gets a clear
UnsupportedPlatformerror from Compose when a project needs the adapter.
Worker VMs
Compose runs VM workers through sandbox-libkrun::worker::*. Because those
requests name host directories (host_path) and carry the guest's
environment, two guards apply:
- Token. Compose generates a per-project token and passes it to the
adapter as
III_SANDBOX_WORKER_TOKEN. Everyworker::*request carries it inauth; a mismatch gets S505. - Host roots.
host_pathis accepted only under the project's Compose directory and the Compose package cache. Anything else gets S501 naming the two roots.
Compose also sets III_DISABLE_TRACE_PAYLOADS=1 on the adapter, so the token
and guest env never land in the engine's trace store.
Known limits
The guards assume bus clients are trusted. A client that registers the
adapter's function ids or its worker name first, while the adapter is down,
receives the auth token and the guest env that Compose sends. The router
has the same limit for sandbox::* forwards.
Errors
Errors carry an S-code with a docs_url. The full list is at
iii.dev/docs/creating-workers/sandboxes.
API reference (JSON)
{
"functions": [
{
"description": "Name and version of this sandbox adapter, and the sandbox contract version it implements.",
"metadata": {},
"name": "sandbox-libkrun::adapter::info",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Request of `<adapter>::adapter::info`; carries no fields.",
"title": "AdapterInfoRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ContractVersion": {
"description": "Contract version. A different major is incompatible (S302); a minor only adds fields.",
"properties": {
"major": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"minor": {
"format": "uint32",
"minimum": 0,
"type": "integer"
}
},
"required": [
"major",
"minor"
],
"type": "object"
}
},
"description": "Reply of `<adapter>::adapter::info`.",
"properties": {
"adapter": {
"description": "The adapter's name, e.g. `\"sandbox-libkrun\"`.",
"type": "string"
},
"adapter_version": {
"type": "string"
},
"contract": {
"allOf": [
{
"$ref": "#/definitions/ContractVersion"
}
],
"description": "The contract version the adapter implements."
}
},
"required": [
"adapter",
"adapter_version",
"contract"
],
"title": "AdapterInfo",
"type": "object"
}
},
{
"description": "List bootable images: bundled presets plus operator-registered custom_images. Call this before sandbox::create when you don't know what's available.",
"metadata": {},
"name": "sandbox-libkrun::catalog::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "`sandbox::catalog::list` request. No fields — kept as a struct (not `()`) so adding optional filters (e.g. `include_oci_refs: bool`) later is a non-breaking serde change.",
"title": "CatalogListRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"CatalogEntry": {
"description": "One row in the catalog response. `name` is the catalog key that callers pass to `sandbox::create` (or `sandbox::run`); `oci_ref` is the fully-qualified OCI reference the daemon will pull. `kind` lets agents distinguish bundled presets from operator-registered custom images without having to maintain their own preset allowlist.",
"properties": {
"kind": {
"$ref": "#/definitions/CatalogEntryKind"
},
"name": {
"type": "string"
},
"oci_ref": {
"type": "string"
}
},
"required": [
"kind",
"name",
"oci_ref"
],
"type": "object"
},
"CatalogEntryKind": {
"oneOf": [
{
"description": "Bundled with the daemon binary. Stable identifier across releases.",
"enum": [
"preset"
],
"type": "string"
},
{
"description": "Operator-registered in the adapter's `custom_images` config. Specific to this deployment.",
"enum": [
"custom"
],
"type": "string"
}
]
}
},
"properties": {
"images": {
"description": "Every image the daemon will accept on `sandbox::create.image`. Presets come first in stable order; custom entries follow, sorted by `name` for determinism so an agent that diffs two `catalog::list` responses sees stable output.",
"items": {
"$ref": "#/definitions/CatalogEntry"
},
"type": "array"
}
},
"required": [
"images"
],
"title": "CatalogListResponse",
"type": "object"
}
},
{
"description": "Create an ephemeral sandbox VM. `image` must be a preset (`\"python\"`, `\"node\"`) or a key from the adapter's `custom_images` config; OCI refs are NOT accepted unless they match a catalog key. `env` accepts both `Vec<\"K=V\">` and `{ K: V }` map shapes.",
"metadata": {},
"name": "sandbox-libkrun::create",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"EnvShape": {
"anyOf": [
{
"description": "Original wire shape: `[\"FOO=bar\", \"PATH=/usr/bin\"]`.",
"items": {
"type": "string"
},
"type": "array"
},
{
"additionalProperties": {
"type": "string"
},
"description": "Agent-natural shape: `{ \"FOO\": \"bar\", \"PATH\": \"/usr/bin\" }`. Iteration is sorted by key (BTreeMap) so two callers passing the same map get the same env-var ordering.",
"type": "object"
}
],
"description": "Environment-variable input. Agents naturally pass `{ FOO: \"bar\" }` (matching Docker/npm/k8s mental models); the original wire shape was `Vec<\"K=V\">`. The untagged enum accepts both; `into_kv_vec()` normalises to the canonical `Vec<String>` the runner expects.\n\n`Default` is the empty vec form (the historical wire shape)."
}
},
"examples": [
{
"env": {
"NODE_ENV": "production"
},
"idle_timeout_secs": 600,
"image": "node",
"memory_mb": 512
}
],
"properties": {
"cpus": {
"default": null,
"description": "vCPU count, at least 1; daemon/image default applies when omitted.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"env": {
"allOf": [
{
"$ref": "#/definitions/EnvShape"
}
],
"description": "Environment entries injected into the VM. Accepts either a `Vec<\"K=V\">` (original wire shape) or a `{ K: V }` map. `handle_create` normalises to the `Vec<String>` shape the boot path expects before invoking the launcher."
},
"idle_timeout_secs": {
"default": null,
"description": "Auto-stop the VM after this many seconds of inactivity; daemon default applies when omitted.",
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"image": {
"description": "Catalog name of the image to boot. Bundled presets are `\"python\"` and `\"node\"`; pass either string verbatim. The only other accepted values are the literal keys of the adapter's `custom_images` config — set by the operator. Do NOT pass an OCI ref like `\"ghcr.io/iii-hq/node:latest\"` or `\"docker.io/library/node:20\"` unless that exact string is the catalog key. Unknown values return S100 with the allowed set in the error message.",
"type": "string"
},
"memory_mb": {
"default": null,
"description": "Memory cap in MiB, at least 64; daemon/image default applies when omitted.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"name": {
"default": null,
"description": "Human label surfaced by `sandbox::list`; not an identifier.",
"type": [
"string",
"null"
]
},
"network": {
"default": null,
"description": "Whether the VM gets outbound networking; daemon default when omitted.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"image"
],
"title": "CreateRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"image": {
"type": "string"
},
"sandbox_id": {
"type": "string"
}
},
"required": [
"image",
"sandbox_id"
],
"title": "CreateResponse",
"type": "object"
}
},
{
"description": "Execute a command inside a live sandbox. `cmd` accepts three shapes: (1) a shell-style line that gets shlex-split (`cmd: \"node -v\"`), (2) `cmd` + `args` (the POSIX shape, `cmd: \"node\", args: [\"-v\"]`), (3) an `argv` array (`argv: [\"node\", \"-v\"]`). Shell metacharacters in the shell-line shape are NOT interpreted; use `sandbox::run` with `lang: \"shell\"` for bash semantics. `env` accepts both `Vec<\"K=V\">` and `{ K: V }` map shapes.",
"metadata": {},
"name": "sandbox-libkrun::exec",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"EnvShape": {
"anyOf": [
{
"description": "Original wire shape: `[\"FOO=bar\", \"PATH=/usr/bin\"]`.",
"items": {
"type": "string"
},
"type": "array"
},
{
"additionalProperties": {
"type": "string"
},
"description": "Agent-natural shape: `{ \"FOO\": \"bar\", \"PATH\": \"/usr/bin\" }`. Iteration is sorted by key (BTreeMap) so two callers passing the same map get the same env-var ordering.",
"type": "object"
}
],
"description": "Environment-variable input. Agents naturally pass `{ FOO: \"bar\" }` (matching Docker/npm/k8s mental models); the original wire shape was `Vec<\"K=V\">`. The untagged enum accepts both; `into_kv_vec()` normalises to the canonical `Vec<String>` the runner expects.\n\n`Default` is the empty vec form (the historical wire shape)."
}
},
"examples": [
{
"args": [
"/home/app/index.js"
],
"cmd": "node",
"env": {
"NODE_ENV": "production"
},
"sandbox_id": "00000000-0000-0000-0000-000000000000",
"timeout_ms": 300000
}
],
"properties": {
"args": {
"default": [],
"description": "Argv tail passed to `cmd` (each entry is one argv slot).",
"items": {
"type": "string"
},
"type": "array"
},
"argv": {
"default": [],
"description": "Alternative input shape: a single argv array where the first element is the binary and the rest are arguments. Mutually exclusive with `cmd` having whitespace OR `args` being set.",
"items": {
"type": "string"
},
"type": "array"
},
"cmd": {
"default": "",
"description": "The binary to execute. Accepts three shapes (`handle_exec` picks one and normalises `cmd`/`args` before passing to the runner):\n\n1. **Shell line**: `cmd: \"node /home/app/index.js\"`. If `cmd` contains whitespace AND `args` is empty AND `argv` is empty, `cmd` is shlex-split into `(head, tail)` and `head` becomes the binary while `tail` becomes the argv. 2. **cmd + args**: `cmd: \"node\", args: [\"-v\"]`. The classic POSIX shape; unchanged from earlier versions. 3. **argv array**: `argv: [\"node\", \"/home/app/index.js\"]`. Wins over `cmd`/`args` if non-empty; the first element is the binary, the rest are arguments.\n\nShlex is NOT bash. Shell metacharacters (`;`, `|`, `&&`, `>`, pipes, redirects, variable expansion) inside the shell-line shape are split as text, not interpreted. Use `sandbox::run` with `lang: \"shell\"` if you need bash semantics.",
"type": "string"
},
"env": {
"allOf": [
{
"$ref": "#/definitions/EnvShape"
}
],
"description": "Environment entries added to the child. Accepts either a `Vec<\"K=V\">` (the original wire shape) or a `{ K: V }` map. `handle_exec` normalises to `Vec<String>` before invoking the runner."
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
},
"stdin": {
"default": null,
"description": "Base64-encoded bytes piped to the child's stdin.",
"type": [
"string",
"null"
]
},
"timeout_ms": {
"default": null,
"description": "Kill-after window in ms. Defaults to 300_000 (5 minutes) — sized for cold `npm install` / `pip install` / `cargo build`. Pass a smaller value (e.g. 10_000) for probes and version checks.",
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"workdir": {
"default": null,
"description": "Working directory inside the sandbox; `/` when omitted.",
"type": [
"string",
"null"
]
}
},
"required": [
"sandbox_id"
],
"title": "ExecRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"duration_ms": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"stderr": {
"type": "string"
},
"stderr_truncated": {
"description": "`stderr` was cut at the 1 MiB output cap. Since contract 1.1.",
"type": "boolean"
},
"stdout": {
"type": "string"
},
"stdout_truncated": {
"description": "`stdout` was cut at the 1 MiB output cap. Since contract 1.1.",
"type": "boolean"
},
"success": {
"type": "boolean"
},
"timed_out": {
"type": "boolean"
}
},
"required": [
"duration_ms",
"stderr",
"stderr_truncated",
"stdout",
"stdout_truncated",
"success",
"timed_out"
],
"title": "ExecResponse",
"type": "object"
}
},
{
"description": "Change file permissions (and optionally owner) inside a sandbox. Example: { sandbox_id: \"...\", path: \"/home/app/script.sh\", mode: \"0755\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::chmod",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"mode": "0755",
"path": "/home/app/script.sh",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"gid": {
"default": null,
"description": "Optional GID to chown to. Pair with `uid` for a full chown.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"mode": {
"description": "Octal permissions (e.g. `\"0644\"`, `\"0755\"`).",
"type": "string"
},
"path": {
"description": "Absolute path to modify inside the sandbox guest.",
"type": "string"
},
"recursive": {
"default": false,
"description": "Apply recursively to all entries under `path`.",
"type": "boolean"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
},
"uid": {
"default": null,
"description": "Optional UID to chown to. Pair with `gid` for a full chown.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"required": [
"mode",
"path",
"sandbox_id"
],
"title": "ChmodRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"updated": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"updated"
],
"title": "ChmodResponse",
"type": "object"
}
},
{
"description": "Search for a regex pattern in files inside a sandbox. Walks `path` recursively by default. Example: { sandbox_id: \"...\", path: \"/home/app/src\", pattern: \"TODO\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::grep",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"include_glob": [
"**/*.js",
"**/*.ts"
],
"path": "/home/app/src",
"pattern": "TODO|FIXME",
"recursive": true,
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"exclude_glob": {
"default": [],
"description": "Gitignore-style exclude filter applied relative to `path`.",
"items": {
"type": "string"
},
"type": "array"
},
"ignore_case": {
"default": false,
"description": "Case-insensitive match.",
"type": "boolean"
},
"include_glob": {
"default": [],
"description": "Gitignore-style include filter applied relative to `path`.",
"items": {
"type": "string"
},
"type": "array"
},
"max_line_bytes": {
"default": 4096,
"description": "Maximum bytes per matched line before content is truncated with `…`. Default 4096.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"max_matches": {
"default": 10000,
"description": "Maximum number of matches before truncation. Default 10_000.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"path": {
"description": "Root path to search inside the sandbox guest. Treated as a directory when `recursive: true`, else as a single file.",
"type": "string"
},
"pattern": {
"description": "Regex pattern (Rust regex syntax, anchored fragments allowed).",
"type": "string"
},
"recursive": {
"default": true,
"description": "Descend into subdirectories under `path`. Defaults to true.",
"type": "boolean"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"pattern",
"sandbox_id"
],
"title": "GrepRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FsMatch": {
"description": "Single grep hit. `line` is 1-based. `content` is already truncated to `max_line_bytes` (with a trailing `…`) if the original line was longer.",
"properties": {
"content": {
"type": "string"
},
"line": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"path": {
"type": "string"
}
},
"required": [
"content",
"line",
"path"
],
"type": "object"
}
},
"properties": {
"matches": {
"items": {
"$ref": "#/definitions/FsMatch"
},
"type": "array"
},
"truncated": {
"type": "boolean"
}
},
"required": [
"matches",
"truncated"
],
"title": "GrepResponse",
"type": "object"
}
},
{
"description": "List directory contents inside a sandbox. Example: { sandbox_id: \"...\", path: \"/home/app\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::ls",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"path": "/home/app",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"path": {
"description": "Absolute path of the directory to list inside the sandbox guest.",
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "LsRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FsEntry": {
"description": "Single directory entry returned by `FsOp::Ls` / `FsOp::Stat`. `mode` is the octal permission string (e.g. `\"0644\"`); `mtime` is Unix seconds. `is_symlink` reflects the entry itself — FS handlers never follow symlinks unless the op doc-comment says otherwise.",
"properties": {
"is_dir": {
"type": "boolean"
},
"is_symlink": {
"type": "boolean"
},
"mode": {
"type": "string"
},
"mtime": {
"format": "int64",
"type": "integer"
},
"name": {
"type": "string"
},
"size": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"is_dir",
"is_symlink",
"mode",
"mtime",
"name",
"size"
],
"type": "object"
}
},
"properties": {
"entries": {
"items": {
"$ref": "#/definitions/FsEntry"
},
"type": "array"
}
},
"required": [
"entries"
],
"title": "LsResponse",
"type": "object"
}
},
{
"description": "Create a directory inside a sandbox. Pass `parents:true` to make missing parents like `mkdir -p`. Example: { sandbox_id: \"...\", path: \"/home/app/cache\", mode: \"0755\", parents: true }",
"metadata": {},
"name": "sandbox-libkrun::fs::mkdir",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"mode": "0755",
"parents": true,
"path": "/home/app/cache",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"mode": {
"default": "0755",
"description": "Octal permissions for the new directory (e.g. `\"0755\"`).",
"type": "string"
},
"parents": {
"default": false,
"description": "Create intermediate parent directories like `mkdir -p`.",
"type": "boolean"
},
"path": {
"description": "Absolute path of the directory to create inside the sandbox guest.",
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "MkdirRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"created": {
"type": "boolean"
}
},
"required": [
"created"
],
"title": "MkdirResponse",
"type": "object"
}
},
{
"description": "Move or rename a path inside a sandbox. Pass `overwrite:true` to clobber an existing destination. Example: { sandbox_id: \"...\", src: \"/home/app/old.js\", dst: \"/home/app/new.js\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::mv",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"dst": "/home/app/new.js",
"overwrite": false,
"sandbox_id": "00000000-0000-0000-0000-000000000000",
"src": "/home/app/old.js"
}
],
"properties": {
"dst": {
"description": "Destination absolute path inside the sandbox guest.",
"type": "string"
},
"overwrite": {
"default": false,
"description": "Allow overwriting `dst` if it already exists.",
"type": "boolean"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
},
"src": {
"description": "Source absolute path inside the sandbox guest.",
"type": "string"
}
},
"required": [
"dst",
"sandbox_id",
"src"
],
"title": "MvRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"moved": {
"type": "boolean"
}
},
"required": [
"moved"
],
"title": "MvResponse",
"type": "object"
}
},
{
"description": "Read a file from a sandbox. Always returns `content`: a StreamChannelRef callers can subscribe to for the full file bytes. For UTF-8 text files under 1 MiB, the response also carries an inline `body` string so callers can short-circuit the subscription. Example: { sandbox_id: \"...\", path: \"/home/app/index.js\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::read",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"path": "/home/app/index.js",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"path": {
"description": "Absolute path to read inside the sandbox guest.",
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "ReadRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ChannelDirection": {
"enum": [
"read",
"write"
],
"type": "string"
},
"StreamChannelRef": {
"properties": {
"access_key": {
"type": "string"
},
"channel_id": {
"type": "string"
},
"direction": {
"$ref": "#/definitions/ChannelDirection"
}
},
"required": [
"access_key",
"channel_id",
"direction"
],
"type": "object"
}
},
"properties": {
"body": {
"description": "Inline UTF-8 body. Populated for text files under [`INLINE_BUFFER_CAP`] (1 MiB) that decode cleanly as UTF-8. `None` for large or binary files; subscribe to `content` instead. When `Some`, the same bytes are also delivered through `content` so legacy callers keep working — new callers can use `body` directly and skip the channel subscription.",
"type": [
"string",
"null"
]
},
"content": {
"allOf": [
{
"$ref": "#/definitions/StreamChannelRef"
}
],
"description": "Channel ref for the file body. Always set; callers can subscribe to receive the full file contents as bytes. Preserved for wire compatibility with peers that statically type this field as `StreamChannelRef`."
},
"mode": {
"type": "string"
},
"mtime": {
"format": "int64",
"type": "integer"
},
"size": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"content",
"mode",
"mtime",
"size"
],
"title": "ReadResponse",
"type": "object"
}
},
{
"description": "Remove a file or directory inside a sandbox. Pass `recursive:true` to remove directories with contents. Example: { sandbox_id: \"...\", path: \"/home/app/temp\", recursive: true }",
"metadata": {},
"name": "sandbox-libkrun::fs::rm",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"path": "/home/app/temp",
"recursive": true,
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"path": {
"description": "Absolute path to remove inside the sandbox guest.",
"type": "string"
},
"recursive": {
"default": false,
"description": "Remove directories and their contents recursively (like `rm -rf`).",
"type": "boolean"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "RmRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"removed": {
"type": "boolean"
}
},
"required": [
"removed"
],
"title": "RmResponse",
"type": "object"
}
},
{
"description": "Find-and-replace in files inside a sandbox. Pass either `path` (walked like grep) OR `files` (explicit list), not both. Example: { sandbox_id: \"...\", path: \"/home/app/src\", pattern: \"foo\", replacement: \"bar\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::sed",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Find-and-replace request, accepting either an explicit `files` list or a `path` walked like grep does. Exactly one of those two must be provided — `handle_sed` returns S210 otherwise.",
"examples": [
{
"path": "/home/app/src",
"pattern": "foo",
"recursive": true,
"replacement": "bar",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"exclude_glob": {
"default": [],
"description": "Gitignore-style exclude filter applied to paths relative to `path`. Only meaningful with `path`.",
"items": {
"type": "string"
},
"type": "array"
},
"files": {
"default": [],
"description": "Legacy form: explicit list of paths to rewrite.",
"items": {
"type": "string"
},
"type": "array"
},
"first_only": {
"default": false,
"type": "boolean"
},
"ignore_case": {
"default": false,
"type": "boolean"
},
"include_glob": {
"default": [],
"description": "Gitignore-style include filter applied to paths relative to `path`. Only meaningful with `path`.",
"items": {
"type": "string"
},
"type": "array"
},
"path": {
"default": null,
"description": "New form: walk `path` like grep does. May be a directory or a single file. Mutually exclusive with `files`.",
"type": [
"string",
"null"
]
},
"pattern": {
"type": "string"
},
"recursive": {
"default": true,
"description": "Whether to descend into subdirectories. Only meaningful with `path`. Defaults to `true` so the path-form behaves like grep.",
"type": "boolean"
},
"regex": {
"default": true,
"type": "boolean"
},
"replacement": {
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"pattern",
"replacement",
"sandbox_id"
],
"title": "SedRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FsSedFileResult": {
"description": "One `sed` file-level outcome. `success=false` carries the human failure message in `error`; otherwise `error` is absent.",
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"path": {
"type": "string"
},
"replacements": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"success": {
"type": "boolean"
}
},
"required": [
"path",
"replacements",
"success"
],
"type": "object"
}
},
"properties": {
"results": {
"items": {
"$ref": "#/definitions/FsSedFileResult"
},
"type": "array"
},
"total_replacements": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"results",
"total_replacements"
],
"title": "SedResponse",
"type": "object"
}
},
{
"description": "Stat a path inside a sandbox. Example: { sandbox_id: \"...\", path: \"/home/app/index.js\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::stat",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"examples": [
{
"path": "/home/app/index.js",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"path": {
"description": "Absolute path to inspect inside the sandbox guest.",
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "StatRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Mirrors `FsEntry`. Note: the shell protocol does not carry uid/gid; those fields are absent at this trigger level.",
"properties": {
"is_dir": {
"type": "boolean"
},
"is_symlink": {
"type": "boolean"
},
"mode": {
"type": "string"
},
"mtime": {
"format": "int64",
"type": "integer"
},
"name": {
"type": "string"
},
"size": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"is_dir",
"is_symlink",
"mode",
"mtime",
"name",
"size"
],
"title": "StatResponse",
"type": "object"
}
},
{
"description": "Write a file into a sandbox. `content` accepts a UTF-8 string (recommended for source/text), a StreamChannelRef object (for large uploads), or use `content_b64` for small binary. Example: { sandbox_id: \"...\", path: \"/home/app/index.js\", content: \"console.log('hi')\\n\" }",
"metadata": {},
"name": "sandbox-libkrun::fs::write",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ChannelDirection": {
"enum": [
"read",
"write"
],
"type": "string"
},
"StreamChannelRef": {
"properties": {
"access_key": {
"type": "string"
},
"channel_id": {
"type": "string"
},
"direction": {
"$ref": "#/definitions/ChannelDirection"
}
},
"required": [
"access_key",
"channel_id",
"direction"
],
"type": "object"
},
"WriteContent": {
"anyOf": [
{
"description": "Inline UTF-8 string. Written to the file verbatim.",
"type": "string"
},
{
"allOf": [
{
"$ref": "#/definitions/StreamChannelRef"
}
],
"description": "Streaming channel for large / binary uploads."
}
],
"description": "File body for `sandbox::fs::write`. Untagged so the JSON shape decides which variant runs:\n\n- A bare JSON string (`\"console.log('hi')\"`) → [`WriteContent::Utf8`]. This is what LLM agents naturally pass and the recommended form for source files / configs / small text. - An object that matches [`StreamChannelRef`] → [`WriteContent::Stream`]. The existing channel-streaming path for large or binary payloads coming from a programmatic caller that can construct a channel.\n\nSerde tries variants in declaration order; `Utf8` matches first because every JSON string deserialises into `String`, and `StreamChannelRef` requires an object. Binary inline data uses the separate `content_b64` field on [`WriteRequest`] (not a variant here, so a caller can't accidentally pass base64 expecting it to be decoded — they have to opt in by name)."
}
},
"examples": [
{
"content": "console.log('hello world')\n",
"mode": "0644",
"parents": true,
"path": "/home/app/index.js",
"sandbox_id": "00000000-0000-0000-0000-000000000000"
}
],
"properties": {
"content": {
"anyOf": [
{
"$ref": "#/definitions/WriteContent"
},
{
"type": "null"
}
],
"description": "File body. Pass a UTF-8 string for source/text (the agent-natural form), or a `StreamChannelRef` object for streaming large/binary uploads. Mutually exclusive with `content_b64`; exactly one of the two must be set."
},
"content_b64": {
"default": null,
"description": "Base64-encoded inline body for small binary payloads. Mutually exclusive with `content`.",
"type": [
"string",
"null"
]
},
"mode": {
"default": "0644",
"description": "Octal permissions for the new file (default `\"0644\"`).",
"type": "string"
},
"parents": {
"default": false,
"description": "Create missing parent directories before writing.",
"type": "boolean"
},
"path": {
"description": "Absolute destination path inside the sandbox guest.",
"type": "string"
},
"sandbox_id": {
"description": "UUID returned by `sandbox::create`.",
"type": "string"
}
},
"required": [
"path",
"sandbox_id"
],
"title": "WriteRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes_written": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"path": {
"type": "string"
}
},
"required": [
"bytes_written",
"path"
],
"title": "WriteResponse",
"type": "object"
}
},
{
"description": "List active sandboxes",
"metadata": {},
"name": "sandbox-libkrun::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ListRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SandboxSummary": {
"properties": {
"age_secs": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"exec_in_flight": {
"description": "Execs running right now.",
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"exec_in_progress": {
"description": "Any exec running. NOTE: this no longer implies the next exec will be refused — a sandbox admits `max_concurrent_exec_per_sandbox` at once. Use `exec_in_flight` / `exec_slots_free` for admission decisions; a caller that polls this waiting for `false` will wait forever against a resident process while slots sit idle.",
"type": "boolean"
},
"exec_slots_free": {
"description": "Execs this sandbox would admit before returning S003.",
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"image": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"sandbox_id": {
"type": "string"
},
"stopped": {
"type": "boolean"
}
},
"required": [
"age_secs",
"exec_in_flight",
"exec_in_progress",
"exec_slots_free",
"image",
"sandbox_id",
"stopped"
],
"type": "object"
}
},
"properties": {
"sandboxes": {
"items": {
"$ref": "#/definitions/SandboxSummary"
},
"type": "array"
}
},
"required": [
"sandboxes"
],
"title": "ListResponse",
"type": "object"
}
},
{
"description": "Run code in an ephemeral sandbox in ONE call. Composes create + fs::write + exec + stop. `lang` selects the interpreter (`node`, `python`, `shell`, or a custom binary path). Sandbox auto-stops on success and on failure unless `keep_sandbox: true`. Example: { image: \"node\", code: \"console.log('hi')\", lang: \"node\" }",
"metadata": {},
"name": "sandbox-libkrun::run",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"EnvShape": {
"anyOf": [
{
"description": "Original wire shape: `[\"FOO=bar\", \"PATH=/usr/bin\"]`.",
"items": {
"type": "string"
},
"type": "array"
},
{
"additionalProperties": {
"type": "string"
},
"description": "Agent-natural shape: `{ \"FOO\": \"bar\", \"PATH\": \"/usr/bin\" }`. Iteration is sorted by key (BTreeMap) so two callers passing the same map get the same env-var ordering.",
"type": "object"
}
],
"description": "Environment-variable input. Agents naturally pass `{ FOO: \"bar\" }` (matching Docker/npm/k8s mental models); the original wire shape was `Vec<\"K=V\">`. The untagged enum accepts both; `into_kv_vec()` normalises to the canonical `Vec<String>` the runner expects.\n\n`Default` is the empty vec form (the historical wire shape)."
},
"RunFile": {
"description": "Optional sibling file to drop into the sandbox before the main code runs.",
"properties": {
"content": {
"description": "UTF-8 file body. Streaming and base64 are not supported here; callers needing those should use `sandbox::create` + repeated `sandbox::fs::write` calls instead.",
"type": "string"
},
"path": {
"description": "Absolute path inside the sandbox guest where the file lands.",
"type": "string"
}
},
"required": [
"content",
"path"
],
"type": "object"
}
},
"examples": [
{
"code": "console.log('hello world')",
"image": "node",
"lang": "node",
"timeout_ms": 300000
}
],
"properties": {
"code": {
"description": "The actual code to run. Written to a `/tmp/run.{ext}` file inside the sandbox; the chosen interpreter runs that file.",
"type": "string"
},
"env": {
"allOf": [
{
"$ref": "#/definitions/EnvShape"
}
],
"description": "Env vars exposed to the interpreter. Accepts both `Vec<\"K=V\">` and `{ K: V }` map shapes (same as `sandbox::exec.env`)."
},
"files": {
"description": "Optional sibling files (extra source modules, config, fixtures).",
"items": {
"$ref": "#/definitions/RunFile"
},
"type": "array"
},
"image": {
"description": "Catalog name of the image to boot (preset or `custom_images` key). Same value space as `sandbox::create`.",
"type": "string"
},
"keep_sandbox": {
"default": false,
"description": "If true, the sandbox is NOT stopped after the run completes; `sandbox_id` is returned so the caller can poke around. Default false (the sandbox is torn down on either success or failure).",
"type": "boolean"
},
"lang": {
"description": "Selects the interpreter and file extension. Required. Built-in values: `\"node\"`, `\"python\"`, `\"shell\"`. Any other string is treated as a literal interpreter binary path inside the VM and the file is written to `/tmp/run.txt`. There is no default — there's no honest universal answer to \"what language is this code\", and silently defaulting to shell makes Python or JS code produce confusing line-by-line failures.",
"type": "string"
},
"stdin": {
"default": null,
"description": "Base64-encoded bytes piped to the interpreter's stdin.",
"type": [
"string",
"null"
]
},
"timeout_ms": {
"default": null,
"description": "Kill-after window for the interpreter, in ms. Defaults to 300_000 (5 minutes); pass a smaller value to fail fast on quick probes.",
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"required": [
"code",
"image",
"lang"
],
"title": "RunRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"duration_ms": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"sandbox_id": {
"description": "Present only if `keep_sandbox: true` was set on the request. Otherwise null (sandbox auto-stopped).",
"type": [
"string",
"null"
]
},
"stderr": {
"type": "string"
},
"stderr_truncated": {
"description": "As `ExecResponse::stderr_truncated`.",
"type": "boolean"
},
"stdout": {
"type": "string"
},
"stdout_truncated": {
"description": "As `ExecResponse::stdout_truncated`.",
"type": "boolean"
},
"success": {
"type": "boolean"
},
"timed_out": {
"type": "boolean"
}
},
"required": [
"duration_ms",
"stderr",
"stderr_truncated",
"stdout",
"stdout_truncated",
"success",
"timed_out"
],
"title": "RunResponse",
"type": "object"
}
},
{
"description": "Stop and remove a running sandbox. Set `wait: true` to block until the VM process exits and resources are reclaimed.",
"metadata": {},
"name": "sandbox-libkrun::stop",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"sandbox_id": {
"type": "string"
},
"wait": {
"default": false,
"description": "Block until the VM is fully reaped before returning.",
"type": "boolean"
}
},
"required": [
"sandbox_id"
],
"title": "StopRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"sandbox_id": {
"type": "string"
},
"stopped": {
"type": "boolean"
}
},
"required": [
"sandbox_id",
"stopped"
],
"title": "StopResponse",
"type": "object"
}
},
{
"description": "Remove the state of `state_key`'s worker VM. Needs the project token; S502 while that VM is preparing or running.",
"metadata": {},
"name": "sandbox-libkrun::worker::destroy",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Refused while the VM is running.",
"properties": {
"auth": {
"type": "string"
},
"state_key": {
"type": "string"
}
},
"required": [
"auth",
"state_key"
],
"title": "WorkerDestroyRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"destroyed": {
"type": "boolean"
}
},
"required": [
"destroyed"
],
"title": "WorkerDestroyResponse",
"type": "object"
}
},
{
"description": "Stream a worker VM's console log into `channel`, one `LogRecord` JSON per text frame, from `cursor` on; with `follow`, until the instance exits. Needs the project token.",
"metadata": {},
"name": "sandbox-libkrun::worker::logs",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ChannelDirection": {
"enum": [
"read",
"write"
],
"type": "string"
},
"StreamChannelRef": {
"properties": {
"access_key": {
"type": "string"
},
"channel_id": {
"type": "string"
},
"direction": {
"$ref": "#/definitions/ChannelDirection"
}
},
"required": [
"access_key",
"channel_id",
"direction"
],
"type": "object"
}
},
"properties": {
"auth": {
"type": "string"
},
"channel": {
"allOf": [
{
"$ref": "#/definitions/StreamChannelRef"
}
],
"description": "Writer end of a channel Compose created; one `LogRecord` JSON per text frame."
},
"cursor": {
"description": "`LogRecord.cursor` of the last record the caller has; reading resumes right after it. Opaque to Compose: an offset into all the instance logged, valid across a log rotation. A cursor past the end (another instance's) reads from the oldest record kept.",
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"follow": {
"description": "Keep the channel open while the instance runs.",
"type": "boolean"
},
"vm_id": {
"type": "string"
}
},
"required": [
"auth",
"channel",
"follow",
"vm_id"
],
"title": "WorkerLogsRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Returned once the log pump starts; the records travel over the channel.",
"title": "WorkerLogsResponse",
"type": "object"
}
},
{
"description": "Validate a worker VM's source and pull its base image; idempotent. Needs the project token in `auth`, and `host_path` under the host roots.",
"metadata": {},
"name": "sandbox-libkrun::worker::prepare",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"WorkerSource": {
"description": "Where the worker's code comes from.",
"oneOf": [
{
"properties": {
"host_path": {
"description": "The bundle in Compose's package cache.",
"type": "string"
},
"kind": {
"enum": [
"bundle"
],
"type": "string"
},
"package": {
"description": "Manifest name, not the container key.",
"type": "string"
}
},
"required": [
"host_path",
"kind",
"package"
],
"type": "object"
},
{
"description": "Local sources always sync into the VM.",
"properties": {
"host_path": {
"type": "string"
},
"kind": {
"enum": [
"local"
],
"type": "string"
},
"run_override": {
"type": [
"string",
"null"
]
}
},
"required": [
"host_path",
"kind"
],
"type": "object"
}
]
}
},
"description": "Idempotent image and base-layer pull; long-running.",
"properties": {
"auth": {
"description": "Per-project token.",
"type": "string"
},
"source": {
"$ref": "#/definitions/WorkerSource"
}
},
"required": [
"auth",
"source"
],
"title": "WorkerPrepareRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "WorkerPrepareResponse",
"type": "object"
}
},
{
"description": "Boot the worker VM of `state_key` as its next instance. Needs the project token; S502 while that VM is preparing or running.",
"metadata": {},
"name": "sandbox-libkrun::worker::start",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"WorkerSource": {
"description": "Where the worker's code comes from.",
"oneOf": [
{
"properties": {
"host_path": {
"description": "The bundle in Compose's package cache.",
"type": "string"
},
"kind": {
"enum": [
"bundle"
],
"type": "string"
},
"package": {
"description": "Manifest name, not the container key.",
"type": "string"
}
},
"required": [
"host_path",
"kind",
"package"
],
"type": "object"
},
{
"description": "Local sources always sync into the VM.",
"properties": {
"host_path": {
"type": "string"
},
"kind": {
"enum": [
"local"
],
"type": "string"
},
"run_override": {
"type": [
"string",
"null"
]
}
},
"required": [
"host_path",
"kind"
],
"type": "object"
}
]
}
},
"description": "Boots the VM. The adapter reads resources from the worker's manifest.",
"properties": {
"auth": {
"description": "Per-project token.",
"type": "string"
},
"engine_url": {
"description": "The engine's URL as seen from the host.",
"type": "string"
},
"env": {
"additionalProperties": {
"type": "string"
},
"description": "Complete guest env. Never on the `__vm-boot` argv: the adapter writes it to `__vm-boot`'s stdin, which sends it to the guest init over the `iii.env` virtio-console port, not the kernel cmdline (only a build without an embedded init still uses the cmdline).",
"type": "object"
},
"source": {
"$ref": "#/definitions/WorkerSource"
},
"state_key": {
"description": "Hash of the compose state dir and container key; the same key gets the same persistent upper.",
"type": "string"
},
"worker_name": {
"description": "Container key; becomes `III_WORKER_NAME`.",
"type": "string"
}
},
"required": [
"auth",
"engine_url",
"env",
"source",
"state_key",
"worker_name"
],
"title": "WorkerStartRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"instance": {
"description": "Increments on every boot of this `vm_id`.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"vm_id": {
"description": "Opaque; stable per `state_key`.",
"type": "string"
}
},
"required": [
"instance",
"vm_id"
],
"title": "WorkerStartResponse",
"type": "object"
}
},
{
"description": "State of one worker VM instance. Needs the project token.",
"metadata": {},
"name": "sandbox-libkrun::worker::status",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"auth": {
"type": "string"
},
"instance": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"vm_id": {
"type": "string"
}
},
"required": [
"auth",
"instance",
"vm_id"
],
"title": "WorkerStatusRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"State": {
"enum": [
"preparing",
"running",
"exited",
"stopped",
"unknown"
],
"type": "string"
}
},
"description": "Reply of `worker::status` and `worker::stop`.",
"properties": {
"ended_at_ms": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"instance": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"signal": {
"description": "The signal that ended the VM, if one did.",
"format": "int32",
"type": [
"integer",
"null"
]
},
"started_at_ms": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"state": {
"$ref": "#/definitions/State"
},
"vm_id": {
"type": "string"
}
},
"required": [
"instance",
"started_at_ms",
"state",
"vm_id"
],
"title": "WorkerStatus",
"type": "object"
}
},
{
"description": "SIGTERM a worker VM instance, then SIGKILL after `grace_ms` (0 kills at once); returns its final status. Needs the project token.",
"metadata": {},
"name": "sandbox-libkrun::worker::stop",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Idempotent; `grace_ms: 0` kills. Replies with the final `WorkerStatus`.",
"properties": {
"auth": {
"type": "string"
},
"grace_ms": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"instance": {
"description": "Names the boot to stop, so a stale stop cannot hit a newer one.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"vm_id": {
"type": "string"
}
},
"required": [
"auth",
"grace_ms",
"instance",
"vm_id"
],
"title": "WorkerStopRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"State": {
"enum": [
"preparing",
"running",
"exited",
"stopped",
"unknown"
],
"type": "string"
}
},
"description": "Reply of `worker::status` and `worker::stop`.",
"properties": {
"ended_at_ms": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"instance": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"signal": {
"description": "The signal that ended the VM, if one did.",
"format": "int32",
"type": [
"integer",
"null"
]
},
"started_at_ms": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"state": {
"$ref": "#/definitions/State"
},
"vm_id": {
"type": "string"
}
},
"required": [
"instance",
"started_at_ms",
"state",
"vm_id"
],
"title": "WorkerStatus",
"type": "object"
}
}
],
"triggers": []
}