Octavo
Contents

Octavo guide

The quantitative social science starter pack

Octavo turns Markdown manuscripts into papers, handouts and slides — Typst (to PDF), Word, and, if you have TeX, LaTeX and Beamer — with the citations from one .bib file and the numbers, figures and tables from your Quarto analysis. This guide is the manual; the README is the short introduction. 日本語の手引き


1. Install

Octavo needs a few tools besides itself: pandoc (conversion), Typst (typesetting to PDF), Quarto and R (the analysis), the fonts, and uv (which installs the octavo command). One setup installs all of them. Pick your system:

You use Read
Ubuntu or another Debian-like Linux — a PC, or a server you reach over SSH Linux
A Mac macOS
Windows Windows — WSL (recommended) or Windows itself

On every system there are two ways to do it: with VS Code (install the extension and press one button) or from a terminal (four commands). They install the same things. LaTeX is not included — it is optional (see LaTeX, if you want it).

1.1 Linux

Ubuntu 24.04 is what Octavo is tested on; Debian and other Ubuntu versions work too (a font the distribution doesn’t package is replaced by Noto). You need a user who can use sudo.

With VS Code

  1. Install VS Code on the computer you work at. If Octavo is to run on a server, also install the Remote - SSH extension and connect to the server (Remote-SSH: Connect to Host…); everything below then happens on the server.
  2. Install the Octavo extension (search “Octavo” in the Extensions view, publisher yoshida-kd). Over Remote-SSH, click Install in SSH: … so it lands on the server.
  3. Open a folder. The extension checks the tools and offers Set up. Press it: a terminal opens, asks for your password once (for sudo), and installs everything. It takes a while the first time (R and the fonts are the large part).
  4. When it finishes, the extension checks again. Nothing to report means you are done.

From a terminal

curl -LsSf https://astral.sh/uv/install.sh | sh   # uv
source ~/.local/bin/env                           # put uv on PATH in this terminal (or open a new one)
uv tool install octavo-kit                        # the octavo command
octavo setup                                      # pandoc, Typst, Quarto, fonts, R, renv (asks for your password)
octavo doctor                                     # everything should read ok

octavo setup adds CRAN’s repository so that R is the latest release, and points R at Posit Package Manager, from which a project’s renv installs packages as ready-made binaries instead of compiling them.

1.2 macOS

First install Homebrew, which Octavo uses to install everything else. Open Terminal and run the one line from brew.sh:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Follow what it prints at the end (on Apple Silicon it asks you to add Homebrew to your PATH), then open a new Terminal window.

With VS Code

  1. Install VS Code and the Octavo extension.
  2. Open a folder and press Set up when the extension offers it. A terminal opens and installs everything through Homebrew (your password may be asked for R and Quarto).
  3. If the extension says it cannot find octavo afterwards, quit VS Code completely (⌘Q) and start it again — it was started before the new command existed.

From a terminal

curl -LsSf https://astral.sh/uv/install.sh | sh   # uv
source ~/.local/bin/env                           # put uv on PATH in this terminal (or open a new one)
uv tool install octavo-kit                        # the octavo command
octavo setup                                      # pandoc, Typst, Quarto, fonts, R, renv (with Homebrew)
octavo doctor                                     # everything should read ok

R is CRAN’s own build (Homebrew’s r cask), so CRAN’s binary packages work.

1.3 Windows

There are two ways. WSL is recommended: Octavo is developed and tested on Linux first, and WSL gives you exactly that inside Windows. Use Windows itself only if you cannot use WSL.

  1. Install WSL. Open PowerShell as administrator (right-click the Start button → Terminal (Admin), or Windows PowerShell (Admin) on Windows 10) and run:

    wsl --install

    Restart when it asks. Ubuntu then starts and asks you to choose a user name and password — remember the password, the setup asks for it.

  2. Install VS Code on Windows, then the WSL extension.

  3. In VS Code, WSL: Connect to WSL (bottom-left corner). Open a folder inside Ubuntu (for example /home/<user name>).

  4. Install the Octavo extension.

  5. The Octavo extension offers Set up; press it and enter the Ubuntu password. From here on it is the Linux setup.

From a terminal instead: open Ubuntu from the Start menu and follow Linux → From a terminal.

1.3.2 Windows itself (without WSL)

This uses winget, which comes with Windows 11 and current Windows 10 (if winget is not found, install App Installer from the Microsoft Store). No administrator rights are needed. LaTeX is not installed on Windows (install MiKTeX yourself if you need it).

With VS Code: install VS Code and the Octavo extension, open a folder, and press Set up. On a PC without WSL the extension uses Windows’ own tools. When it has finished, restart VS Code so it sees the new commands.

