> ## Documentation Index
> Fetch the complete documentation index at: https://solo-09d10f60.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration overview

> Required and optional Enoch config fields, with safe defaults and secret-handling guidance.

Enoch reads its configuration from a single JSON file whose path you set in the `ENOCH_CONFIG` environment variable, with `ENOCH_CONTROL_PLANE_CONFIG` accepted as a secondary explicit config variable. Every field is validated at startup using Pydantic; the service refuses to start if a required field is missing or a value is out of range. This page documents the core configuration fields, shows you how to generate the secure tokens the service needs, and walks through the annotated `config.example.json` used as the repository baseline. Worker, evidence-sync, and paper-writer fields are covered on their respective sub-pages.

Enoch reads JSON configuration from the path in `ENOCH_CONFIG`. The app validates required fields at startup with Pydantic.

Start from `config.example.json`, then replace every placeholder before running a live deployment.
For current runtime topology and compatibility naming, see
[current runtime snapshot](/current-runtime-snapshot).

## Required fields

* `control_api_bearer_token` — bearer token for dashboard/control API calls and incoming worker event posts.
* `completion_callback_url` — URL called when a worker-gated run completes.
* `completion_callback_token` — bearer token sent to the completion callback endpoint.

The config model also requires sensible paths for state, projects, and dispatch: `state_dir`, `project_root`, and `dispatch_script_path`.

## Core runtime fields

* `listen_host`, `listen_port`
* `dispatch_timeout_sec`
* `log_events`
* `live_dispatch_enabled`
* `worker_wake_gate_url`
* `worker_wake_gate_bearer_token`

Use dry-run dispatch until you have intentionally enabled and tested live dispatch.

## Worker-gate thresholds

Configure sampling, sustain windows, CPU/GPU thresholds, VRAM delta limits, workload profiles, and maximum wait after idle through the `sample_interval_sec`, `idle_sustain_sec`, `cpu_idle_threshold_pct`, `gpu_idle_*`, `vram_delta_threshold_mib`, `workload_profiles`, and `max_wait_after_idle_sec` fields.

Supported workload classes are `unknown`, `cpu_only`, `gpu_required`, `inference_eval`, `training`, `control_plane`, and `agent_harness`.

## Optional integrations

* Pushover queue alerts: `pushover_alerts_enabled`, `pushover_app_token`, `pushover_user_key`, `pushover_api_url`, `queue_alert_*`.
* Hermes alert webhook (optional): `hermes_alert_webhook_enabled`, `hermes_alert_webhook_url`, `hermes_alert_webhook_secret`, `hermes_alert_webhook_timeout_sec`.
* Queue pump (timer-driven dispatch): `queue_pump_enabled`, `queue_pump_followup_launch_enabled`, `queue_pump_paper_draft_enabled`.
* Multi-worker routing: `worker_targets`, `workload_machine_targets` (maps workload classes such as `cpu_only` and `gpu_required` to named worker targets).
* Store backend: `control_plane_store_backend` (`sqlite`, `supabase_readonly`, or `supabase`), `enoch_core_store_backend`, `supabase_database_url`. Current deployments use the `supabase` adapter name for Postgres-backed storage; treat the setting name as a compatibility adapter label, not a Supabase Cloud claim.
* Paper writer: `paper_writer_provider`, `paper_writer_base_url`, `paper_writer_model`, `paper_writer_api_key`, `paper_writer_*` tuning, and fallback.
* Evidence sync: `paper_evidence_sync_enabled`, `paper_evidence_sync_ssh_host`, `paper_evidence_sync_remote_root`, `paper_evidence_sync_timeout_sec`.
* Route observability (private diagnostics): `route_observability_enabled`, `route_observability_log_path`, `route_observability_slow_ms`, `route_observability_memory_warn_rss_mib`.
* Operational trace (private diagnostics): `operational_trace_enabled`, `operational_trace_log_path`, `operational_trace_max_payload_bytes` (minimum 1024). Keep disabled unless you intentionally want raw request/response payloads captured.

