Skip to content

Configuration

Status: 2026-09-19. Living document.

Configure command options, provider credentials, console settings and run storage separately. Each section below gives its precedence rules.

executionProfile selects the local execution boundary, not the LLM backend. The operator-global setting is local by default for existing installations. Choose smolvm after provisioning the online Kali workbench:

Terminal window
0 workbench setup --image /absolute/path/0-workbench-linux-arm64.tar \
--provider openai --provider chatgpt-codex
0 workbench status --json
0 console

The native runtime is currently qualified for Apple Silicon macOS. Setup downloads and verifies the pinned signed SmolVM bundle, preserving its runtime layout, and approves a digest-pinned local image archive. An initial image is an explicit operator choice (--image); an archive discovered in a checkout or a mutable registry tag is never silently trusted. Re-running setup and normal launches resolve the saved approved image automatically. Approved archives are limited to 8 GiB for both the main guest and broker siblings. This compressed-archive ceiling is separate from guest storage.

Setup optionDefaultEffect
--image <archive>saved approved imageExplicit local OCI/Docker archive approval
--state <directory>~/.0/workbenchPrivate runtime, image approval, guest state and admission
--workspace <directory>invocation’s current directorySelected host workspace mounted at guest /workspace
--provider <id>no host provider grantsRepeat to grant selected provider accounts; list IDs with workbench providers
--github / --no-githubnot grantedExplicit token grant from GH_TOKEN, GITHUB_TOKEN, or existing gh authentication
--cpus <count>2Virtual CPUs
--memory <MiB>4096Guest RAM
--storage <GiB>20VM-owned writable storage
--sandbox-image <reference=archive>no additional imagesRepeat to approve a full repository@sha256:<64hex> identity for isolated container actions

Operator choices live in the private, owner-only ~/.0/workbench.json; credential values are not persisted there or displayed by status. Granted provider values are resolved only when launching. Ungranted accounts, host HOME, SSH authority, Docker sockets and unrelated environment variables are not forwarded. You may authenticate a provider directly inside the guest instead.

Guest preferences preserve the more restrictive of saved sharing consent and explicit environment policy. DO_NOT_TRACK and ZERO_NO_TELEMETRY keep analytics and problem reports off without disabling ordinary workbench networking. Reporting endpoints, account/API authority and unrelated environment values are not copied into guest configuration.

Guest 0 receives the original argument array and stdin/stdout/stderr, with its working directory at /workspace and private HOME at /home/zero. Use paths relative to the selected workspace. The whole console, child agents and tools execute in that guest. Networking is online by default. An explicitly enabled ZERO_OFFLINE starts it without networking and keeps analytics/problem reports off; workbench status shows the effective mode. This does not widen the separate offline evolution/sandbox policy or substitute an offline sandbox for the online workbench profile. Broker siblings copy their bounded source snapshot into fresh, guest-owned /tmp/0-workspace scratch and return verified artifacts from there. They never receive the main guest’s writable /workspace mount or provider credentials.

Container/reproduction actions that request another image use an explicit operator-owned catalog, not a guest-selected archive or registry pull:

Terminal window
0 workbench configure --sandbox-image \
'registry.example/security/runner@sha256:<64hex>=/absolute/path/runner.tar'
0 workbench configure --clear-sandbox-images

The operator asserts that this immutable OCI identity corresponds to that local archive. Setup also digest-pins the archive bytes, a distinct digest from the OCI identity. Only the approved reference and archive digest enter guest admission; host archive paths and environment authority stay host-side. Unknown explicit references are refused. Adding an image grant does not enable mutable tags, nested Docker/KVM, host sockets or unrestricted code execution in the credential-bearing console guest.

Setup and status also show the isolated-action broker’s concrete hard ceilings: 4 MiB workspace/source, 256 files, 1 MiB stdin, 1 MiB output, 2 simultaneous jobs, 256 requests per workbench lifetime, 600 seconds, 2 CPUs and 2048 MiB RAM. These are separate from the outer workbench’s resource options. A workflow’s larger source/output limit does not raise this transport boundary; oversized inputs are refused rather than silently falling back to another execution backend.

0 workbench configure --provider openai,anthropic --no-github replaces grants; --provider none revokes host provider grants. --current-workspace removes a fixed workspace choice. 0 workbench status is read-only and never provisions or downloads. Runtime, image, admission or cleanup failures refuse execution rather than falling back to host or Docker. Retained admission remains visible in status. A subsequent launch recovers it only under the native admission lock with successful cleanup proof; missing or failed proof still refuses launch. 0 workbench disable is an explicit return to the local profile; it retains the approved image and guest state.

A configured workbench requires an explicit valid operator execution profile. Missing or malformed profile settings refuse launch instead of resetting the choice to host-local. Use 0 workbench setup or 0 workbench disable to repair that selection explicitly; ordinary display settings retain their normal defaulting behavior.

The host workbench and config management commands stay available to repair configuration. Project settings cannot select, disable or override this operator-owned execution boundary. Changing the settings-screen profile takes effect at the next process launch and does not retroactively isolate a running host session.

--runtime selects the LLM backend.

RuntimeFlagDescription
api--runtime apiDirect HTTP calls to a configured provider.
claude--runtime claudeSpawns the authenticated Claude Code CLI; capabilities depend on the workflow and installed CLI.
codex--runtime codexUses the Codex CLI for source review. For live target scans, routes to the direct ChatGPT Codex provider when ZERO_CHATGPT_OAUTH_REFRESH_TOKEN is configured.
gemini--runtime geminiSpawns the authenticated Gemini CLI for source-oriented work.
auto--runtime autoResolve an available runtime for the selected workflow. Default for scan, review, and audit.
ollama--runtime ollamaLocal Ollama /api/chat runtime, exposed by review; requires an available tool-calling model.

The api runtime makes direct HTTP calls to a provider. Set one of:

