Skip to content

Latest commit

 

History

History
308 lines (234 loc) · 15.6 KB

File metadata and controls

308 lines (234 loc) · 15.6 KB

Configuration Reference

Nerve uses two YAML config files:

  • config.yaml — Template settings (version controlled)
  • config.local.yaml — Secrets and personal overrides (gitignored)

Values in config.local.yaml are deep-merged on top of config.yaml. Unknown keys are ignored but logged as warnings at startup (and shown by nerve doctor) so typos don't fail silently.

Config Directory Resolution

nerve commands locate the config directory via a waterfall, so they work from any working directory:

  1. --config-dir / -c flag
  2. NERVE_CONFIG_DIR environment variable
  3. The current directory, if it contains config.yaml or config.local.yaml
  4. The pointer file ~/.nerve/config_dir (written by nerve init and on daemon start)
  5. The current directory (fresh-install fallback)

nerve doctor reports which directory was used and how it was found.

Core

Key Type Default Description
workspace path ~/nerve-workspace Path to workspace directory
timezone string America/New_York Local timezone for scheduling
deployment string server server (bare metal) or docker. Set during nerve init; determines whether CLI commands run directly or proxy to docker compose.

Note: The mode (personal vs worker) is not a config field — it's determined at nerve init time and expressed through which workspace templates, cron jobs, and memory categories are active. There's no mode key in config.

Agent

Key Type Default Description
agent.model string claude-opus-4-8 Primary model for conversations
agent.cron_model string claude-sonnet-4-6 Model for cron jobs (cheaper)
agent.max_turns int 50 Max agentic turns per request
agent.max_concurrent int 4 Max concurrent agent sessions
agent.prompt_rewrite.enabled bool true Offer the first-prompt rewrite feature in the web UI (per-user toggle lives in the composer)
agent.prompt_rewrite.model string "" Model for prompt rewriting (empty = agent.model, the chat model)
agent.prompt_rewrite.max_tokens int 1024 Max tokens for the rewritten prompt
agent.prompt_rewrite.timeout_seconds float 45.0 Rewrite API call timeout

Prompt rewrite: when the ✨ toggle in the composer is on, the first prompt of a new chat is rewritten by a fast model to better express intent. The result is previewed (editable) and only sent after explicit approval — the user can always send the original instead. Trivial or already-clear prompts are sent unchanged without a preview.

Note: The engine uses a can_use_tool callback (not bypassPermissions) so that interactive tools (AskUserQuestion, ExitPlanMode, EnterPlanMode) can pause mid-turn for user input. All other tools are auto-approved. See sdk-sessions.md for details.

Gateway

Key Type Default Description
gateway.host string 0.0.0.0 Bind address
gateway.port int 8900 Port number
gateway.ssl.cert path - SSL certificate path
gateway.ssl.key path - SSL private key path

Telegram

Key Type Default Description
telegram.enabled bool true Enable Telegram bot
telegram.bot_token string - Bot token from @BotFather
telegram.dm_policy string pairing pairing (allowlist + one-time pairing codes) or open (anyone — dangerous)
telegram.allowed_users list[int] [] Telegram user IDs allowed to DM the bot
telegram.stream_mode string partial partial (edit msgs) or full

Pairing

With dm_policy: pairing (the default), the bot only talks to users in allowed_users and rejects everyone else. To authorize a user without editing config files:

  1. Run nerve pair on the server — it prints a one-time 6-digit code (valid 1 hour). On a fresh install with no allowed_users, a code is also generated automatically at startup and printed to the log.
  2. Send the bot /pair <code> from the Telegram account to authorize.
  3. The user ID is appended to telegram.allowed_users in config.local.yaml and takes effect immediately.

An unauthorized /start gets a reply with the sender's numeric ID and pairing instructions (rate-limited); all other messages from unauthorized users are ignored.

Quiet Hours

Key Type Default Description
quiet_start string 02:00 HH:MM — start of quiet period (local timezone)
quiet_end string 08:00 HH:MM — end of quiet period (local timezone)

Sources (sync)

Sources pull data from external services on a schedule. See sources.md for full details.

Common fields (available on all sources):