## Deprecated aliases

Older private prototypes used `omx_inbound_bearer_token`, `n8n_callback_url`, `n8n_bearer_token`, and `n8n_callback_timeout_sec`. New configs should use `control_api_bearer_token` and `completion_callback_*` fields.

## Secret handling

<ParamField path="sample_interval_sec" type="number" default="5">
  How often (in seconds) the gate samples CPU and GPU telemetry. Minimum value is `1`.
</ParamField>

<ParamField path="idle_sustain_sec" type="number" default="180">
  How long (in seconds) all idle thresholds must remain satisfied before the gate considers the workload complete. Minimum value is `30`.
</ParamField>

<ParamField path="cpu_idle_threshold_pct" type="number" default="35.0">
  CPU utilisation percentage below which the gate counts a sample as idle. Range `0.0`–`100.0`.
</ParamField>

<ParamField path="gpu_idle_avg_threshold_pct" type="number" default="10.0">
  Average GPU utilisation percentage below which a sample is considered idle. Range `0.0`–`100.0`.
</ParamField>

<ParamField path="gpu_idle_peak_threshold_pct" type="number" default="20.0">
  Peak GPU utilisation percentage below which a sample is considered idle. Range `0.0`–`100.0`.
</ParamField>

<ParamField path="vram_delta_threshold_mib" type="number" default="1024">
  Maximum VRAM change in MiB between consecutive samples that is still counted as idle. Set to `0` to require no VRAM movement.
</ParamField>

<ParamField path="max_wait_after_idle_sec" type="number" default="43200">
  Hard ceiling (in seconds) on how long the gate will wait for a workload to become idle before timing out. Minimum value is `60`.
</ParamField>

<ParamField path="default_workload_class" type="string" default="inference_eval">
  Workload class applied when a dispatch request does not specify one. Valid values are `unknown`, `cpu_only`, `gpu_required`, `inference_eval`, `training`, `control_plane`, and `agent_harness`. Each class maps to a threshold profile; `inference_eval` applies stricter idle requirements (longer sustain, lower CPU threshold) than `training`.
</ParamField>

<Tip>
  You can override per-workload thresholds using the `workload_profiles` map in your config. Define an object keyed by workload class name with the same fields as `GateThresholdProfile` (`idle_sustain_sec`, `cpu_idle_threshold_pct`, `gpu_idle_avg_threshold_pct`, `gpu_idle_peak_threshold_pct`, `vram_delta_threshold_mib`).
</Tip>

## Annotated example config

The following JSON mirrors the repository `config.example.json` baseline at the time this docs page was audited. It includes optional/default-off sections such as queue pump, Pushover alerts, route observability, and provider-backed paper writing. Copy it, remove fields you do not need, and replace every placeholder value before use.

