> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xorcise.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration keys

> Every key XORCISE reads from config.toml or the environment, with its type, default, environment variable and precedence order.

XORCISE reads its configuration from `~/.xorcise/config.toml`, `~/.xorcise/.env` and the process environment. Every key below is settable in all three places.

## Every configuration key

`config.toml` is a flat key-and-value file with no sections. Keys are lowercase and unprefixed. The environment variable for any key is `XORCISE_` followed by the key in upper case.

| Key                                | Type                         | Default                                         | Environment variable                       | Meaning                                                                      |
| ---------------------------------- | ---------------------------- | ----------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------- |
| `model_key`                        | `str`                        | unset                                           | `XORCISE_MODEL_KEY`                        | API key for the judge model. Secret                                          |
| `model_base_url`                   | `str`                        | unset (client uses `https://api.openai.com/v1`) | `XORCISE_MODEL_BASE_URL`                   | OpenAI-compatible base URL for the judge                                     |
| `model_name`                       | `str`                        | unset                                           | `XORCISE_MODEL_NAME`                       | Judge model name                                                             |
| `model_timeout_seconds`            | `float`                      | `120.0`                                         | `XORCISE_MODEL_TIMEOUT_SECONDS`            | HTTP timeout for one judge call                                              |
| `judge_transcript_max_tokens`      | `int`                        | `0` (disabled)                                  | `XORCISE_JUDGE_TRANSCRIPT_MAX_TOKENS`      | Pre-flight ceiling on the estimated judge prompt                             |
| `judge_span_max_tokens`            | `int`                        | `2000`                                          | `XORCISE_JUDGE_SPAN_MAX_TOKENS`            | Per-span body cap in the distilled transcript                                |
| `judge_tokenizer`                  | `str`                        | `"o200k_base"`                                  | `XORCISE_JUDGE_TOKENIZER`                  | tiktoken encoding used to count the token budget                             |
| `terrain_model_key`                | `str`                        | unset (falls back to `model_key`)               | `XORCISE_TERRAIN_MODEL_KEY`                | API key for terrain attribution. Secret                                      |
| `terrain_model_base_url`           | `str`                        | unset (falls back to `model_base_url`)          | `XORCISE_TERRAIN_MODEL_BASE_URL`           | Base URL for terrain attribution                                             |
| `terrain_model_name`               | `str`                        | unset (falls back to `model_name`)              | `XORCISE_TERRAIN_MODEL_NAME`               | Model name for terrain attribution                                           |
| `terrain_transcript_max_tokens`    | `int`                        | `256000`                                        | `XORCISE_TERRAIN_TRANSCRIPT_MAX_TOKENS`    | Safety cap on one attribution call                                           |
| `terrain_auto_attribute`           | `bool`                       | `true`                                          | `XORCISE_TERRAIN_AUTO_ATTRIBUTE`           | Attribute terrain automatically when a run goes terminal                     |
| `database_url`                     | `str`                        | `sqlite:///~/.xorcise/xorcise.db`               | `XORCISE_DATABASE_URL`                     | SQLAlchemy URL for all durable state                                         |
| `missions_root`                    | `str`                        | `~/.xorcise/missions`                           | `XORCISE_MISSIONS_ROOT`                    | Where installed missions live                                                |
| `tailscale_cache_root`             | `str`                        | `~/.xorcise/cache/tailscale`                    | `XORCISE_TAILSCALE_CACHE_ROOT`             | Cache for the pinned Tailscale client                                        |
| `catalog_url`                      | `str`                        | `https://api.xorcise.ai`                        | `XORCISE_CATALOG_URL`                      | The hosted mission library endpoint                                          |
| `catalog_enabled`                  | `bool`                       | `true`                                          | `XORCISE_CATALOG_ENABLED`                  | Connect or disconnect the hosted library                                     |
| `catalog_key`                      | `str`                        | unset                                           | `XORCISE_CATALOG_KEY`                      | **Read by nothing.** See [keys that nothing reads](#keys-that-nothing-reads) |
| `use_stubs`                        | `bool`                       | `false`                                         | `XORCISE_USE_STUBS`                        | Force stub adapters for a Docker-less demo                                   |
| `docker_platform`                  | `str`                        | `"linux/amd64"`                                 | `XORCISE_DOCKER_PLATFORM`                  | Platform passed to `docker pull` and `docker run`                            |
| `role`                             | `str`                        | `"all"`                                         | `XORCISE_ROLE`                             | Which service role `xorcise serve` boots                                     |
| `host`                             | `str`                        | `"127.0.0.1"`                                   | `XORCISE_HOST`                             | Address XORCISE prints and health-polls. **Not the bind address**            |
| `rest_port`                        | `int`                        | `3001`                                          | `XORCISE_REST_PORT`                        | REST API and web UI port                                                     |
| `otlp_port`                        | `int`                        | `4318`                                          | `XORCISE_OTLP_PORT`                        | OTLP/HTTP ingest port                                                        |
| `runner_port`                      | `int`                        | `8800`                                          | `XORCISE_RUNNER_PORT`                      | Port for the experimental `runner` role                                      |
| `headscale_port`                   | `int`                        | `8080`                                          | `XORCISE_HEADSCALE_PORT`                   | Legacy fallback login-server port. Never used on a normal install            |
| `headscale_container`              | `str`                        | `"headscale"`                                   | `XORCISE_HEADSCALE_CONTAINER`              | Container name control operations exec into                                  |
| `orchestrator_user`                | `str`                        | `"orchestrator"`                                | `XORCISE_ORCHESTRATOR_USER`                | Headscale user owning the per-run routers                                    |
| `router_tag`                       | `str`                        | `"tag:router"`                                  | `XORCISE_ROUTER_TAG`                       | Access-policy tag for per-run subnet routers                                 |
| `headscale_url`                    | `str`                        | `""` (written by `xorcise up`)                  | `XORCISE_HEADSCALE_URL`                    | Login server URL for tailnet joins                                           |
| `headscale_ca_cert`                | `str`                        | `""` (written by `xorcise up`)                  | `XORCISE_HEADSCALE_CA_CERT`                | PEM path delivered to each run's router                                      |
| `headscale_host_alias`             | `str`                        | `""` (written by `xorcise up`)                  | `XORCISE_HEADSCALE_HOST_ALIAS`             | `headscale.local:<ip>` injected as the router's `extra_hosts`                |
| `headscale_advertise_host`         | `str`                        | `""` (written by `xorcise up`)                  | `XORCISE_HEADSCALE_ADVERTISE_HOST`         | Host that per-run routers and agents dial                                    |
| `deployment_topology`              | `"local"` or `"distributed"` | `"local"`                                       | `XORCISE_DEPLOYMENT_TOPOLOGY`              | Reachability topology. Also decides the bind address                         |
| `base_network`                     | `str`                        | `"10.200.0.0/16"`                               | `XORCISE_BASE_NETWORK`                     | Address pool runs are carved from                                            |
| `cidr_prefix`                      | `int`                        | `24`                                            | `XORCISE_CIDR_PREFIX`                      | Size of each run's carved subnet                                             |
| `key_expiration`                   | `str`                        | `"1h"`                                          | `XORCISE_KEY_EXPIRATION`                   | Time-to-live of a Headscale pre-auth key                                     |
| `default_budget_seconds`           | `int`                        | `3600`                                          | `XORCISE_DEFAULT_BUDGET_SECONDS`           | Default wall-clock budget for a run                                          |
| `budget_watchdog_interval_seconds` | `float`                      | `5.0`                                           | `XORCISE_BUDGET_WATCHDOG_INTERVAL_SECONDS` | How often XORCISE scans for expired runs                                     |
| `readiness_timeout_seconds`        | `float`                      | `90.0`                                          | `XORCISE_READINESS_TIMEOUT_SECONDS`        | How long a run may take to bring its environment up                          |
| `readiness_scan_interval_seconds`  | `float`                      | `5.0`                                           | `XORCISE_READINESS_SCAN_INTERVAL_SECONDS`  | Readiness gate scan interval                                                 |
| `telemetry_drain_seconds`          | `float`                      | `5.0` (0 to 300)                                | `XORCISE_TELEMETRY_DRAIN_SECONDS`          | How long OTLP ingest stays open after a run goes terminal                    |
| `attachment_ttl_seconds`           | `int`                        | `300`                                           | `XORCISE_ATTACHMENT_TTL_SECONDS`           | Lifetime of a signed attachment download URL                                 |
| `run_control_signing_secret`       | `str`                        | `"dev-insecure-signing-secret"`                 | `XORCISE_RUN_CONTROL_SIGNING_SECRET`       | HMAC secret for signed attachment URLs. Secret                               |
| `otel_mirror_enabled`              | `bool`                       | `false`                                         | `XORCISE_OTEL_MIRROR_ENABLED`              | **Reserved seam.** Enabling it fails boot                                    |
| `otel_mirror_endpoint`             | `str`                        | `""`                                            | `XORCISE_OTEL_MIRROR_ENDPOINT`             | **Reserved seam.** Nothing reads it                                          |

## Precedence

Highest wins:

```text theme={"theme":"css-variables"}
CLI flags  →  XORCISE_* environment  →  ~/.xorcise/.env  →  ~/.xorcise/config.toml
```

CLI flags sit at the top because `xorcise up` and `xorcise serve` resolve `--port`, `--otlp-port` and `--stub` and then stamp the resolved values into the environment before settings are read.

The rung that surprises people is the third one: **`.env` beats `config.toml`.** A key written in both files is read from `.env`. Since the web UI and the `xorcise config` setters all write to `.env`, a value you edited by hand in `config.toml` can be silently overridden by a value the UI wrote.

An `XORCISE_*` variable set in your shell beats both files, including when the CLI is only talking to a brain rather than starting one. Setting `XORCISE_REST_PORT` in your shell is read as a deliberate "talk to this port" instruction.

## Where to put each key

`.env` is created at mode `0600` and re-set to `0600` on every write. `config.toml` is world-readable. That difference is the whole rule.

Put in `.env`:

| Key                                         | Why                                                                                  |
| ------------------------------------------- | ------------------------------------------------------------------------------------ |
| `model_key`, `terrain_model_key`            | API keys. `.env` is the only copy on your machine                                    |
| `run_control_signing_secret`                | Ships with a knowingly insecure default                                              |
| `catalog_enabled`                           | Not a secret, but this is where the UI switch and `xorcise catalog connect` write it |
| `headscale_url`, `headscale_advertise_host` | Where `xorcise config set-network` writes them                                       |

Put in `config.toml`: non-secret shape — `role`, `host`, and the port keys. This is what `xorcise up` scaffolds on first start, and it is where `up` appends its managed Headscale block.

Both files are created by the first `xorcise up` and never overwritten afterwards.

## Judge model keys

The judge is bring-your-own-model. XORCISE bundles none, and calls whichever OpenAI-compatible endpoint you configure.

<Warning>
  Judge and terrain calls are billed to you by your model provider. `terrain_auto_attribute` defaults to `true`, so every run that reaches a terminal state makes attribution calls without anyone opening the run. Set it to `false` to keep that spend strictly to runs you view.
</Warning>

### `model_key`

`str` · default unset · `XORCISE_MODEL_KEY`

Your API key. With no key set, the judge half of every score degrades to `0.0` and the run is still graded deterministically. Keep it in `.env`.

### `model_base_url`

`str` · default unset · `XORCISE_MODEL_BASE_URL`

The OpenAI-compatible base URL. Unset means the client's own default, `https://api.openai.com/v1`. Point it at a self-hosted endpoint to keep transcripts on infrastructure you control.

### `model_name`

`str` · default unset · `XORCISE_MODEL_NAME`

The model to grade with, for example `gpt-4o-mini`.

### `model_timeout_seconds`

`float` · default `120.0` · `XORCISE_MODEL_TIMEOUT_SECONDS`

HTTP timeout for one judge call. The default is generous so that a slow reasoning model does not report as judge-unavailable.

### `judge_transcript_max_tokens`

`int` · default `0` · `XORCISE_JUDGE_TRANSCRIPT_MAX_TOKENS`

A pre-flight ceiling on the estimated judge prompt. `0` disables it, which is the default: the token count is an estimate, so a hard gate risks rejecting prompts the provider would have accepted. Letting the provider's own limit be the gate returns an accurate error, and the run stays re-gradeable. Set a positive value only for a small-context self-hosted judge.

### `judge_span_max_tokens`

`int` · default `2000` · `XORCISE_JUDGE_SPAN_MAX_TOKENS`

Caps each span's body in the distilled transcript, keeping a head and tail window with an elision marker between them. Transcripts are fat-tailed — a few enormous tool-output spans dominate the count — so this collapses the tail without dropping any span. `0` disables it.

### `judge_tokenizer`

`str` · default `"o200k_base"` · `XORCISE_JUDGE_TOKENIZER`

The tiktoken encoding used to count the budget. Tokenizers are not interchangeable, so the choice is explicit. An unrecognised name degrades to a coarse characters-divided-by-four heuristic. For a non-OpenAI judge this is an approximation, not an exact count.

## Terrain attribution keys

Terrain attribution asks a model which part of the mission map each event touched. Each key falls back to its judge equivalent when unset, so by default terrain uses the same model as the judge. The timeout is always `model_timeout_seconds`.

### `terrain_model_key`

`str` · default unset · `XORCISE_TERRAIN_MODEL_KEY`

Overrides `model_key` for attribution only. Secret; keep it in `.env`.

### `terrain_model_base_url`

`str` · default unset · `XORCISE_TERRAIN_MODEL_BASE_URL`

Overrides `model_base_url` for attribution only.

### `terrain_model_name`

`str` · default unset · `XORCISE_TERRAIN_MODEL_NAME`

Overrides `model_name` for attribution only. A cheaper, smaller model is a reasonable choice here.

### `terrain_transcript_max_tokens`

`int` · default `256000` · `XORCISE_TERRAIN_TRANSCRIPT_MAX_TOKENS`

A safety cap on a single attribution call. Unlike the judge, terrain attributes in bounded batches, and an oversized batch is shrunk by dropping trailing events rather than failed. Lower it for a small-context attribution model.

### `terrain_auto_attribute`

`bool` · default `true` · `XORCISE_TERRAIN_AUTO_ATTRIBUTE`

Attributes the terrain plane when a run goes terminal, so every run's map is complete afterwards regardless of who looked at it. It is a no-op when no terrain or judge model is configured.

## Storage keys

Each of these is empty in the model and filled at load time with a path under `~/.xorcise`. Setting one moves that store.

### `database_url`

`str` · default `sqlite:///~/.xorcise/xorcise.db` · `XORCISE_DATABASE_URL`

A SQLAlchemy URL. This one database holds agents, runs, results, grades and the raw OTLP traces and logs. PostgreSQL needs the `postgres` extra and is not a tested path for normal use.

### `missions_root`

`str` · default `~/.xorcise/missions` · `XORCISE_MISSIONS_ROOT`

Where ingested and pulled missions are installed.

### `tailscale_cache_root`

`str` · default `~/.xorcise/cache/tailscale` · `XORCISE_TAILSCALE_CACHE_ROOT`

Where the pinned static Tailscale client is cached, one tarball of roughly 37 MB per architecture. Pre-seeding this directory lets an air-gapped agent join the tailnet with no public egress.

## Mission library keys

XORCISE is connected to the hosted library when `catalog_enabled` is true **and** `catalog_url` is set. Both ship that way, so a default install is **connected** to the production catalog and the library is populated on first run. Disconnected means an empty remote library, never a fabricated one. No API key, account or sign-in is involved at any point.

### `catalog_url`

`str` · default `https://api.xorcise.ai` · `XORCISE_CATALOG_URL`

The library endpoint, defaulting to the production XORCISE catalog. Point it at another tier to use one, or clear it and the library reports `disconnected` rather than probing an unreachable host. Use `catalog_enabled` rather than this key to disconnect: the switch is a clean boolean, and clearing the URL is what a disconnect should not depend on.

### `catalog_enabled`

`bool` · default `true` · `XORCISE_CATALOG_ENABLED`

The connect and disconnect switch, written by the Settings page and by `xorcise catalog connect`. It is a boolean rather than an empty URL so that disconnecting cannot silently revert to the default endpoint.

### `catalog_key`

`str` · default unset · `XORCISE_CATALOG_KEY`

Declared but read by nothing. Setting it has no effect. See [keys that nothing reads](#keys-that-nothing-reads).

## Runner keys

### `use_stubs`

`bool` · default `false` · `XORCISE_USE_STUBS`

Forces stub adapters so XORCISE boots without Docker. Runs created in this mode do not launch containers. `xorcise up --stub` sets it for one boot.

### `docker_platform`

`str` · default `"linux/amd64"` · `XORCISE_DOCKER_PLATFORM`

The platform passed to `docker pull` and `docker run`. Mission images are built for amd64 only, so an arm64 host must request `linux/amd64` and run them under emulation, or the pull fails on a missing manifest. An empty value lets Docker choose the host platform.

## Role and endpoint keys

XORCISE serves two planes: the REST API with the web UI on `3001`, and OTLP/HTTP ingest on `4318`. Both scan up to 50 ports above the requested one when the port is busy, printing a notice for each move, so read the ports `xorcise up` printed rather than assuming the defaults. **There is no MCP plane and no port `3100`.**

### `role`

`str` · default `"all"` · `XORCISE_ROLE`

Which service role `xorcise serve` boots. See [deployment roles](#deployment-roles). `xorcise up` always boots `all`.

### `host`

`str` · default `"127.0.0.1"` · `XORCISE_HOST`

The address XORCISE prints in URLs, health-polls and scans during preflight. It is **not** the bind address. In the default `local` topology both planes bind `127.0.0.1` and `::1`, plus the Docker bridge gateway on native Linux. Setting `host` to any value other than `0.0.0.0` leaves that bind as it is; setting it to `0.0.0.0` is the one value that widens it to the IPv4 wildcard. See [Security and isolation](/operate/security).

### `rest_port`

`int` · default `3001` · `XORCISE_REST_PORT`

The REST API and web UI port. `xorcise up --port` overrides it for one boot.

### `otlp_port`

`int` · default `4318` · `XORCISE_OTLP_PORT`

The OTLP/HTTP ingest port, matching the OpenTelemetry specification default. `xorcise up --otlp-port` overrides it for one boot.

### `runner_port`

`int` · default `8800` · `XORCISE_RUNNER_PORT`

Only used by the experimental `runner` role, which serves nothing but a health endpoint.

### `headscale_port`

`int` · default `8080` · `XORCISE_HEADSCALE_PORT`

A fallback used to derive a plain-HTTP login server when `headscale_url` is unset. On a normal install `xorcise up` always writes `headscale_url`, so this never applies.

## Per-run network keys

`xorcise up` writes `headscale_url`, `headscale_ca_cert`, `headscale_host_alias` and `headscale_advertise_host` into a managed block in `config.toml`, delimited by `# >>> xorcise headscale (managed) >>>`. The block is rewritten on every `up` and any hand-written configuration outside it survives. Set these by hand only when you are pointing XORCISE at a control plane you run yourself, and use `xorcise config set-network`, which is marked experimental and needs a restart.

### `headscale_container`

`str` · default `"headscale"` · `XORCISE_HEADSCALE_CONTAINER`

The container name that control operations `docker exec` into. Control is container-based, not URL-based, which is why `xorcise doctor` probes the container.

### `orchestrator_user`

`str` · default `"orchestrator"` · `XORCISE_ORCHESTRATOR_USER`

The Headscale user that owns per-run subnet routers.

### `router_tag`

`str` · default `"tag:router"` · `XORCISE_ROUTER_TAG`

The access-policy tag whose auto-approvers accept each router's advertised routes.

### `headscale_url`

`str` · default `""` · `XORCISE_HEADSCALE_URL`

The login server tailnet joins use. A locally provisioned control plane sets `https://<host-ip>:443`. A value that does not match the managed block is treated as an external control plane, verified at boot rather than provisioned.

### `headscale_ca_cert`

`str` · default `""` · `XORCISE_HEADSCALE_CA_CERT`

Path to the PEM delivered to each run's router so it trusts the self-signed control-plane certificate.

### `headscale_host_alias`

`str` · default `""` · `XORCISE_HEADSCALE_HOST_ALIAS`

A `headscale.local:<ip>` pair injected as the router's `extra_hosts`, and the source of the host-to-IP rewrite in a join URL.

### `headscale_advertise_host`

`str` · default `""` · `XORCISE_HEADSCALE_ADVERTISE_HOST`

The host per-run routers and agents dial. `host` is the REST bind address and is not reachable from inside the fused container's nested network, so this is set to the Docker bridge gateway instead.

### `deployment_topology`

`"local"` or `"distributed"` · default `"local"` · `XORCISE_DEPLOYMENT_TOPOLOGY`

`local` binds both planes to loopback — plus, on native Linux, the Docker bridge gateway — which is the narrowest set that still lets a container-launched agent reach them through `host.docker.internal`. `distributed` binds `host` alone and adds an orchestrator router to the control-plane compose file. Distributed operation is unfinished; treat it as experimental.

### `base_network`

`str` · default `"10.200.0.0/16"` · `XORCISE_BASE_NETWORK`

The address pool each run's subnet is carved from. Change it if it collides with your own networks.

### `cidr_prefix`

`int` · default `24` · `XORCISE_CIDR_PREFIX`

The size of each run's carved subnet. With the defaults this gives 254 concurrent runs.

### `key_expiration`

`str` · default `"1h"` · `XORCISE_KEY_EXPIRATION`

Time-to-live of the single-use Headscale pre-auth keys minted for each run's agent and router.

## Run lifecycle keys

### `default_budget_seconds`

`int` · default `3600` · `XORCISE_DEFAULT_BUDGET_SECONDS`

The wall-clock budget a run gets when you do not set one. A run terminated by its budget is marked partial.

### `budget_watchdog_interval_seconds`

`float` · default `5.0` · `XORCISE_BUDGET_WATCHDOG_INTERVAL_SECONDS`

How often XORCISE scans for runs past their budget. Expired runs are terminated even when they send no traffic.

### `readiness_timeout_seconds`

`float` · default `90.0` · `XORCISE_READINESS_TIMEOUT_SECONDS`

How long a deployed run may take to bring its environment up before XORCISE closes it out as `deploy_failed`. Deployment does not block on bring-up, so without this gate a run whose environment died would sit non-terminal forever while the agent worked a target that never existed. `0` disables the gate.

### `readiness_scan_interval_seconds`

`float` · default `5.0` · `XORCISE_READINESS_SCAN_INTERVAL_SECONDS`

How often the readiness gate scans.

### `telemetry_drain_seconds`

`float` · default `5.0`, clamped to 0 through 300 · `XORCISE_TELEMETRY_DRAIN_SECONDS`

How long OTLP ingest stays open after a run goes terminal. Short-lived harnesses commonly flush their final tool result after completing the run, and sealing before that flush rejects the last batch permanently.

### `attachment_ttl_seconds`

`int` · default `300` · `XORCISE_ATTACHMENT_TTL_SECONDS`

Lifetime of a signed attachment download URL.

## Signing and telemetry keys

### `run_control_signing_secret`

`str` · default `"dev-insecure-signing-secret"` · `XORCISE_RUN_CONTROL_SIGNING_SECRET`

The HMAC secret that signs short-lived attachment download URLs. The default is insecure by name. Override it in `.env` on any host other than your own laptop, then restart XORCISE.

### `otel_mirror_enabled`

`bool` · default `false` · `XORCISE_OTEL_MIRROR_ENABLED`

A reserved seam for mirroring traces to your own OpenTelemetry service. No exporter is built. Setting it to `true` fails the boot with an explicit message rather than quietly doing nothing.

### `otel_mirror_endpoint`

`str` · default `""` · `XORCISE_OTEL_MIRROR_ENDPOINT`

Reserved alongside `otel_mirror_enabled`. Nothing reads it.

## Keys that nothing reads

Two keys exist in the settings model and have no effect. They are listed here so that setting one and seeing no change is not mistaken for a bug.

| Key                    | Status                                                                                                                                                                        |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `catalog_key`          | Declared, never read. The hosted library needs no API key, account or sign-in. Private mission images use short-lived scoped registry credentials the library mints on demand |
| `otel_mirror_endpoint` | Declared, never read. Its companion `otel_mirror_enabled` is read only to fail the boot when it is on                                                                         |

`headscale_port` is a third near-miss: it is read, but only as a fallback that a normal install never reaches.

## Deployment roles

`xorcise up` always boots role `all` and never passes a role flag, so a default install cannot reach any other role. The role surface is reachable only through `xorcise serve --role`, and the CLI labels it EXPERIMENTAL.

| Role        | Binds             | Maturity     | What it does today                                                                                          |
| ----------- | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------- |
| `all`       | `3001` and `4318` | Ready        | The complete install: evaluation, runner, networking, telemetry, library                                    |
| `control`   | `3001`            | Experimental | **Silently stubs run execution.** `POST /runs` answers 201 with a run id, and no container is ever launched |
| `runner`    | `8800`            | Experimental | Serves `GET /healthz` and nothing else. No brain can hand it work                                           |
| `headscale` | `8080`            | Experimental | Serves `GET /healthz` and nothing else. Unrelated to the Headscale container that runs actually use         |
| `collector` | `4318`            | Experimental | Receives and stores OTLP. The one non-`all` role that does real work                                        |

Booting an experimental role prints its caveat before it does any work.

## The \~/.xorcise directory

`$XORCISE_HOME` overrides the location. The first `xorcise up` creates everything below.

| Path                               | What it is                                                                                                   |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `config.toml`                      | Non-secret configuration, plus the managed Headscale block `up` appends                                      |
| `.env`                             | Secrets and UI-written settings, mode `0600`                                                                 |
| `xorcise.db`                       | Every agent, run, result, grade and raw OTLP trace and log. Sidecar `-wal` and `-shm` files belong to SQLite |
| `xorcise.pid`                      | The detached brain's process id. Deleting it while XORCISE runs orphans the process                          |
| `runtime-ports.json`               | The ports actually bound, so sibling CLI calls find a relocated brain                                        |
| `serve.log`                        | **The brain's stderr. This is where a failed boot leaves its traceback.** Truncated on every `up`            |
| `frontend-build.log`               | Web UI build output. Source checkouts only                                                                   |
| `logs/`                            | **Empty. Nothing writes here.** Boot failures go to `serve.log`                                              |
| `runs/<run_id>/agent-events.jsonl` | Derived event export, rebuildable from the raw traces in the database                                        |
| `missions/<slug>/`                 | An installed mission. `installed.json` is the install marker; delete the whole directory, not that file      |
| `cache/tailscale/`                 | The pinned Tailscale client, one tarball per architecture                                                    |
| `headscale/config.yaml`            | Control-plane configuration, re-rendered on every `up`                                                       |
| `headscale/compose.yaml`           | Control-plane compose file, re-rendered on every `up`                                                        |
| `headscale/certs/`                 | The private CA key and the control-plane certificate. Delete the whole directory or none of it               |
| `headscale/.owned`                 | The ownership marker `xorcise down` uses to find the control plane it created                                |

<Warning>
  Never delete `~/.xorcise/headscale/.owned` by hand. It is the only thing that lets `xorcise down` find and remove the Headscale container and its volume. Without it they keep running and no XORCISE command will clean them up again.
</Warning>

`xorcise down` removes only `logs/`, `runtime-ports.json` and `xorcise.pid`. `xorcise down --purge` removes the entire directory, including `.env` and your database.

## Related pages

* [Security and isolation](/operate/security) — what the bind address, the signing secret and the model keys mean in practice.
* [CLI reference](/reference/cli) — the commands that read and write these keys.
