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

# NSP Axon Daemon Configuration Reference: axon.toml

> Complete reference for every axon.toml section and AXON_* environment variable, with a full example config and reload instructions.

The daemon reads its configuration from `axon.toml` at startup. Most deployments only need to touch a few keys — the defaults are production-safe — but the full file is documented here so you know exactly what every option controls. Environment variables are available for every key and always take precedence over the file, making them ideal for CI, containers, or quick overrides without editing the file on disk.

## Config File Location

The daemon loads configuration from these locations in order, with later sources overriding earlier ones:

```text theme={null}
C:\ProgramData\Nelieo\axon.toml   ← system-wide default (applied first)
%APPDATA%\Nelieo\axon.toml        ← per-user overrides
.\axon.toml                        ← working directory (development only)
AXON_* environment variables       ← highest priority, always wins
```

The system-wide file at `C:\ProgramData\Nelieo\axon.toml` is created automatically by the installer or by `axon-daemon.exe init`.

<Tip>
  The daemon watches `axon.toml` for changes and reloads most settings live without a restart. Changes to `[server]` (port/host) and `[service]` require a full service restart to take effect.
</Tip>

## Full Example Config

The following file documents every available option with its default value. Copy this as a starting point and remove any sections you don't need to change.

```toml theme={null}
# ─────────────────────────────────────────────────────────
# HTTP Server
# ─────────────────────────────────────────────────────────
[server]
host = "127.0.0.1"
port = 7842
request_timeout_ms = 30000
max_body_bytes = 10485760

# ─────────────────────────────────────────────────────────
# Authentication
# ─────────────────────────────────────────────────────────
[auth]
require_key = true
keys_file = "C:\\ProgramData\\Nelieo\\axon_keys.json"

# ─────────────────────────────────────────────────────────
# Rate Limiting
# ─────────────────────────────────────────────────────────
[rate_limit]
enabled = true
state_per_second = 100
action_per_second = 10
snapshot_per_minute = 2
bucket_ttl_secs = 3600

# ─────────────────────────────────────────────────────────
# Process Watcher
# ─────────────────────────────────────────────────────────
[watcher]
scan_interval_secs = 5
poll_interval_secs = 2
min_confidence = 0.4
probe_unknown = false
max_tracked_processes = 256

# ─────────────────────────────────────────────────────────
# Action Dispatcher
# ─────────────────────────────────────────────────────────
[dispatcher]
post_action_wait_ms = 200
verify_expression_max_bytes = 2048
cdp_action_timeout_ms = 30000

# ─────────────────────────────────────────────────────────
# Schema Registry
# ─────────────────────────────────────────────────────────
[registry]
db_path = "C:\\ProgramData\\Nelieo\\axon_registry.db"
in_memory = false

# ─────────────────────────────────────────────────────────
# CORS
# ─────────────────────────────────────────────────────────
[cors]
allow_all_origins = false
allowed_origins = []

# ─────────────────────────────────────────────────────────
# Logging
# ─────────────────────────────────────────────────────────
[logging]
level = "info"
format = "json"
include_spans = false

# ─────────────────────────────────────────────────────────
# Async Runtime
# ─────────────────────────────────────────────────────────
[runtime]
worker_threads = 0

# ─────────────────────────────────────────────────────────
# Windows Service
# ─────────────────────────────────────────────────────────
[service]
name = "NSPDaemon"
display_name = "NSP Daemon"
description = "Nelieo State Protocol — Universal runtime substrate for AI agents"
auto_start = true
```

## Configuration Reference

