Environment variables
Kasm Session Runtime takes its run contract from the environment: which app, which model endpoint, where the output goes, how long the run may take, and how it can be reached. They are set by whoever launches the run, whether an orchestrator, a CI job, a Kasm workspace’s environment settings or a person at a shell.
The runtime’s own variables start with KASM_RUNTIME_. The exceptions are KASM_SESSION_RUNTIME_PORT, KASM_ENABLE_CDP and DISPLAY.
Value parsing
Section titled “Value parsing”- Booleans take these spellings:
1,t,T,TRUE,true,True, and0,f,F,FALSE,false,False. Anything else logs a warning and the variable is treated as unset. - An empty variable counts as unset, except for the list variables noted below, where setting a variable to nothing clears the list.
- Some bad values stop the run before it starts; the rows say which. Every other bad value logs a warning and keeps the default.
KASM_RUNTIME_CONFIG_STRICT=truemakes those warnings fatal too.
Run settings
Section titled “Run settings”| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_APP |
required for run |
Names the app under test. Fills in the scenario’s app, window and process when the scenario leaves them out, and names the report. Under mcp it is optional and defaults to session |
Always, for run and the no-argument invocation |
KASM_RUNTIME_SCENARIO_B64 |
empty | The scenario YAML, base64-encoded, for the no-argument invocation. Empty means the default scenario: launch, settle, one observation, verdict, no steps. Under mcp it only supplies declared names. run ignores it |
When the orchestrator cannot mount a scenario file |
KASM_RUNTIME_OUT |
/testbench/out |
The directory the report, trace, screenshots, log tails and DONE are written to. Must be writable |
When the host mounts output somewhere else |
KASM_RUNTIME_BASELINE |
/testbench/baseline |
A read-only directory of known-good screenshots (good-*.png or good-*.jpg). It may be missing; the run then saves a candidate for a person to promote |
When baselines live elsewhere |
KASM_RUNTIME_DEADLINE_S |
600 |
The run’s time limit in seconds. The last timing.lifecycle.wrap_up_reserve_s (30 by default) is kept for diagnosis and the report. Under run it bounds all the scenario files together. Under mcp there is no limit unless you set this. Not a positive integer: fatal |
Raise it for long installs or remediation loops, lower it to fail fast in CI, set it under mcp for a maximum server lifetime |
DISPLAY |
:1 |
The X display to capture from and inject into | Only when the session’s display is not :1 |
Vision model settings
Section titled “Vision model settings”A model is optional. With KASM_RUNTIME_VISION_ENDPOINT empty the runtime runs in deterministic-only mode: the window and process probes own the verdict, screenshots are still taken, and a step that needs visual judgement is recorded as not judged. Scripted steps, cdp_* browser steps, postconditions other than screen, plans, and an outside agent driving the session over MCP all work without one. A goal: scenario, click_grounded, and the model-backed MCP methods need one. See When you need a model.
The same endpoint is used for judging screenshots, for locating things on screen and for the runtime’s own agent loop. Any OpenAI-compatible chat-completions server works, local or hosted.
| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_VISION_ENDPOINT |
empty | Base URL of an OpenAI-compatible server, for example http://host:8001/v1. Empty means deterministic-only mode |
Whenever runs should judge screenshots, ground clicks or pursue a goal |
KASM_RUNTIME_VISION_MODEL |
qwen3-vl-4b |
The model name sent with each request. It implies nothing about image shape or answer format | When the server hosts another model |
KASM_RUNTIME_VISION_API_KEY |
empty | Sent as Authorization: Bearer <key>. Never logged; redacted from every report and trace |
Only for a hosted API that needs a key |
KASM_RUNTIME_VISION_CAPTURE_GEOMETRY |
native |
The shape of the screenshot sent to the model: native sends the session’s pixels as captured, square-padded centres them on a black square. Any other value: fatal |
When changing model family. See Vision models |
KASM_RUNTIME_VISION_ANSWER_CONVENTION |
point |
What the model is asked to return when locating something: a point or a box2d bounding box. Any other value: fatal |
Same as above |
KASM_RUNTIME_VISION_GROUNDING_SCALE |
1000 |
The size of the normalised grid the model answers in, on each axis: coordinates run from 0 to this number. A wrong value produces no error. The clicks land in the wrong place instead. Not a positive integer: fatal | Only for a model family that grounds in another range. Check the model card |
The three vision-format settings are independent of the model name, so any model can use any combination.
Browser connection settings
Section titled “Browser connection settings”| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_CDP_ENDPOINT |
http://127.0.0.1:9222 |
The browser’s Chrome DevTools Protocol HTTP endpoint, used by scenarios with cdp: true. Must be a loopback address unless the next variable is set; otherwise fatal |
Only when the browser listens on another port |
KASM_RUNTIME_CDP_ALLOW_REMOTE |
false |
Permits a DevTools endpoint that is not on the loopback interface. The runtime still refuses redirects and targets advertised on a different host | Only when deliberately driving a browser in another container |
Operator tuning
Section titled “Operator tuning”| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_CONFIG_FILE |
empty | Path to the operator file. A named file that cannot be read or decoded is fatal | When a deployment tunes loop budgets, sampling, reply caps, timing or evidence sizes |
KASM_RUNTIME_CONFIG_STRICT |
false |
Makes every configuration warning fatal, listing them all | In CI, and wherever running on a default you did not choose is worse than not running |
Every operator-file leaf also has its own override, listed below.
MCP, HTTP and the sidebar
Section titled “MCP, HTTP and the sidebar”These apply to mcp and to the read-only observe routes the in-session sidebar watches.
| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_SESSION_TOKEN |
empty | Switches mcp from stdio to HTTP. Every acting request (MCP methods, the HTTP API, the DevTools proxy) must carry it in the X-Kasm-Runtime-Session-Token header. Redacted from every report and trace |
When a caller outside the container drives the session through Kasm’s port map |
KASM_SESSION_RUNTIME_PORT |
9434 |
The port the HTTP transport and the observe listener bind. Note the word order. Not a port number: warning, default kept | Only when the workspace’s port map registers another port |
KASM_RUNTIME_BIND_ADDR |
0.0.0.0 |
The interface those listeners bind. Kasm’s port-map proxy needs the default | 127.0.0.1 when a proxy on the same host fronts the runtime |
KASM_RUNTIME_OBSERVE |
false |
Under run and the no-argument invocation, also serve GET /events (a live copy of trace.jsonl) and GET /artifacts/<file> (the output directory) for the run’s lifetime. mcp serves them whenever HTTP is on |
When the sidebar or another viewer should watch a scripted or agentic run |
KASM_RUNTIME_OBSERVE_TOKEN_REQUIRED |
false |
Makes the observe routes and inbox reads require the session token or the inbox token, from the header or a token query parameter. With neither token set they refuse every request |
When the port is reachable from other containers or hosts |
KASM_RUNTIME_OBSERVE_INPUT |
false |
Records every key and button event the session receives, from any source, as input trace events. Key events carry no key or text while the runtime itself is typing. Forces KASM_RUNTIME_OBSERVE_TOKEN_REQUIRED on |
When a test drives the session from outside and needs proof its input arrived |
KASM_RUNTIME_INBOX_TOKEN |
empty | The messaging credential for the human-in-the-loop routes: post messages and replies, upload attachments, and issue stop and finish_handoff. With neither this nor the session token set, there is no inbox. Redacted from every report and trace |
When a person or a backend should be able to talk to a running run. See People in the loop |
KASM_ENABLE_CDP |
false |
Under mcp over HTTP, also mounts a raw DevTools proxy at /cdp/, gated by the session token. Ignored, with a log line, without a session token |
When a client such as Playwright needs the whole protocol |
KASM_RUNTIME_MCP_LOCALHOST_PROTECTION |
false |
Makes /mcp require a localhost Host header, a guard against DNS rebinding. Kasm’s proxy never sends one, so turning this on behind the proxy rejects every request |
Only when serving /mcp directly to a browser on the same machine |
KASM_RUNTIME_UPLOAD_MAX_BYTES |
1G |
The most one upload may carry (PUT /v1/files/, or a PUT /v1/dirs/ archive as sent). A byte count or a K, M or G binary suffix. Not a positive size: fatal |
When larger files must go in |
KASM_RUNTIME_EXTRACT_MAX_BYTES |
1G |
The most one uploaded archive may extract to. Same format and rule | When archives legitimately expand beyond it |
The routes are in HTTP API, MCP methods and Sidebar protocol.
Secrets and redaction
Section titled “Secrets and redaction”A scenario references a secret as $NAME in a type step, a cdp_fill value or a provides: value. The runtime expands it when the step runs. See Secrets and evidence.
| Variable | Default | What it does | When to change it |
|---|---|---|---|
KASM_RUNTIME_SECRET_* |
none | Any variable with this prefix is a secret: its value is replaced with [REDACTED] in the report, the trace and log output |
Name every credential a scenario types this way |
KASM_RUNTIME_REDACT_ENV |
empty | A comma-separated list of further variable names whose values are redacted the same way. Names only; the values are never logged | When an orchestrator injects a credential under a name of its own |
VNC_PW and VNC_VIEW_ONLY_PW, the vision API key, the session token and the inbox token are always redacted. Screenshots are not redacted: a secret visible on screen is in the image.
Provided by the session
Section titled “Provided by the session”The runtime reads these when the session provides them. There is nothing to set.
| Variable | What the runtime does with it |
|---|---|
KASM_ID |
Set by Kasm in every session. The DevTools proxy needs it to give out addresses that work from outside |
DBUS_SESSION_BUS_ADDRESS |
Where the session bus is, for reaching applications over AT-SPI. The runtime can find the bus without it |
XAUTHORITY |
Read by input observation |
Read by the image’s scripts
Section titled “Read by the image’s scripts”The image reads these before the viewer starts. The runtime binary ignores them.
| Variable | Default | What it does |
|---|---|---|
KASM_RUNTIME_SIDEBAR |
empty | Selects a named sidebar installed beside the stock viewer. Empty or unknown means the stock viewer |
KASM_SIDEBAR_ROOT |
/usr/share/kasmvnc-sidebars |
Where named sidebars are installed |
See Replace the sidebar.
Operator-file overrides
Section titled “Operator-file overrides”Each leaf of the operator file can be set on its own as KASM_RUNTIME_<BLOCK>_<FIELD>, upper-cased, with nested blocks joined the same way. The environment wins over the file, and the file over the default. Defaults and meanings are on the operator-file page. List leaves take comma-separated values, and setting one to nothing clears it.
| Block | Variables |
|---|---|
runner |
KASM_RUNTIME_RUNNER_MAX_ITERATIONS, KASM_RUNTIME_RUNNER_MAX_RETRIES_PER_STEP, KASM_RUNTIME_RUNNER_MAX_TOOL_ERRORS, KASM_RUNTIME_RUNNER_REASONING_REPLAY, KASM_RUNTIME_RUNNER_RESCUE_ENABLED, KASM_RUNTIME_RUNNER_RESPOND, KASM_RUNTIME_RUNNER_MAX_HOLD_S, KASM_RUNTIME_RUNNER_ESCALATION_PAUSE_S, KASM_RUNTIME_RUNNER_GROUNDING_ATTEMPTS, KASM_RUNTIME_RUNNER_MAX_CONTEXT_RECOVERIES, KASM_RUNTIME_RUNNER_WAIT_TOOL_MAX_S, KASM_RUNTIME_RUNNER_ASK_HUMAN_BUDGET_S, KASM_RUNTIME_RUNNER_ASK_HUMAN_TIMEOUT_S |
sampling |
KASM_RUNTIME_SAMPLING_TEMPERATURE, KASM_RUNTIME_SAMPLING_TOP_P, KASM_RUNTIME_SAMPLING_TOP_K, KASM_RUNTIME_SAMPLING_MIN_P |
function_calling |
KASM_RUNTIME_FUNCTION_CALLING |
context |
KASM_RUNTIME_CONTEXT_STRATEGY, KASM_RUNTIME_CONTEXT_BUDGET_TOKENS, KASM_RUNTIME_CONTEXT_KEEP_RECENT, KASM_RUNTIME_CONTEXT_PHASE_THRESHOLDS (list), KASM_RUNTIME_CONTEXT_WARN_AT (list), KASM_RUNTIME_CONTEXT_CHARS_PER_TOKEN, KASM_RUNTIME_CONTEXT_COMPACT_TRUNCATE_CHARS |
max_tokens |
KASM_RUNTIME_MAX_TOKENS_JUDGE, KASM_RUNTIME_MAX_TOKENS_TOOLS |
model |
KASM_RUNTIME_MODEL_TIMEOUT_S, KASM_RUNTIME_MODEL_ATTEMPTS, KASM_RUNTIME_MODEL_BACKOFF_S, KASM_RUNTIME_MODEL_DISABLE_AFTER |
baseline |
KASM_RUNTIME_BASELINE_SIMILAR_MAX, KASM_RUNTIME_BASELINE_DRIFTED_MAX |
findings |
KASM_RUNTIME_FINDINGS_UPDATER_MARKERS (list), KASM_RUNTIME_FINDINGS_FIRST_RUN_MARKERS (list), KASM_RUNTIME_FINDINGS_ERROR_DIALOG_MARKERS (list) |
timing.input |
KASM_RUNTIME_TIMING_INPUT_ACTIVATE_SETTLE_MS, KASM_RUNTIME_TIMING_INPUT_KEYSTROKE_MS, KASM_RUNTIME_TIMING_INPUT_CLICK_MS, KASM_RUNTIME_TIMING_INPUT_CHORD_SETTLE_MS |
timing.settle |
KASM_RUNTIME_TIMING_SETTLE_POLL_MS, KASM_RUNTIME_TIMING_SETTLE_MAX_CHANGED_FRACTION, KASM_RUNTIME_TIMING_SETTLE_MAX_S, KASM_RUNTIME_TIMING_SETTLE_POST_POLL_MS, KASM_RUNTIME_TIMING_SETTLE_KILL_SETTLE_MS |
timing.cdp |
KASM_RUNTIME_TIMING_CDP_DIAL_S, KASM_RUNTIME_TIMING_CDP_CALL_S, KASM_RUNTIME_TIMING_CDP_RESOLVE_S, KASM_RUNTIME_TIMING_CDP_POLL_MS, KASM_RUNTIME_TIMING_CDP_DEFAULT_WAIT_S, KASM_RUNTIME_TIMING_CDP_READ_LIMIT_MIB |
timing.atspi |
KASM_RUNTIME_TIMING_ATSPI_PROBE_BUDGET_S, KASM_RUNTIME_TIMING_ATSPI_PROBE_APP_WAIT_S, KASM_RUNTIME_TIMING_ATSPI_APP_WAIT_AFTER_ENABLE_S, KASM_RUNTIME_TIMING_ATSPI_ACTION_BUDGET_S, KASM_RUNTIME_TIMING_ATSPI_ACTION_APP_WAIT_S, KASM_RUNTIME_TIMING_ATSPI_MAX_NODES, KASM_RUNTIME_TIMING_ATSPI_MAX_DEPTH, KASM_RUNTIME_TIMING_ATSPI_MAX_ACTIONABLE |
timing.lifecycle |
KASM_RUNTIME_TIMING_LIFECYCLE_RUN_BOOT_TIMEOUT_S, KASM_RUNTIME_TIMING_LIFECYCLE_MCP_BOOT_TIMEOUT_S, KASM_RUNTIME_TIMING_LIFECYCLE_WRAP_UP_RESERVE_S, KASM_RUNTIME_TIMING_LIFECYCLE_WINDOW_ONLY_GRACE_S, KASM_RUNTIME_TIMING_LIFECYCLE_CRASH_RECHECK_DWELL_S, KASM_RUNTIME_TIMING_LIFECYCLE_CRASH_RESCAN_S |
evidence |
KASM_RUNTIME_EVIDENCE_SHELL_OUTPUT_CHARS, KASM_RUNTIME_EVIDENCE_TOOL_RESULT_CHARS, KASM_RUNTIME_EVIDENCE_PAGE_TEXT_CHARS, KASM_RUNTIME_EVIDENCE_PAGE_ELEMENTS, KASM_RUNTIME_EVIDENCE_ELEMENT_TEXT_CHARS, KASM_RUNTIME_EVIDENCE_LISTED_CANDIDATES, KASM_RUNTIME_EVIDENCE_ACCESSIBLE_NAME_CHARS, KASM_RUNTIME_EVIDENCE_LOG_TAIL_LINES, KASM_RUNTIME_EVIDENCE_REPORT_LOG_LINES, KASM_RUNTIME_EVIDENCE_JPEG_QUALITY, KASM_RUNTIME_EVIDENCE_TRACE_REPLAY_EVENTS, KASM_RUNTIME_EVIDENCE_INBOX_MESSAGE_CHARS, KASM_RUNTIME_EVIDENCE_INBOX_ATTACHMENT_BYTES, KASM_RUNTIME_EVIDENCE_INBOX_CONTEXT_CHARS, KASM_RUNTIME_EVIDENCE_INBOX_SUMMARY_CHARS, KASM_RUNTIME_EVIDENCE_INBOX_DRAIN_MAX |
tools |
KASM_RUNTIME_TOOLS_DISABLED (list) |
Legacy TESTBENCH_* names
Section titled “Legacy TESTBENCH_* names”Every KASM_RUNTIME_<NAME> variable is also accepted as TESTBENCH_<NAME>, and TESTBENCH_SECRET_* is redacted like KASM_RUNTIME_SECRET_*. The modern name wins when both are set. KASM_SESSION_RUNTIME_PORT, KASM_ENABLE_CDP and DISPLAY have no legacy form.
Every legacy name a run used is listed in report.json under agent.legacy_env and called out in report.md.