Get Started

Installation

quarto add jeroenjanssens/quarto-term

On first render, the correct binary for your platform is automatically downloaded from GitHub Releases and cached locally. Supported platforms: macOS (ARM and Intel), Linux (x86_64 and ARM), and Windows.

To build from source instead (requires Rust):

cargo build --release

Your first document

Create a file called hello.qmd:

---
title: "Hello Terminal"
format: html
engine: markdown
extensions:
  term:
    shell: zsh
---

```{term}
echo 'Hello, world!'
```

```{term}
for i in 1 2 3; do
  echo "Item $i"
done
```

```{term}
sleep 100 #! expect-prompt: false
ctrl-c #! literal: false, delay: 0.5
```

Render it:

quarto render hello.qmd

Here’s how the rendered output looks:

echo 'Hello, world!'
Hello, world!
for i in 1 2 3; do
  echo "Item $i"
done
Item 1
Item 2
Item 3
sleep 100
^C

The engine: markdown line tells Quarto to skip its built-in execution engines. The extensions: term: key holds all configuration.

How it works

  1. The Lua filter collects all ```{term} cells from your document.
  2. It sends them to the quarto-term binary, which spawns a persistent shell.
  3. Each line is typed into the shell (simulating a real user), and output is captured via a terminal emulator.
  4. The rendered output (with ANSI colors, prompts, etc.) replaces the original code cells in the document.

Because the shell session persists, variables, the working directory, and all other state carry over between cells.

What it captures

Multi-line constructs like loops work automatically — the shell’s PS2 continuation prompt (>) is detected and lines are grouped together:

for planet in Mercury Venus Earth Mars; do
  echo "- $planet"
done
- Mercury
- Venus
- Earth
- Mars

ANSI colors render faithfully, so colored output from compilers, linters, and CLI tools looks just like it does in your terminal:

printf '\033[1;31mError:\033[0m file not found\n'
Error: file not found

printf '\033[1;33mWarning:\033[0m deprecated API\n'
Warning: deprecated API

printf '\033[1;32mSuccess:\033[0m all tests passed\n'
Success: all tests passed

Multi-line pipes work naturally:

seq 1 5 |
paste -sd+ |
bc
15

Configuration

All configuration goes under extensions: term: in your YAML front matter:

extensions:
  term:
    shell: zsh
    spacing: true
    timeout: 15.0
    style:
      colorscheme: solarized-dark

See the Reference for the full list of options, Styling for colorschemes and fonts, and Recipes for common patterns.

Using in a website or book

For standalone .qmd files, the filter is discovered automatically. In a Quarto project (website or book), you need to explicitly declare the filter in your _quarto.yml:

project:
  type: website

filters:
  - term

extensions:
  term:
    shell: zsh
    style:
      colorscheme: solarized-dark

Individual pages still need engine: markdown in their front matter (or use the knitr/Jupyter setup described below).

Using in a presentation

quarto-term works in RevealJS presentations. Terminal cells render on each slide with full ANSI color support and persistent state across slides.

---
title: "My Presentation"
format: revealjs
engine: markdown
extensions:
  term:
    shell: zsh
    style:
      colorscheme: catppuccin-mocha
      cols: 64
---

Use smaller cols (e.g., 64) and optionally a smaller font-size to fit terminal output on slides. Here’s a live demo:

Using with other output formats

quarto-term supports all major Quarto output formats. Use format-specific style overrides to tailor the terminal appearance:

extensions:
  term:
    style:
      colorscheme: dracula
      typst:
        font-family: "Fira Code"
        font-size: 9pt
      docx:
        font-family: "Consolas"
        font-size: 10pt

For PDF via Typst, use format: typst in your document — terminal output renders as styled monospace blocks with full ANSI color support.

For Word (format: docx), terminal output renders as a monospace table with background color, font styling, and ANSI colors.

For EPUB, the HTML renderer is used automatically — all styling works as in HTML.

See the Reference for the complete format support matrix and Styling for override examples.

Using with knitr or Jupyter

For documents that only contain terminal cells, engine: markdown is recommended. If you need to mix {term} cells with {r} or {python} cells:

Jupyter works without changes. {term} blocks pass through to the Lua filter.

knitr requires registering a pass-through engine in a setup chunk:

```{r}
#| include: false
knitr::knit_engines$set(term = function(options) {
  knitr:::one_string(c("```{term}", options$code, "```"))
})
```

Note that {term} cells are always executed after all knitr/Jupyter cells have finished. The terminal session runs during the Pandoc filter phase, not during engine execution.