config.json Reference

July 19, 2026 · View on GitHub

This document describes the application configuration file used by the agent server. It is based on the runtime schema in packages/agent-server/src/config.ts and the example at data/config.example.json.

Table of Contents

Source files

  • packages/agent-server/src/config.ts
  • data/config.example.json

Environment variables

Provider API keys (Pi SDK)

Pi SDK chat uses provider-specific environment variables. Common examples include:

  • OpenAI: OPENAI_API_KEY
  • Anthropic: ANTHROPIC_OAUTH_TOKEN (preferred) or ANTHROPIC_API_KEY
  • Google Gemini: GEMINI_API_KEY
  • Groq: GROQ_API_KEY
  • Mistral: MISTRAL_API_KEY
  • OpenRouter: OPENROUTER_API_KEY
  • XAI: XAI_API_KEY
  • Cerebras: CEREBRAS_API_KEY
  • Minimax: MINIMAX_API_KEY
  • Minimax (CN): MINIMAX_CN_API_KEY
  • ZAI: ZAI_API_KEY
  • Vercel AI Gateway: AI_GATEWAY_API_KEY
  • OpenCode: OPENCODE_API_KEY
  • Azure OpenAI: AZURE_OPENAI_API_KEY (with AZURE_OPENAI_BASE_URL/AZURE_OPENAI_RESOURCE_NAME)

The assistant does not resolve these itself; it passes requests to the Pi SDK, which reads the provider environment variables directly. For a complete list, see the @earendil-works/pi-ai README.

Server

VariableDefaultDescription
PORT3000HTTP/WebSocket server port
DATA_DIR./dataDirectory for session data (event logs, preferences, plugin settings)
APP_CONFIG_PATH-Override config file location

TTS

VariableDefaultDescription
TTS_BACKENDopenaiTTS backend: openai or elevenlabs
OPENAI_TTS_MODELgpt-4o-mini-ttsOpenAI TTS model
TTS_VOICEalloyVoice name for TTS output
TTS_FRAME_DURATION_MS250PCM frame duration for TTS output; larger values reduce client scheduling overhead
AUDIO_OUTPUT_SPEED-Playback speed multiplier (e.g., 1.2)

OpenAI TTS requires OPENAI_API_KEY.

Realtime voice (Android)

Realtime duplex voice reuses the same server-side OpenAI credential as TTS/chat:

VariableDefaultDescription
OPENAI_API_KEY-Required for Realtime. Held only on the agent-server host; never sent to Android/web clients.
OPENAI_REALTIME_MODELgpt-realtime-2.1Pinned Realtime model id (matches T3).
OPENAI_REALTIME_VOICEmarinOpenAI Realtime output voice (matches T3 default; female).

Storage plan: set OPENAI_API_KEY in the agent-server environment (systemd unit, shell profile, or secrets manager that injects env). Do not put the raw key in client apps, Capacitor assets, or committed config.json. Optional ${OPENAI_API_KEY} substitution in config.json is fine for other agent fields; Realtime reads the env via loadEnvConfig() the same way OpenAI TTS does.

Capability probe: GET /api/voice/capabilities reports agentRealtime.status as ready or not-configured.

Realtime tool allowlist (config.json)

Realtime tool exposure is explicit opt-in. Configure under voice.realtime:

{
  "voice": {
    "realtime": {
      "toolAllowlist": ["lists_*", "web_search"],
      "toolDenylist": []
    }
  }
}
FieldDescription
toolAllowlistGlob patterns for tool names available on Realtime sessions. Missing or empty ⇒ no host tools (hangup may still be built-in).
toolDenylistOptional globs removed after allowlist matching.
instructionsOptional system-instruction override for the Realtime model.

Text agents use per-agent toolAllowlist / toolDenylist independently of this block.

Built-in web_search tool

web_search is a built-in tool (not a plugin). It runs the local Grok CLI headless for live public web and X research.

ItemDetail
Parametersquery (required natural-language question), continue (optional bool to resume prior Grok session for this conversation)
Enable for text agentsAdd web_search to the agent’s toolAllowlist
Enable for RealtimeAdd web_search to voice.realtime.toolAllowlist
Host prerequisitesgrok on PATH (or ASSISTANT_GROK_BIN); Grok auth (~/.grok/auth.json and/or XAI_API_KEY); do not lock off bypassPermissions in Grok requirements; avoid untrusted Grok MCP servers for the service user
Not the same asPlugin search_* tools (in-app notes/lists search)