```json theme={null}
{
  "listen_host": "0.0.0.0",
  "listen_port": 8787,
  "state_dir": "~/.local/state/enoch-worker-gate",
  "project_root": "~/enoch/projects",
  "dispatch_script_path": "~/enoch/bin/enoch_codex_dispatch.sh",
  "dispatch_timeout_sec": 30,
  "control_api_bearer_token": "replace-with-local-control-api-token",
  "sample_interval_sec": 5,
  "default_workload_class": "inference_eval",
  "idle_sustain_sec": 180,
  "cpu_idle_threshold_pct": 35.0,
  "gpu_idle_avg_threshold_pct": 10.0,
  "gpu_idle_peak_threshold_pct": 20.0,
  "vram_delta_threshold_mib": 1024,
  "workload_profiles": {
    "inference_eval": {
      "idle_sustain_sec": 300,
      "cpu_idle_threshold_pct": 20.0,
      "gpu_idle_avg_threshold_pct": 10.0,
      "gpu_idle_peak_threshold_pct": 20.0,
      "vram_delta_threshold_mib": 1024
    },
    "training": {
      "idle_sustain_sec": 180,
      "cpu_idle_threshold_pct": 35.0,
      "gpu_idle_avg_threshold_pct": 10.0,
      "gpu_idle_peak_threshold_pct": 20.0,
      "vram_delta_threshold_mib": 1024
    },
    "cpu_only": {
      "idle_sustain_sec": 300,
      "cpu_idle_threshold_pct": 20.0,
      "gpu_idle_avg_threshold_pct": 10.0,
      "gpu_idle_peak_threshold_pct": 20.0,
      "vram_delta_threshold_mib": 1024
    },
    "gpu_required": {
      "idle_sustain_sec": 180,
      "cpu_idle_threshold_pct": 35.0,
      "gpu_idle_avg_threshold_pct": 10.0,
      "gpu_idle_peak_threshold_pct": 20.0,
      "vram_delta_threshold_mib": 1024
    }
  },
  "max_wait_after_idle_sec": 43200,
  "stale_project_process_reaper_enabled": true,
  "stale_project_process_grace_sec": 900,
  "stale_project_process_term_grace_sec": 5.0,
  "stale_project_process_command_markers": [
    "timeout ",
    "llama-cli",
    "llama-server",
    "vllm",
    "sglang"
  ],
  "completion_callback_url": "https://automation.example.com/webhook/enoch-worker-callback",
  "completion_callback_token": "replace-with-callback-token",
  "completion_callback_timeout_sec": 120,
  "worker_wake_gate_url": "http://worker.example:8787",
  "worker_wake_gate_bearer_token": "replace-with-worker-token",
  "worker_targets": {
    "gb10": {
      "wake_gate_url": "http://gb10-worker.example:8787",
      "bearer_token": "replace-with-gb10-worker-token",
      "role": "gpu_worker"
    },
    "cpu-worker": {
      "wake_gate_url": "http://cpu-worker.example:8787",
      "bearer_token": "replace-with-cpu-worker-token",
      "role": "cpu_worker",
      "min_memory_available_mib": 16384
    }
  },
  "workload_machine_targets": {
    "cpu_only": "cpu-worker",
    "gpu_required": "gb10"
  },
  "log_events": true,
  "pushover_alerts_enabled": false,
  "pushover_app_token": "",
  "pushover_user_key": "",
  "pushover_api_url": "https://api.pushover.net/1/messages.json",
  "queue_alert_cooldown_sec": 1800,
  "queue_alert_hang_after_sec": 3600,
  "queue_pump_enabled": false,
  "queue_pump_followup_launch_enabled": false,
  "queue_pump_paper_draft_enabled": false,
  "paper_writer_provider": "deterministic",
  "paper_writer_base_url": "https://api.synthetic.new/openai/v1",
  "paper_writer_model": "hf:zai-org/GLM-5.1",
  "paper_writer_api_key": "",
  "paper_writer_timeout_sec": 180,
  "paper_writer_temperature": 0.2,
  "paper_writer_max_tokens": 12000,
  "paper_writer_fallback_enabled": true,
  "route_observability_enabled": false,
  "route_observability_log_path": "",
  "route_observability_slow_ms": 1000,
  "route_observability_memory_warn_rss_mib": 0,
  "operational_trace_enabled": false,
  "operational_trace_log_path": "",
  "operational_trace_max_payload_bytes": 16384,
  "control_plane_store_backend": "sqlite",
  "enoch_core_store_backend": "control_plane",
  "supabase_database_url": "",
  "legacy_notion_api_enabled": false
}
```

## Configuration sections

The full configuration covers two additional areas, each documented on its own page:

* **[Worker and evidence sync](/configuration/worker)** — connecting the control plane to a worker machine, enabling evidence sync, and configuring the stale-process reaper.
* **[Paper writer and AI model settings](/configuration/paper-writer)** — choosing between the `deterministic` template provider and the `synthetic.new` production provider, and tuning generation parameters.