<AccordionGroup>
  <Accordion title="[server] — HTTP API server">
    <ParamField body="host" type="string" default="127.0.0.1">
      The IP address the daemon binds to. The default `127.0.0.1` restricts access to localhost only. Never set this to `0.0.0.0` unless the machine is behind a firewall and you have a specific multi-host use case.
    </ParamField>

    <ParamField body="port" type="integer" default="7842">
      The port the NSP Agent API listens on. Change this only if `7842` conflicts with another service on your machine — and update every SDK client and agent to match.
    </ParamField>

    <ParamField body="request_timeout_ms" type="integer" default="30000">
      Maximum duration in milliseconds for standard API routes before the daemon returns a timeout error. Action routes use a separate hardcoded 120-second timeout.
    </ParamField>

    <ParamField body="max_body_bytes" type="integer" default="10485760">
      Maximum HTTP request body size in bytes (default: 10 MB). Raise this only if you are sending unusually large action payloads.
    </ParamField>
  </Accordion>

  <Accordion title="[auth] — API key authentication">
    <ParamField body="require_key" type="boolean" default="true">
      Whether the daemon requires a valid `X-Substrate-Key` header on all requests. Set to `false` only for local development. The daemon emits a loud startup warning and repeats it every 60 seconds when this is `false`.
    </ParamField>

    <ParamField body="keys_file" type="string" default="C:\ProgramData\Nelieo\axon_keys.json">
      Path to the JSON file that stores hashed API keys. The daemon reloads this file on every request — adding a key with `axon-daemon.exe keygen` takes effect immediately with no restart required.
    </ParamField>
  </Accordion>

  <Accordion title="[rate_limit] — Per-key request limits">
    <ParamField body="enabled" type="boolean" default="true">
      Toggle rate limiting on or off globally. Disable only in test environments with a single trusted caller.
    </ParamField>

    <ParamField body="state_per_second" type="integer" default="100">
      Maximum state-read requests allowed per second per API key. Burst traffic beyond this limit receives a `429 Too Many Requests` response.
    </ParamField>

    <ParamField body="action_per_second" type="integer" default="10">
      Maximum action-execution requests allowed per second per API key. Keep this conservative — actions interact with live application UI.
    </ParamField>

    <ParamField body="snapshot_per_minute" type="integer" default="2">
      Maximum heap snapshot requests per minute. Heap snapshots are expensive operations that can take up to 47 seconds to complete; this default prevents accidental resource exhaustion.
    </ParamField>

    <ParamField body="bucket_ttl_secs" type="integer" default="3600">
      How long an idle rate-limit bucket persists in memory before being evicted. Reduce this if you have many short-lived API keys.
    </ParamField>
  </Accordion>

  <Accordion title="[watcher] — Process scanner">
    <ParamField body="scan_interval_secs" type="integer" default="5">
      How often (in seconds) the daemon scans the OS process list for new or removed applications. Lower values reduce detection latency at the cost of slightly higher CPU usage.
    </ParamField>

    <ParamField body="poll_interval_secs" type="integer" default="2">
      How often (in seconds) the daemon re-probes each tracked process to refresh its cached state. This is the maximum staleness of any state read through the API.
    </ParamField>

    <ParamField body="min_confidence" type="number" default="0.4">
      Minimum classification confidence (0.0–1.0) for a process to be tracked. Processes scored below this threshold are ignored. Raise this value if unrelated processes are being incorrectly detected as trackable apps.
    </ParamField>

    <ParamField body="probe_unknown" type="boolean" default="false">
      Whether to probe processes whose runtime type cannot be classified. Enabling this may pick up additional apps but increases probe overhead.
    </ParamField>

    <ParamField body="max_tracked_processes" type="integer" default="256">
      Hard cap on the number of simultaneously tracked processes. The daemon stops tracking new apps once this limit is reached until existing ones exit.
    </ParamField>
  </Accordion>

  <Accordion title="[dispatcher] — Action execution">
    <ParamField body="post_action_wait_ms" type="integer" default="200">
      Milliseconds to wait after an action before reading the post-action state. This gives UI animations and backend writes time to settle before the daemon captures the result.
    </ParamField>

    <ParamField body="verify_expression_max_bytes" type="integer" default="2048">
      Maximum byte length of a `verify_expression` string submitted with an action. Increase this only if your agent sends unusually complex verification expressions.
    </ParamField>

    <ParamField body="cdp_action_timeout_ms" type="integer" default="30000">
      How long the daemon waits for a Chrome DevTools Protocol command to complete before timing out the action.
    </ParamField>
  </Accordion>

  <Accordion title="[registry] — Schema database">
    <ParamField body="db_path" type="string" default="C:\ProgramData\Nelieo\axon_registry.db">
      Path to the on-disk database where the daemon persists application schema definitions. This file grows as the daemon discovers new apps and schema versions.
    </ParamField>

    <ParamField body="in_memory" type="boolean" default="false">
      Use an ephemeral in-memory registry instead of the on-disk database. All schema data is lost when the daemon exits. Useful for testing to guarantee a clean state on every run.
    </ParamField>
  </Accordion>

  <Accordion title="[cors] — Cross-origin requests">
    <ParamField body="allow_all_origins" type="boolean" default="false">
      Allow any web origin to call the daemon. Set this to `true` only when building a local web dashboard that needs to call the API directly. Never enable in production.
    </ParamField>

    <ParamField body="allowed_origins" type="string[]" default="[]">
      Explicit list of allowed origins when `allow_all_origins` is `false`. Example: `["http://localhost:3000", "https://your-dashboard.com"]`.
    </ParamField>
  </Accordion>

  <Accordion title="[logging] — Log output">
    <ParamField body="level" type="string" default="info">
      Log verbosity. One of `trace`, `debug`, `info`, `warn`, or `error`. Use `debug` during development to see per-probe timing and classified objects; use `info` or `warn` in production.
    </ParamField>

    <ParamField body="format" type="string" default="json">
      Log format. `json` emits structured JSON lines (suitable for log aggregation). `text` emits human-readable output (suitable for terminal development).
    </ParamField>

    <ParamField body="include_spans" type="boolean" default="false">
      Include OpenTelemetry span traces in log output. Enable when debugging performance issues across probe pipelines.
    </ParamField>
  </Accordion>

  <Accordion title="[runtime] — Async thread pool">
    <ParamField body="worker_threads" type="integer" default="0">
      Number of async worker threads. `0` means auto (one thread per logical CPU core). Increase only if profiling shows the daemon is CPU-bottlenecked on large deployments with many tracked processes.
    </ParamField>
  </Accordion>

  <Accordion title="[service] — Windows Service metadata">
    <ParamField body="name" type="string" default="NSPDaemon">
      The SCM service name — no spaces allowed. This is the name you use in PowerShell commands like `Get-Service -Name NSPDaemon`. Changing this requires re-running `axon-daemon.exe uninstall` then `axon-daemon.exe install`.
    </ParamField>

    <ParamField body="display_name" type="string" default="NSP Daemon">
      The human-readable name shown in `services.msc` and Task Manager.
    </ParamField>

    <ParamField body="description" type="string">
      The service description shown in `services.msc`.
    </ParamField>

    <ParamField body="auto_start" type="boolean" default="true">
      Whether the service starts automatically when Windows boots. Set to `false` to switch to manual start.
    </ParamField>
  </Accordion>