Terminal window
# API-key providers can be exported normally.
export OPENROUTER_API_KEY="sk-or-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export AZURE_OPENAI_API_KEY="..."
export OPENAI_API_KEY="sk-..."
export DEEPSEEK_API_KEY="..."
export Z_AI_API_KEY="..."
export KIMI_API_KEY="..."
export QWEN_API_KEY="..."
export XAI_API_KEY="..."
export OPENCODE_API_KEY="..."
export CLINE_API_KEY="..."
# `ZERO_*` names begin with a digit; pass a Codex token with env.
env ZERO_CHATGPT_OAUTH_REFRESH_TOKEN="..." 0 doctor

See API Keys for the full provider list, default models, and credential priority.

For Azure, configure an explicit endpoint and deployment. Ambient API routing can also read an Azure-backed ~/.codex/config.toml; explicit provider pinning and fallback routes require an environment endpoint. For the Responses API, include /openai/v1. See Azure setup for precedence and a complete pinned example.

For ChatGPT Codex, run codex login, then either rely on ~/.codex/auth.json or supply an explicit access/refresh token with env. Codex auth leads the ambient API credential order, but an explicit provider pin or recognized model with its own configured provider can override it.

Use --runtime api when you specifically want these HTTP provider rules rather than workflow-dependent auto selection. Model selection is not runtime selection: --model alone does not require auto to choose the API runtime.

These spawn the respective CLI as a subprocess — install and authenticate it first:

Terminal window
# Claude Code CLI
npm i -g @anthropic-ai/claude-code
# Codex CLI
npm i -g @openai/codex
# Gemini CLI
npm i -g @google/gemini-cli

Then use them:

Terminal window
0 scan --target https://api.example.com/chat --scope ./scope.json --runtime claude
0 review ./my-repo --runtime codex --depth deep

The Codex CLI isn’t used as a live-target wrapper. For live scans on a Codex subscription, configure the direct provider instead:

Terminal window
env ZERO_CHATGPT_OAUTH_REFRESH_TOKEN="..." \
0 scan --target https://example.com --scope ./scope.json --runtime codex

Codex routing depends on the entry point and credentials. Source review can use the authenticated CLI; live-target subscription calls use the direct provider.

SurfaceCommandSupported via direct provider
Web / URL scan0 scan --target https://example.com --scope ./scope.json --runtime codexyes
npm package audit0 audit lodash --ecosystem npm --runtime codexyes
PyPI package audit0 audit requests --ecosystem pypi --runtime codexyes
crates.io package audit0 audit tokio --ecosystem cargo --runtime codexyes
OCI image audit0 audit nginx:1.25 --ecosystem oci --runtime codexyes
Default source-code review0 review ./repo --runtime codexyes
Linux kernel review0 review ./linux --profile linux-kernel --runtime codexyes
C/C++ library review0 review ./lib --profile c-library --runtime codexyes

Managed runtime availability follows the separate 0cloud deployment policy.

Start your Ollama server and provision a tool-calling model before running:

Terminal window
OLLAMA_HOST=http://localhost:11434 \
0 review ./authorized-repo --runtime ollama --model gemma4:27b

The runtime uses --model, then ZERO_OLLAMA_MODEL, then gemma4:27b. OLLAMA_HOST defaults to http://localhost:11434. A remote host sends source context to that server; a local model is not a guarantee that every tool or optional integration stays offline.

--mode controls what kind of target is scanned.

ModeDescription
deepAgentic LLM/AI-target probing; select explicitly for an HTTP endpoint that should not use web mode.
probeLightweight surface scan — recon and fingerprinting without deep exploitation.
webShell-first web application assessment. The automatic mode for HTTP/HTTPS targets passed to scan.
mcpScan MCP (Model Context Protocol) servers for tool poisoning and schema abuse. Default when the target starts with mcp://.
http_auditWorker-driven authenticated HTTP assessment using operator-provided ZERO_TARGET_* configuration.
Terminal window
# LLM API assessment: select deep mode explicitly.
0 scan --target https://api.example.com/chat --scope ./scope.json --mode deep
# Web application assessment.
0 scan --target https://example.com --scope ./scope.json --mode web

--depth controls how thorough the scan is.

DepthUse
quickShorter investigation budget
defaultNormal workflow budget
deepLarger investigation budget

These are not fixed test-case counts or guaranteed completion times. See Budget Management for the budget mechanisms.

Terminal window
0 scan --target https://api.example.com/chat --scope ./scope.json --mode deep --depth quick
0 audit express --depth deep
0 review ./my-repo --depth deep --runtime claude

Set with --format:

FormatDescription
terminalHuman-readable terminal summary
htmlRich browser report saved to a temporary file
pdfPrintable report saved to a temporary file
jsonMachine-readable JSON output for pipelines
sarifSARIF format for the GitHub Security tab
md / markdownHuman-readable Markdown report (md is the CLI alias)

For GitHub Code Scanning, run the CLI with --format sarif and upload the result with github/codeql-action/upload-sarif. A dedicated 0 composite action has not shipped; use the complete GitHub CI workflow.

Review only changed files against a base branch — handy in CI to skip scanning the whole codebase on every PR:

Terminal window
0 review ./my-repo --diff-base origin/main --changed-only

--verbose shows detailed agent output:

Terminal window
0 scan --target https://api.example.com/chat --scope ./scope.json --verbose

Enable metadata-only operational records on stderr:

Terminal window
env ZERO_LOG_FORMAT=json 0 review ./my-repo

Each NDJSON record contains timestamp, level, service, event, and allowlisted lifecycle or cost metadata. Prompts, responses, reasoning, tool arguments/results, finding evidence, summaries and raw error text are excluded from these records. Credential-like values in retained identifiers are redacted.

This adds records alongside existing stderr diagnostics; it does not make all stderr output JSON or replace --format. Stdout and the ZERO_EVENT_* cloud relay protocol are unchanged. Unset ZERO_LOG_FORMAT to disable the sink; only the json format enables it. These operational log records are not uploaded automatically; collect stderr through your runner or container logging pipeline.

