Skip to content

Configuration reference ​

The server reads kestrel.config.json from the working directory, or from KESTREL_CONFIG / --config. A missing default file is ignored; an explicitly named file must exist.

Precedence: defaults → configuration file → environment variables → command-line flags.

Full example ​

json
{
  "name": "Kestrel",
  "server": {
    "host": "127.0.0.1",
    "port": 7331,
    "token": "",
    "corsOrigins": ["*"],
    "bodyLimitBytes": 10485760,
    "webRoot": "apps/web/dist"
  },
  "model": {
    "default": "gpt-4o-mini",
    "temperature": 0.2,
    "maxTokens": 8192,
    "maxSteps": 60
  },
  "agent": {
    "workspace": ".",
    "systemPrompt": "Prefer small, verifiable changes."
  },
  "plugins": {
    "directories": ["plugins"],
    "allow": ["@kestrel/plugin-openai", "@kestrel/plugin-tools-core"],
    "config": {
      "@kestrel/plugin-tools-core": {
        "shellPermission": "ask"
      },
      "@kestrel/plugin-context": {
        "files": ["AGENTS.md"],
        "maxBytes": 32000
      }
    }
  },
  "storage": { "directory": ".kestrel", "driver": "file" },
  "auth": {
    "mode": "token",
    "bootstrapToken": "",
    "workspaces": { "acme-corp": "/srv/kestrel/acme" }
  },
  "approvals": { "timeoutMs": 900000 }
}

server ​

KeyTypeDefaultDescription
hoststring127.0.0.1Bind address. Use 0.0.0.0 in containers.
portnumber7331Bind port.
tokenstring—Bearer token. Empty disables auth.
corsOriginsstring[]["*"]Allowed origins. * is convenient locally and unsafe publicly.
bodyLimitBytesnumber10485760Maximum request body.
webRootstringapps/web/distDirectory served for non-API paths.