Key Type Default Description
sync.<source>.enabled bool true Enable/disable this source
sync.<source>.schedule cron/interval varies Fetch frequency (crontab or interval like 2h)
sync.<source>.processor string agent agent (LLM review), memorize (direct memU), notify (channel forward), none
sync.<source>.batch_size int 50 Max records per fetch cycle
sync.<source>.prompt_hint string "" Extra instructions for the agent prompt
sync.<source>.model string "" Override model (empty = agent.cron_model)
sync.<source>.condense bool false LLM-condense long records via memory.fast_model before processing

Telegram-specific:

Key Type Default Description
sync.telegram.api_id int - Telethon API ID (from my.telegram.org)
sync.telegram.api_hash string - Telethon API hash
sync.telegram.schedule cron */5 * * * * Fetch frequency
sync.telegram.exclude_chats list[int] [] Chat IDs to skip
sync.telegram.monitored_folders list [] Telegram folder names to filter

Gmail-specific:

Key Type Default Description
sync.gmail.accounts list [] Gmail accounts to sync
sync.gmail.schedule cron */15 * * * * Fetch frequency
sync.gmail.keyring_password string - gog keyring password

GitHub-specific:

Key Type Default Description
sync.github.schedule cron */15 * * * * Fetch frequency

Memory (memU)

Key Type Default Description
memory.recall_model string claude-sonnet-4-6 Model for recall routing
memory.memorize_model string claude-sonnet-4-6 Model for extraction & preprocessing
memory.fast_model string claude-haiku-4-5-20251001 Model for categorization, date resolution, knowledge filtering
memory.embed_model string (empty) Embedding model (only used when openai_api_key is set, e.g. text-embedding-3-small)
memory.semantic_dedup_threshold float 0.85 Cosine similarity threshold for semantic deduplication (0 to disable)
memory.knowledge_filter bool false Post-extraction LLM filter that deletes generic knowledge items (extra Haiku API call per memorize)
memory.categories list [] Seed categories — each entry has name and description fields. Used for semantic routing when memorizing and recalling facts. nerve init populates mode-appropriate defaults (personal: relationships, finances, health, etc.; worker: patterns, procedures, approvals, etc.).

xmemory (optional, alongside memU)

xmemory.ai is an optional schema-backed memory layer that runs alongside memU — it never replaces it. Activated only when both xmemory.api_key and xmemory.instance_id are set (put them in config.local.yaml); otherwise it is completely inert (no SDK calls, zero overhead). The instance and its schema are created out of band on xmemory's side.

When active:

  • The memorize tool dual-writes: memU (as always) plus an async write_async to xmemory. Failures on the xmemory side never fail the tool.
  • memory_recall appends xmemory's single synthesized answer (its SINGLE_ANSWER read mode) to memU's N items, run concurrently so the dual lookup is one round-trip.
  • The memorization sweep (session-close / cron) stays memU-only — it does not go through the memorize tool handler.
Key Type Default Description
xmemory.api_key string (empty) xmemory bearer token (invite-only). Secret → config.local.yaml.
xmemory.instance_id string (empty) The xmemory instance to bind. Both this and api_key are required to activate.
xmemory.api_url string https://api.xmemory.ai API base URL.
xmemory.extraction_logic string deep Write extraction mode: deep (accurate) or fast (high-volume).
xmemory.timeout float 60.0 Per-request timeout in seconds.

Docker

Configuration for Docker deployment. Only relevant when deployment: docker.

Key Type Default Description
docker.extra_mounts list[string] [] Additional host:container mount pairs to add to docker-compose.yml. Example: ["~/code:/code", "~/projects:/projects"]

The core Docker mounts (source code, ~/.nerve, workspace) are always included. GitHub CLI (~/.config/gh) and Gmail CLI (~/.config/gog) auth directories are mounted automatically if they exist on the host.

MCP Servers

External MCP servers can be added via config without code changes or restarts. The agent picks up new servers on the next session creation, or immediately via the "Reload" button in the UI / mcp_reload tool.

Config uses a dict format so _deep_merge correctly overlays secrets from config.local.yaml:

# config.yaml — server definitions
mcp_servers:
  filesystem:
    type: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"]

  remote-api:
    type: http
    url: https://mcp.example.com/v1
# config.local.yaml — secrets merge on top
mcp_servers:
  remote-api:
    headers:
      Authorization: "Bearer sk-secret-token"