Analytics sharing is opt-in and starts at off. Optional /onboard setup and /settings → Data sharing offer only off and usage. Skipping setup does not grant consent or change a saved choice. Saved legacy commands and full console choices migrate to usage; an existing opt-out remains off.

ChoiceCollected records
offNo analytics uploads
usageFeature/finding counters, finite error categories, turns, duration and available cost totals; no tool arguments/results, code, scope or finding content

The preference is operator-global; project settings cannot broaden it. An explicit ZERO_ANALYTICS_LEVEL can restrict it. ZERO_OFFLINE, ZERO_NO_TELEMETRY, or DO_NOT_TRACK forces analytics off when set to a non-empty value other than 0, false, or no.

Terminal window
env ZERO_ANALYTICS_LEVEL=off 0 console
env ZERO_ANALYTICS_LEVEL=usage 0 scan https://authorized.example

Usage goes through the configured first-party Cloud host’s /api/cli-analytics receiver, using an explicitly supplied ZERO_CLOUD_TOKEN with analytics:submit. ZERO_CLOUD_HOST can select an operator-provided deployment. The CLI does not contact PostHog directly or need a PostHog key. The Cloud receiver can export usage-only aggregates to PostHog when its deployment provides POSTHOG_PROJECT_TOKEN and POSTHOG_CAPTURE_HOST; vendor configuration is separate from CLI consent and credentials.

The first-party envelope includes the running CLI version and finite OS, architecture and runtime labels. Authenticated delivery and random install/session identifiers are not anonymity. The inspected Cloud vendor adapter exports allowlisted counter buckets, not tool/code content, and does not currently forward CLI release, source revision or development/production labels to PostHog. Those vendor properties require a corresponding Cloud deployment change; CLI configuration alone cannot supply them.

Consent is checked again before every POST. Lowering it discards disallowed pending records; re-enabling does not replay those discarded records. Post-redaction payloads attempted over HTTP are recorded in ~/.0/analytics-sent.log; that log is not proof of server acceptance. Analytics consent does not grant automatic problem-report consent or broaden diagnostic content. Run contributions have their own enrollment below.

/feedback <message> is local-only and appends to ~/.0/feedback.md. With ZERO_CLOUD_TOKEN explicitly configured, staged feedback defaults to the configured Cloud host’s authenticated /api/cli-feedback receiver. It attributes the message to the token’s organization and delivers through the existing team-feedback channel. Ask the operator for a token with feedback:submit if an older grant lacks that scope. ZERO_CLOUD_HOST can select an agreed service host.

Use /feedback submit <message> to save locally and inspect the exact endpoint, JSON body, headers, and secret-shaped-content warnings. Only a second /feedback send transmits that exact staged payload; /feedback cancel drops the pending network action while retaining the local file.

ZERO_FEEDBACK_URL overrides the cloud receiver for a self-hosted HTTPS relay:

Terminal window
env ZERO_FEEDBACK_URL="https://feedback.example.org/v1/feedback" 0 console

Do not place an incoming Slack webhook URL directly in the CLI environment: it is a bearer secret and does not accept 0’s feedback wire schema. ZERO_OFFLINE, ZERO_NO_TELEMETRY, and DO_NOT_TRACK block every submission before any connection is made.

The console’s Problem reports setting defaults to ask. After a tool or runtime problem, it can stage a limited diagnostic summary for review; nothing is submitted without confirmation. Saved automatic or off choices remain effective. This is separate from operational stderr logs and manually staged /feedback messages.

Use /feedback → Problem-report preferences to select off, ask, or automatic. The preference is global to this computer; project settings cannot override it. An explicit saved opt-out remains off after upgrading. ZERO_OFFLINE, ZERO_NO_TELEMETRY, and DO_NOT_TRACK still block submission.

With an explicitly configured ZERO_SENTRY_DSN, diagnostic reports use that operator-provisioned CLI Sentry project’s HTTPS envelope endpoint. There is no built-in DSN and no fallback to dashboard/server/browser Sentry configuration. Invalid, credential-secret-bearing or non-HTTPS DSNs are refused rather than silently rerouted. Provision a CLI project and distribute its approved DSN to enable this destination; merely enabling Problem reports does not provision Sentry.

When ZERO_SENTRY_DSN is absent, the existing ZERO_FEEDBACK_URL or authenticated Cloud /api/cli-feedback route remains available. That Cloud route delivers through first-party Slack/email feedback, not Sentry. Ordinary manually staged /feedback messages continue to use this feedback route even when a Sentry DSN is present. Manual crash feedback keeps its explicit HTTPS feedback action, with recognized credentials, authorization tokens, URL credentials, emails and home usernames scrubbed from the note and captured crash text. This is best-effort redaction; the always-on raw crash log remains local and is not uploaded.

Reports contain finite failure categories and bounded runtime metadata. Configured Sentry additionally receives at most 32 allowlisted built-in package-relative stack locations with line/column numbers; absolute paths, function names, arbitrary stack text, error messages and captured tool output are excluded. The full local review detail is never passed to the transport. This content policy is independent of every analytics level. Reports do not upload the feedback file, source code, credentials or enable update checks.

Sentry’s release identifies the actual running VERSION as 0-cli@<version>, with the existing embedded __ZERO_BUILD_COMMIT__ SHA appended when available; cli_version and build_commit tags carry the same identity. environment is development for source execution and production for bundled releases, with an explicit NODE_ENV=development or NODE_ENV=production taking precedence. Unknown build revisions are omitted, not guessed from the working directory.

Without an available transport, automatic reports are saved locally and the console reports submission as unavailable. ask and off cannot transmit a diagnostic without individual confirmation; an explicitly saved automatic preference permits automatic diagnostic submission after the first-report consent flow. Hard environment opt-outs still win before any request. The review shows the exact destination/body and redacted authentication headers; changes to the reviewed destination or body require a new review.