Design: docs/design/web-search-tool.md.

ElevenLabs TTS

Used when TTS_BACKEND=elevenlabs.

VariableDefaultDescription
ELEVENLABS_API_KEY-ElevenLabs API key (required)
ELEVENLABS_TTS_VOICE_ID-ElevenLabs voice ID (required)
ELEVENLABS_TTS_MODELeleven_multilingual_v2ElevenLabs model ID
ELEVENLABS_TTS_BASE_URLhttps://api.elevenlabs.ioAPI base URL

MCP Tools

VariableDefaultDescription
MCP_TOOLS_ENABLEDautoExplicit enable/disable for external MCP servers (true/1 or false/0)

External MCP servers are configured in config.json under mcpServers.

Rate Limits

Per session, 1-minute sliding window.

VariableDefaultDescription
MAX_MESSAGES_PER_MINUTE60Max client messages per minute
MAX_AUDIO_BYTES_PER_MINUTE2000000Max audio bytes per minute
MAX_TOOL_CALLS_PER_MINUTE30Max tool calls per minute

Audio

VariableDefaultDescription
AUDIO_SAMPLE_RATE24000Audio sample rate in Hz
AUDIO_INPUT_MODEmanualInput mode: server_vad or manual
AUDIO_TRANSCRIPTION_ENABLEDfalseForward transcription events to client

Debug

VariableDefaultDescription
DEBUG_CHAT_COMPLETIONSfalseLog Pi SDK request/response payloads (tools included, auth redacted)
DEBUG_HTTP_REQUESTSfalseLog HTTP request details

Application configuration (config.json)

Location and Loading

The agent server loads configuration from:

  • ${DATA_DIR}/config.json by default
  • APP_CONFIG_PATH when set (absolute or relative path)

Environment defaults such as DATA_DIR are described above.

Environment Variable Substitution

config.json supports ${VARNAME} substitution in all string values. This is useful for:

  • Paths that depend on home directory: "workspaceRoot": "${HOME}/workspaces"
  • API keys and secrets: "apiKey": "${LOCAL_LLM_KEY}"
  • Runtime-specific paths: "socketPath": "${XDG_RUNTIME_DIR}/podman/podman.sock"

If the environment variable is missing, the placeholder is replaced with an empty string.

Examples:

{
  "plugins": {
    "coding": {
      "enabled": true,
      "local": {
        "workspaceRoot": "${HOME}/coding-workspaces"
      }
    }
  },
  "agents": [
    {
      "agentId": "claude-cli",
      "displayName": "Claude",
      "description": "Claude via CLI",
      "chat": {
        "provider": "claude-cli",
        "config": {
          "workdir": "${HOME}/projects",
          "wrapper": {
            "path": "${HOME}/bin/claude-wrapper.sh"
          }
        }
      }
    }
  ],
  "mcpServers": [
    {
      "command": "${HOME}/bin/mcp-server",
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    }
  ]
}

Top-Level Keys

KeyTypeDescription
sessionsobjectSession cache settings.
agentsarrayAgent persona definitions and chat provider config.
profilesarrayShared profile (instance) definitions for cross-plugin scoping.
pluginsobjectPlugin enablement and per-plugin config.
mcpServersarrayExternal MCP servers launched over stdio.

sessions

Controls session cache behavior.

{ "sessions": { "maxCached": 100 } }
  • maxCached: maximum number of sessions cached in memory

agents

Defines agent personas and chat providers.

{
  "agents": [
    {
      "agentId": "general",
      "displayName": "General Assistant",
      "description": "A helpful assistant.",
      "systemPrompt": "You are a helpful assistant.",
      "toolAllowlist": ["*"],
      "chat": {
        "provider": "pi"
      }
    }
  ]
}

See the Agents section below for the full schema and provider-specific config.

profiles

Defines shared profile identifiers that can be reused across plugin instances. Instance ids must match an entry in this list (the built-in default profile is always available).

{
  "profiles": [
    { "id": "default", "label": "Global" },
    { "id": "work", "label": "Work" },
    { "id": "personal", "label": "Personal" }
  ]
}

Use these ids in plugin instance configuration:

{
  "profiles": [{ "id": "default" }, { "id": "work" }],
  "plugins": {
    "notes": { "enabled": true, "instances": ["default", "work"] }
  }
}

