dawn.config.ts Reference
dawn.config.ts is a TypeScript file at your app root that exports a single default object conforming to the DawnConfig interface. Dawn loads it (via tsx) before every CLI command and at runtime startup. If the file is absent, all keys take their documented defaults — no file is required for a working app.
Run dawn verify as your preflight before dawn dev or dawn start: it validates this config and app integrity plus environment readiness (Node version, the provider API key your routes need, and — when sandbox is configured — the Docker daemon).
// dawn.config.ts
export default {
// ...
} satisfies import("@dawn-ai/core").DawnConfigComplete annotated example
The snippet below is an extended version of the research starter template's config. It demonstrates every commonly-used key in one place.
// dawn.config.ts
export default {
// Where Dawn discovers your routes. Defaults to "src/app".
appDir: "src/app",
// HITL permissions. Default mode is "interactive": any bash command not on
// the allow-list pauses the run for human approval via interrupt().
// Override at runtime with the DAWN_PERMISSIONS_MODE env variable.
permissions: {
mode: "interactive",
allow: {
bash: ["ls", "cat", "head", "wc"],
},
deny: {
bash: ["rm -rf", "sudo", "chmod 777", "curl", "wget"],
},
},
// Tool-output offloading. Large results are spilled to
// workspace/tool-outputs/ and replaced in-context with a short stub that
// the agent reads back on demand via readFile.
toolOutput: {
offloadThresholdChars: 1500, // default 40000
previewLines: 10, // default 10
// maxBytes: 268435456, // default 256 MB
// ttlMs: 10800000, // default 3 h
// gcThrottleMs: 10000, // default 10 s
// noOffloadTools: [], // merged with built-in exempt tools
},
// Conversation summarization — compress older history once a thread exceeds
// maxTokens. Disabled by default.
summarization: {
enabled: true,
maxTokens: 12000, // default 12000
keepRecentTurns: 6, // default 6
// model: "gpt-5-mini", // defaults to the route's own model
},
// Long-term memory governance. A route opts in by adding a memory.ts; the
// keys below tune how those typed memories are stored, recalled, and written.
// Defaults apply to every route with a memory.ts even when this key is absent.
memory: {
writes: "candidate", // "off" | "candidate" | "auto" | "ask" — default "candidate"
indexMaxEntries: 20, // default — cap on memories injected into the prompt index
// store: myMemoryStore, // default: SQLite at .dawn/memory.sqlite
// resolveScope: ({ routePath, appRoot }) => ({ tenant: "acme" }),
// recall: { weights: { relevance: 0.6, recency: 0.3, confidence: 0.1 } }, // ranked-recall tuning (see Memory)
},
// SQLite persistence is on by default — no config needed.
// Threads survive a restart. Override only if you need a custom backend.
// checkpointer: myCheckpointer,
// threadsStore: myThreadsStore,
// Path to the env file used by `dawn dev` and `dawn verify`.
// env: "./.env", // default
}Key reference
appDir
| Type | Default |
|---|---|
string | "src/app" |
The directory (relative to the app root) where Dawn discovers routes. Dawn walks appDir and treats every index.ts it finds as a route entry. Most apps never need to set this.
backends
Controls the workspace filesystem and exec backends. See Workspace Filesystem for a full explanation of what backends do and how to swap or layer them.
backends?: {
filesystem?: FilesystemBackend
exec?: ExecBackend
}| Sub-key | Type | Default | Description |
|---|---|---|---|
filesystem | FilesystemBackend | Built-in local FS | Handles readFile, writeFile, listDir workspace operations. |
exec | ExecBackend | Built-in child_process exec | Handles runBash workspace operations. |
Swap out either backend to sandbox filesystem access, redirect writes, or add custom logging middleware (see compose() and withFilesystemLogging / withExecLogging in @dawn-ai/workspace).
permissions
Controls the Human-in-the-Loop (HITL) permission gate. The permissions key governs which workspace operations require human approval, which are pre-approved, and which are always denied. See the Permissions reference for the full interrupt/resume lifecycle.
permissions?: {
mode?: PermissionMode
allow?: Record<string, string[]>
deny?: Record<string, string[]>
}permissions.mode
| Type | Default | Env override |
|---|---|---|
"interactive" | "non-interactive" | "bypass" | "interactive" | DAWN_PERMISSIONS_MODE |
interactive— Commands and paths not on the allow-list triggerinterrupt(), pausing the run for human approval. The default for local development.non-interactive— Unknown commands are denied automatically without pausing. Use in CI or headless environments.bypass— All permission checks are skipped. Use only in trusted, sandboxed environments.
DAWN_PERMISSIONS_MODE (set to interactive, non-interactive, or bypass) overrides the config-file value at runtime.
permissions.allow and permissions.deny
Pattern maps keyed by tool name (e.g. bash, readFile). Values are glob-style pattern strings matched against the candidate command or path. allow entries are seeded into .dawn/permissions.json at startup; deny entries are checked first and cannot be overridden by a human approval. Both lists are merged with any patterns the user approves interactively during a session.
permissions.allow.tool
Pre-approves tools gated by a route's tools: { approve } (see Tools and Permissions). Unlike bash and path patterns, entries under the reserved tool key match the tool name exactly — no prefix matching.
export default {
permissions: {
allow: { tool: ["deployProd"] },
},
}checkpointer
| Type | Default |
|---|---|
BaseCheckpointSaver (LangGraph) | SQLite at .dawn/checkpoints.sqlite |
A LangGraph checkpoint saver. Dawn defaults to a SQLite-backed saver that persists graph state across restarts — no configuration is needed for local development. Override to plug in a different storage backend (e.g. Redis, Postgres).
Thread state survives a dawn dev restart automatically when the default checkpointer is in use.
threadsStore
| Type | Default |
|---|---|
ThreadsStore (@dawn-ai/sqlite-storage) | SQLite at .dawn/threads.sqlite |
Stores Agent Protocol thread metadata (create time, status, latest checkpoint reference). Like checkpointer, Dawn defaults to SQLite and no configuration is needed for most apps. The AP thread endpoints (POST /threads, GET /threads/:id/state, and related) operate on this store — see Dev Server for the full endpoint reference. Override to provide a custom store implementation.
env
| Type | Default | Scope |
|---|---|---|
string | "./.env" | dawn dev, dawn verify only |
Path to the .env file loaded for local development commands, relative to the app root. This setting does not affect the deploy artifact — environment variables for production are configured separately in langgraph.json (see Deployment).
toolOutput
Configures tool-output offloading. When a tool returns a result whose serialized length exceeds offloadThresholdChars, Dawn writes the full output to workspace/tool-outputs/ and injects a compact stub into the agent's context. The agent can retrieve the full content on demand via the readFile tool. See Context Management for the full offloading and summarization picture.
| Key | Type | Default | Description |
|---|---|---|---|
offloadThresholdChars | number | 40000 | Serialized character length above which a tool output is offloaded. |
previewLines | number | 10 | Number of leading lines kept in the in-context stub (the "preview"). |
maxBytes | number | 268435456 | Maximum total bytes retained under workspace/tool-outputs/. Oldest files are removed first when the budget is exceeded. That is 256 MB. |
ttlMs | number | 10800000 | Delete offloaded files older than this many milliseconds. Default is 3 hours (10,800,000 ms). |
gcThrottleMs | number | 10000 | Minimum milliseconds between GC scans. Default is 10 seconds. |
noOffloadTools | string[] | [] | Additional tool names whose output is never offloaded. Merged with the built-in exempt set (readFile, listDir), which are always exempt so the agent can read back offloaded content without triggering re-offload. |
summarization
Configures conversation summarization. When enabled, Dawn compresses older message history once the thread exceeds maxTokens, keeping the most-recent turns verbatim. See Context Management for how offloading and summarization interact.
| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable conversation summarization. Off by default. |
maxTokens | number | 12000 | Token count above which older history is summarized. |
keepRecentTurns | number | 6 | Most-recent turns (each starting at a HumanMessage) kept verbatim, never summarized. |
model | string | Route's model | Model used for the summary LLM call. Defaults to the same model the route uses. |
tokenCounter | (text: string) => number | Promise<number> | Lazy gpt-tokenizer (o200k_base) | Custom token counting function. |
summarize | (args) => Promise<string> | Built-in single-LLM-call summarizer | Custom summary generator. Receives messages, model, previousSummary, and signal. |
memory
Configures long-term memory governance. A route opts into memory by adding a memory.ts next to its index.ts (see defineMemory in the Memory reference) — that file's presence is what activates the recall/remember tools and the memory-index prompt fragment. The keys below tune how those typed memories are stored, recalled, and written. They apply to every memory-enabled route even when the memory config key is omitted.
memory?: {
store?: MemoryStore
writes?: "off" | "candidate" | "auto" | "ask"
indexMaxEntries?: number
recall?: {
weights?: { relevance?: number; recency?: number; confidence?: number }
recencyHalfLifeMs?: number
candidatePool?: number
}
resolveScope?: (ctx: { routePath: string; appRoot: string }) => Record<string, string>
}| Key | Type | Default | Description |
|---|---|---|---|
store | MemoryStore | SQLite at .dawn/memory.sqlite | The memory store backend. Defaults to an SQLite-backed store at <appRoot>/.dawn/memory.sqlite. Override to plug in a custom backend. |
writes | "off" | "candidate" | "auto" | "ask" | "candidate" | Write governance for the remember tool. off — recall-only; the remember tool is not exposed. candidate — writes land as candidates for review, hidden from recall until promoted with dawn memory approve. auto — writes are active immediately, with inline identity reconciliation (idempotent updates and supersede-on-conflict). ask — same as auto, except a supersede (belief contradiction) interrupts for human Once/Always/Deny approval when running interactively; headless behaves exactly like auto. |
indexMaxEntries | number | 20 | Cap on how many in-scope memories are injected into the prompt memory index. |
recall | { weights?, recencyHalfLifeMs?, candidatePool? } | relevance/recency/confidence 0.6/0.3/0.1, 14-day half-life, pool 256 | Ranked-recall tuning for recall({ query }). weights blends IDF relevance, recency decay, and stored confidence; recencyHalfLifeMs sets the recency half-life; candidatePool caps how many newest token-matches a ranked search scores. Query-less recall (the injected index) is unaffected. |
resolveScope | (ctx: { routePath; appRoot }) => Record<string, string> | — | Supplies runtime namespace dimensions (e.g. tenant, user, agent) for the memory namespace. Only the dimensions a route declares in its memory.ts scope are applied. |
See Memory for the full long-term-memory model and Permissions for the ask-mode HITL flow, plus the dawn memory CLI for reviewing candidate writes.
build
| Type | Default |
|---|---|
{ targets?: string[] } | { targets: ["node", "langsmith"] } |
Deployment build configuration for dawn build.
build?: {
targets?: string[]
}targets selects which deployment artifacts dawn build emits. Known targets:
"node"— a runnable Node server entry (.dawn/build/server.mjs, which bootsserveRuntime) plus a hardenedDockerfile. This is the only target that engages the sandbox in production. Run it withdawn startordocker build/docker run."langsmith"— the LangSmith deploy config (.dawn/build/langgraph.jsonand the per-route materialized graph entry files).
Both are emitted by default. Restrict to one target — e.g. { build: { targets: ["node"] } } — if you only deploy that way. See Deployment for the full bridge.
sandbox
| Type | Default |
|---|---|
SandboxConfig | none — filesystem/exec run on the host by default |
Routes workspace filesystem and exec calls through an isolated SandboxProvider (e.g. dockerSandbox or kubernetesSandbox from @dawn-ai/sandbox) instead of the host process. Opt in per app; omit entirely for the default host-backed behavior.
sandbox?: {
provider: SandboxProvider
network?: { mode: "allow"; denylist?: string[] } | { mode: "deny"; allowlist?: string[] }
env?: Record<string, string>
resources?: { memoryMb?: number; cpus?: number; timeoutMs?: number; diskGb?: number }
security?: {
dropAllCapabilities?: boolean
noNewPrivileges?: boolean
readOnlyRootFilesystem?: boolean
runAsNonRoot?: boolean | { uid: number; gid: number }
pidsLimit?: number
}
idleTimeoutMs?: number
}| Sub-key | Type | Default | Description |
|---|---|---|---|
provider | SandboxProvider | — (required) | The sandbox implementation, e.g. dockerSandbox({ image }) or kubernetesSandbox({ image, namespace? }). |
network | { mode: "allow" | "deny"; denylist?/allowlist? } | provider-defined | Network egress policy applied inside the sandbox. |
env | Record<string, string> | {} | Explicit env injected into the sandbox. The host env is never inherited. |
resources | { memoryMb?; cpus?; timeoutMs?; diskGb? } | provider-defined | Resource limits and per-command timeout. diskGb sizes the per-thread volume on PVC-backed providers (Kubernetes); Docker ignores it. |
security | SandboxSecurityPolicy | hardened (Docker) | Provider-agnostic hardening intent — capability drop, no-new-privileges, read-only rootfs, non-root uid/gid, pids limit. Fields left unset take the provider's secure default. |
idleTimeoutMs | number | 600000 (10 min) | Manager-level idle reap window before a warm sandbox is released. |
See Execution Sandbox for provider setup, the security-hardening defaults, and the Kubernetes provider.