Run contributions use a separate, explicit enrollment. Analytics preferences, problem reports and service tokens don’t enroll a run.

ZERO_RUN_CONTRIBUTION_CONFIG points to an absolute, operator-owned JSON file with private permissions (0600). It contains orgId, the authoritative receipt, the matching policy, and an optional absolute spoolDir. Use the configuration issued for your enrollment. A locally written receipt doesn’t grant permission at the collector.

The client validates this configuration before capture and rechecks the receipt before upload. The existing ZERO_OFFLINE, ZERO_NO_TELEMETRY and DO_NOT_TRACK switches take precedence. Without valid enrollment, it creates no contribution spool or contribution upload. Collection doesn’t change target scope or tool authorization.

The spool defaults to run-contributions under the configured state directory. Receipt content flags control model, tool and scope capture; redaction isn’t anonymization. Versioned manifests and ordered transitions retain missing usage as unknown, and interrupted attempts aren’t treated as successful runs. Upload uses the existing Cloud credential loader and resumes from the collector’s acknowledged chunk index. The policy and receipt bound local retention.

This is a candidate integration contract, not production enrollment or a grant of model-training, licensing or public-distribution rights.

Startup behavior depends on the saved global updatePolicy:

  • off: no startup update request.
  • notify: check asynchronously and report a newer release.
  • automatic: check and, if needed, run the canonical installer before proceeding. This can delay startup; the current process keeps its running version, so restart to use the installed binary.

In an interactive terminal, updates show one status line with the current stage and elapsed time. Reduced motion keeps the indicator still. Redirected output stays plain text, and installer errors remain visible. Direct install.sh downloads show a terminal progress bar.

If no global policy is saved, the built-in setting default alone does not grant automatic installation. The compatibility path checks asynchronously only when ZERO_UPDATE_CHECK=1. All startup paths require a TTY and honor CI, ZERO_NO_UPDATE_CHECK and ZERO_OFFLINE (nonempty values other than 0 or false suppress the check). Project settings cannot enable updates.

Terminal window
env ZERO_UPDATE_CHECK=1 0 --version
env ZERO_NO_UPDATE_CHECK=1 0 console

Release checks use GitHub’s API and cache results for 24 hours. Automatic installation downloads through the repository installer; repeated attempts for the same tag are bounded. Windows automatic installation is unavailable. Use /settings or the global config to set policy intentionally.

Most per-user state is under ~/.0. Scan execution state is run-local, while console settings and credentials are user-level. Project overrides, Codex authentication and temporary reports have separate paths; moving one directory does not relocate every subsystem.

Fresh scans default to ~/.0/runs/<scan-id>/state.db. --db-path overrides ZERO_DB_PATH; ZERO_RUN_DIR controls the run directory. The legacy 0.db is a resume fallback, not the default database for every new scan.

PathPurpose
tui-settings.jsonConsole display settings (global layer).
credentials.jsonStored API-key credentials (console credential store).
console-sessions/Transcript JSON files, one per session. Owner-only (0600 file, 0700 dir).
feedback.mdLocally staged feedback entries.

The 0 config command lets you inspect, export, and import the console display settings without launching the TUI.

Terminal window
0 config show # effective config, each key labelled default/global/project
0 config export # write effective config as shareable JSON to stdout
0 config export ./my-settings.json
0 config import ./my-settings.json # merge into global layer (default)
0 config import ./my-settings.json --global # explicit global (same as default)
0 config import ./my-settings.json --project # merge into project override

Settings are resolved per-key, highest-priority first:

  1. Project — <cwd>/.0/tui-settings.json overrides individual keys.
  2. Global — ~/.0/tui-settings.json is the per-user base.
  3. Default — built-in defaults shown below.

Operator-global settings are exceptions: a project cannot override analytics, problem-report consent, update policy, onboarding state, or authorization for development-engine updates, or the whole-harness execution profile.

On load, settings are normalized against the schema: unknown keys are dropped and invalid values reset to defaults. Saving writes the normalized object. Persisted messenger framing migrates to bubble; new sessions default to minimal. Other saved styles and explicit off settings remain effective.

0 config import refuses to change security-sensitive settings, including executionProfile, allowModelSelfExtension, allowDevSourceUpdates, allowSubagentPeerMessaging and allowSubagentOperatorMessaging, unless --yes is passed. The specific changes are printed so you know what was rejected.

KeyTypeDefaultDescription
executionProfilelocal, smolvmlocalOperator-global whole-harness execution boundary; requires workbench setup before SmolVM launch
showStatusBarbooleantrueBottom bar with model, working directory, git state and counters
showComposerHintsbooleantrueKeyboard-hint line under the input
showLogobooleantrueProduct mark on an empty transcript
showObjectivebooleantrueHeader objective derived from the first message
showScopebooleantrueHeader include/exclude scope; absent and explicitly empty scope remain distinct
densitycomfortable, compactcomfortableTranscript spacing
composerStyleborder, rail, plainborderInput frame
transcriptStyleminimal, bubble, rail, plain, compact, documentminimalMinimal transcript by default; alternative framed and document layouts
roleLabelStylefull, short, glyph, offoffSpeaker label treatment
toolCardStylecompact, rail, inline, hiddencompactSuccessful tool/subagent-card treatment; failures always show
richToolCardsbooleantrueRender shell and edit results as rich cards
transcriptDetailexpanded, collapsedexpandedWhether successful reasoning and tool steps are folded
showRuntimeNoticesbooleantrueSurface runtime stdout/stderr as transcript notices
showTurnSummarybooleanfalsePer-turn tool-call and token summary
showSubagentsbooleantrueList active subagents while workers run
showTimestampsbooleanfalseRelative timestamps on transcript entries
allowSubagentPeerMessagingbooleantrueAllow direct sibling-subagent messages
allowSubagentOperatorMessagingbooleantrueAllow sanitized child-to-operator transcript messages
allowModelSelfExtensionbooleantrueEnable sandboxed model self-extension for new sessions, subject to role and capability gates
allowDevSourceUpdatesbooleanfalseGlobally authorize trusted development-engine replacement between turns; requires ZERO_DEV_SOURCE_ROOT
themebuilt-in or installed theme IDslateColour palette; installed themes live in ~/.0/themes
showTokenUsagebooleanfalsePer-turn input/output token line
showCostbooleanfalseEstimated dollar cost, per turn and in the status bar
showContextMeterbooleantrueContext-usage bar; missing context-window data displays unavailable
modelDisplaystatusbar, message, offstatusbarWhere the model name appears
logoAnimationanimation name or offglitchIntro or idle logo effect
reduceMotionbooleanfalseDisable decorative animations