Key Type Default Description
mcp_servers.<name>.type string stdio Transport: stdio, sse, or http
mcp_servers.<name>.enabled bool true Enable/disable this server
mcp_servers.<name>.command string - Command to run (stdio only)
mcp_servers.<name>.args list [] Command arguments (stdio only)
mcp_servers.<name>.env dict {} Environment variables (stdio only)
mcp_servers.<name>.url string - Server URL (sse/http only)
mcp_servers.<name>.headers dict {} HTTP headers (sse/http only)

The built-in nerve server (SDK type, in-process) is always present and cannot be overridden.

Claude Code Plugins

Nerve automatically discovers MCP servers from Claude Code's enabled plugins. Any plugin enabled in ~/.claude/settings.json is loaded via the SDK's --plugin-dir flag, so the CLI handles OAuth, credentials, and plugin lifecycle natively.

  • No config needed — just enable a plugin in Claude Code and restart Nerve.
  • OAuth works — the CLI uses cached tokens from ~/.claude/.credentials.json.
  • Auto-registered in UI — plugin MCP servers appear in the MCP Servers page on first tool invocation (type: plugin).
  • No conflicts — Nerve-configured MCPs (from config.yaml) and Claude Code plugin MCPs coexist; they use separate mechanisms (--mcp-config vs --plugin-dir).

Auth

Key Type Default Description
auth.password_hash string - bcrypt hash for login
auth.jwt_secret string - JWT signing secret

API Keys (config.local.yaml)

Key Type Description
anthropic_api_key string Anthropic API key (agent + memU chat). Not required when proxy is enabled.
openai_api_key string OpenAI API key (optional — enables vector-based memory search via embeddings; without it, LLM-based recall is used)
brave_search_api_key string Brave Search API key (optional)

Proxy (CLIProxyAPI)

Optional local proxy that routes Anthropic API calls through Claude Code's OAuth authentication instead of a direct API key. When enabled, the API key is not required — all API calls go through the proxy at localhost.

Key Type Default Description
proxy.enabled bool false Enable CLIProxyAPI proxy
proxy.port int 8317 Proxy listen port
proxy.host string 127.0.0.1 Proxy bind address
proxy.binary_path path ~/.nerve/bin/cli-proxy-api Path to CLIProxyAPI binary (auto-downloaded if missing)
proxy.auth_dir path ~/.nerve/cli-proxy-auth Directory for OAuth token storage
proxy.api_key string sk-nerve-local-proxy Local auth key between Nerve and the proxy
proxy.log_file path ~/.nerve/proxy.log Proxy log file

Setup:

# During nerve init, choose "Claude Code proxy" at the API configuration step.
# Or enable manually:
# config.yaml
proxy:
  enabled: true
  port: 8317
# Authenticate with Claude (one-time):
~/.nerve/bin/cli-proxy-api --claude-login --no-browser \
  --config ~/.nerve/cli-proxy-config.yaml

The proxy binary is automatically downloaded from CLIProxyAPI on first start if not present. OAuth tokens are refreshed automatically.

Sessions

Key Type Default Description
sessions.archive_after_days int 30 Auto-archive idle/stopped sessions older than this
sessions.max_sessions int 500 Max active (non-archived) sessions before cleanup
sessions.cron_session_mode string per_run per_run (unique session per cron run) or reuse (shared session per job)

Retention

Opt-in nerve.db maintenance. Disabled by default. When enabled, a background pass every interval_hours drops the verbose blocks/thinking JSON of old, already-memorized messages (keeping the rendered content), prunes append-only telemetry and file snapshots older than retention_days, and checkpoints the WAL. This frees space inside the database but does not shrink the file on disk; run nerve db vacuum once (with the daemon stopped) to reclaim it.

Key Type Default Description
retention.enabled bool false Master switch for the background retention pass
retention.retention_full_days int 30 Compact blocks/thinking of memorized messages older than this
retention.retention_days int 90 Prune telemetry and file snapshots older than this
retention.interval_hours int 24 How often the background pass runs

Manual commands (run regardless of enabled):

  • nerve db prune [--dry-run] runs one pass immediately. --dry-run reports what would change without mutating.
  • nerve db vacuum rewrites the file to reclaim freed pages. It takes a write lock, so stop the daemon first.

Cron

Key Type Default Description
cron.system_file path ~/.nerve/cron/system.yaml System cron jobs (managed by nerve init)
cron.jobs_file path ~/.nerve/cron/jobs.yaml User-defined custom cron jobs