plugins

Enable or configure server plugins.

{
  "plugins": {
    "sessions": { "enabled": true },
    "agents": { "enabled": true },
    "scheduled-sessions": { "enabled": true },
    "lists": { "enabled": true },
    "notes": { "enabled": true },
    "questions": { "enabled": true },
    "url-fetch": { "enabled": true }
  }
}

Many plugins accept additional settings. See each plugin README for details.

Plugins that support multiple data instances can also define instances:

{
  "plugins": {
    "time-tracker": {
      "enabled": true,
      "instances": ["work", { "id": "personal", "label": "Personal" }]
    }
  }
}
  • Instance entries can be strings or objects. Object entries may include label and plugin-specific overrides (either inline or under config):
{
  "plugins": {
    "diff": {
      "enabled": true,
      "workspaceRoot": "/path/to/workspace",
      "instances": [
        "work",
        { "id": "oss", "label": "Open Source", "workspaceRoot": "/path/to/oss" },
        { "id": "client", "config": { "workspaceRoot": "/path/to/client" } }
      ]
    }
  }
}
  • Instance ids are lowercased slugs ([a-z0-9_-]).
  • The default instance id is always default and cannot be renamed or removed.

Plugins can opt into automatic git snapshots of their data directories using gitVersioning:

{
  "plugins": {
    "notes": {
      "enabled": true,
      "gitVersioning": {
        "enabled": true,
        "intervalMinutes": 5
      }
    }
  }
}
  • One git repository is created per plugin instance directory.
  • Snapshots are committed on the configured interval and use a local "AI Assistant" git author.
  • Requires git available on the server PATH.
Execution Mode (Coding Plugins)

Plugins that execute code (like the coding/terminal plugin) can run in local or sidecar mode. In local mode, local.workspaceRoot may use the session-scoped macro ${session.workingDir} so relative file paths and bash commands anchor to the session picker’s working directory.

{
  "plugins": {
    "coding": {
      "enabled": true,
      "mode": "local",
      "local": {
        "workspaceRoot": "/path/to/workspaces"
      }
    }
  }
}
FieldTypeDescription
modestringExecution mode. Only local is supported.
local.workspaceRootstringRoot directory for local workspaces. ${session.workingDir} resolves from attributes.core.workingDir for interactive tool calls.

Notes:

  • Coding tools now execute directly through the imported @earendil-works/pi-coding-agent local tool implementations.
Agents plugin tools (when enabled)

Agent coordination is provided by the agents plugin. Enable it in config.json and use the generated tools:

ToolDescription
agents_messageSend a message to another agent (sync or async) without switching sessions.
agents_listList configured agents for delegation or messaging.

Terminology: users may say "agent" to refer to a configured assistant persona (for example, "journal agent" or "todo agent").

mcpServers

Defines external MCP tool servers (Model Context Protocol) launched over stdio.