</AccordionGroup>

## Environment Variable Reference

Every config key has a corresponding `AXON_*` environment variable. Variables always override the `.toml` file, making them ideal for CI pipelines or per-run overrides.

**Format:** `AXON_<SECTION>__<KEY>` (double underscore separates section from key)

| Variable                               | Default     | Description                         |
| -------------------------------------- | ----------- | ----------------------------------- |
| `AXON_SERVER__PORT`                    | `7842`      | Daemon listen port                  |
| `AXON_SERVER__HOST`                    | `127.0.0.1` | Bind address                        |
| `AXON_SERVER__REQUEST_TIMEOUT_MS`      | `30000`     | Standard route timeout (ms)         |
| `AXON_AUTH__REQUIRE_KEY`               | `true`      | Enable or disable authentication    |
| `AXON_AUTH__KEYS_FILE`                 | system path | Path to the keys JSON file          |
| `AXON_RATE_LIMIT__ENABLED`             | `true`      | Enable or disable rate limiting     |
| `AXON_RATE_LIMIT__STATE_PER_SECOND`    | `100`       | State read rate limit per key       |
| `AXON_RATE_LIMIT__ACTION_PER_SECOND`   | `10`        | Action execution rate limit per key |
| `AXON_WATCHER__POLL_INTERVAL_SECS`     | `2`         | State cache refresh interval        |
| `AXON_WATCHER__SCAN_INTERVAL_SECS`     | `5`         | Process scan interval               |
| `AXON_WATCHER__MIN_CONFIDENCE`         | `0.4`       | Minimum probe confidence threshold  |
| `AXON_DISPATCHER__POST_ACTION_WAIT_MS` | `200`       | Post-action settle time (ms)        |
| `AXON_REGISTRY__IN_MEMORY`             | `false`     | Use ephemeral in-memory registry    |
| `AXON_LOGGING__LEVEL`                  | `info`      | Log verbosity                       |
| `AXON_LOGGING__FORMAT`                 | `json`      | Log output format                   |
| `AXON_CORS__ALLOW_ALL_ORIGINS`         | `false`     | Allow all CORS origins              |

## Minimal Development Config

For local development with a single agent and no key management overhead:

```toml theme={null}
# axon.toml — development only, do not use in production
[auth]
require_key = false

[server]
port = 7842

[watcher]
scan_interval_secs = 1
poll_interval_secs = 1

[registry]
in_memory = true

[rate_limit]
enabled = false

[logging]
level = "debug"
format = "text"
```

Alternatively, set the same options at runtime without editing any file:

```powershell theme={null}
$env:AXON_AUTH__REQUIRE_KEY = "false"
$env:AXON_REGISTRY__IN_MEMORY = "true"
$env:AXON_LOGGING__LEVEL = "debug"
$env:AXON_LOGGING__FORMAT = "text"
axon-daemon.exe run
```

## Startup Warnings

The daemon emits loud warnings on startup for any insecure configuration it detects. These warnings are intentional — fix the configuration rather than suppressing them.

```text theme={null}
⚠️  NSP DAEMON RUNNING WITHOUT AUTHENTICATION — All API requests pass without
    a key. Set AXON_AUTH__REQUIRE_KEY=true before any production use.

⚠️  CORS allow_all_origins=true — Any web origin can call this daemon.
    Unsafe in production.
```

<Warning>
  If you see the `RUNNING WITHOUT AUTHENTICATION` warning in a production environment, set `AXON_AUTH__REQUIRE_KEY=true` immediately and restart the daemon. Any process on the machine can read your application state and trigger actions while auth is disabled.
</Warning>
