Contenox CLI Reference
contenox is the local AI agent CLI. It runs the Contenox chain engine entirely on your machine.

Global Flags
Persistent flags on the root command (also shown under Global Flags on subcommands). Run contenox --help for the full list.
| Flag | Description |
|---|---|
--model <name> | Model override for this invocation; persistent default is contenox config set default-model <name> |
--provider <type> | Provider override for this invocation. See contenox backend add --help for supported backend types. |
--db <path> | SQLite DB path (default: ~/.contenox-harness/local.db). The one global database is shared by every workspace. |
--data-dir <path> | Override the .contenox data directory (skips walk-up search). Used to locate the workspace’s workspace.id and chain files; does not change the database location. |
--timeout | Max execution time per invocation (default 5m) |
--context | Context length hint for the tokenizer |
--ollama | Ollama base URL (default http://127.0.0.1:11434) |
--no-delete-models | Legacy compatibility flag; a no-op in the OSS runtime (model deletion is disabled). Defaults to true. |
--chain <path> | Chain JSON for injected run / chat when applicable |
--input <value> | Input string or @file (chat / bare run paths) |
--trace | Structured operation telemetry on stderr |
--steps | Print execution steps after the result |
--think <level> | Set reasoning level for supported models: auto, off, minimal, low, medium, high, xhigh |
--raw | Print full structured output (e.g. entire chat JSON) |
--shell | Enable local_shell tools (trusted environments only) |
--local-exec-allowed-dir <dir> | Restrict local filesystem access and local_shell executable/script paths for this invocation |
--alt-model <name> | Alt model name (for chains referencing {{var:alt_model}}). Overrides default-alt-model config. |
--alt-provider <type> | Alt provider type (for chains referencing {{var:alt_provider}}). Overrides default-alt-provider config. |
--max-tokens <N> | Response token cap (for chains referencing {{var:max_tokens}}). Overrides default-max-tokens config. |
-e, --editor | Open $EDITOR (or $VISUAL, fallback nano) to compose the prompt. |
Subcommands
contenox setup
Runs an interactive setup wizard to configure your primary provider, model, and API key. This is the recommended first step for all new users. It ensures your global ~/.contenox-harness/ configuration is ready for use.
contenox setup
The wizard will guide you through picking a provider (like a local model, OpenAI, or Gemini), entering an API key if required, and setting your first default model.
contenox (bare — stateful chat)
If the first token is not a reserved subcommand (chat, init, run, …), the CLI prepends chat. This starts or continues a stateful, session-backed conversation. It is the default, interactive mode.
The default chat chain is resolved by name: workspace .contenox/default-chain.json wins when present, otherwise Contenox falls back to ~/.contenox-harness/default-chain.json.
contenox "what can you do?"
echo "summarise README.md" | contenox
contenox --shell "list files here"
contenox --local-exec-allowed-dir . "summarise the README"
contenox chat
Sends a message to the active chat session and prints the response. History is persisted across invocations in SQLite. This is the explicit version of the bare contenox command.
contenox chat "what can you do?"
echo "summarise README.md" | contenox chat
contenox chat --shell "list files here"
| Flag | Description |
|---|---|
--trim N | Only send last N messages from session history to the model (0 = all) |
--last N | Print last N user/assistant turns after the reply (0 = only new reply) |
--shell | Enable local_shell tools |
--local-exec-allowed-dir <dir> | Restrict local filesystem access and shell executable/script paths |
--auto | Disable HITL prompts for this invocation. HITL is on by default. |
contenox session
Manage named chat sessions. Each session maintains its own conversation history. list and show default to the active scope; the whole database can also be inspected across workspaces and namespaces, and any session opened directly by id — useful for recovering a session an editor lost track of.
contenox session list # list all sessions (* = active)
contenox session new [name] # create a session (becomes active)
contenox session switch <name> # switch to a different session
contenox session show # show active session's history
contenox session show <name> # show any session by name
contenox session show <id> # show any session by id (any workspace)
contenox session show --tail 10 # show last 10 messages
contenox session show --head 5 # show first 5 messages
contenox session show default --tail 6 # tail a non-active session
contenox session fork [name] # copy the active session to a new one (becomes active)
contenox session fork --summary # compact older history into a summary, then fork and continue
contenox session delete <name> # delete session and all messages
session fork branches the current conversation into a new session so you can explore an alternate direction without losing the original. --summary first compacts the older turns into a summary (via chain-compact.json) before forking, which trims a long history while preserving context.
Inspect the whole database, not just the active workspace/identity:
contenox session workspaces # list workspaces and namespaces (counts)
contenox session list --all # every session across the whole DB
contenox session list --workspace <id> # sessions in a workspace
contenox session list --namespace <ns> # sessions in a namespace (e.g. jetbrainsgoland)
A namespace is the session-name prefix before its generated id (e.g. jetbrainsgoland, zed, default). To recover a session an editor abandoned: find it with session list --namespace <ns>, then session show <id>.
contenox run
Executes a chain non-interactively. Unlike chat, run does not use session history. It is for stateless, one-shot chain executions.
contenox run --chain .contenox/chain-nws.json --input-type chat "how is the weather?"
contenox run --chain .contenox/my-chain.json --shell "refactor main.go"
--chain <path>: Optional if<resolved .contenox>/default-run-chain.jsonexists; otherwise required.--input-type <type>:string(default),chat,json,int— seecontenox run --help.--shell: Enable shell execution for this invocation (use only in trusted environments).--auto: Disable HITL approval prompts for non-interactive runs. Default is HITL on.--think/--trace/--steps: Global flags (see table above).
contenox doctor
Prints local LLM setup readiness: default model, default provider, and backend reachability.
contenox doctor
contenox doctor --json # machine-readable output
contenox doctor --skip-cycle # faster; skips backend sync (status may be stale)
| Flag | Description |
|---|---|
--json | Print results as JSON instead of human-readable text |
--skip-cycle | Skip syncing backends before the check (faster but may show stale status) |
contenox model
List the models your configured backends expose, override a model’s context window, and manage capability overrides for models whose catalog entry is missing a capability.
contenox model list
List models currently available from all configured backends (live query, requires at least one backend).
contenox model list
contenox model set-context
Override the context window size for a specific model name. Useful when a backend reports a different (or no) context size than the model actually supports.
contenox model set-context qwen2.5:7b --context 32k
contenox model set-context gpt-5-mini --context 128k
contenox model set-context gemini-3.1-pro-preview --context 1m
| Flag | Description |
|---|---|
--context | Context window size: bare integer or shorthand (12k, 128k, 1m). Required. |
contenox model capability
Manage manual provider/model capability overrides — the reasoning (think) and image-input (vision) capabilities the runtime assumes for a given provider/model when the catalog doesn’t declare them.
contenox model capability set <provider> <model> --think true # mark the model as supporting reasoning
contenox model capability set <provider> <model> --vision true # mark the model as accepting image input
contenox model capability show <provider> <model> # show the current override
contenox model capability unset <provider> <model> # remove the override (revert to catalog)
contenox tools
Manage remote OpenAPI tools. See Remote Tools and Tools Allowlist Patterns.
contenox tools add <name> --url <url>
contenox tools add <name> --url <url> --header "Authorization: Bearer $TOKEN" --inject "tenant_id=acme"
contenox tools add <name> --url <url> --spec ~/my-spec.yaml # local file spec
contenox tools list
contenox tools show <name>
contenox tools update <name> --header <...> --inject <...> --spec <url-or-path>
contenox tools remove <name>
| Flag | Description |
|---|---|
--url | Base URL of the service — where API calls are sent (required) |
--spec | URL or local file path of the OpenAPI v3 spec (https://..., ~/path, ./path, /abs/path). Local paths stored as file:// URIs; must exist at registration time. Defaults to <url>/openapi.json. |
--header | HTTP header to inject on every call, e.g. "Authorization: Bearer $TOKEN" (repeatable) |
--inject | Tool call argument to inject and hide from the model, e.g. "tenant_id=acme" (repeatable) |
--timeout | Request timeout in milliseconds (default: 10000) |
contenox agent
Inspect and manage the runtime’s declared agents. An agent is one of the runtime’s own task chains, addressable and spawnable as an ACP peer. Agents are registered automatically by chain-agent discovery from the chain files on disk — this command inspects them, toggles their enabled state, and removes stale registrations. They appear in Beam’s agent picker and over the read-only GET /api/agents endpoint.
contenox agent list # id, name, source, kind, enabled
contenox agent show agent-reviewer # provenance + config_json
contenox agent enable agent-reviewer # (and: disable)
contenox agent remove agent-reviewer # (alias: rm)
remove deletes only the local registration; discovery may re-register it on the next startup if its chain file still exists.
contenox init [provider]
Initializes a workspace (.contenox/) and ensures default runtime presets exist globally (~/.contenox-harness/). It’s best to run contenox setup first for a guided configuration.
init creates the .contenox/workspace.id marker — a project’s portable identity. The marker carries a stable workspace UUID (the database scoping token every session under the project is filed under) plus an optional friendly name (what the Beam project registry and the folder picker show). It travels with the directory, so a project means one thing to serve, the CLI, and the API alike. Default chains and HITL policies are written under ~/.contenox-harness/ unless they already exist. Workspace-local .contenox/ files can override these global presets by name.
By default init walks up to reuse an ancestor’s .contenox if one exists (like git). Pass --project to force a fresh project marker in the current directory instead — a distinct workspace nested under a larger one — and --name to give it a friendly name (default: the folder’s own name). Marking a project does not by itself let sessions open it; init --project prints the contenox workspace add line that grants it.
You can optionally specify a provider to pre-configure defaults.
contenox init # local-first default
contenox init gemini # pre-configure for Gemini
contenox init openai # pre-configure for OpenAI
contenox init --force # overwrite existing files
contenox init --update # refresh unchanged default files
contenox init --project --name "API" # a fresh named project in the current dir
| Flag | Description |
|---|---|
-f, --force | Overwrite existing preset files |
--update | Refresh unchanged default files to the latest embedded versions |
--project | Create a fresh project marker in the current directory (a new workspace id) instead of reusing an ancestor’s .contenox |
--name <name> | Friendly project name for the marker (default: the directory name) |
contenox backend
Register and manage LLM backend endpoints.
contenox backend add ollama --type ollama
contenox backend add ollama-cloud --type ollama --url https://ollama.com/api --api-key-env OLLAMA_API_KEY
contenox backend add openai --type openai --api-key-env OPENAI_API_KEY
contenox backend add openrouter --type openrouter --api-key-env OPENROUTER_API_KEY
contenox backend add anthropic --type anthropic --api-key-env ANTHROPIC_API_KEY
contenox backend add mistral --type mistral --api-key-env MISTRAL_API_KEY
contenox backend add bedrock --type bedrock --url https://bedrock-runtime.us-east-1.amazonaws.com
contenox backend add gemini --type gemini --api-key-env GEMINI_API_KEY
contenox backend add myvllm --type vllm --url http://gpu-host:8000
contenox backend add vertex --type vertex-google \
--url "https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/us-central1"
contenox backend list
contenox backend show openai
contenox backend remove myvllm
| Flag | Description |
|---|---|
--type | Backend type: ollama, openai, openrouter, anthropic, mistral, gemini, bedrock, vllm, vertex-google. |
--url | Base URL (auto-inferred for openai/openrouter/anthropic/mistral/gemini; required for vllm, bedrock, and vertex-google) |
--api-key-env | Environment variable holding the API key (preferred) |
--api-key | API key literal (avoid — use --api-key-env) |
contenox config
Manage persistent CLI defaults stored in SQLite.
contenox config set default-provider ollama
contenox config set default-model qwen2.5:7b
contenox config set default-alt-model gemini-2.5-flash
contenox config set default-alt-provider gemini
contenox config set default-autocomplete-model qwen2.5-coder:7b
contenox config set default-autocomplete-provider ollama
contenox config set default-max-tokens 8192
contenox config set default-think high
contenox config set default-chain .contenox/default-chain.json
contenox config set hitl-policy-name hitl-policy-strict.json
contenox config get default-model
contenox config list
Valid global keys: default-model, default-provider, default-alt-model, default-alt-provider, default-autocomplete-model, default-autocomplete-provider, default-max-tokens, default-think, telemetry-enabled, update-check, default-mission-agent, default-mission-policy.
Valid workspace keys: default-chain, hitl-policy-name.
default-mission-agent and default-mission-policy are the fallbacks mission mode fires with when none is named — see contenox mission and the /mission slash command.
contenox mcp
Register and manage MCP (Model Context Protocol) servers.
# Shorthand: name + URL (transport defaults to http)
contenox mcp add notion https://mcp.notion.com/mcp --auth-type oauth
# Stdio transport (local process)
contenox mcp add myserver --transport stdio --command npx \
--args "-y,@modelcontextprotocol/server-filesystem,/tmp"
# SSE transport (remote) with bearer auth
contenox mcp add remote --transport sse --url https://mcp.example.com/sse \
--auth-type bearer --auth-env MCP_TOKEN
# Inject hidden params into every tool call (model never sees them)
contenox mcp add myserver --transport http --url http://localhost:8090 \
--header "X-Tenant: acme" \
--inject "tenant_id=acme" --inject "env=production"
# OAuth with pre-issued client credentials (HubSpot, Salesforce, MS Graph,
# any vendor MCP without RFC 7591 dynamic registration)
contenox mcp add hubspot --transport http --url https://mcp.hubspot.com/ \
--auth-type oauth \
--oauth-client-id <client_id from vendor UI> \
--oauth-client-secret-env HUBSPOT_MCP_CLIENT_SECRET
# For OAuth servers, run the authorization flow AFTER adding (opens a browser).
# This is a required, separate step — `mcp add --auth-type oauth` only registers
# the server; it does not authenticate it. Re-run only when the token expires.
contenox mcp auth notion
contenox mcp list
contenox mcp show myserver
contenox mcp update myserver --inject "tenant_id=newvalue"
contenox mcp remove myserver
For OAuth servers the full sequence is: contenox mcp add <name> ... --auth-type oauth, then contenox mcp auth <name> to complete the OAuth 2.1 PKCE flow in the browser. The token is stored locally and reused until it expires.
| Flag | Description |
|---|---|
[url] | URL as a second positional arg — sets --url and defaults --transport to http |
--transport | Server transport: stdio, sse, http |
--command | Command to execute (stdio only) |
--args | Comma-separated command arguments |
--url | Remote endpoint URL (sse, http) |
--auth-type | Authentication type: bearer or oauth |
--auth-env | Environment variable holding auth token (preferred over --auth-token) |
--auth-token | Auth token literal (avoid — use --auth-env) |
--oauth-client-id | Pre-issued OAuth client_id for vendors without RFC 7591 dynamic registration (HubSpot, etc.) |
--oauth-client-secret-env | Env var holding the pre-issued OAuth client_secret (only the var name is stored locally) |
--header | Additional HTTP header for SSE/HTTP connections, e.g. "X-Tenant: acme" (repeatable) |
--inject | Tool call argument to inject and hide from the model, e.g. "tenant_id=acme" (repeatable) |
[!NOTE]
mcp update --headerandmcp update --injecteach replace the entire corresponding map. Pass all required values in a single update call.
contenox serve
Starts the Contenox HTTP server and serves the Beam web UI. Foundation routes live at /health and /version; the product API is under /api; chat (with its HITL approvals and execution-state replay) runs over the /acp WebSocket; the Beam UI is served at /.
contenox serve # binds 127.0.0.1:32123 by default
contenox serve ./repo ./another-repo # extra allowed session workspace roots
Binds 127.0.0.1:32123 by default (override with ADDR/PORT). Set TOKEN to require a bearer token on mutating/cross-origin requests (mandatory when ADDR is not loopback). A configured model is required — run contenox setup first. Terminal routes are on by default under /api/terminal/sessions (disable with TERMINAL_ENABLED=false).
| Flag / env | Description |
|---|---|
--workspace-root <dir> | Directory a browser client may choose as a session workspace (repeatable). The serve directory is always allowed; also settable via WORKSPACE_ROOTS or as positional args. These are the launch-time roots; grant more at runtime — without a restart — via contenox workspace add or POST /workspace/roots. |
ADDR / PORT | Override the bind address/port. |
TOKEN | Bearer token required on mutating API requests and cross-origin reads. |
BEAM_DEV_PROXY_URL | Proxy Beam UI requests to a Vite dev server while keeping /api on this server. |
TERMINAL_ENABLED | Terminal routes under /api/terminal/sessions, on by default (false disables). |
TERMINAL_ALLOWED_ROOT | Directory terminal sessions are confined to (default: the workspace root). |
TERMINAL_MAX_SESSIONS | Concurrent terminal session cap (default 8; 0 = unlimited). |
TERMINAL_SHELL | Shell binary for terminal sessions (default: $SHELL). |
TERMINAL_IDLE_TIMEOUT | Idle duration after which a terminal session is reaped. |
HITL_APPROVAL_TIMEOUT | Ceiling for pending HITL approvals, a Go duration (e.g. 1h); expired asks are auto-resolved. |
ALLOWED_API_ORIGINS / PROXY_ORIGIN | CORS: extra allowed API origins / the trusted reverse-proxy origin. |
SANDBOX_SHELL_SCRUB | Environment-scrub policy for agent-reachable shells (local_shell, the ! / shell_session PTY): deny-secrets (default), strict, off. See Least-privilege shell environment. |
SANDBOX_TERMINAL_SCRUB | Environment-scrub policy for the interactive terminal panel: off (default), deny-secrets, strict. Enable it for LAN-exposed serves. |
SANDBOX_ENV_ALLOW / SANDBOX_ENV_DENY | Extra variable names or globs to also pass through / always drop under the active scrub. Preview the result with contenox sandbox env. |
contenox fleet
Operate the fleet — the supervised agent units a running contenox serve is hosting — from the shell. These verbs act on units (the running processes); the work a unit was sent to do lives under contenox mission.
The fleet is not in the database — it is a set of live subprocesses owned by the serve process’s in-memory manager — so, unlike contenox state/session, these verbs reach serve over its REST API. By default that is http://127.0.0.1:32123; override with --server/--token or CONTENOX_SERVER_URL/CONTENOX_SERVER_TOKEN (the same client contenox approvals uses).
contenox fleet list # the board: every declared agent + its live units + intent
contenox fleet list --json # the raw /fleet records (declared agents + instances)
contenox fleet show <instance-id> # one unit's status (state, sessions, viewers, session ids)
contenox fleet stop <instance-id> # tear a unit down (idempotent)
contenox fleet cancel <instance-id> # cancel every in-flight turn on the unit
contenox fleet cancel <instance-id> --session <session-id> # cancel just that session
list renders the config+runtime join: every declared agent (idle ones included), each live instance’s kind/state/session/viewer counts, and the mission INTENT the unit was fired with (joined from the bound mission; - when the unit has no mission behind it). stop is idempotent by the kernel contract — stopping an unknown or already-stopped instance succeeds — so a script may call it without a preceding existence check. To FIRE a new unit, use contenox mission fire; there is deliberately no fleet dispatch.
| Flag | Description |
|---|---|
--server <url> | Base URL of a running contenox serve (default http://127.0.0.1:32123; also CONTENOX_SERVER_URL). |
--token <token> | Bearer token, when serve was started with one (also CONTENOX_SERVER_TOKEN). |
--json | Emit the raw route response instead of a table (list, show). |
--session <id> | cancel only this session id, instead of every session on the unit. |
contenox mission
Work with an agent in mission mode — the dual of chat mode. In chat you prompt turn by turn and approve each gated action yourself. In mission mode you fire a one-line intent at a declared agent under an envelope (a HITL policy that bounds what it may do unattended) and detach; the unit acts inside the envelope and only crossing it costs your attention, in the approvals inbox. A mission is a subagent of whatever process fires it — the /mission slash command runs one in-process inside your editor session; these CLI verbs are the operator’s remote lever, firing onto (and reading from) a running contenox serve over the same REST API as contenox fleet.
contenox mission fire --agent reviewer --intent "triage the failing CI run" --policy hitl-policy-strict.json
contenox mission fire --intent "summarise today's commits" # --agent/--policy from config defaults
contenox mission list # what is running, for whom, under what envelope, and why
contenox mission show <mission-id> # the mission plus its reports, newest first
fire brings up a unit, hands it the intent as its first turn, and returns as soon as the session is open (the turn runs detached); the printed mission/instance/session ids let you follow it with mission show and fleet show. --intent is always required; --agent and --policy fall back to the config keys default-mission-agent / default-mission-policy, so a configured operator can fire with intent alone. A mission with no agent or no envelope is refused. --cwd roots the unit’s session in an absolute directory serve allows.
show prints the mission record — intent, agent, envelope, status, the session/instance it spawned, the parent session that supervises it (set only when a mission is fired from a chat by /mission, not by an operator directly), and liveness — followed by the unit’s reports, newest first.
| Flag | Description |
|---|---|
--server <url> / --token <token> | Reach a running contenox serve (as contenox fleet). |
--agent <name> | Declared agent to fire (fire; default: config default-mission-agent). |
--intent <line> | One-line mission intent — required for fire. |
--policy <name> | Envelope: the HITL policy bounding the unit (fire; default: config default-mission-policy). |
--cwd <dir> | Absolute working directory for the unit’s session (fire; default: serve’s project root). |
--limit <n> | Cap the mission list (list) or the reports shown (show). |
--json | Emit raw records: the dispatch ids (fire), the mission list (list), or {mission, reports} (show). |
The /mission slash command
From inside a chat (contenox acp, or the Beam chat) you can fire a mission without leaving the conversation:
/mission <intent>— fires the configureddefault-mission-agentunder thedefault-mission-policyenvelope./mission <agent-name> <intent>— fires the named agent instead.
The two forms are the same shape, so contenox resolves the first token against the declared-agent registry: a hit is the named form, a miss means the whole line is the intent for the default agent. The confirmation always states which agent was chosen and echoes the intent, so a misread is visible immediately. A mission fired this way is supervised by the calling session — its reports return there rather than to the operator inbox.
In a standalone contenox acp editor session the dispatch runs in-process by default: the fired unit is a child subprocess of the editor process itself, no running serve is needed, and the unit’s reports stream live back into the firing session as they land (the operator inbox only catches a report whose firing session has already ended). Setting CONTENOX_SERVER_URL opts into forwarding the dispatch to that serve instead — for firing onto a bigger box — in which case reports land in that serve’s operator inbox (contenox approvals), since a remote kernel cannot deliver into an editor session it does not own. The hardened acpx profile never offers /mission.
contenox approvals
List and answer everything a running contenox serve is holding for you — the inbox for asks raised by an agent working with no attached session (dispatched fleet work, a headless API caller). A permission request that would otherwise hang until its policy-rule timeout, or the serve-level ceiling, is answerable here as soon as it lands.
Two kinds of ask arrive in this one queue, and they are answered differently:
- a permission ask — a gated tool call waiting on a verdict. Answer it with
--approveor--deny. - an attention ask — a running mission unit’s question (
mission / mission_ask_attentionin the list). Answer it with--reply "<text>": your words are handed straight back to the unit as the result of the tool call it is parked on, and it continues with them on the same turn.
A pending approval is a goroutine parked inside the running serve process — answering it has to reach that process, not just its database — so, unlike contenox state/session, this command talks to serve’s REST API (default http://127.0.0.1:32123; override with --server/--token or CONTENOX_SERVER_URL/CONTENOX_SERVER_TOKEN).
contenox approvals list # pending asks, newest first
contenox approvals list --json # raw records, including full diff content
contenox approvals answer <id> --approve
contenox approvals answer <id> --deny
contenox approvals answer <id> --reply "the contenox runtime repo, docs/ only"
list prints each ask’s id, tool, args summary, policy and matched rule, diff presence, the agent/mission/instance/session attribution (with several units running, the row has to say whose action is gated; - for an ask raised outside the fleet), and the created/expires timestamps. For an attention ask the args summary is the question, and the mission column names who is waiting on you.
answer requires exactly one of --approve/--deny/--reply. --reply is refused on a permission ask (prose is not a verdict); --approve/--deny on an attention ask leaves the unit with no answer, so it falls back to filing its question as a blocker. An id that is unknown, already answered, or expired (auto-resolved by serve’s sweeper) fails with a non-zero exit status saying which — answering twice is never silently a no-op.
| Flag | Description |
|---|---|
--server <url> / --token <token> | Reach a running contenox serve (as contenox fleet). |
--limit <n> | Cap the pending list (list; 0 = server default cap). |
--reply <text> | Answer a unit’s question with text (answer, attention asks) — the unit receives it as its tool result. |
--json | Emit raw records (list) or the answer result (answer). |
contenox workspace
Grant or revoke the workspace roots a session may run in — the directories a chat, a dispatched mission unit, or a Beam file browse may choose as its working directory. Granting a root grants everything under it; a directory outside every granted root (a sibling, a prefix-trick neighbour like /home/meX against /home/me, or a symlink whose real target escapes) is refused. A too-broad root — the filesystem root, your home directory, or a top-level system directory like /srv — is also refused, so a grant can never hand a session an entire home or disk; grant the specific project directory.
contenox workspace add /home/me/src # grant a root (and everything under it)
contenox workspace add /home/me/api --name "API" # grant AND name the project
contenox workspace list # the roots you have granted
contenox workspace remove /home/me/scratch # revoke a grant
Granting a root also registers it as a project: add writes (or reuses) the folder’s .contenox/workspace.id marker, so a root added here shows the same friendly name in list, the API, and the Beam project registry. --name sets that name (default: the folder’s own name); re-running add on an already-granted path with a new --name renames the project without changing its workspace id, so its existing sessions stay attached. This is the exact same marker stamp init --project and Beam’s “Add project” apply — one on-disk result across all three entry points.
Unlike fleet / mission, these do not reach serve over REST. A grant is durable config in the shared database (~/.contenox-harness/local.db), so add/remove write it directly and then ring a reload doorbell on the shared bus. A running contenox serve picks up the signal and swaps its live workspace-root set without a restart; a serve started later reads the same durable config at boot. So these verbs work whether or not serve is up, and a running serve applies them live.
add requires the path to be an existing directory (a workspace root must be a real directory); remove does not, so a grant to a since-deleted directory can be cleaned up. Both are idempotent. list prints the durable grants these verbs manage, each with its project name when set — serve additionally always allows its own launched default root (its served directory, or home for a bare contenox serve), which is not a grant and appears in the API and Beam folder picker (GET /workspace/roots) rather than here.
| Flag | Description |
|---|---|
--name <name> (on add) | Friendly project name stamped into the folder’s marker; re-adding with a new name renames the project |
A LAN operator working only through the browser has the same verbs over the authenticated REST surface: POST /workspace/roots {"path": "<dir>", "name": "<name>"} grants (and names) and DELETE /workspace/roots?path=<dir> revokes, each token-authed and returning the new root list — the same validation, project-marker stamp, durable write, and reload doorbell as the CLI. Each returned root carries its name (the marker’s, empty when unset), a default flag, and a managed flag marking the operator-added roots the browser may forget (as opposed to serve’s structural launch roots).
contenox workspace access [--root <root>] [--policy <name>] <path> [<path>...]
Preview what the active HITL policy would decide for a read and a write access to one or more paths — without touching the filesystem, prompting for approval, or running any tool call. This is the same evaluation the live agent’s tool dispatch gates run for local_fs (read_file/list_dir for the read dimension, write_file for the write dimension); it is also the batch, structured-reason data source behind Beam’s access-preview panel.
Unlike add/remove/list (durable grants, no serve required), a verdict is computed live by a running contenox serve — this reaches its REST API (POST /workspace/access), the same --server/--token/CONTENOX_SERVER_URL/CONTENOX_SERVER_TOKEN convention as contenox approvals.
contenox workspace access src/main.go
contenox workspace access --policy hitl-policy-strict.json .ssh/id_rsa
contenox workspace access --root /home/me/project src/main.go .ssh/id_rsa ../escape
Each <path> is relative to the workspace root being evaluated. A path that does not resolve inside that root (outside every allowlisted root, or past a symlink escape) comes back reachable:false with no read/write verdict — no policy is evaluated for a path that is not really inside the root. Sample run against a workspace root containing a normal source file and a .ssh/id_rsa key, evaluated under hitl-policy-strict.json:
$ contenox workspace access --policy hitl-policy-strict.json src/main.go .ssh/id_rsa ../escape
Policy: hitl-policy-strict.json
PATH REACHABLE READ WRITE REASON
src/main.go true allow approve write:matched_rule#30
.ssh/id_rsa true deny deny read:matched_rule#0 write:matched_rule#0
../escape false - - -
The header line names the resolved policy (the one that actually gated the batch — the active-policy KV value or the configured fallback, not merely whatever --policy was requested). READ/WRITE show each dimension’s action (allow/approve/deny); the REASON column omits a plain allow (the routine, expected case) and otherwise shows which rule decided it (matched_rule#<index>) or that the policy’s default_action applied.
| Flag | Description |
|---|---|
--root <root> | Workspace root the paths resolve against (a granted root, or a directory under one); omitted resolves to serve’s default (first-configured) root |
--policy <name> | HITL policy file name to evaluate against, e.g. hitl-policy-strict.json; omitted uses the runtime’s active policy resolution, the same one the live agent uses |
--server <url> / --token <token> | Reach a running contenox serve (as contenox approvals) |
contenox state
Inspects captured execution state from past chain runs — the per-task steps, handlers, transitions, and timings recorded for each request.
contenox state list # list request IDs with captured execution state
contenox state show <reqID> # print the captured steps for a request
contenox state show <reqID> --raw # print the raw captured state as JSON
contenox cache clear
Clears cached backend model lists so the next chat/run refetches them from the live backends. Use it after adding models to a backend that the runtime hasn’t picked up yet.
contenox cache clear
contenox update
Updates contenox to the latest release, or just checks for one.
contenox update # download and install the latest release
contenox update check # report whether a newer version exists, without installing
contenox acp / contenox acpx
Run Contenox as an ACP agent over stdio, for editor/desktop clients (Zed, JetBrains, AionUi, OpenClaw). acp uses the standard editor profile (gated tools route through the client’s approval UI); acpx uses the hardened headless / untrusted-driver profile.
contenox acp # standard editor profile
contenox acp --auto # unattended: disable HITL permission prompts
contenox acpx # headless / untrusted-driver profile
The chain each profile loads is overridable via CONTENOX_ACP_CHAIN_PATH (acp) and CONTENOX_ACPX_CHAIN_PATH (acpx). See the editor integration guides for client setup.
contenox version
Prints the current binary version and exits.
contenox version
Environment variables
| Variable | Description |
|---|---|
CONTENOX_ACP_CHAIN_PATH | Override the chain file used by ACP sessions |
CONTENOX_ACPX_CHAIN_PATH | Override the chain file used by headless ACPX sessions |
CONTENOX_SERVER_URL | Base URL of a running contenox serve for fleet/mission/approvals (instead of --server). In a contenox acp editor session, setting it is also the explicit opt-in that forwards /mission dispatches to that serve instead of running them in-process. |
CONTENOX_SERVER_TOKEN | Bearer token for the serve API (instead of --token). |
CONTENOX_DEFAULT_MODEL / CONTENOX_DEFAULT_PROVIDER | Process-level override of the configured default model/provider (nothing is persisted). Also the ACP env_var auth-method contract for non-interactive setup. |
CONTENOX_DEFAULT_ALT_MODEL / CONTENOX_DEFAULT_ALT_PROVIDER | Same, for the alt model pair. |
CONTENOX_DEFAULT_MAX_TOKENS / CONTENOX_DEFAULT_THINK | Same, for the response token cap and reasoning level. |
CONTENOX_BASE_URL | Endpoint URL for account-specific providers whose URL cannot be defaulted (e.g. Vertex: project + region). |