flowchart LR
A["Plain-text Markdown<br/>hello.qmd"] --> B["Quarto"]
B --> C["HTML page"]
B --> D["PDF document"]
B --> E["Word document"]
B --> F["Reveal.js slides"]
A three-hour workshop for academic teaching and publishing
Use plain-text Quarto sources to create and review two teaching outputs during the three-hour workshop. The later projects apply the same workflow to research.
| During the workshop | After the workshop, if useful |
|---|---|
hello.qmd → reviewed hello.html |
Three-page municipal IRCA essay as PDF |
| Deliberate error → diagnosis → repaired render | Runnable IRCA analysis notebook |
talk.qmd → reviewed Reveal.js talk.html |
Six-slide water-quality introduction and separate blog |
[ Your Scientific Question & Data ]
│
▼
[ AI Coding Agent Session ] ◀── "Draft sections and check the source"
│ generates & edits
▼
[ Plain-Text Markdown (.qmd) ]
│
▼
[ Quarto CLI Render ]
┌──────┴──────┐
▼ ▼
hello.html talk.html
(web page) (Reveal.js slides)The same source pattern can later produce PDFs, Word documents, notebooks, slide decks, websites, and blogs. Check each output before sharing it.
| Time | Section | Focus & Observable Deliverables |
|---|---|---|
| 00:00–01:00 | Hour 1 · Anatomy & the Agent | Prompt agent; render and revise hello.html |
| 01:00–01:10 | Break | |
| 01:10–02:00 | Hour 2 · Execution & Formatting | Read Python cells; diagnose and repair a failed render |
| 02:00–02:10 | Break | |
| 02:10–03:00 | Hour 3 · Outputs & Publishing | Review talk.html; optionally publish to Quarto Pub |
Working rhythm: ask the agent → inspect its edits → render → inspect the output → revise. Follow-on projects later in the deck extend this core path.
Most slides repeat one three-part pattern:
Ask your coding agent
Paste the plain-English request into your agent session.
Commands
See what performs the work, or run the step yourself.
Check
Inspect an observable result before continuing.
The agent can edit files and run local tools, subject to its permissions. You do not need to repeat a command it has already completed.
The terminal examples use macOS, Linux, or WSL on Windows. The same prompts work with Claude Code, Codex, or Antigravity CLI.
On macOS, Linux, or WSL, run once in your terminal:
Open a new terminal, then check and start it:
Complete sign-in with an account that has Claude Code access. Choose one coding agent for the exercises.
Official setup and other platforms. Verified 2026-10-06.
With Node.js and npm available, run once in your terminal:
Complete the sign-in flow with an account authorized to use Codex. Start it inside your exercise folder, or select that folder in a graphical client.
Official CLI guide and npm installation example. Verified 2026-10-06.
For an individual Google account, install Antigravity CLI on macOS or Linux:
Open a new terminal, then check and start it:
Complete the interactive setup and sign in with an eligible Google account. Choose one coding agent for the exercises.
Official installation guide. Verified 2026-10-28.
Terminal, once: from the workshop clone, prepare a practice folder and copy the reported IRCA data used in the computation exercise.
mkdir -p ~/code/quarto-play
mkdir -p ~/code/quarto-play/context
cp examples/irca-colombia/irca_boyaca_cundinamarca_santander.csv \
~/code/quarto-play/context/
cd ~/code/quarto-play
# Start one coding agent:
claude
# Or: codex
# Or: agyAsk your coding agent:
I am learning Quarto. Use this folder for the exercises. Check the tools available, initialize Git if needed, and work on a workshop branch. Tell me which folder you are using and what is missing.
Check: the session names quarto-play as its working folder.
Ask your coding agent in quarto-play:
Check whether GitHub CLI (
gh) is available here. If it is missing, help me install it for this terminal. Guide me through signing in to my GitHub account in the browser, then verify the active account. Do not create a repository yet.
Commands to recognize:
Check: gh auth status names the GitHub account you intend to use.
GitHub CLI login and status, checked 2026-10-28.
Ask your coding agent:
Create hello.qmd, a short HTML page for a student new to Quarto. Set
format: htmlin its YAML frontmatter. Include a title, a brief explanation, and two things I can publish. Show Markdown for a heading, bold phrase, and list beside its rendered result. Add a self-contained Mermaid diagram of a .qmd file becoming HTML. Render, fix errors, and tell me which file to open.
Command behind the render:
Check: compare hello.qmd with hello.html. The Markdown example matches its rendered result, and the diagram is visible.
| Your request | Work to inspect |
|---|---|
| “Create hello.qmd” | A new editable source file |
| “A short HTML page” | YAML selecting HTML and concise Markdown |
| “Show a Markdown example” | Source syntax and its rendered result |
| “Add a simple graphic” | A visible graphic defined in the source |
| “Render it” | A Quarto command and its output |
| “Fix any build errors” | Further edits and a successful rerun |
The coding agent can carry out this sequence from a plain-English request. The generated source remains yours to read, edit, and version.
Continue in the same coding agent conversation:
Change the title to “What Do Municipal IRCA Values Show?”. Add a question about reported water-quality risk in Boyacá and nearby departments. Add sections for code, interpretation, and sources. Render again.
Check: both titles change. This HTML practice page can later support the optional notebook project.
Request one different revision in your own words. Point to the changed source and show its effect in the browser.
In hello.qmd, explain Quarto to first-year data science students. Use a municipal water-quality notebook example in under 100 words. Preserve my title. Render the page and check that the example appears.
| Include what matters | In this request |
|---|---|
| Context | hello.qmd, first-year data science students |
| Desired result | A short introduction with a municipal IRCA example |
| Constraint | Preserve the title |
| Completion check | Render and find the example |
Quarto combines prose, code, and results into a publication. The coding agent can write the source and run Quarto for you.
| Source | Role |
|---|---|
| Markdown | Headings, paragraphs, links, lists |
| YAML | Title, output format, document options |
| Executable cells | Computation and generated figures |
| CSS | Appearance of HTML pages and slides |
Browse the Quarto gallery. Describe one feature you would ask your coding agent to add to your project.
hello.qmd
│ executable chunks, if present
▼
Jupyter (often Python) or Knitr (often R)
│ code and results become Markdown
▼
intermediate .md
│ document conversion
▼
Pandoc
├── HTML page or Reveal.js slides
└── PDF (with a PDF engine)When a render fails: locate the source/YAML, code-execution, or output conversion stage before asking the agent for a fix.
flowchart LR
A["Plain-text Markdown<br/>hello.qmd"] --> B["Quarto"]
B --> C["HTML page"]
B --> D["PDF document"]
B --> E["Word document"]
B --> F["Reveal.js slides"]
The .qmd file stays editable. Quarto renders the requested format; some formats need additional tools or document settings.
Ask your coding agent:
Add a “Reading list” to hello.qmd with a link to the official Colombian water-quality dataset and one bold phrase stating the unit of analysis. Verify the link, render, and explain the Markdown.
Source pattern:
## Reading list
Each row is a **municipality-year summary**, not an individual water sample.
[INS/SIVICAP water-quality dataset](https://www.datos.gov.co/Salud-y-Protecci-n-Social/Calidad-del-Agua-para-Consumo-Humano-en-Colombia/nxt2-39c3)Check: a heading, bold text, and a working link appear on the page.
Ask your coding agent:
Add a table of contents to hello.qmd. Keep the existing title and sections. Render it and explain the YAML change.
Source pattern at the top of the file:
Check: the contents links lead to your section headings.
Name the part to change, the action, and the visible check.
| Precise term | What it identifies |
|---|---|
| YAML frontmatter | Metadata between the opening --- lines |
| format option | html, pdf, or revealjs output |
| Markdown heading | A section or slide title in the body |
| code chunk | Executable code in a {python} or {r} fence |
| chunk execution options | #| controls such as echo and fig-cap |
Try: “Change the YAML format to html; add a caption to the plot chunk; render and check that the caption appears.”
Ask your coding agent:
Add two tabs to hello.qmd: “Question” and “Evidence”. Put a short municipal IRCA note in each. Use Quarto’s tabset syntax and render.
Source pattern:
::: {.panel-tabset}
## Question
How do reported IRCA values vary across municipalities?
## Evidence
The official table reports annual municipal IRCA values, with gaps in rural data.
:::Check: clicking each tab reveals the corresponding text.
Ask your coding agent:
Add one displayed Python example and one executable Python cell to hello.qmd. Have each say hello. Explain how their fences differ. Render the page with execution enabled.
Check: only the executable cell produces a separate output line.
If the executable example needs dependencies, ask your coding agent:
Inspect the available Python environments. Reuse a suitable local environment or prepare one for this project. Render hello.qmd with execution enabled. Fix failures and record the interpreter, dependencies, and working command in README.md.
Commands you should recognize:
Check: the output exists and the recorded build command works.
This cell counts 2024 municipality records in the three selected departments from the bundled official-data extract when the deck renders:
import csv
from collections import Counter
with open("examples/irca-colombia/irca_boyaca_cundinamarca_santander.csv", newline="") as source:
group_counts = Counter(
row["departamento"] for row in csv.DictReader(source)
if row["a_o"] == "2024" and row["municipiocodigo"] != "#TODOS"
)
total = sum(group_counts.values())
largest_share = 100 * max(group_counts.values()) / total
print(f"Municipality records in 2024: {total}")
print(f"Largest group share: {largest_share:.1f}%")Municipality records in 2024: 318
Largest group share: 37.4%
Check: the total is 318. Boyacá has the most records (119).
The max function selects the largest department group. What happens if we ask for the smallest group instead?
Add this computation to hello.qmd, adjusting the CSV path to
context/irca_boyaca_cundinamarca_santander.csv. Changemaxtomin, render, and explain what changes.
Check: the total stays 318 while the reported department share changes.
Ask your coding agent:
Hide the group-count calculation’s code in the page, but keep its output visible and recompute it on render. Explain the option used.
Source pattern inside the executable cell:
#| echo: false
import csv
from collections import Counter
with open("context/irca_boyaca_cundinamarca_santander.csv", newline="") as source:
group_counts = Counter(
row["departamento"] for row in csv.DictReader(source)
if row["a_o"] == "2024" and row["municipiocodigo"] != "#TODOS"
)
print(f"Municipality records: {sum(group_counts.values())}")echo: false hides source. eval: false would stop the calculation.
Check: the result remains visible and agrees with the practice inputs.
Copy this deliberately broken chunk into your practice hello.qmd. Ask the agent to render without fixing the chunk first:
Then ask: “Quote the first useful error in the Quarto CLI output. Point to the failing chunk, explain the cause, and propose the smallest fix. Do not change unrelated text.” Apply the fix, render again, and inspect the output.
| CLI evidence | Request to the agent |
|---|---|
| YAML parse error before execution | “Show the frontmatter line and valid indentation.” |
Python NameError in a chunk |
“Trace this name to its definition.” |
| Pandoc or PDF engine error | “Identify the output stage and missing tool.” |
Require the agent to quote the relevant error and show the smallest source change. A successful rerender tests the explanation.
Ask the agent to copy the repaired hello.qmd to talk.qmd and change its YAML format from html to revealjs:
Use ## headings for individual slides. Ask the agent to split long sections and keep each result with its meaning. Then render:
Check: open talk.html and advance through every slide.
Ask your coding agent:
Render
talk.qmd, inspect every slide at desktop and laptop presentation sizes, and report text overflow or missing results. Fix the source and rerender. Tell me which slides changed.
Check yourself: Can someone read every slide? Do links work? Is a computed result still explained? Is any private note or local path visible by mistake?
In your practice folder, after checking the destination and output:
Follow Quarto’s interactive account and destination prompts. Open the returned URL and confirm the public deck matches your reviewed local talk.html.
Agent request: “Prepare the publish command and tell me what it will make public. Wait for my approval before running it.”
Show a partner hello.qmd, the rendered HTML, the repaired error, and talk.html. If you published, show the Quarto Pub URL too. Explain:
html became revealjs.Done: your partner can reproduce the render and follow your diagnosis.
The same agent workflow can produce a six-slide introduction, a three-page essay, a runnable notebook, and a separate blog from the reported INS/SIVICAP municipal IRCA table. Inspect each output before sharing it.
These projects extend the workshop; they are not required in three hours.
From the workshop clone, copy the teaching bundle into your practice folder:
| Input | Purpose |
|---|---|
irca_boyaca_cundinamarca_santander.csv |
Unchanged extract of reported annual IRCA, 2007–2024 |
notes.md |
Question, definitions, limits, and task checks |
sources.bib |
INS and DANE source records |
notebook.qmd |
Worked descriptive notebook source |
Check: return to your quarto-play agent session. Preserve the CSV.
Ask your coding agent in quarto-play:
Create intro.qmd for first-year data science students. Generate exactly six Reveal.js slides: title, the municipal IRCA question, what one row represents, the three departments in 2024, variation and limits, and sources. Use context/notes.md and context/sources.bib. Keep the dark theme, add speaker notes, and render intro.html.
Outputs: intro.qmd and intro.html, six slides including title and sources.
Check: distinguish municipal annual summaries from water samples. Inspect every slide at desktop and laptop sizes, including links and captions.
Ask your coding agent in quarto-play:
Write essay.qmd for data science students about reported 2024 municipal IRCA in Boyacá, Cundinamarca, and Santander. Use context/irca_boyaca_cundinamarca_santander.csv for every number and context/sources.bib for provenance. Exclude
#TODOSdepartment aggregates from municipality comparisons. Explain counts, medians, variation, and missing rural IRCA. Follow the next slide’s page plan. Render exactly three pages to essay.pdf and inspect them.
Outputs: editable essay.qmd and a three-page essay.pdf.
| Page | Argument |
|---|---|
| 1 | Question, INS/SIVICAP provenance, municipality-year unit of analysis |
| 2 | 2024 municipality counts and distributions of IRCA (%) by department |
| 3 | Missing rural reporting, inference limits, and references |
Use A4 paper, 11-point text, and 1-inch margins. Three pages total, including references, with no separate cover. Revise prose to fit.
Trace each numerical claim to the CSV. Find one sentence that treats the municipal average as an individual water sample and ask your agent to revise it.
Ask your coding agent in quarto-play:
Adapt context/notebook.qmd into notebook.qmd here. Fix data and bibliography paths to context/. Include the question, 2024 municipal counts, medians, ranges, missing rural values, and a captioned IRCA distribution chart by department. State what a row represents. Include limitations and readable source links in Markdown. Convert to notebook.ipynb and execute it with saved results.
Outputs: editable notebook.qmd and runnable notebook.ipynb.
Check: all 318 municipality rows contribute; summaries and chart agree with the CSV. ND values are missing, not zero.
Run in quarto-play with the selected Python/Jupyter environment:
quarto convert notebook.qmd --output notebook.ipynb
jupyter nbconvert --to notebook --execute --inplace notebook.ipynbOpen notebook.ipynb, restart its kernel, and run all cells from the task folder.
Done: code cells execute, the saved table and chart agree with the CSV, and source links work. An HTML page alone does not complete this task.
Terminal, once: start a separate blog project and coding agent session.
Ask your coding agent:
Create a Quarto blog titled “Municipal Water Quality Notebook”. Initialize Git if needed and work on a blog-setup branch. Render the starter site and tell me how to preview it locally.
Output: an HTML website with a home page and a water-quality post. Check: the home page lists the starter posts before you add your own.
The coding agent can run the scaffold command as part of that request:
| Generated path | What to inspect |
|---|---|
_quarto.yml |
Site title, navigation, theme |
index.qmd |
Post listing |
posts/ |
A folder for each post |
posts/_metadata.yml |
Shared post defaults |
about.qmd |
About page |
Check: the coding agent edits the generated configuration without losing its structure.
Ask your coding agent:
In the blog’s _quarto.yml, restrict project.render to the home page, about page, and posts. Keep context/ as source material for the analysis. Preserve the existing site configuration.
Check: after rendering, _site/context/notes.html and _site/context/notebook.html are absent. Add any new public pages to the list.
Copy the shared teaching inputs into the separate blog:
| Input | Purpose |
|---|---|
irca_boyaca_cundinamarca_santander.csv |
Annual municipal and department summaries |
notes.md |
Question, provenance, and limits |
sources.bib |
INS and DANE references |
notebook.qmd |
Worked descriptive notebook to adapt |
Check: #TODOS rows are department aggregates, not municipalities.
Ask your coding agent:
Read context/notes.md and context/notebook.qmd. Create posts/municipal-irca/index.qmd with a question, executable Python reading the CSV, a 2024 municipal IRCA distribution chart, interpretation, and cited sources. Exclude
#TODOSrows, fix paths for the post folder, and include a title, date, caption, and alt text. Render the blog and check its listing.
Outputs: posts/municipal-irca/index.qmd, _site/posts/municipal-irca/index.html, and a listing in _site/index.html.
Check: the chart uses municipality rows and the home page links to the post.
One possible source pattern inside posts/municipal-irca/index.qmd:
```{python}
#| label: fig-irca-municipal
#| fig-cap: "Reported 2024 municipal IRCA (%) in three Colombian departments."
#| fig-alt: "Dot plot of 2024 municipal IRCA values grouped by department."
import pandas as pd
import matplotlib.pyplot as plt
water = pd.read_csv("../../context/irca_boyaca_cundinamarca_santander.csv")
municipal = water[(water.a_o == 2024) & (water.municipiocodigo != "#TODOS")]
for department, group in municipal.groupby("departamento"):
plt.scatter([department] * len(group), group.irca, alpha=0.4)
plt.ylabel("Reported municipal IRCA (%)")
plt.ylim(0, 100)
plt.show()
```Check: each point is an annual municipality summary, not a sample.
Ask your coding agent:
Cite INS/SIVICAP for the reported IRCA values and explain the municipality-year unit of analysis. State that the chart describes reported 2024 values; it does not identify causes, measure individual exposure, or predict future water quality. Render the references.
Check: the post has working source links and a specific limitation.
Ask your coding agent:
Start a local preview of this blog and give me its URL. I want to inspect the post, the listing, and the navigation in a browser.
Commands for your own terminal:
Preview serves the site while you edit. Render creates the output files. Neither command publishes the blog to the public web.
Continue the same conversation after inspecting the post:
The plot does not explain that points represent annual municipality summaries. Add that to its caption and alt text. Re-render the whole blog.
Find one real defect in your own preview and describe it to your coding agent.
Check: show the before-and-after source and the corrected page.
Ask your coding agent:
Review this blog for broken local links, missing figure captions, and unsupported claims. Fix the issues you can verify. Render the whole site and report what you checked and what still needs my review.
Open the home page, follow the post link, and return using navigation. Inspect the chart at a laptop viewport size.
Done: the listing works, the figure is readable, and the prose explains the dataset provenance and limits.
intro.html has exactly six readable slides, including the title and references.essay.pdf has exactly three pages including references and explains what the reported municipal summaries can support.notebook.ipynb runs from a fresh kernel and saves the 2024 municipal summaries and chart.For every task, keep editable sources, unchanged inputs, and a README.md with build commands. Check source links, provenance, and the unit of analysis.
Audience: students who have completed the execution exercise and can read a chart. Input: INS/SIVICAP annual municipal IRCA summaries for Boyacá, Cundinamarca, and Santander. One row is one municipality-year or department-year.
Source: Colombian open-data portal. The deck renders from the unchanged extract in examples/irca-colombia/.
Question: how did reported IRCA (%) vary among the three departments’ municipalities in 2024? The table has no individual samples or sensor readings.
import pandas as pd
import matplotlib.pyplot as plt
water = pd.read_csv(
"examples/irca-colombia/irca_boyaca_cundinamarca_santander.csv",
dtype={"departamentocodigo": str, "municipiocodigo": str},
)
current = water[(water["a_o"] == 2024) & (water["municipiocodigo"] != "#TODOS")]
summary = current.groupby("departamento")["irca"].agg(
municipalities="count", median="median", minimum="min", maximum="max"
)
print(summary.round(1).to_string()) municipalities median minimum maximum
departamento
Boyacá 119 7.1 0.0 50.6
Cundinamarca 113 5.0 0.0 43.2
Santander 86 9.6 0.0 93.9
Check: the three department counts sum to 318 municipality records.
The median reported municipal IRCA is 7.1% in Boyacá, 5.0% in Cundinamarca, and 9.6% in Santander in 2024. These medians give each municipality equal weight; they are not population-weighted exposure estimates.
Question: what does a municipality with a higher reported value tell us, and what can this summary not establish about individual households?
The source also reports urban and rural IRCA, but ND means unavailable. Only 152 of 318 2024 municipality rows have numeric rural IRCA. Missing values cannot be treated as zero.
Using examples/irca-colombia/, verify the three municipality counts and the number of available rural values. Then rewrite this claim:
“The chart shows that individual water samples in Santander will have a higher risk next year.”
Done: your statement names the 2024 municipality-level summaries and avoids predicting future samples or inferring individual exposure.
Ask your coding agent:
Summarize the changes and explain which files are source, generated output, or local dependencies. Check the diff and suggest the files that belong in a commit. Keep this review local.
Commands for inspection:
Check: inspect new files too. A normal git diff omits untracked files.
Ask your coding agent:
Prepare this personal blog for GitHub Pages. Inspect its configuration, render it, and explain the files and repository settings needed. Show the destination and intended visibility. Stop before creating a remote repository, pushing, or publishing.
Check: you recognize the account, repository name, visibility, and content.
The next slide uses Quarto’s gh-pages method for your new blog. This workshop itself serves committed docs/ from main.
After reviewing the destination, ask your coding agent:
Commit the reviewed blog files, create a public GitHub repository named my-blog under my account, push the source, and publish using Quarto’s gh-pages method. Check deployment and give me the live URL.
Commands involved, after the reviewed local commit:
gh auth status
# If needed, complete gh auth login yourself.
gh repo create my-blog --public --source=. --push
quarto publish gh-pagesCheck: open the live URL and test a post link after deployment completes.
Ask your coding agent: include the failed command, exact error, and file path.
Running quarto render fails in posts/municipal-irca/index.qmd with the error below. Reproduce it, identify the cause, fix it, and rerun the full build. Keep execution enabled and preserve the figure. Explain what changed.
Check: the same command succeeds and the expected result still appears.
In a disposable copy, misspell a Python variable. Ask your coding agent to repair the failure, then explain the diff before accepting it.
Work in groups of 3–4. Each person owns a different post on their own branch.
Create a branch for my contribution. Write a post about my chosen topic using the notes I provide. Follow this blog’s existing conventions, render it, and show me the changes for review.
A partner reviews the evidence and preview. Ask your coding agent to address the feedback. One integrator combines the reviewed contributions and publishes.
Done: each post has a working link, an identifiable author, and a reviewed claim.
A notebook:
Adapt my municipal-IRCA analysis.ipynb into a blog post. Preserve the computations, add the missing explanation, and verify that the rendered results agree.
An R analysis:
Create a post from my R script. Prepare the required packages, add captions and units, and record a working render command.
Use the same checks: source, computation, evidence, and rendered result.
Continue with AI workflows: promotion experiments and sales outcomes.
New Quarto Pub and Reveal.js guidance checked 2026-10-28; other listed CLI and publishing guidance checked 2026-10-06.
Which part of your next publication would you ask your coding agent to build first?
Quarto Workshop