{
  "mcpServers": [
    {
      "name": "github",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  ]
}
  • name: optional display name
  • command: executable to launch
  • args: optional arguments list
  • env: optional environment map (supports ${ENV} substitution)

Agents

Common Fields

{
  "agentId": "notes",
  "displayName": "Notes",
  "description": "Manages notes.",
  "systemPrompt": "You are a notes assistant.",
  "type": "chat",
  "toolAllowlist": ["notes_*"],
  "toolDenylist": [],
  "toolExposure": "skills",
  "skillAllowlist": ["notes"],
  "sessionWorkingDir": {
    "mode": "prompt",
    "roots": ["/home/kevin/worktrees"]
  },
  "skills": [
    { "root": "~/skills", "available": ["*"], "inline": ["my-critical-*"] },
    { "root": "worktrees/assistant/skills" }
  ],
  "capabilityAllowlist": ["*"],
  "agentAllowlist": ["*"],
  "uiVisible": true,
  "apiExposed": false
}
FieldTypeDescription
agentIdstringUnique id (used by tools and session routing).
displayNamestringUI label.
descriptionstringUI description and prompt context.
typestringAgent type: chat (default) or external.
systemPromptstringOptional custom prompt.
toolAllowlistarrayGlob patterns for tool access.
toolDenylistarrayGlob patterns for tool denylist.
toolExposurestringtools, skills, or mixed.
skillAllowlistarrayPlugin ids exposed as CLI skills.
skillDenylistarrayPlugin ids blocked from skill exposure.
skillsarrayInstruction skills (filesystem SKILL.md discovery + Pi-style prompt inclusion).
capabilityAllowlistarrayGlob patterns for capability access.
capabilityDenylistarrayGlob patterns for capability denylist.
agentAllowlistarrayGlob patterns for agents this agent can delegate to.
agentDenylistarrayGlob patterns for agents blocked from delegation.
sessionWorkingDirobjectOptional working-directory policy for new sessions. Use { "mode": "fixed", "path": "/abs/path" }, { "mode": "prompt", "roots": ["/abs/root"] }, or { "mode": "none" } to leave core.workingDir unset by default.
uiVisiblebooleanHide from built-in UI if false.
apiExposedbooleanReserved for external API tools (currently unused).

Working directory behavior

When sessionWorkingDir is set to { "mode": "prompt", "roots": [...] }, the UI shows a working directory picker for new sessions created with that agent. The options are the immediate subdirectories of each configured root (all of which must be absolute paths).

When sessionWorkingDir is set to { "mode": "fixed", "path": "/abs/path" }, new sessions for that agent automatically use the fixed directory without prompting.

When sessionWorkingDir is set to { "mode": "none" }, new sessions do not get a default working directory from the agent. This is equivalent to omitting the field and makes the intent explicit in config.

The selected or fixed directory is stored in attributes.core.workingDir and can be consumed by other systems such as ${session.workingDir} CLI macros and the coding plugin's local workspace configuration.

Instruction skills (skills)

The skills field is for instruction skills discovered from SKILL.md files on disk and injected into the agent's system prompt. This is separate from plugin/manifest-driven “CLI skills” controlled by toolExposure + skillAllowlist.

Each entry is a “source”:

{
  "skills": [
    {
      "root": "~/skills",
      "available": ["*"],
      "inline": ["my-critical-*"],
    },
  ],
}
  • root: directory to recursively scan for SKILL.md.
  • available: glob patterns over skill name to include in <available_skills>.
  • inline: glob patterns over skill name to inline as <skill name="...">...</skill>.
  • If both available and inline are omitted for a source, it defaults to available: ["*"].

Context files (contextFiles)

The contextFiles field injects ordinary UTF-8 text files into the agent's system prompt after instruction skills. This is intended for static project context that should be loaded once at startup and reused for later prompt rebuilds.

Each entry is a rooted source:

{
  "contextFiles": [
    {
      "root": "./context",
      "include": ["README.md", "product/overview.md", "product/policies/*.md", "shared/**/*.md"],
    },
  ],
}
  • root: directory to search within. Relative roots resolve against the config file directory when the config is loaded.
  • include: root-relative file paths or glob patterns. Matches are ordered by source order, then include-pattern order, then lexical path order within each pattern.
  • Matches are restricted to files inside the declared root, even when symlinks are involved.
  • Duplicate matches are kept only on the first match.
  • Startup fails if a root is missing, unreadable, outside-root traversal is detected, an include pattern matches nothing, or a matched file is binary / invalid UTF-8.
  • File contents are cached at startup. Changes on disk are not picked up until restart.

External Agents

When type is external, the agent forwards messages to an external HTTP endpoint instead of using a local chat provider. This is useful for integrating with external AI services or custom agent implementations.

{
  "agentId": "external-example",
  "displayName": "External Agent",
  "description": "An external agent implementation.",
  "type": "external",
  "external": {
    "inputUrl": "http://external.internal/v1/assistant/input",
    "callbackBaseUrl": "http://agent-server.internal"
  }
}
FieldTypeDescription
external.inputUrlstringURL where messages are POSTed to the external agent.
external.callbackBaseUrlstringBase URL the external agent uses to call back with responses.

External agents receive messages via POST and respond asynchronously via callbacks. See docs/design/external-agents.md for the full protocol specification.

chat Provider Selection

{
  "chat": {
    "provider": "claude-cli",
    "config": {
      "workdir": "/path/to/workspace",
      "extraArgs": ["--model", "sonnet"]
    }
  }
}

Supported providers:

  • pi (default)
  • claude-cli
  • codex-cli
  • pi-cli
ProviderCLI ToolDescription
pi-Pi SDK in-process chat (upstream providers configured via Pi).
claude-cliclaudeAnthropic Claude CLI with tool use.
codex-clicodexOpenAI Codex CLI with file editing and shell.
pi-clipiPi CLI agent.

CLI provider example

{
  "agents": [
    {
      "agentId": "claude-cli",
      "displayName": "Claude",
      "description": "Claude via CLI",
      "chat": {
        "provider": "claude-cli",
        "config": {
          "workdir": "/path/to/workspace",
          "extraArgs": ["--model", "sonnet", "--dangerously-skip-permissions"]
        }
      }
    }
  ]
}

Scheduled sessions

Scheduled sessions are no longer configured on agents. Use the scheduled-sessions plugin to create and manage them dynamically. They are stored in the plugin data directory under data/plugins/scheduled-sessions/default/schedules.json.

The same plugin also stores pending one-shot session wake-ups under data/plugins/scheduled-sessions/default/wakeups.json. Wake-ups are limited to native Pi SDK sessions (chat.provider: "pi"), target the current tool session for create/list/update/cancel operations, and send the configured message back to that session at the requested time. If the session is busy when the wake-up fires, the message is added to the existing per-session message queue. A session can have up to 25 active wake-ups.

Each persisted schedule record includes:

  • agentId
  • scheduleId
  • cron
  • optional prompt
  • optional preCheck
  • optional sessionTitle
  • optional sessionConfig
    • optional model
    • optional thinking
    • optional workingDir
    • optional skills
  • enabled
  • reuseSession (defaults to true)
  • maxConcurrent

Notes:

  • Each schedule must define prompt, preCheck, or both.
  • sessionConfig values are validated against the selected agent on create/update and revalidated when a scheduled run starts.
  • sessionTitle stays a top-level schedule field; it is not part of scheduled sessionConfig.
  • preCheck runs in the agent chat.config.workdir and uses the wrapper environment when configured.
  • When reuseSession is true, scheduled runs reuse one backing session per agentId + scheduleId.
  • Reused scheduled sessions are created up front and reconciled from the schedule on later runs after edits.
  • When reuseSession is false, each run creates a fresh backing session.
  • maxConcurrent only matters when reuseSession is false.
  • Enable the scheduled-sessions plugin to create, edit, delete, run, and toggle schedules, and to list/create/update/cancel pending session wake-ups.

Wake-up tools:

  • scheduled_sessions_wakeup_create
    • message
    • exactly one of runAt or delaySeconds
    • runAt must be an absolute ISO timestamp with an explicit timezone offset or Z, for example 2026-06-03T08:56:00-05:00 or 2026-06-03T13:56:00Z
  • scheduled_sessions_wakeup_update
    • wakeupId
    • at least one of message, runAt, or delaySeconds
    • if a time is provided, provide exactly one of runAt or delaySeconds
  • scheduled_sessions_wakeup_cancel
    • wakeupId
  • scheduled_sessions_wakeup_list

Wake-up tools intentionally do not accept a sessionId; they use the current tool context. update and cancel only operate on wake-ups belonging to the current session. In a session context, list returns manageable current-session wake-ups with IDs and message details plus read-only other-session wake-ups with only safe summary fields: kind, scope, manageable, runAt, status, summary, false capabilities, and an omitted list for redacted fields. The scheduled-sessions panel uses the same plugin operation without a session context to show all wake-ups for administration.

pi Provider

{
  "chat": {
    "provider": "pi",
    "models": ["anthropic/claude-sonnet-4-5", "openai-codex/gpt-5.2-codex"],
    "thinking": ["off", "low", "medium", "high", "xhigh"],
    "config": {
      "provider": "anthropic",
      "apiKey": "${ANTHROPIC_API_KEY}",
      "baseUrl": "https://api.anthropic.com",
      "maxTokens": 4096,
      "temperature": 0.7,
      "maxToolIterations": 100,
      "compaction": {
        "enabled": true,
        "reserveTokens": 16384,
        "keepRecentTokens": 20000
      },
      "headers": {
        "X-Request-Source": "assistant"
      }
    }
  }
}
  • models: optional list of allowed model ids (first is default). Entries may be provider/model.
  • thinking: optional list of allowed thinking levels (first is default). Selected level is passed to the Pi SDK reasoning option; use off to disable reasoning.
  • config.provider: default provider used when a model omits a prefix (required if any model omits a prefix).
  • config.apiKey, config.baseUrl, config.headers: optional connection overrides applied when the resolved provider matches config.provider.
  • When config.baseUrl is set and the chosen provider has no built-in Pi model catalog entry, the server synthesizes an openai-responses model for the configured provider/model id. This allows custom endpoints such as local mocks or proxies to be targeted without adding extra config fields.
  • config.maxTokens, config.temperature, config.timeoutMs: optional Pi SDK request overrides.
  • config.contextWindow: optional context window override used for synthesized models (providers without a built-in Pi catalog entry when config.baseUrl is set).
  • config.maxToolIterations: max consecutive tool iterations before aborting with an error (default: 100).
  • config.compaction: optional Pi SDK context compaction controls. Compaction is enabled by default with Pi-compatible defaults: reserveTokens: 16384 and keepRecentTokens: 20000. Manual compaction is available from the chat request history menu for in-process Pi SDK sessions, and automatic threshold compaction runs after completed Pi turns when usage exceeds contextWindow - reserveTokens.

Pi SDK sessions are mirrored to the Pi JSONL format so they can be resumed by the pi-mono CLI. Sessions are written to: ~/.pi/agent/sessions/<encoded-cwd>/*_<pi-session-id>.jsonl. The cwd comes from attributes.core.workingDir when available (otherwise the server working directory). Canceled runs still write partial assistant/tool entries so the pi-mono CLI can resume. Pi-backed sessions always persist canonical Pi JSONL history for replay and reload. Compacted Pi JSONL logs keep the full raw history on disk and add Pi-compatible compaction entries; future model context is rebuilt as summary plus the recent kept messages.

CLI Providers (claude-cli, codex-cli, pi-cli)

All CLI providers share the same config shape:

{
  "chat": {
    "provider": "pi-cli",
    "models": ["anthropic/claude-sonnet-4-5", "openai-codex/gpt-5.2-codex"],
    "thinking": ["off", "low", "medium", "high", "xhigh"],
    "config": {
      "wrapper": {
        "path": "/home/kevin/devtools/container/run.sh",
        "env": {
          "PERSISTENT": "1",
          "PROXY": "1",
          "CONTAINER_NAME": "assistant"
        }
      }
    }
  }
}
  • models: optional list of allowed model ids for CLI providers (first is default). For pi-cli, entries may be provider/model and are split into --provider + --model. When set, do not include --model in extraArgs (and for pi-cli, do not include --provider).
  • thinking: optional list of allowed thinking levels for pi-cli and codex-cli (first is default). For codex-cli, the selected level maps to --config model_reasoning_effort=<level>. When set, do not include --thinking in extraArgs (pi) or model_reasoning_effort overrides in extraArgs (codex).
  • workdir: optional working directory for the CLI process
  • extraArgs: optional extra CLI flags (reserved flags are managed by the server)
  • wrapper.path: optional wrapper executable used to run the CLI (for containerized runs)
  • wrapper.env: optional environment map for the wrapper (supports ${ENV} substitution)

For pi-cli, history is read from the default Pi sessions directory: ~/.pi/agent/sessions/<encoded-cwd>/*_<pi-session-id>.jsonl. The cwd comes from the Pi session header, so set workdir if you need a stable path across runs. No extra config is required.

For claude-cli, history is read from the default Claude projects directory: ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl. The CLI defaults to the user home directory when workdir is not set, so history typically lands under ~/.claude/projects/-home-<user>. Set workdir if you need Claude history under a different path. No extra config is required.

For codex-cli, history is read from the default Codex sessions directory: ~/.codex/sessions/<yyyy>/<mm>/<dd>/...-<codex-session-id>.jsonl. The session id is emitted by the CLI and tracked automatically; no extra config is required.

Reserved flags (must not be in extraArgs):

  • claude-cli: --output-format, --session-id, --resume, -p, --include-partial-messages, --verbose
  • codex-cli: --json, resume
  • pi-cli: --mode, --session, --session-dir, --continue, -p

When chat.models is set for a CLI provider, --model is managed by the server and must not be included in extraArgs. For pi-cli, --provider is also managed by the server when chat.models is set, and --thinking is managed by the server when chat.thinking is set. For codex-cli, model_reasoning_effort is managed by the server when chat.thinking is set.

Security Notes

  • Store API keys in environment variables or a secure secrets manager; avoid committing them to config.json.
  • Limit wrapper.path usage to trusted scripts or containers because the wrapper runs as the server user.
  • MCP server commands run as the server user and inherit env settings, so review each command and token scope.

Full Example

See data/config.example.json for a complete working example including plugins and agents.