From a terminal: open PowerShell (not as administrator) and run:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"   # uv

Close PowerShell and open a new one (so it finds uv), then:

uv tool install octavo-kit    # the octavo command
octavo setup                  # pandoc, Typst, Quarto, fonts, R, renv (with winget)

Open a new PowerShell once more and check:

octavo doctor                 # everything should read ok

Two habits keep a project working on every system: write paths with / (../assets/figures/trend.png), and keep the upper and lower case of file names exactly as the manuscript writes them — Windows does not tell Trend.png from trend.png, Linux does.

1.4 Check that it works

octavo doctor       # what is installed; anything missing comes with the command that installs it
octavo selftest     # typesets a small sample and prints the citations as they come out

octavo doctor marks each tool ok, missing, or a note (nice to have). octavo selftest builds a sample with English and Japanese references, a table, a figure and cross-references in a temporary folder and shows how the citations came out — run it once per machine and read it.

1.5 Updating

uv tool upgrade octavo-kit    # the newest octavo
octavo setup                  # the tools it expects (safe to run again: what is there is skipped)

In VS Code, update the extension and run Tools → Install or Update the Tools in the Octavo sidebar.

1.6 LaTeX, if you want it

Everything above makes PDFs through Typst; LaTeX is only needed for the latex and beamer formats. On Linux, octavo setup --with-tex adds TeX Live (several GB). On a Mac, install MacTeX; on Windows, MiKTeX. octavo doctor lists TeX separately and does not count it as missing.

1.7 The language Octavo speaks

Messages come out in English, or in Japanese when your system is set to Japanese. export OCTAVO_LANG=ja (or en) chooses. This is only the language of the messages; the language a project is written in is lang in its octavo.config.py (octavo init --lang ja|en). The VS Code extension follows VS Code’s language.


2. Your first project

In VS Code you can do all of this without typing a command: the Octavo sidebar offers New project in a folder that is not a project yet (where, the language, the parts, the examples — an analysis also gets its environment set up), and its + adds manuscripts, analyses, figures and tables later. The commands below are what those buttons run; see 10. VS Code.

2.1 Try the example first

octavo init demo --all --example
cd demo
octavo env                    # the project's analysis environment (.venv and renv)
octavo build --compile        # runs the analysis, then typesets everything to PDF

This makes a project with an analysis of made-up data, a paper, a slide deck and lecture notes that use it. The PDFs land in build/.

2.2 Start your own

octavo init makes the frame of a project; everything else is added with octavo new, as many of each as you like:

octavo init study --with analysis,paper   # the frame, an analysis and a paper
cd study
octavo env                                # the project's analysis environment (.venv and renv)
octavo new analysis model           # analysis/model.qmd (the first also brings octavo.R and data/)
octavo new analysis model --engine python   # the same, written in Python (brings octavo_helper.py)
octavo new paper example-paper      # docs/example-paper/: example-paper.md and the layout main.typ
octavo new paper example-paper --appendix   # add appendix.md (to an existing paper too)
octavo new paper example-paper --tex        # add main.tex for LaTeX (to an existing paper too)
octavo new slides example-talk      # docs/example-talk/example-talk.md
octavo new lecture example-lecture  # docs/example-lecture/example-lecture.md
octavo new poster example-poster    # docs/example-poster/example-poster.md
octavo new figure dag               # figures/dag.typ, a figure drawn in Typst
octavo new table compare            # tables/compare.csv, a table you make by hand

init --with takes the same parts (--with lecture, --with analysis,slides=talk; --all for every kind; --engine python makes the analysis one in Python), and --example fills the parts with worked examples instead of bare headings. Add --env to init or new analysis to set up the analysis environment in the same step.

A document is docs/<name>/<name>.md. Its appendix (appendix.md) and a paper’s layout (main.typ) sit in the same folder. A document is referred to by its name: octavo build example-paper. paper, slides and lecture are different templates; each makes the same kind of document. What a document makes is decided at the top of the manuscript (3.6).

2.3 What is in a project

study/
  octavo.config.py   the project's settings
  literature.bib     the bibliography, exported from your reference manager
  AGENTS.md          the project's working rules for AI assistants (Claude Code, GitHub Copilot, Codex, Antigravity read it)
  CLAUDE.md          one line that points Claude Code at AGENTS.md
  README.md          a few lines for you to finish
  docs/<name>/       <name>.md (the manuscript), and appendix.md and main.typ (the journal layout) if any
  analysis/          the .qmd files and the helper (octavo.R, or octavo_helper.py for Python)
  data/raw/          the data as you got it (not in git; describe it in data/raw/README.md)
  data/derived/      data the analysis made (not in git)
  figures/           figures you make: drawn in Typst (<name>.typ), photos
  tables/            tables you make (<name>.csv)
  assets/            what the analysis and octavo build write — never edited by hand
    values/          the numbers behind {{…}}
    figures/         figures (.pdf and .png)
    tables/          tables (.typ, .tex, .md)
  build/             the output, a folder per output (pdf/, slides/, script/, word/, tex/, handouts/); everything here can be deleted and rebuilt

