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).

ts
// dawn.config.ts
export default {
  // ...
} satisfies import("@dawn-ai/core").DawnConfig

Complete 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.

ts
// 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

TypeDefault
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.

ts
backends?: {
  filesystem?: FilesystemBackend
  exec?: ExecBackend
}
Sub-keyTypeDefaultDescription
filesystemFilesystemBackendBuilt-in local FSHandles readFile, writeFile, listDir workspace operations.
execExecBackendBuilt-in child_process execHandles 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.

ts
permissions?: {
  mode?: PermissionMode
  allow?: Record<string, string[]>
  deny?: Record<string, string[]>
}

permissions.mode

TypeDefaultEnv override
"interactive" | "non-interactive" | "bypass""interactive"DAWN_PERMISSIONS_MODE
  • interactive — Commands and paths not on the allow-list trigger interrupt(), 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.

dawn.config.ts
export default {
  permissions: {
    allow: { tool: ["deployProd"] },
  },
}

checkpointer

TypeDefault
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

TypeDefault
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

TypeDefaultScope
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.

KeyTypeDefaultDescription
offloadThresholdCharsnumber40000Serialized character length above which a tool output is offloaded.
previewLinesnumber10Number of leading lines kept in the in-context stub (the "preview").
maxBytesnumber268435456Maximum total bytes retained under workspace/tool-outputs/. Oldest files are removed first when the budget is exceeded. That is 256 MB.
ttlMsnumber10800000Delete offloaded files older than this many milliseconds. Default is 3 hours (10,800,000 ms).
gcThrottleMsnumber10000Minimum milliseconds between GC scans. Default is 10 seconds.
noOffloadToolsstring[][]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.

KeyTypeDefaultDescription
enabledbooleanfalseEnable conversation summarization. Off by default.
maxTokensnumber12000Token count above which older history is summarized.
keepRecentTurnsnumber6Most-recent turns (each starting at a HumanMessage) kept verbatim, never summarized.
modelstringRoute's modelModel 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 summarizerCustom 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.

ts
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>
}
KeyTypeDefaultDescription
storeMemoryStoreSQLite at .dawn/memory.sqliteThe 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.
indexMaxEntriesnumber20Cap 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 256Ranked-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

TypeDefault
{ targets?: string[] }{ targets: ["node", "langsmith"] }

Deployment build configuration for dawn build.

ts
build?: {
  targets?: string[]
}

targets selects which deployment artifacts dawn build emits. Known targets:

  • "node" — a runnable Node server entry (.dawn/build/server.mjs, which boots serveRuntime) plus a hardened Dockerfile. This is the only target that engages the sandbox in production. Run it with dawn start or docker build/docker run.
  • "langsmith" — the LangSmith deploy config (.dawn/build/langgraph.json and 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

TypeDefault
SandboxConfignone — 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.

ts
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-keyTypeDefaultDescription
providerSandboxProvider— (required)The sandbox implementation, e.g. dockerSandbox({ image }) or kubernetesSandbox({ image, namespace? }).
network{ mode: "allow" | "deny"; denylist?/allowlist? }provider-definedNetwork egress policy applied inside the sandbox.
envRecord<string, string>{}Explicit env injected into the sandbox. The host env is never inherited.
resources{ memoryMb?; cpus?; timeoutMs?; diskGb? }provider-definedResource limits and per-command timeout. diskGb sizes the per-thread volume on PVC-backed providers (Kubernetes); Docker ignores it.
securitySandboxSecurityPolicyhardened (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.
idleTimeoutMsnumber600000 (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.


Related