Additional practical settings include composerSuggestions: true, mouseSupport: true, busyInputMode: "steer", autoCompaction: true, compactionThreshold: "80%", and elapsedTimer: "left". Finder-lens autoEvolveFinderLenses and autoPromoteFinderLenses both default to false. Operator-global analyticsLevel defaults to "off", diagnosticReporting to "ask", and updatePolicy to "automatic". Use 0 config show for the full effective inventory and each value’s source; see the privacy sections above before sharing a configuration.

Self-extension defaults on for new sessions, including the desktop checkbox. Explicit or saved false stays off. Workspace-trusted ESM requires a separate, acknowledged grant scoped to the canonical workspace.

Autonomy, self-extension and host trust are separate controls. Desktop retains unscoped-standard and scoped-YOLO authorization. See self-evolution for details.

This is separate from sandboxed self-extension. Enable Development engine updates in global settings only for a trusted source checkout. Project settings cannot grant it. Loading that code runs with the console process’s host permissions, including credential access.

Start a development console from the current checkout:

Terminal window
./scripts/0dev.sh console

0dev rebuilds the CLI dependency chain on launch and runs it with Bun. Build failure stops launch; it never falls back to stale output. Provider connections and explicit shell overrides work as they do in the normal CLI.

For frontend iteration:

Terminal window
./scripts/0dev.sh --watch console

Put --watch before the CLI command. It builds immutable TUI generations and remounts the frontend on the same renderer only when every audit is safe. Conversation, drafts, models, routes and audit state remain in memory; tools are not replayed. Active turns, workers, approvals and authentication flows defer activation. A rejected build or render keeps the known-good UI.

When enabled, changed Core source is built into an immutable generation and activated at an idle boundary. Conversation, scope decisions, task progress and usage survive the handoff. A build or checkpoint rejection leaves the current engine active. Disabling the setting stops later replacements; it does not revert an already-active generation.

Frontend watching is not component FastRefresh or Core engine replacement. Startup, non-TUI CLI code, Core/shared dependencies, native integration and the reload ABI require a full 0dev restart. Shared settings-store, output-guard and crash services stay pinned. See development engine replacement.

In the terminal UI, /connect offers Use my own API key and a separate Provider subscription section. ChatGPT Codex uses device sign-in and its own auth file. The local console does not use a Cloud account for inference.

Keys are stored in plaintext at ~/.0/credentials.json by default, with 0600 file and 0700 directory permissions. Nonblank environment credentials win. See credential storage.

In the BYOK /model picker, Tab opens the full catalog and a nonblank query searches it from either view. Check credentials and account access. Treat missing price data as unknown. See Model picker. Model and role-model selections apply to an existing audit while idle or after its active turn finishes. A normal /connect choice prepares the next chat; after connecting a new provider, reselect its model to apply it live. See Model picker.

If your organization opts to submit analytics or feedback to the Cloud service, provide an operator-issued ZERO_CLOUD_TOKEN explicitly. ZERO_CLOUD_HOST optionally selects the operator’s deployment; the default is https://cloud.0.security. These credentials do not configure local model inference or authorize a managed scan. There is no standalone CLI login command; use a provider key or subscription for the local console.

ZERO_SELECTED_PROVIDER selects the primary direct provider for a run or chat. The public console offers openrouter, anthropic, openai, azure, deepseek, chatgpt-codex, z-ai, kimi, qwen, xai, opencode, cline, copilot, and google. Set an explicit ZERO_MODEL alongside an environment selection. The provider must have its own credentials; a separately configured model can use a different route for cross-model verification.

ZERO_FORCE_PROVIDER is an unconditional benchmark override. Setting it and ZERO_SELECTED_PROVIDER to different values is an error.

Terminal window
env ZERO_SELECTED_PROVIDER=deepseek ZERO_MODEL=deepseek-flash \
0 scan --target https://example.com --scope ./scope.json --mode web --runtime api

When no explicit pin is set, --model <id> (or ZERO_MODEL) routes the call to the provider whose credentials are available. The runtime maps model prefixes:

