Options reference
Complete reference for Kiira config options: include, exclude, tsconfig, engine, packageMode, defaultValidate, defaultGroup, checkUnusedSymbols, checkRelativeImports, plugins, presets, rules, overrides, externalPackages, fixtures, defaultFixture, and languages.
Options at a glance
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| include | string[] | ["**/*.{md,mdx}"] | Glob patterns for the Markdown files to check. Presets can add to it. |
| exclude | string[] | [] | Glob patterns to exclude from include. |
| tsconfig | string | auto | Path to the tsconfig used to compile snippets. Auto-resolves tsconfig.docs.json, then tsconfig.json. |
| engine | "auto" \| "classic" \| "native" | "auto" | Which TypeScript engine type-checks snippets. "auto" uses TypeScript 7's native compiler when your project has it, else the bundled one. |
| packageMode | "workspace" \| "packed" | "workspace" | How package imports are resolved. |
| workspacePackageResolution | "exhaustive" \| "owner" | "exhaustive" | Which workspace node_modules directories are dependency fallbacks. |
| defaultValidate | "type" \| "runtime" \| "none" | "type" | Default validation level for fences. |
| defaultGroup | "none" \| "file" | "none" | Implicitly group every checkable fence in a file so later fences see earlier declarations. |
| checkUnusedSymbols | boolean | false | Report unused symbols (TS6133). |
| checkRelativeImports | boolean | false | Report unresolved relative imports. |
| plugins | KiiraPlugin[] | [] | Plugins that add rules and presets. Experimental. |
| presets | (string \| Preset)[] | [] | Named or inline bundles of include, exclude, codeFenceLanguages, and rules. Experimental. |
| rules | Record<string, RuleSetting> | {} | Turn rules "off", "warn", or "error", optionally with options. Experimental. |
| overrides | Override[] | [] | Per-glob compiler options, codeFenceLanguages, rules, and presets. |
| externalPackages | Record<string, string> | {} | Doc-only packages to install into a hidden, isolated cache so fences that import them type-check. |
| fixtures | Record<string, Fixture> | {} | Named prepend/wrap code applied to fences. |
| defaultFixture | string | — | Fixture applied to every fence by default. |
| languages | string[] | ["ts","tsx","js","jsx"] | Fence languages Kiira checks. |
include
Glob patterns for the Markdown files Kiira checks. When neither your config nor a preset sets one, it defaults to every .md and .mdx file.
include: ["docs/**/*.{md,mdx}", "README.md"]Kiira checks both .md and .mdx files out of the box — .mdx is parsed MDX-aware, so fences nested inside JSX components (<Tabs>, <Callout>, …) and files with ESM import/export are extracted correctly. A bare glob like "docs/**/*" only ever picks up .md/.mdx; other files are ignored.
--entry on the CLI overrides include, including any preset include, for a single run.
exclude
Glob patterns removed from the set matched by include. Defaults to [].
exclude: ["docs/api/**", "**/*.generated.md"]tsconfig
Path to the TypeScript config used when compiling your snippets. When omitted, Kiira auto-resolves tsconfig.docs.json first (so you can use docs-specific settings) and falls back to tsconfig.json.
tsconfig: "tsconfig.docs.json"engine
Which TypeScript engine type-checks your snippets:
"auto"(default) — use the TypeScript 7 native compiler (the Go port) when your project hastypescript@>=7installed; otherwise fall back to Kiira's bundled TypeScript. A missing or older TypeScript never breaks a check."classic"— always use Kiira's bundled TypeScript, in-process. Pin this if you want checks to stay independent of the TypeScript version installed in your project."native"— always use the project's TypeScript 7 native compiler. Errors if the project has notypescript@>=7.
engine: "auto"The diagnostics are the same either way. Two things to know about "native":
- It loads TypeScript from your project (Kiira bundles a v5 for the classic path),
so
typescript@>=7must be installed alongside Kiira. - The native compiler runs as a subprocess, which adds start-up overhead per check. For
the small snippets in docs the classic in-process engine is usually faster, so
"auto"only switches to native when your project is already on TypeScript 7. - Editor code-fixes (the VS Code lightbulb) always use the bundled TypeScript — the native compiler has no code-fix API yet. Diagnostics are unaffected.
packageMode
How Kiira resolves package imports referenced in your snippets:
"workspace"(default) — discovers your monorepo's workspaces and resolves package names to their source. See Monorepos."packed"— resolves against the packed/published form of the package.
packageMode: "workspace"workspacePackageResolution
Workspace dependency lookup is exhaustive by default. Set this option to "owner" to try the
package that owns each Markdown file first, then the workspace root, then the workspace packages
that the owner declares as dependencies. Other packages add only their @types. This can miss
undeclared workspace dependencies. Kiira checks the Markdown files of each owner package in a
separate TypeScript program, so a file gets the same result in the CLI and in the editor.
Workspace package exports, user paths, and typeRoots remain in effect. If Kiira cannot find
the owner (a file outside the project root, or an unreadable package.json), it prints a
warning and uses exhaustive lookup. Kiira rejects values other than "exhaustive" and "owner".
defaultValidate
The default validation level applied to every fence (override per-fence with the validate= token):
"type"(default) — full TypeScript type-checking."runtime"— runtime-oriented validation."none"— skip validation for that fence.
defaultValidate: "type"defaultGroup
How fences in a single file are grouped when you haven't tagged them with group=:
"none"(default) — each fence is its own isolated module (the original behavior)."file"— every checkable fence in a file shares one implicit group, concatenated in document order, so a later fence sees declarations from earlier ones.
defaultGroup: "file""file" is built for literate docs — pages where one fence sets up imports and values and later fences build on them — collapsing the TS2304 Cannot find name noise without hand-tagging every fence. An explicit group= on a fence always wins, and group=none detaches a single fence (handy when two fences in the same file each redeclare the same name). You can also set defaultGroup per-glob via overrides.
checkUnusedSymbols
When true, Kiira reports unused symbols (TypeScript's TS6133). Defaults to false because docs snippets frequently declare imports or variables for illustration without using them.
checkUnusedSymbols: falseThis is an alias for the unused-symbols rule: true means "error" and false means "off". Set the rule instead if you want "warn".
checkRelativeImports
When true, Kiira reports unresolved relative imports (e.g. ./utils). Defaults to false, because relative paths in docs often point at files that don't exist in the docs project. Bare package imports (e.g. your-lib) are always checked regardless of this setting.
checkRelativeImports: falseThis is an alias for the relative-imports rule, the same way checkUnusedSymbols is for unused-symbols.
plugins
Plugins add rules and presets. A plugin is an object with a name, and optionally rules and presets. Build one with definePlugin from kiira-core/plugin.
import { defineConfig } from "kiira-core"import { definePlugin, defineRule } from "kiira-core/plugin"const noTodo = defineRule({ meta: { scope: "document", defaultSeverity: "warn" }, create(ctx) { // ... },})export default defineConfig({ plugins: [definePlugin({ name: "docs", rules: { "no-todo": noTodo } })], rules: { "docs/no-todo": "error" },})A plugin's rules are named <plugin>/<rule>, so docs/no-todo above. Plugins need a JavaScript or TypeScript config file; they can't be written in kiira.config.json. See Writing a plugin for how to write one.
presets
A preset is a named bundle of settings. Reference one by name (<plugin>/<preset>) or write it inline:
presets: [ "docs/recommended", { name: "intent", include: ["docs/**/*.md"], codeFenceLanguages: ["ts", "tsx", "typescript", "js", "jsx", "javascript"], rules: { group: "off" }, },]| Field | Type | What it does |
| --- | --- | --- |
| name | string | Required. |
| extends | string[] | Presets applied before this one, by name. Each preset is applied once, at its first use. A cycle is an error. |
| include | string[] \| (project) => string[] | Added to the top-level include. The function form is called with the project (cwd, packageJson, workspacePackages, isTracked) before files are discovered. |
| exclude | string[] | Added to the top-level exclude. |
| allowEmpty | boolean | When true and no file matches, Kiira skips the run, prints No files matched; nothing to check., and exits 0. Without it, an empty match is a normal run with zero files. |
| codeFenceLanguages | string[] | The fence identifiers to recognize. The last preset that sets it wins, unless you set markdown.codeFenceLanguages yourself. |
| rules | Record<string, RuleSetting> | Rule settings, applied in the order described in how settings merge. |
| typescript | (file, ctx) => TypescriptHookResult \| undefined | Per-file TypeScript options. See the TypeScript hook. |
The presets reference has more on each field.
--entry and positional paths on the CLI replace the whole include set, presets included.
Inside overrides[].presets, only rules and codeFenceLanguages apply.
rules
Sets the level of each rule by id. A level is "off", "warn" (reports a warning), or "error" (reports an error). Use a [level, options] pair to pass options to a rule that takes them.
rules: { "language-tag": "off", "unused-symbols": "warn", "docs/max-length": ["error", { lines: 40 }],}An unknown rule id, an invalid level, or options a rule rejects throw an error that lists the known ids, and kiira check exits 2.
You can also set a level for one run with --rule.
How rule settings merge
Each layer is applied on top of the one before it:
- Each rule's built-in default level.
presets, in order, with each preset'sextendsapplied first.- Top-level
rules.checkUnusedSymbolsandcheckRelativeImportscount as this layer; an explicitrulesentry for the same rule wins. - Matching
overrides, in order. Within an override, itspresetsapply before itsrules. --ruleon the CLI.
A level without options keeps the options set by an earlier layer.
The reference shows each step with an example.
overrides
Per-glob overrides — for example, setting a different jsxImportSource for docs that target another framework. Kiira runs a separate TypeScript program per distinct option set. See Per-glob overrides.
overrides: [ { include: ["docs/solid/**/*.mdx"], jsxImportSource: "solid-js", },]Besides compiler options, defaultGroup, and externalPackages, an override can set:
codeFenceLanguages— the fence identifiers recognized in matching files. The last matching override wins.rules— rule levels for matching files, applied after the top-levelrules.presets— presets whoserulesandcodeFenceLanguagesapply to matching files.
overrides: [ { include: ["docs/intent/**/*.md"], codeFenceLanguages: ["ts", "tsx", "typescript", "js", "jsx", "javascript"], rules: { group: "off" }, },]externalPackages
Packages your docs import but your project does not depend on — a competitor library shown in a comparison, or a third-party tool shown in an integration example. Without them installed, those imports fail to resolve and the fence reports TS2307: Cannot find module.
externalPackages is a Record<string, string> of package name → version range. Kiira installs them into a hidden, isolated cache (node_modules/.kiira) purely for type-checking — your real package.json and node_modules are never touched.
externalPackages: { langchain: "^0.3.0", zod: "^3",}- The install runs on
kiira checkwith your project's package manager (detected from the lockfile), and re-installs only when the list changes — otherwise it's a no-op. - The install runs with
--ignore-scripts: Kiira only needs types on disk to type-check, so dependency build/postinstall scripts are never executed. This keeps doc-only packages from running install-time code, and avoids package managers that gate build scripts (e.g. pnpm) failing the install. - Declarations on
overrides(overrides[].externalPackages) are merged into the same install and resolve globally (one version per package name). - Remove the cache any time with
rm -rf node_modules/.kiira.
fixtures
Named blocks of code that Kiira can prepend to (or wrap around) a fence before compiling it — useful for providing shared imports or setup so individual snippets stay focused. Reference a fixture per-fence with the fixture= token.
fixtures: { setup: { type: "prepend", content: `import { createApp } from "your-lib"\nconst app = createApp()`, },}defaultFixture
The name of a fixture applied to every fence by default (still overridable per-fence):
defaultFixture: "setup"languages
The fence languages Kiira checks. Defaults to all four:
languages: ["ts", "tsx", "js", "jsx"]Narrow this if you only want to check, say, TypeScript fences.