Skip to content

Config schema

defineConfig(config) provides type checking and returns the config unchanged. Nola validates and freezes it when it loads. The table below lists the supported settings.

Key Type Default Invalid → Read by
model ModelConfigInput | ({ default: ModelConfigInput } & Record<string, ModelConfigInput>) — a bare model is { default }; the string "nola" is the platform model (short for nola.infer()), legal only as the bare value or the map’s default — (required) NOLA3003 — neither a model nor an object; a map missing default; an entry missing name or infer() (a complete()-only model is the retired chat form and the error names the migration); any string other than "nola"; the platform model nested anywhere but the root runtime — every ask
project non-empty string — names this app in traces and platform requests; never part of the ask fingerprint the nearest package.json name, walking up from the working directory (unset when none exists) NOLA3003 — empty or non-string trace envelopes and managed infer requests — the console groups runs by it
forceModel string naming a key of the model map unset NOLA3004 runtime — overrides every ask-site pin
telemetry { level?: NolaLogLevel } | NolaTelemetry | string | (NolaTelemetry | string)[] — { level } is the terminal alone (terminalTrace({ level })); an observer or a list replaces it (terminalTrace(...), nola.tracer(...), an http(s) URL string as the alias of nola.tracer(url), or an object with any of onAskStart, onProviderRequest, onProviderResponse, onValidationFailed, onRetry, onAskEnd, onInvocationStart, onInvocationEnd) {} — the terminal at debug NOLA3003 — a bad level; an unknown terminal option; an entry that is not an object with an on* method; a string that is not an http(s) URL; hooks (removed) runtime — every entry gets every event in list order; NOLA_TRACING_URL appends a tracer
middleware NolaMiddleware[] (functions) [] NOLA3003 validated, but currently has no effect; the ask path calls the provider directly
cache {} or { store: NolaCacheStore } unset ({} → in-memory store) NOLA3006 validated, but currently has no effect
system.message string unset NOLA3003 runtime — replaces the default system text of every ask (DEFAULT_SYSTEM from @nola-lang/providers to compose)
ask.timeoutMs non-negative finite number (ms); 0 disables 60000 NOLA3003 — also for unknown keys under ask runtime — per-invocation timeout
compiler.underivableContextType "error" | "prune" | "omit" — keep it a literal "error" NOLA3003 nola build / nola check / the loader / the editor — never the runtime
build.target "app" | "lib" "app" NOLA3003 nola build only
plugins reserved — NOLA3005 — rejected at load —

Nola also raises NOLA3003 if the config is not an object, contains an unknown top-level key or is changed after the first ask. Unknown-key messages list the allowed keys; hooks points to its replacement, telemetry. In tests, call nolaRuntime.reset() before configuring the runtime again.

After loading, the runtime holds a frozen ResolvedNolaConfig:

  • model is always a map; a single model becomes { default }.
  • project? and forceModel? retain their resolved values.
  • telemetry is an observer array. Terminal settings have been converted to terminalTrace(), and the NOLA_TRACING_URL tracer has been appended when applicable.
  • middleware is a frozen array. If cache is configured, it has a concrete store.
  • system? remains optional. Defaults are filled in for ask.timeoutMs, compiler.underivableContextType and build.target.

@nola-lang/runtime exports NolaConfig, NolaTelemetry, NolaMiddleware, NolaLogLevel, LanguageModel, ModelConfigEntry and ModelConfigInput. It also exports defineConfig, resolveNolaConfig, resolveCompilerConfig and resolveBuildConfig.

ModelConfigInput accepts a model instance or the string "nola". NolaCacheStore is not re-exported; cache settings are validated but currently have no effect.

nola.config.ts
import { mockProvider, openai } from "@nola-lang/providers";
import { defineConfig, terminalTrace } from "@nola-lang/runtime";
export default defineConfig({
model: {
default: openai({ model: "gpt-5-mini" }),
mock: mockProvider(() => ({ ok: true })),
},
forceModel: process.env.CI ? "mock" : undefined,
telemetry: [terminalTrace({ level: "info" }), { name: "audit", onAskEnd: ({ receipt }) => console.log(receipt.site, receipt.servedBy) }], // or just { level: "info" }
system: { message: "Answer in British English." },
ask: { timeoutMs: 60_000 },
compiler: { underivableContextType: "error" },
build: { target: "app" },
});

Next: Error codes