octavo.config.py already finds every manuscript and analysis in these folders, so adding one never means editing it.

A project made with an earlier version keeps its manuscripts in papers/<name>/paper.md, slides/<name>.md and lectures/<name>.md, and builds as before. To move them into docs/, run octavo migrate --docs (--dry-run shows what it would do): it moves the manuscripts, fixes the figure paths, writes outputs / sessions at the top and adds docs/*/ to the config. The document names stay the same. octavo check also says when there is something to move.

Two more steps bring such a project fully up to date; both take --dry-run to show what they would change, and work on a committed project (--allow-dirty to go ahead anyway):

2.4 The analysis environment

Tools such as R and Quarto are installed once per machine. The packages an analysis uses belong to the project:

octavo env    # .venv (uv) with requirements.txt, renv with knitr, rmarkdown and what the .qmd files use

A project whose analyses are all in Python gets no renv. In VS Code you do not have to run it: adding the first analysis (or starting a project with one) sets the environment up right after, with the progress in a notification.

R packages the .qmd files use are installed for you — a .qmd brought in from elsewhere included. octavo env installs every package that a library(x) or x::f() in the project uses and is not installed yet; and when an R .qmd fails while running, Octavo installs what that .qmd uses and is missing, then runs it once more. Both record what they added in renv.lock. They install the latest version from CRAN; a package that is not on CRAN (GitHub, Bioconductor) is named, with the command to install it yourself.

Run it again after adding a package to requirements.txt; after install.packages() in R, run renv::snapshot(). Git keeps the records (requirements.txt, renv.lock), not the installed packages, so a coauthor gets the same environment from the same command.

2.5 Examples are marked as examples

What --example writes carries a mark — an octavo:example comment, _placeholder in the values, a figure that is a box with an × — and octavo check counts what is left. Replace the content and delete the mark with it. Placeholder values are fatal in octavo check: before the analysis has ever run, every {{…}} still resolves, and the PDF would carry fake numbers.


3. Writing manuscripts

What How you write it
Heading # Analysis {#sec-analysis} — # is the top section (starting at ## also works); no number; the label makes it referable
Abstract a # Abstract section
Citation @key, [@key; @key2], possessive \poscite{key} (“Smith and Taylor’s (2003)”)
A number from the analysis {{n_obs}}, {{coef_x:.2f}} (§4)
Figure ![Trend](../../assets/figures/trend.png){#fig-trend}
Table a Markdown table with : Caption {#tbl-desc} right below it, or the caption line alone for a table from the analysis or from tables/
Equation $$ … $$ {#eq-model}
Reference @fig-trend → “Figure 2.1”
Title, author, date the YAML front matter at the top

3.1 Referring by label, never by number

Numbers are never typed — not in headings, captions or prose. Label things and refer by name; the numbers are given when it is typeset, so adding or moving a section never means fixing references.

# Analysis {#sec-analysis}

@fig-trend shows the trend and @tbl-desc the descriptive statistics.
We estimate @eq-model (see also [-@eq-model]).

![Trend](../../assets/figures/trend.png){#fig-trend}

| Variable | Mean |
|----------|------|
| x        | 1.2  |

: Descriptive statistics {#tbl-desc}

$$
y_i = \beta_0 + \beta_1 x_i + \varepsilon_i
$$ {#eq-model}

3.2 Cases, questions and other numbered blocks

::: {.question #question-why title="Why is government the main actor?"}
Why is government at the centre of public policy?
:::

::: nb
Unnumbered blocks need no label.
:::

::: {.restate #question-why}
:::

::: {.list-of .question}
:::
'theorem_envs': {
    'case': 'Example case',
    'claim': {'name': {'ja': '主張', 'en': 'Claim'}, 'counter': 'case'},
    'hint': {'name': 'Hint', 'numbered': False},
},

3.3 Math

Write LaTeX notation between dollar signs; it becomes Typst math, Word equations, or stays LaTeX.

The estimate is $\hat\beta = {{coef_x:.3f}}$, with $y_i \sim \mathcal{N}(\mu, \sigma^2)$.

$$
\begin{aligned}
y_i &= \beta_0 + \beta_1 x_i + \varepsilon_i \\
\operatorname{Var}(\varepsilon_i) &= \sigma^2
\end{aligned}
$$

3.4 Figures

Write the .png in the manuscript, with the path relative to the manuscript (../../assets/figures/ from a paper, ../assets/figures/ from slides and lecture notes). For each output Octavo picks the right file:

Output File used Why
Typst (papers, handouts, slides) and LaTeX .pdf vector: sharp at any zoom, its text selectable
Word .png Word cannot embed a PDF figure
The editor’s preview .png

ov_figure() and figures drawn in Typst write both. figure_width sets the default width; {width=60%} after a figure sets one.

A source or note under a figure or table goes in ::: {.figure-note} right after it (after a table’s caption line). It is ordinary Markdown — links and footnotes work — set in small type with the figure, kept on the same page, and left out of the figure’s title. On a slide the figure shrinks to leave room for it. A footnote can go in the title too:

![Officials by level of government[^src]](../assets/figures/staff.png){#fig-staff}

::: {.figure-note}
Source: National Personnel Authority, *Annual Report 2025*.[^checked]
:::

[^src]: Full-time staff only.
[^checked]: Retrieved 1 October 2026.

Photos and other images you have (a photo you took, a screenshot) go in figures/, next to the Typst figure sources, and are placed straight from there; .jpg and .png work in every output. Octavo does not shrink them, so resize a large photo first (about 2,000 pixels on the long side is plenty) or the PDF gets heavy. Where an image came from and whether you may use it is worth a line in figures/README.md, as data/raw/README.md does for data.

![The council chamber](../figures/chamber.jpg){#fig-chamber width=70%}

Drawing a figure in Typst (instead of TikZ). octavo new figure dag writes figures/dag.typ with a small diagram() helper — boxes and arrows:

#diagram(
  (
    z: (2, 0, [Background $Z$]),
    x: (0, 1.6, [Education $X$]),
    y: (4, 1.6, [Income $Y$]),
  ),
  (("z", "x"), ("z", "y"), ("x", "y")),
)

octavo build draws it into assets/figures/dag.pdf and .png whenever the .typ changes, and the manuscript places it like any figure. Anything Typst can draw works; parts several figures share go in figures/_parts.typ; json("/assets/values/analysis.json") brings in the analysis’s numbers.

3.5 Tables

A short table can be a Markdown table in the manuscript. Two other kinds are placed with a caption line alone — : Caption {#tbl-name} with no table next to it:

3.6 What it makes, and settings for one document

What a document makes is outputs: at the top of the manuscript. Without it, pdf.

---
title: Title of the Paper
outputs: [pdf, word]
---
Output What it makes
pdf a PDF. Its layout is the main.typ beside the manuscript if there is one (a paper), otherwise Octavo’s built-in one (A4, with a cover and contents)
word Word
tex LaTeX (needs TeX; uses the main.tex beside the manuscript if there is one)
slides slides
script the speaker script (each page of the deck with its ::: notes)
poster a poster (7.3)
beamer LaTeX slides (needs TeX)

A manuscript made of several class sessions says sessions: true. One # heading (or one \session{…} marker) is one session, and the slides and the script come out as one file per session (7.2). A manuscript with markers is made of sessions without saying so.

The title goes in the front matter (title:). Don’t write a # Title heading — a # heading is a section.

Other settings that change per journal or talk can also go at the top of the manuscript, and then apply to it alone:

---
title: Title of the Paper
csl: apa
word_limit: 8000
---
Key For What
outputs, sessions all what it makes, made of sessions (above)
csl all citation style
japanese_citation_form, citations_by_language all Japanese works in the bibliography (§5)
word_limit, char_limit, abstract_word_limit, abstract_char_limit all submission limits (octavo check)
slides_* slides the look of the decks (§7)
slides_select, poster_select slides, posters marked: only what is marked (.on-slides, .on-poster) goes on them (§7)
date_format all how the date is shown
toc PDF in the built-in layout table of contents (on by default when sessions is)
first_section, pagebreak, font, fontsize PDF in the built-in layout first section number, page breaks, typeface (§7)

octavo config --doc <name> lists them and set / unset changes one line; in VS Code, Settings for this document under each manuscript in the sidebar.

3.7 Page breaks and slide breaks

Each goes on a line of its own:

\newpage

\newslide

\newslide{Another title}

4. The analysis

The manuscript never contains a result. Numbers, figures and tables are made by the analysis (.qmd) and pulled in on every build, so re-running an estimation can never leave the text describing the old one.

analysis/*.qmd  --quarto-->  assets/values/*.json      {{…}} in the text
                             assets/figures/*.pdf|png  figures
                             assets/tables/*           tables

4.1 Handing over numbers, figures and tables

A new .qmd already loads its helper: octavo.R for R, octavo_helper.py for Python (see below). Register what the paper shows:

What In the analysis In the manuscript
A number ov_value("n_obs", nrow(d)) {{n_obs}}
A figure ov_figure(p, "trend") ![Trend](../../assets/figures/trend.png){#fig-trend}
A table ov_table(tab, "summary") : Descriptive statistics {#tbl-summary}

The header of a new .qmd is ready to hand out as one HTML file: the author from meta in octavo.config.py (with affiliation and email if you write them), the date, a contents list and numbered sections.

4.2 How numbers look

Value Example Shown as
Whole number nrow(d) 1,523
Decimal coef(m)[["x"]] 0.342 (3 places by default)
Text ov_pval(p) as it is

{{coef_x:.2f}} in the manuscript, or ov_value(..., fmt = ".2f"), chooses the format. A name with no value stays as {{name}} in the output and is reported.

4.3 When the analysis runs

octavo build runs a .qmd when it, or a file it depends on, changed since the last run. What counts is the contents: switching git branches and back, or a fresh clone, does not make a .qmd out of date.

octavo analysis              # which are out of date
octavo analysis run          # run the out-of-date ones
octavo build --no-analysis   # build without running anything
octavo check values --diff   # which numbers in the text changed at the last run
octavo analysis mark-fresh analysis/00-fetch.qmd   # record it as up to date without running it
'analysis': [
    {'src': 'analysis/01-clean.qmd', 'manual': True},       # slow: only octavo analysis run runs it
    {'src': 'analysis/02-model.qmd', 'deps': ['data/derived/*']},
],
---
title: "Fetch the raw data"
octavo:
  manual: true
---

```{r}
out <- "../data/raw/survey.csv"
if (file.exists(out)) knitr::knit_exit("Already fetched. Move the file away to fetch again.")
```

```{r}
download.file("https://example.org/survey.csv", out)
```

4.4 Python

Add --engine python (or pick Analysis in Python in VS Code) and the .qmd is written in Python. It loads analysis/octavo_helper.py, which has the same functions under the same names and writes the same files, so the manuscript is written exactly as for R:

ov_value("n_obs", len(d))              # {{n_obs}}
ov_value("coef_x", model.params["x"])
ov_figure(fig, "trend")                # a matplotlib Figure (or a plotnine ggplot, or a function that draws)
ov_table(tab, "summary")               # a pandas DataFrame (or a dict, or a list of lists)

4.5 Using Octavo with .qmd files alone

A project need not have a manuscript. A report or an assignment written entirely in Quarto can live in analysis/ like any analysis, helpers or not, and Octavo looks after the environment (octavo env) and running it (octavo analysis run, or ▶ in VS Code). Its output — HTML, PDF or Word — lands beside the .qmd, as Quarto always writes it; to look at a PDF, use the Quarto extension’s Preview. With no manuscript, octavo check and octavo build do not count that as a problem as long as there is a .qmd.

A Japanese PDF from Quarto (format: typst) is set in whatever Japanese typeface the machine happens to have. To use the manuscripts’ typefaces, name them in the .qmd’s header:

format:
  typst:
    papersize: a4
    include-in-header:
      text: |
        #set text(font: ((name: "Libertinus Serif", covers: "latin-in-cjk"), "BIZ UDMincho", "Noto Serif CJK JP"))

4.6 Other languages

Octavo only reads files, so a Julia or other .qmd works if it writes {"name": value} into assets/values/<anything>.json, figures as .pdf and .png into assets/figures/, and tables into assets/tables/.


5. Citations

Export your library from your reference manager (Zotero or any other) as BibTeX or BibLaTeX to literature.bib. With Zotero, Better BibTeX’s “Keep updated” export keeps it current and the keys stable. Octavo never edits the .bib.

octavo check cites        # keys cited but missing from the .bib, and problems in the .bib
octavo csl get apa        # fetch a journal's style

The style is one line in octavo.config.py ('csl': 'apa'), for every format at once. Style IDs are listed at https://www.zotero.org/styles.

Japanese and English works together. In a Japanese document, English works and the citations follow your style; works marked langid = {japanese} in the .bib take one Japanese form whatever the style:

Smith et al. (2003), (山田・田中 2020), 佐藤ほか (2018)

Smith, John, Ann Taylor, Bob Brown, and Carl Green. 2003. "An Example Article." Journal of Examples 4: 1–10.
山田太郎・田中花子 (2020)「日本語論文の例」『見本学会誌』12(3): 1–20.

japanese_citation_form chooses the form of Japanese works (in the project or at the top of a manuscript; in VS Code under the document’s settings):

Value Japanese works look like
'standard' (default) 山田太郎・田中花子 (2020)「題」『誌名』12(3): 1–20.
'fullwidth' 山田太郎・田中花子(2020)「題」『誌名』12巻3号、1–20頁。
'period' 山田太郎・田中花子.2020.「題」『誌名』12巻3号、1–20頁。

'fullwidth' follows what articles in 年報行政研究 commonly print, and 'period' what author–date articles in 年報政治学 print; neither journal’s rules prescribe a form, so follow a journal’s own instructions where it has them. citations_by_language: False sets the whole bibliography in csl_locale instead.

The bibliography goes at the end. A # References heading as a paper’s last section only marks its place (whatever is under it is replaced); a heading of that name with a reading list under it inside lecture notes is kept as written. To put the bibliography somewhere else, write ::: {#refs} and ::: there.

\poscite{key} writes a possessive citation (“Smith and Taylor’s (2003)”, 「山田・田中(2020)」); the joining of several authors is an approximation of the style’s rules, so read it once.


6. Papers: from draft to submission

A paper is docs/<name>/<name>.md plus main.typ, the journal layout you keep by hand (title block, fonts, margins). octavo build writes the body into build/pdf/<name>/ and main.typ typesets it; --compile makes the PDF (build/pdf/<name>/main.pdf, with a copy at build/pdf/<name>.pdf).

octavo build example-paper --compile            # PDF
octavo build example-paper --to word            # Word
octavo build example-paper --compile --appendix # with appendix.md

For an appendix, octavo new paper <name> --appendix, then uncomment #show: octavo-appendix and #include "appendix.typ" in main.typ. Its sections are A, B, … and labels work across both files.

6.1 Before you submit

octavo check           # everything in one pass; fatal problems give a non-zero exit
octavo check lint      # results typed into the text, and nested lists out of line

octavo check looks at: missing figures and tables, unresolved {{…}}, placeholder values, out-of-date analysis, citation keys and the .bib, labels, template leftovers, ::: blocks that will not be read as written, submission limits, and the data fingerprints. A number that is not a result (a grading split, a year) is kept out of the hand-typed check by [40%]{.no-lint} in the text, ::: {.no-lint} … ::: around a passage, or the text around it in lint_accepted ('midterm 40%'). Limits are set in the config or the manuscript (word_limit: 8000, char_limit for Japanese journals).

6.2 Blind review

::: {.no-anonymous}
Acknowledgements: this research was funded by ...
:::
octavo build example-paper --anonymous
octavo bundle example-paper --anonymous   # checks the package for your name

--anonymous drops .no-anonymous blocks (and keeps .anonymous-only ones), removes the author from the title block, and switches main.typ’s title block. The next ordinary build switches everything back.

6.3 Packaging for the journal

octavo bundle example-paper    # submission-example-paper.zip: the files, flattened into one folder

6.4 After you send it


7. Slides, lecture notes and posters

7.1 Slides

A document that makes only slides (outputs: [slides]): with # and ## headings, # is a section and ## a slide; with one level, each heading is a slide. The title slide comes from the front matter. Figures fit the remaining space on the slide.

octavo build example-talk --compile
Key Default What
slides_aspect '16-9' or '4-3'
slides_accent '#0e2f92' the accent colour; None for plain black
slides_numbering None heading numbers ('1.', '1.1')
slides_section_slides False a divider slide for each # section
slides_running_header True the current section in the top-left corner
slides_font BIZ UDGothic + Inter the font

The older names (typst_slides_aspect and so on) are still read.

Where slides break, and their titles, can be set in the manuscript; the handout and other outputs are not affected:

## A long heading for the handout {slide-title="Short title"}

\newslide

### A heading that stays on the same slide {.same-slide}

\newslide{Another title}

::: notes holds speaker notes: they never appear on the projected deck, and --to script makes a speaker script: each page of the typeset deck, shrunk, with the notes written on it underneath (A4, two slides a page). It typesets the deck first, so the pictures are exactly what is projected. Slide decks show no bibliography unless you set slides_bibliography: True and end the manuscript with a heading and ::: {#refs} + :::.

7.2 Lecture notes

How to make them in VS Code, and every mark you can write, is on one page: Making lecture notes. This section is the summary.

One file gives an A4 handout of all sessions and a slide deck per session:

octavo build example-lecture --to pdf --compile      # the handout
octavo build example-lecture --to slides --compile   # one deck per session
octavo build example-lecture-03 --to slides          # just one session

Without markers, each # heading is a session; inside it, ## is a section and ### a slide (a session with only ## headings makes each ## a slide). Give a heading an id to fix its deck’s name (# Second session {#second} → octavo build example-lecture-second, example-lecture-slides-second.pdf); otherwise decks are numbered -01, -02, … in order.

Marking sessions yourself. When a session is not one # heading, put a marker where each session begins; then the markers decide the sessions and headings are free:

\session{Session 3: policy and government} {#third subtitle="Public policy" date="2026-10-14"}

The braces of \session{…} hold the session’s title, and {…} can carry #id (the session’s name), subtitle, date, author and institute (all optional; \session{} for no title). Title, subtitle and date go on that session’s title slide (without a title, its first heading is used). The older ::: {.session #third title="…"} + ::: means the same. The numbers of figures, tables, equations and blocks in a deck are the handout’s (even when some figures are in the handout only or were not picked for the slides). Which level is a slide is decided from the whole of the notes (normally ###), so adding markers does not change it.

What goes where. Conditional blocks choose the output:

::: {.no-slides}
Fill-in-the-blank space and detailed footnotes: handout only.
:::

::: {.slides-only}
Figures and short prompts: slides only.
:::
Marker Kept in
.no-slides everything but slides and speaker scripts — the usual mark for “handout only”
.slides-only slides, speaker scripts
.pdf-only the PDF only (handout, paper; not Word or LaTeX)
.word-only Word
.print-only anything printed (PDF, Word, LaTeX)

The older .handout-only still works; in lecture notes it means the same as .no-slides.

Only part of the notes on the slides. With slides_select: marked at the top, the slides get only what is marked .on-slides (a ::: {.on-slides} block, a section whose heading has {.on-slides}, […]{.on-slides} in a line) and the headings above it; the rest goes into the handout only. A reference to something not picked is written as its number in the handout, and a session with nothing marked gets no deck.

One PDF per session. To hand out one session at a time:

octavo build example-lecture --sessions             # build/handouts/example-lecture-<id>.pdf, one per session
octavo extract example-lecture --session third      # one session (several, comma-separated, make one PDF)
octavo extract example-lecture --pages 12-19        # by printed page numbers
octavo extract example-lecture --session third --cover   # with the cover and contents in front

The whole handout is typeset once and each session’s pages are cut from it, so page numbers, contents and all numbers stay those of the whole. Sessions always begin on a new page. In a terminal, octavo build <name> --sessions makes them along with the build (without it they are not remade). In VS Code, Make the session handouts under the lecture notes in the sidebar makes them, and notes with session markers have them remade in the background on every save (turn that off with the setting octavo.updateHandoutsOnSave).

The handout’s layout. A cover page of its own, the contents on pages i, ii, …, the body from page 1, and type after the Japanese LaTeX class jsarticle (11pt, a generous line pitch, paragraphs indented by one character). The body is set in BIZ UDGothic. In the project or at the top of the notes:

Key Default What
first_section 1 0 numbers a guidance session “0” (figures “0.1”)
pagebreak 'session' a new page at each session; 'section': at each #; None: only at markers
font BIZ UDGothic + Inter the body font
fontsize '11pt' the type size
toc true the table of contents (false for a document without sessions)
date_format '%B %-d, %Y' (Japanese: '%Y年%-m月%-d日') how date: is shown; date: today is the day it was built

7.3 Posters

For a poster session. A manuscript with outputs: [poster] at the top (octavo new poster <name> writes one) becomes one PDF, build/poster/<name>.pdf. By default it is A0 portrait, and each top-level heading (#) is one cell, filling a 2×3 grid from the top left.

---
title: Counting how policy is made
author: [Author One, Author Two]
institute: Example University
event: Example Conference 2026
date: 2026-10-14
logo: ../../figures/logo.png
qr: https://example.org/paper
qr_label: The paper
outputs: [poster]
poster_grid: 3x2
poster_rows: [2, 1]
---

# Question

# Results {span=2}

# Notes {cell="3,2"}
Write Means
{span=2} / {rows=2} after a heading a cell two columns wide / two rows high
{cell="3,2"} put it in column 3, row 2 (counting from 1; the others fill the free cells in order)
poster_size a0 (default), a1, a2, b0, b1 (the Japanese B series), or a size like 1189x841mm
poster_orientation portrait (default) or landscape
poster_grid / poster_rows the grid (columns x rows, 2x3 by default) and the rows’ height ratios (equal by default)
logo / qr / qr_label logos on the left of the title band (any number), a QR code on the right (made from the URL) and the text under it

To make a poster from a paper’s manuscript, write outputs: [pdf, poster] and poster_select: marked, and mark what goes on the poster with .on-poster (written like .on-slides for slides).

Type size and margins scale with the paper. Figures fit the room left in their cell. The works you cite go in the last cell (# References). Content that does not fit in its cell is reported as an overflow when you build (and marked in red at the cell’s corner in the PDF): cut it or make the cell bigger. The colour is slides_accent and the typeface poster_font; octavo template copy poster/typst-poster.typ changes the look.


8. Making it yours

8.1 Templates

Everything Octavo typesets from — the handout and slide layouts, a paper’s main.typ, the manuscripts octavo new writes, the project octavo init writes — is a file you can replace. Copy it and edit the copy; Octavo uses yours from then on:

octavo template list                              # which templates are in use, and from where
octavo template copy slides/typst-slides.typ      # into this project's templates/
octavo template copy paper/en/main.typ --user     # into ~/.config/octavo/templates/, for every project
octavo template diff slides/typst-slides.typ      # after updating Octavo: what changed in the original
Template Replace it to
slides/typst-slides.typ, slides/typst-notes.typ change the look of decks and scripts
poster/typst-poster.typ changes the look of posters
handout/handout.typ change the lecture handout
paper/<lang>/main.typ start every paper from your usual layout
manuscripts/<lang>/*.md start manuscripts from your own skeleton
typst/crossref.typ change how numbers and references look
citations/japanese.lua change the form of Japanese works in the bibliography

8.2 Word styles

octavo template copy word          # templates/word/reference.docx (--user: for all your projects)

Open it in Word, change the styles (Heading 1, Body Text, Theorem, …) and save it: Word output uses it from then on. A .docx named in docx_reference in the config comes first (the older octavo reference-docx still works).

8.3 Fonts

Japanese Latin
Papers BIZ UDMincho Libertinus Serif
Lecture handouts, slides BIZ UDGothic Inter

octavo setup installs them. Without them Typst falls back to Noto CJK, or to the fonts the system has (Hiragino on a Mac, Yu Gothic on Windows); octavo doctor says what is missing. Change them with font, slides_font, or in a paper’s main.typ.


9. Command reference

octavo build [documents...] [--to outputs] [--compile] [--appendix] [--sessions] [--no-analysis] [--anonymous]
octavo watch [documents...] [--to outputs]                           rebuild on every save
octavo extract <lecture> [--session IDS] [--pages 12-19] [--cover]   some sessions, or pages, as one PDF
octavo documents                                                     the registered manuscripts
octavo config [--doc NAME] [set KEY VALUE | unset KEY]               show or change settings
octavo analysis [run [QMD]]                                          is the analysis up to date / run it
octavo check [--strict] [--anonymous]                                everything before you submit
octavo check values [--unused] [--diff [ref]]                        cross-check {{...}} against the analysis
octavo check cites [--list] [--unused]                               citation keys against the .bib
octavo check lint                                                    results typed into the text, nested lists out of line
octavo bundle [name] [--anonymous] [--replication] [--with-raw-data]
octavo review returned.docx                                          a coauthor's tracked changes
octavo release <document> <label>                                    tag, and the PDF to a GitHub Release
octavo data hash|status                                              fingerprints of data/
octavo csl get|list|which [ID]                                       citation styles
octavo init <dir> [--lang ja|en] [--with PARTS | --all] [--engine r|python] [--example] [--env]
octavo new paper|slides|lecture|poster|analysis|figure|table <name> [--example] [--engine r|python] [--env]
octavo template list|copy|diff [name] [--user]                       templates (copy word: a Word style file to edit)
octavo env                                                           the project's R and Python packages (.venv, renv)
octavo setup [--with-tex] [--check] [--r-editor]                     install or update the tools
octavo doctor                                                        what is installed
octavo selftest                                                      a sample typeset end to end
octavo outline [documents...]                                        the heading structure
octavo targets                                                       the outputs
octavo migrate [--docs|--syntax|--rules] [--dry-run]                 bring an older project up to date (manuscripts into docs/, notation, AGENTS.md)

Outputs (in outputs: at the top of a manuscript and after --to, comma-separated; --to all for every one):

Output Makes Needs
pdf a PDF (the paper layout with main.typ, otherwise the built-in one) Typst
slides slide decks Typst
script speaker scripts Typst
poster posters Typst
word Word pandoc only
tex LaTeX (the paper layout with main.tex) TeX
beamer slide decks TeX

The older format names (typst, typst-slides, typst-notes, docx, latex) are read the same way.


10. VS Code

The Octavo extension puts all of this behind buttons:

It runs octavo wherever the folder is: locally, in WSL, or on a server over Remote-SSH.


11. What to check on your own machine

The test suite typesets every format with pandoc and Typst on Linux, macOS and Windows, and runs the example analysis through Quarto, in R and in Python. What it cannot see:

If something looks wrong, please open an issue with the output of octavo doctor.