When authentication is enabled, GET /api/health and static files remain public. Every other /api/* route requires the token.

CORS is applied to API responses. Credentials are not allowed with *; set explicit origins if a separate front-end origin sends cookies (Kestrel uses bearer tokens, so this mostly affects preflight).

model ​

KeyTypeDefaultDescription
defaultstringfirst registeredModel id selected for new sessions.
temperaturenumberprovider defaultForwarded to providers that support it.
maxTokensnumberprovider defaultOutput token cap per model call.
maxStepsnumber40Tool/assistant iterations before the run stops with max_steps.

maxSteps protects against loops. A typical investigation uses 10–25 steps; raise it for large refactors. When the limit is reached the run emits a notice and run.finished with status: "max_steps".

agent ​

KeyTypeDefaultDescription
workspacestring"."Root for tools and new sessions. Resolved at startup.
systemPromptstring—Extra instructions appended to the default prompt.
compaction.enabledbooleantrueSummarize old turns when the prompt approaches the model window.
compaction.thresholdnumber0.8Fraction of the context window that triggers compaction.
compaction.keepRecentnumber8Messages kept verbatim after the summary.
compaction.fallbackContextWindownumber128000Window assumed when a model reports none.
retry.attemptsnumber3Total model-call attempts, including the first. 1 disables retries.
retry.baseDelayMsnumber500Base for exponential backoff.
retry.maxDelayMsnumber8000Cap for a single wait, including Retry-After hints.

A session may pin a different workspace at creation; tools then operate there. The default system prompt always states the active workspace and tool list.

plugins ​

KeyTypeDefaultDescription
directoriesstring[]["plugins"]Scan roots, relative to the working directory.
allowstring[]—Exact allow-list of manifest names.
configobject{}Per-plugin configuration keyed by manifest name.
hotReloadbooleanfalseWatch plugin web/ assets and stream changes to the console.
hotReloadIntervalMsnumber1000Milliseconds between asset scans; values below 250 are clamped.

applyTimeoutMs is a PluginHost option, not a config-file key; the server uses the host default of 20 seconds.

@kestrel/plugin-context reads the first existing file from files in each session workspace and adds it to the system prompt. maxBytes truncates (rather than drops) large files. Paths that resolve outside the workspace are ignored.

storage ​

KeyTypeDefaultDescription
directorystring.kestrelData root: sessions, accounts and per-tenant workspaces.
driver"file" | "sqlite"fileHow transcripts are stored. See below.

With the file driver, transcripts live in <directory>/sessions for the default tenant and <directory>/tenants/<tenantId>/sessions for every other tenant. Accounts live in <directory>/auth/accounts.json.

With the sqlite driver, every session lives in <directory>/kestrel.db (plus -wal/-shm sidecars). It uses Node's built-in SQLite, so there is nothing to compile, and listing sessions does not parse transcripts. Both drivers are single-process stores: run one server per data directory.

The two drivers do not share data. Choose sqlite for a new deployment; switching an existing installation requires exporting and re-creating sessions.

In containers, point this at a mounted volume (/data) so sessions survive restarts.

auth ​

KeyTypeDefaultDescription
mode"none" | "token" | "accounts"derivedDerived as token when server.token is set, otherwise none.
bootstrapTokenstring—First-run administrator token in accounts mode.
bootstrapNamestringAdminDisplay name for the bootstrap administrator.
workspacesobject{}Workspace root per tenant id. Unlisted tenants use <data>/tenants/<id>/workspace.

Accounts mode is described in Authentication and tenants. In short: none and token keep the single-operator model, while accounts adds users, roles and tenant isolation.

approvals ​

KeyTypeDefaultDescription
timeoutMsnumber900000How long a tool call waits for a decision before it is declined.

checkpoints ​

KeyTypeDefaultDescription
enabled"auto" | boolean"auto"auto uses git when available; false disables snapshots.
maxFilesnumber20000Refuse to snapshot larger workspaces.
excludestring[][]Extra ignore patterns, appended to .gitignore and the built-in list.

Snapshots live in <storage.directory>/checkpoints as a shadow git repository per workspace. See Checkpoints and rollback.

Environment variables ​

VariableOverridesExample
KESTREL_CONFIGconfig file path/etc/kestrel/kestrel.config.json
KESTREL_HOSTserver.host0.0.0.0
KESTREL_PORTserver.port7331
KESTREL_TOKENserver.tokenlong random string
KESTREL_CORS_ORIGINSserver.corsOriginshttps://app.example.com
KESTREL_MODELmodel.defaultdeepseek-chat
KESTREL_WORKSPACEagent.workspace/workspace
KESTREL_SYSTEM_PROMPTagent.systemPromptBe terse.
KESTREL_PLUGINSplugins.directoriesplugins,examples/plugins
KESTREL_HOT_RELOADplugins.hotReloadfalse
KESTREL_HOT_RELOAD_INTERVAL_MSplugins.hotReloadIntervalMs1000
KESTREL_DATA_DIRstorage.directory/data
KESTREL_STORAGE_DRIVERstorage.driversqlite
KESTREL_CHECKPOINTScheckpoints.enabledauto
KESTREL_CHECKPOINTS_MAX_FILEScheckpoints.maxFiles20000
KESTREL_AUTH_MODEauth.modeaccounts
KESTREL_BOOTSTRAP_TOKENauth.bootstrapTokenfirst-run admin token
KESTREL_LOG_LEVELlogger leveldebug
KESTREL_LOG_FORMATlogger formatjson

Comma-separated lists (KESTREL_PLUGINS, KESTREL_CORS_ORIGINS) are trimmed and empty entries are dropped.

Provider credentials are read by the provider plugin, not the server. The bundled OpenAI plugin uses OPENAI_API_KEY unless apiKeyEnv names another variable.

Command-line flags ​

kestrel serve / kestrel-server:

FlagEquivalent
--hostKESTREL_HOST
--portKESTREL_PORT
--tokenKESTREL_TOKEN
--workspaceKESTREL_WORKSPACE
--configKESTREL_CONFIG

Flags are applied by setting the environment before the runtime is created, so they win over both the file and inherited environment values.

Plugin configuration ​

@kestrel/plugin-openai ​

KeyDefault
baseUrlhttps://api.openai.com/v1
apiKey / apiKeyEnv— / OPENAI_API_KEY
provideropenai
modelgpt-4o-mini
models["gpt-4o-mini"]
labelmodel id
contextWindow—
supportsToolstrue
supportsReasoningfalse
temperature / maxTokens—
timeoutMs180000
streamUsagetrue

@kestrel/plugin-tools-core ​

KeyDefault
restrictToWorkspacetrue
shellPermissionask
shellTimeoutMs120000
webPermissionask
fetchTimeoutMs30000
maxOutputChars100000

@kestrel/plugin-memory ​

KeyDefault
path.kestrel/memory.json (relative to each session workspace)
maxEntries2000

@kestrel/plugin-skills ​

KeyDefault
directories[".kestrel/skills", "skills"] (relative to each session workspace)
maxSkillBytes64000
maxSkills100
toolNameuse_skill

See Skills for the file format and the loading model.

@kestrel/plugin-subagents ​

KeyDefault
maxDepth2
maxConcurrent3 — shared by delegate and delegate_many; 0 is unbounded
maxFanOut6
maxBatchResultChars40000
maxSteps12
timeoutMs600000
maxResultChars20000
exposeApprovalToolsfalse
rolesbuilt-in general, researcher, reviewer, implementer

See Subagents for roles, budgets and observability.

@kestrel/plugin-browser ​

KeyDefault
executableauto-detected Chrome, Chromium or Edge
args[]
headlesstrue
permissionask — approval for browser_open
timeoutMs30000
settleMs250
idleMs900000 — close a session's unused page
maxTextChars12000
maxElements120
noSandboxauto — enabled on Linux in Docker, Kubernetes or as root

See Browser automation for tool behaviour and security notes.

@kestrel/plugin-mcp ​

KeyDefault
servers{} — an object keyed by server name, matching the MCP mcpServers shape
servers.<name>.command— — stdio transport
servers.<name>.args[] — stdio argv
servers.<name>.env{} — extra environment for the child process
servers.<name>.cwdprocess cwd — stdio working directory
servers.<name>.url— — streamable HTTP endpoint
servers.<name>.headers{} — HTTP headers; ${ENV_VAR} is expanded
servers.<name>.approvalask — auto runs its tools without prompting
servers.<name>.timeoutMs120000 — per request

A server must set exactly one of command and url. See Model Context Protocol.

Released under the MIT License.