Document Structure

A .knot file is a valid Typst document with two additions: code chunks and inline expressions. Everything else — headings, paragraphs, equations, figures, references — is standard Typst.

The required import

Every .knot document must start with:

#import "lib/knot.typ": *
#show: knot-init

knot-init installs the Typst functions (code-chunk, etc.) that Knot's output relies on. Without it, the compiled .typ will not render correctly.

Code chunks

A code chunk is a fenced block with a language tag in braces:

```{r}
x <- 1:10
mean(x)
```
```{python}
import numpy as np
np.mean([1, 2, 3])
```

The language tag (r, python) determines which interpreter runs the block.

Options are specified as YAML comments at the top of the block, prefixed with #|:

```{r}
#| label: summary-stats
#| echo: false
#| fig-width: 6
x <- rnorm(100)
hist(x)
typst(current_plot())
```

See Chunk Options for the complete reference.

Inline expressions

An inline expression evaluates a short snippet and inserts the result into the surrounding prose:

The average is `{r} mean(x)` and the count is `{python} len(values)`.

Inline expressions share the same namespace as code chunks — x defined in an R chunk above is available in a later {r} inline expression.

Inline expressions should return a simple scalar (a number, a string, a boolean). For complex objects, use a code chunk instead.

Multi-file projects

Large projects can split content across multiple .knot files. Declare them in knot.toml:

[document]
main = "main.knot"
includes = ["chapter1.knot", "chapter2.knot"]

Each file gets its own isolated R and Python environment. Variables defined in chapter1.knot are not visible in chapter2.knot. If you need to share data between files, write it to disk (e.g., an RDS file, a CSV, a pickle) in one file and read it in the next.

The main file must contain a /* KNOT-INJECT-CHAPTERS */ placeholder where the compiled include files will be inserted:

#import "lib/knot.typ": *
#show: knot-init

= My Book

/* KNOT-INJECT-CHAPTERS */