Type-check the code in your Markdown.
Kiira extracts TypeScript and JavaScript code fences from your Markdown docs, type-checks them against your real project API, and reports any errors right back on the Markdown line — in your editor, on the command line, and in CI.
📚 Full documentation lives in /docs — a browsable site covering every CLI
feature, configuration, CI recipes, and the VS Code extension. Run it locally with
pnpm install && pnpm run dev from inside docs/, or deploy it (Docker / Fly.io configs are
included).
Docs are increasingly written and updated by agents, and agents hallucinate APIs. Kiira catches the things that make a copy-pasted example fail:
- invalid imports and missing exports
- wrong package subpaths
- wrong function, option, or prop names
- invalid TypeScript / JavaScript (with
checkJs) - non-copy-pasteable examples — unless explicitly marked partial or ignored
| Package | Description |
|---|---|
kiira-core |
Extraction, virtual files, type-checking, diagnostics. |
kiira |
kiira check for local and CI validation. |
kiira-vscode |
Live squiggles inside Markdown code fences. |
AlemTuzlak/kiira@v1 |
GitHub composite action for CI. |
pnpm add -D kiiraCreate a tsconfig.docs.json and (optionally) a kiira.config.ts, then run:
kiira check```ts
import { createAgent } from "@tanstack/ai"
```Add metadata to control validation:
```tsx fixture=react validate=type name=basic-chat
import { useChat } from "@tanstack/ai/react"
export function Chat() {
const chat = useChat()
return <div>{chat.messages.length}</div>
}
```Supported metadata: ignore, validate=type|runtime|none, fixture=<name>, name=<id>,
package=workspace|packed, group=<id>.
By default each fence is checked as an isolated module. When a walkthrough is split across
several fences (a later fence uses a const declared in an earlier one), tag them with the
same group:
```ts group=quickstart
const client = createClient()
```
```ts group=quickstart
await client.send("hi") // resolves: same group as the snippet above
```Kiira also detects ungrouped continuations automatically — if grouping a document's
snippets would resolve "cannot find name" errors, it warns and kiira check --fix adds the
group= tags for you.
In packageMode: "workspace" (the default) Kiira discovers your pnpm/npm/yarn workspace,
maps every package name to its source, and adds each package's node_modules as a resolution
fallback. So in a monorepo, docs that import @your-scope/* and third-party libs resolve
out of the box — no hand-written tsconfig paths required.
When a docs set spans multiple frameworks, a single jsx/jsxImportSource can't serve all of
them. Use overrides to set compiler options for matching files:
export default defineConfig({
include: ["docs/**/*.md"],
overrides: [
{ include: ["**/*solid*"], jsxImportSource: "solid-js" },
{ include: ["**/*preact*"], jsxImportSource: "preact" },
],
})Each override's non-include fields are merged onto the base compiler options for matching
files (Kiira runs a separate TypeScript program per distinct option set). Kiira also
detects the framework from the file path: if a file's JSX fails for lack of the right
runtime types (TS7026), it suggests a jsxImportSource override and kiira check --fix
writes it into a JSON config for you.
Kiira warns when a ts fence actually contains JSX (it should be tsx), checks it as tsx
anyway so you get real type errors instead of a syntax-error cascade, and can rewrite the tag
for you:
kiira check --fix # rewrites mistagged fences (ts/typescript -> tsx)kiira check # validate everything in your include globs
kiira check --entry docs # check a directory (repeatable)
kiira check --entry docs --ignore docs/api # ...excluding a subdirectory
kiira check "docs/**/*.md" # validate specific files/globs
kiira check --reporter json # machine-readable output
kiira check --reporter github # GitHub Actions annotations
kiira check --fix # rewrite mistagged code fences (ts -> tsx)
kiira check --verbose # full messages + code frames (default is compact)
kiira init # scaffold kiira.config.ts + tsconfig.docs.json| Flag | Description |
|---|---|
--entry <path> |
Directory, file, or glob to check. Repeatable. Overrides include. |
--ignore <path> |
Directory, file, or glob to exclude. Repeatable (e.g. --ignore docs/api). |
--config <path> |
Path to a Kiira config file. |
--reporter <name> |
Output format: pretty (default), json, or github (Actions annotations). |
--fix |
Apply auto-fixes: rewrite mistagged fences (ts→tsx), add group= tags, write framework jsxImportSource overrides. |
--verbose |
Full error messages and code frames (default output is compact). |
--raw |
Plain text — disable colored output. |
--static |
Disable the loading spinner. |
-h, --help |
Show help. |
-v, --version |
Show the version. |
Exit codes: 0 clean, 1 validation errors, 2 config/runtime failure.
kiira.config.ts (or .js/.json); all fields are optional except include:
import { defineConfig } from "kiira-core"
export default defineConfig({
include: ["docs/**/*.md", "README.md"],
exclude: ["**/node_modules/**"],
tsconfig: "tsconfig.docs.json", // defaults to tsconfig.docs.json, then tsconfig.json
packageMode: "workspace", // "workspace" (default) | "packed"
defaultValidate: "type", // "type" (default) | "runtime" | "none"
checkUnusedSymbols: false, // report TS6133 unused locals/params/imports
checkRelativeImports: false, // report unresolved ./ and ../ imports
overrides: [
{ include: ["**/*solid*"], jsxImportSource: "solid-js" },
],
fixtures: {
react: { type: "wrap", before: "import React from 'react'", after: "" },
},
defaultFixture: undefined,
languages: ["ts", "tsx", "js", "jsx"],
})| Option | Default | Description |
|---|---|---|
include |
— | Markdown globs to check (required). |
exclude |
[] |
Globs to skip. |
tsconfig |
auto | tsconfig to source compiler options from. |
packageMode |
workspace |
Resolve monorepo packages (workspace) or rely on installed packages (packed). |
defaultValidate |
type |
Default validation mode for fences without a validate= tag. |
checkUnusedSymbols |
false |
Report unused locals/params/imports (TS6133). |
checkRelativeImports |
false |
Report unresolved relative imports. |
overrides |
[] |
Per-glob compilerOptions (e.g. jsxImportSource). |
fixtures |
{} |
Named code to prepend/wrap around snippets. |
defaultFixture |
— | Fixture applied to fences without a fixture= tag. |
languages |
all | Fence languages to check. |
Add tokens after the language on the fence info string:
```tsx fixture=react validate=type name=basic-chat group=quickstart| Token | Description |
|---|---|
ignore |
Skip this fence entirely. |
validate=type|runtime|none |
Override the validation mode for this fence. |
fixture=<name> |
Wrap the snippet with a named fixture from config. |
name=<id> |
A stable label for the snippet (shown in tooling). |
group=<id> |
Type-check fences sharing an id together, in document order. |
package=workspace|packed |
Override the package resolution mode for this fence. |
Unused locals/parameters/imports (TS6133) are ignored by default — doc snippets
routinely declare things they don't use. Set checkUnusedSymbols: true in your config to
enforce them.
Unresolved relative imports (./x, ../x) are also ignored by default — snippets
often "import" from an imaginary sibling file standing in for an earlier snippet or the
reader's project. Bare package imports (@scope/pkg, react) are always checked. Set
checkRelativeImports: true to enforce relative imports too.
Install Kiira from the
VS Code Marketplace
(or ext install CodeForge.kiira-vscode). It also publishes to
Open VSX.
It type-checks your Markdown code fences against your real project, live:
- Live diagnostics — type errors appear as you type (debounced) and on save, mapped to the exact line inside the fence.
- Quick fixes (
Ctrl+./Cmd+.):- TypeScript's own fixes inside fences — auto-import a missing symbol, fix a
misspelled name, add a missing
await, implement an interface, … - Kiira's fixes — change a mistagged
```tsfence to```tsxfor JSX, or tag continuation snippets withgroup=….
- TypeScript's own fixes inside fences — auto-import a missing symbol, fix a
misspelled name, add a missing
- Inspect the generated virtual file for any snippet.
| Command | Description |
|---|---|
Kiira: Check Current File |
Re-check the active Markdown document. |
Kiira: Check Workspace |
Check every Markdown file in the workspace. |
Kiira: Open Virtual File For Snippet |
Inspect the generated code for a fence. |
Kiira: Restart Kiira Server |
Clear and re-check all open documents. |
| Setting | Default | Description |
|---|---|---|
kiira.enable |
true |
Enable Kiira diagnostics in Markdown files. |
kiira.configPath |
kiira.config.ts |
Path to the Kiira config, relative to the workspace root. |
kiira.debounceMs |
300 |
Delay before re-checking after a change. |
kiira.checkOnChange |
true |
Re-check as the document changes (debounced). |
kiira.checkOnSave |
true |
Re-check when the document is saved. |
kiira.showGeneratedDiagnostics |
false |
Show diagnostics from generated fixture code (debugging). |
Use the composite action:
- uses: AlemTuzlak/kiira@v1
with:
command: pnpm kiira check
reporter: github| Example | Shows |
|---|---|
examples/basic |
Plain TypeScript snippets against the node types. |
examples/react |
tsx snippets with react and wrap fixtures. |
examples/monorepo |
One config validating docs across many packages. |
This is a pnpm + Nx monorepo.
pnpm install
pnpm build:all # build every package
pnpm test # check + typecheck + unit tests + buildMIT © AlemTuzlak