Model prefix / identifierProvider
openrouter/*OpenRouter
glm-*, z-ai/*, IDs containing glmZ.ai (GLM)
qwen*, exact deepseek-v4-flash-0731Alibaba Qwen / Token Plan
k3*, kimi*Moonshot Kimi
grok*, xai/*, x-ai/*xAI Grok
opencode/*, muse-spark*, mimo*, ling*, big-pickle, nemotron*, minimax*OpenCode Zen
cline/*, cline-pass/*Cline API (Pass slugs preserved; subscription required)
copilot/*GitHub Copilot
gemini*, google/*Google Gemini Code Assist
claude*, anthropic/*, IDs containing sonnet, opus or haikuAnthropic, then OpenRouter when Anthropic auth is absent
gpt-*, o1–o4ChatGPT Codex when configured, otherwise OpenAI
Exact deepseek-flash, deepseek-v4-flashDirect DeepSeek
Recognized Azure Foundry deployment IDsAzure; takes precedence over family routing

Natural-provider routing requires that provider’s credentials. If no matching credential is available, selection falls through to ambient priority; an unrecognized model is not proof of a supported route. Pin a provider to fail early rather than accidentally send a model ID to another account. Arbitrary Azure deployment names need an explicit Azure pin; pricing aliases do not configure provider routing. See API Keys for the Azure/DeepSeek identifier collision and wire protocols.

The interactive console can use different models for different child-agent roles. This is not the same as provider failover, and it does not automatically enable an independent verification stage.

For a concrete multi-family setup, connect one gateway account that serves both models, then launch the console:

Terminal window
export OPENROUTER_API_KEY="sk-or-..."
env ZERO_SELECTED_PROVIDER=openrouter \
ZERO_MODEL=anthropic/claude-sonnet-4.6 0 console

In /model:

  1. Select the parent model with Enter.
  2. Use Ctrl+Left/Right to target verify (or another role), search for an account-supported model such as openai/gpt-4o, and press Enter.
  3. Use Ctrl+S to turn single-model policy off if it is on. When on, all role assignments are inactive and children use the parent model.
  4. Ctrl+Backspace clears the targeted role’s assignment so it inherits the parent again.

Role choices apply to the current audit while idle or after the active turn finishes. They affect subsequently created child runtimes, not an already running child’s in-flight request. Forked children retain the parent’s resolved provider, endpoint and credentials and do not inherit its cross-provider fallback chain. Choose models served by that same account/route; connecting another provider does not turn a role assignment into a cross-account router.

Embedded API callers can supply RuntimeConfig.agentModels, singleModel, and autoRoute. The "auto" role sentinel or autoRoute widens the model selection guard to credential-reachable choices, but does not change the inherited transport boundary. The stock console has no --agent-model or --auto-route flag. Independently constructed runtimes (for example, a workflow’s cross-model refuter) use the per-model provider routing above instead.

When no model is specified enough to route to one provider, the runtime checks env vars in this priority order:

  1. ZERO_CHATGPT_ACCESS_TOKEN / ZERO_CHATGPT_OAUTH_REFRESH_TOKEN → ChatGPT Codex
  2. DEEPSEEK_API_KEY → DeepSeek
  3. OPENROUTER_API_KEY → OpenRouter
  4. AZURE_OPENAI_API_KEY → Azure OpenAI
  5. OPENAI_API_KEY → OpenAI
  6. Z_AI_API_KEY → Z.ai GLM
  7. KIMI_API_KEY → Moonshot Kimi
  8. QWEN_API_KEY → Alibaba Qwen
  9. XAI_API_KEY → xAI Grok
  10. OPENCODE_API_KEY → OpenCode Zen
  11. CLINE_API_KEY → Cline
  12. ZERO_COPILOT_GITHUB_TOKEN → GitHub Copilot
  13. ZERO_GEMINI_ACCESS_TOKEN / ZERO_GEMINI_OAUTH_REFRESH_TOKEN → Google Gemini Code Assist
  14. ANTHROPIC_API_KEY → Anthropic
  15. No usable credential → Anthropic (reports missing credentials at runtime)

ZERO_LLM_FALLBACK configures an ordered chain of backup providers when the primary exhausts its retry budget or hits a plan quota limit:

Terminal window
env ZERO_LLM_FALLBACK=deepseek:deepseek-flash,azure:gpt-5-deployment \
0 review ./authorized-repo --runtime api

Each entry is <providerId>:<model>, comma-separated. Eligible retry-budget exhaustion or recognized plan quota exhaustion advances to the next usable route. Missing credentials (and missing endpoint configuration for Azure) skip that entry. Failover changes the recipient of model context and the account that pays; it is not a free retry or an automatic switch to a Cloud account.

The console stores transcripts as one JSON file per session in console-sessions/ under the state directory, so you can close it and resume later. Files are owner-only (0600 file, 0700 dir), filtered per working directory, capped at the 20 most recent.

A transcript is the full engagement record — every operator prompt, model reply, and tool call with its result. That means target hostnames, approved scope, untriaged findings, and raw request/response bodies, which can include cookies, bearer tokens, and anything a tool echoed.

Secrets are not scrubbed. A partial scrub over free-form output would corrupt resume evidence. Transcripts are not encrypted. Protection is filesystem permissions. Stored on local disk only.

Source reviews and package source scans use Foxguard by default for pre-agent static leads. Set ZERO_STATIC=semgrep to route them through Semgrep instead; --changed-only narrowing works with either. Dependency advisory checks (npm audit, OSV, OCI inventory) run separately for package targets regardless.

The static runner uses foxguard from PATH when provisioned. Otherwise it launches npx --yes [email protected], which requires Node/npm and access to the package and release download on first use. Native v1 JSON reports and legacy finding arrays are accepted. Launch failures, invalid reports, and scanner error exits are surfaced as failures; the default path does not silently invoke Semgrep or report a failed scan as clean. Exit 1 with a valid report means findings were detected. Scans run from the requested source root, so an explicitly selected installed package is not skipped just because an ancestor directory is node_modules. Finding paths are resolved back to that source root.

This pre-agent scan is separate from ZERO_FEATURE_MULTIMODAL=1, the opt-in white-box cross-validation layer. Cross-validation and kernel variant-hunt require an installed Foxguard binary (--foxguard can override it for variant hunting). Static hits and scanner agreement remain leads, not proof of exploitability.

Terminal window
env ZERO_STATIC=semgrep 0 review ./repo --depth quick

Semgrep is required only when explicitly selected. Legacy report fields named semgrepFindings and the SemgrepFinding type describe the existing wire shape, not a runtime dependency. FoxGuard cross-validation remains opt-in; it does not turn scanner agreement into independent exploit verification. The historical ablation baseline is still unmeasured, so equal coverage or a speed advantage over Semgrep is not established by the integration alone.

Stateful authorization and fix verification

Section titled “Stateful authorization and fix verification”

Foxguard findings are static leads. Three complementary paths test authorization state changes, find incomplete application fixes, and replay a PoC with a negative control.

The agent tool access_control_workflow observes a JSON resource as its owner, executes up to ten ordered requests as a distinct actor, then observes it again. It uses the existing per-identity sessions, cookie jars, scope checks, attribution, and rate limiter without switching the active identity.

{
"allow_mutation": true,
"owner_identity": "owner",
"actor_identity": "other-tenant",
"observation_url": "https://app.example/api/items/42",
"observation_json_pointer": "/marker",
"expected_state": "fresh-disposable-test-marker",
"steps": [
{
"method": "PATCH",
"url": "https://app.example/api/items/42",
"body": "{\"marker\":\"fresh-disposable-test-marker\"}"
}
]
}

Use only disposable resources covered by the engagement. There is no automatic cleanup or rollback. Every step is validated before requests start; actor requests cannot override authentication headers. Both owner observations must succeed and contain complete JSON. confirmed requires an exact string-marker transition, not merely HTTP 2xx. An unchanged state is no_change; incomplete observations, transport failures, or an unexpected state change are inconclusive. Choose a unique marker to reduce ambiguity from concurrent legitimate activity.

Terminal window
0 review ./repo --fix-commit <sha> --variants-only
0 review ./repo --fix-commit <sha>

--variants-only emits deterministic JSON without model calls. The second command feeds candidates into the normal review pipeline as low-confidence SeedFinding leads. The hunter compares the fix commit to its first parent, extracts added authorization/validation checks, and searches current tracked working-tree files in the affected directories for similar unguarded functions.

Extraction is heuristic for JavaScript, TypeScript, and Python—not a complete AST, control-flow, or exploitability analysis. Other languages are explicitly skipped. The default bound is 200 related files and 50 candidates; source files over 1 MiB are skipped with an error entry. Guarded siblings are excluded. This is separate from Foxguard’s kernel variant-hunt.

Create a plan with exactly one of finding_path or an inline finding, explicit source roots, and file allowlists. Finding JSON uses the same schema as verify --finding, including timestamp. Plan-relative paths resolve beside the plan.

{
"version": 1,
"finding_path": "./finding.json",
"vulnerable_root": "./before",
"patched_root": "./after",
"files": {
"vulnerable": ["app.cjs"],
"patched": ["app.cjs"]
},
"runner": "local"
}
Terminal window
0 verify --create-bundle ./plan.json --out ./bundle
0 verify --bundle ./bundle --runner local --out ./replay-results

Creation never executes PoC steps. Replay requires an explicit runner, validates SHA-256 content, sizes, paths, and compatibility before execution, and uses fresh vulnerable/patched workspaces. Output directories must be empty. Symlinks, traversal paths, source/output overlap, and dirty output are rejected. Snapshot content is bounded to 256 MiB; plans and manifests to 4 MiB.

confirmed (exit 0) requires reproduction on the vulnerable side and a genuine assertion failure on a successfully executed patched side. Reproduction on both sides is inconclusive (exit 1); failure to reproduce the vulnerable side is not_reproduced (exit 1). A crash, failed setup, timeout, or missing command is error (exit 3), never proof of a fix. PoC processes must exit zero on both sides and express the exploit condition through assertions. Results include both sides; vulnerable.json, patched.json, and result.json are retained with artifacts.

Local replay executes trusted PoC code on the host. It checks the Node/engine version and platform/architecture; external tools and services remain outside the snapshot. Digests establish file integrity, while authorship requires separate review. Check bundles for secrets before execution or sharing, including source, finding metadata, and process output.

For Docker, set "runner": "docker" in the plan and provide docker_shell_image / docker_http_image for the action types used, each as a full repository@sha256:<64-hex-digest> reference. Docker action images must also be digest-pinned. Replay binds the images to those references and uses the existing Docker isolation controls; provision images locally first. HTTP replay additionally requires --scope <scope.json> and an explicit --docker-network <name>. Local replay supports shell actions; Docker supports shell, container, and scoped HTTP actions. Notes are not executable bundle steps. Shell cwd is relative to the mounted workspace; absolute paths and traversal outside it are rejected before a container is launched.

The Docker replay CI workflow runs real containers. It covers isolation, writable workspaces, relative cwd and escape rejection, pinned-image execution, timeout cleanup, scoped HTTP, and vulnerable/patched negative controls. To run the same checks against the default local Docker daemon:

Terminal window
pnpm --filter @0/core... -r build
node scripts/smoke-docker-replay.mjs

The smoke script pulls its fixture images, resolves their digests, and removes its test containers, network, and temporary workspaces afterward.

Features is the canonical flag inventory. Do not copy a flag from an archival experiment and assume the current engine reads it. ZERO_FEATURE_TRIAGE_MEMORIES and ZERO_FEATURE_DEBATE are not current standalone toggles.

Use env for names beginning with ZERO_; POSIX shells cannot export names beginning with a digit. Enabling a capability does not supply its credentials, scope, toolchain, or other prerequisites.

Jev is a bounded advisory evaluator, not a chat-provider replacement. No feature is enabled merely by having a key. ZERO_JEV_FEATURES explicitly opts selected workflows into sending evaluation state to the selected provider: browser, memory, dedupe, rank, specialist, redteam, kernel, crash, radar, and foxguard (comma-separated). Probabilities do not authorize actions, establish an exploit, or replace deterministic verification. Unknown feature/provider names are configuration errors.

ZERO_JEV_PROVIDERRequired credential / endpointRoute
vercel (default when enabled)AI_GATEWAY_API_KEYVercel AI Gateway evaluation model typesafe-ai/jev, billed to your own gateway key
cloudZERO_JEV_CLOUD_TOKEN and ZERO_JEV_CLOUD_URLYour evaluation endpoint, which reaches the same upstream model and bills workspace credits; HTTPS except loopback HTTP

Consumers are workflow-specific. Agentic scans use memory ranking, deduplication, and final finding prioritization (rank); specialist selects methodologies only inside native EGATS branches (scan --egats). Browser and red-team helpers have their own entry points, as do explicit kernel, crash-triage, and radar commands. Putting agentic-scan selectors on a source review does not add those consumers to the source pipeline.

For example, opt only the browser helper in, through the gateway:

Terminal window
export AI_GATEWAY_API_KEY="..."
env ZERO_JEV_FEATURES=browser ZERO_JEV_PROVIDER=vercel \
ZERO_JEV_BROWSER_READ_ONLY_URLS=https://authorized.example/docs \
0 console --scope ./scope.json

To pilot finding prioritization and EGATS specialist selection after configuring AI_GATEWAY_API_KEY:

Terminal window
env ZERO_JEV_FEATURES=rank,specialist ZERO_JEV_PROVIDER=vercel \
0 scan --mode web --egats --target https://authorized.example \
--scope ./scope.json

rank orders final canonical findings before reporting; it does not skip investigation or verification. Scores and model provenance are recorded as finding_priority events, separately from vulnerability confidence. Uncertain or unavailable ranking evaluations return the complete set to the existing generative ranker. specialist selects from existing methodologies only when the chosen probability is at least 0.8; generic or uncertain answers remain generic, while request failures retain the prior flag-gated regex path. This threshold is a conservative pilot policy, not demonstrated security-domain calibration. Each workflow shares one evaluator budget across its batches/nodes.

ZERO_JEV_BROWSER_READ_ONLY_URLS is a comma-separated list of exact normalized URLs required for assisted navigation, in addition to explicit scope. Jev never replaces target authorization; absent scope or approved URLs makes assistance hand off without navigation. A normal ZERO_CLOUD_TOKEN is not automatically used as the Jev token. See Jev budgets for per-instance request, timeout, classification and estimated-cost limits.

The runtime layers that keep a provider failure from silently corrupting a scan:

VariableDefaultPurpose
ZERO_LLM_STREAM_IDLE_TIMEOUT_MS120000SSE byte-idle watchdog; aborts a stream that stops emitting bytes.
ZERO_LLM_STREAM_EVENT_IDLE_TIMEOUT_MS240000SSE event-idle watchdog; keep-alive comments and whitespace alone do not reset it.
ZERO_LLM_MAX_RETRIES6Max retries for retryable statuses (429 + transient 5xx), with exponential backoff.
ZERO_LLM_MAX_RETRY_WAIT_MS60000Cumulative backoff cap (ms) for the generic retry loop.
ZERO_LLM_429_MAX_RETRIES12Max retries for 429 rate-limits specifically. Falls back to ZERO_LLM_MAX_RETRIES when unset.
ZERO_LLM_429_MAX_RETRY_WAIT_MS300000Cumulative 429 backoff cap (ms). Falls back to ZERO_LLM_MAX_RETRY_WAIT_MS when unset. Bound server-guided Retry-After waits.
ZERO_SUPPRESS_PROVIDER_STARTUP_LOGunsetSet to 1 to suppress the “Provider: …” startup banner line.

These watchdogs are separate from the request’s overall timeout, which remains armed while streaming. scan --timeout defaults to 30000 ms; review and audit --timeout default to 600000 ms. Retry counts mean retries after the initial request. Generic retryable HTTP statuses are 429, 500, 502, 503 and 504; eligible transport failures also use bounded retries. Retry-After / retry-after-ms waits are capped at 120 seconds per wait, with the cumulative caps above and the request’s cancellation/timeout still applying. An explicit operator cancellation is terminal, not a reason to fail over.

Auth errors (401/403) are never retried: the agent loop exits immediately, warnings[] carries the provider error, and the run is marked failed, never clean “0 findings”. Package audits add a per-file circuit breaker (3 identical-signature failures abort the rest).

The provider failover configuration is opt-in. It advances only on eligible failure paths, never because a model answer was unhelpful. Keep backup credentials and account limits intentional.

Backend selection is command-specific and separate from the whole-harness execution profile above:

  • Source evolution defaults to Docker. Set backend: "smolvm" and a local imageArchive in its config to use qualified Linux microVM workers. See Improvement Plane for prerequisites, image provisioning, restrictions, and real qualification commands.
  • Deterministic replay selects --runner local|docker|qemu; Docker replay networking follows the explicit scope and --docker-network rules above.
  • Agentic exploit execution requires --container or --exec-script; it does not default to running exploit commands on the host.

Selecting smolvm for evolution does not move general console/PTY tools, replay, or exploit executors into that VM. Provision toolbox dependencies before offline evaluation; candidate execution does not bootstrap packages over the network.

Set a soft estimated-model-cost stop per scan, audit, or review. On a ceiling breach, 0 preserves partial findings, exits with code 4, and emits exit_reason: "cost_ceiling_exceeded" in the optional machine-readable result line. --cost-ceiling overrides ZERO_COST_CEILING_USD; neither supplied means no dollar ceiling. In-flight/concurrent calls can overshoot. This is not an invoice cap, infrastructure budget, or guarantee that every external service is metered. See Budget Management.

Terminal window
env ZERO_COST_CEILING_USD=5 \
0 scan --target https://example.com --scope ./scope.json --mode web
0 audit lodash --cost-ceiling 2
0 review ./my-repo --cost-ceiling 10

Set ZERO_EMIT_RESULT_LINE=1 to print one final ZERO_RESULT=... JSON line with success/failure, exit code and reason, target type, finding counts, and estimated cost/token usage. Useful for wrappers and CI parsers.

After enabling gates, inspect their execution records and evidence before accepting a finding.

Terminal window
env \
ZERO_FEATURE_CONSENSUS_VERIFY=1 \
ZERO_FEATURE_REACHABILITY_GATE=1 \
ZERO_FEATURE_POV_GATE=1 \
ZERO_FEATURE_MULTIMODAL=1 \
0 scan --target https://example.com --scope ./scope.json --mode web --depth deep
Terminal window
env ZERO_FEATURE_WEB_SEARCH=1 \
0 scan --target https://example.com --scope ./scope.json --mode web