This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Lab material for the "Introduction to Programming" (C) course at the University of Athens. It is content, not software: the deliverable is a set of PDF lab handouts built from Greek-language Markdown. There is no application, no test suite, and no linter.
The same Markdown is consumed two ways:
- PDF handouts —
makeruns a Docker/pandoc pipeline, output lands inbuild/. - GitHub Pages site — the
labs/*/README.mdfiles render directly on GitHub;_includes/head-custom.htmlis the Jekyll hook that adds MathJax and client-side mermaid rendering (it rewritescode.language-mermaidblocks into.mermaiddivs).
Any change to a lab must keep both paths working.
Requires make, docker and python3 — no pandoc or LaTeX is installed locally;
both rendering stages run in containers.
make # build every lab PDF + build/all.pdf
make -j4 # same, in parallel; the per-lab targets are independent
make build/lab05.pdf # single lab (fastest edit/preview loop)
make labs/lab05/README-out.md # just the mermaid->PNG stage, to debug diagram rendering
make lint # defect linter (see tools/lint.py)
make toc / make check-toc # regenerate / verify the per-lab tables of contentsBoth images are multi-arch, so nothing runs under emulation any more: a full
make -j4 takes about 2 minutes and produces twelve PDFs. (Until the
pandoctex:20260825 bump the pandoc stage had no arm64 manifest and a serial build
on Apple silicon took ~13 minutes.)
The pandoc image is pinned to a dated tag rather than latest, because a pandoc
major version can silently change the generated LaTeX — see the babel note below for
exactly that happening. minlag/mermaid-cli is still unpinned.
If a build dies with Error 137 (SIGKILL), the Docker daemon is out of resources
rather than the document being at fault. The docker run invocations now pass --rm;
before that every build left ~11 stopped containers behind, which is how this repo
accumulated 216 of them (5.3 GB) and started getting builds OOM-killed. Clear any
strays with:
docker ps -a --format '{{.ID}} {{.Image}}' \
| grep -E 'mermaid-cli|pandoctex|poppler' | awk '{print $1}' | xargs docker rmGreek/babel gotcha (pandoc 3.7). -V lang=el alone no longer builds. pandoc 3.1.3
emitted \babelprovide[main,import]{greek}, which reads babel's locale/el/babel-el.ini;
pandoc 3.7 instead passes greek as a documentclass option, which makes babel look for
greek.ldf — the babel-greek package, which the pandoctex image does not ship. The
build then dies with Package babel Error: Unknown option 'greek'. The fix is split
across two files: the Makefile passes -V babel-lang= to suppress the class option
while keeping lang=el (so pdflang metadata survives), and labs/header.tex issues
the \babelprovide call itself. Without this the TOC heading reverts to English.
The cleaner long-term fix is to add babel-greek to the image.
Fontconfig noise: the pandoc stage runs with -e HOME=/tmp. The containers run as
the invoking uid via -u, so $HOME is unwritable and fontconfig printed three
No writable cache directories errors on every single invocation. They were harmless
but buried real diagnostics.
Encoding gotcha: the pandoc stage must run with -e LANG=C.UTF-8. Without a UTF-8
locale the container's GHC runtime decodes command-line arguments as Latin-1, so any
non-ASCII value passed via -V (e.g. the Greek lab title used in the running header)
silently becomes one replacement character per UTF-8 byte. Files read via -H are
unaffected — this only bites values passed on the command line.
Pipeline (see Makefile), per lab:
minlag/mermaid-cli— rewrites```mermaidfences into PNGs at--scale 10and emitsREADME-out.md. Runs for every lab, including ones with no diagrams.ghcr.io/ethan42/pandoctex:20260825(pandoc 3.7) —pandoc README-out.md -f gfmthroughxelatex, withlabs/header.tex(Greek setup, brand palette, running headers, masthead) and fontsLinux Libertine O/Noto Mono, which exist only inside that image.build/all.pdfis not a merge of the per-lab PDFs.tools/build-all.pyconcatenates the elevenREADME-out.mdfiles intobuild/all.md— stripping front matter and the injected TOC, and rewriting image paths to be repo-root-relative — and a single pandoc run compiles it withlabs/cover.tex. That is what makes a cover page, a book-wide contents list and continuous page numbering possible;pdfunitecould not produce any of the three. Image paths are rewritten rather than resolved via--resource-pathbecause basenames collide across labs (nearly every lab has animage1.png).
README-out.md, README-out*.png and build/ are gitignored intermediates — never commit them.
labs/labNN/README.md— the source of truth. Currently lab00–lab10. The Makefile derives its target list from$(shell seq -w 0 10), so adding a lab11 means editing that range too.labs/labNN/img/media/*.png— images, referenced as./img/media/imageN.png.lab03is the exception:./img/imageN.png.docs/lab01.doc…docs/lab11.doc— the legacy Word originals the Markdown was converted from. Historical reference only; nothing in the build reads them, and they are not kept in sync withlabs/. The numbering is offset by one:docs/labNN.doccorresponds tolabs/lab(NN-1)/— solab11.docis lab10 (file I/O), not a missing lab. Two exceptions worth knowing:docs/lab05.docanddocs/lab06.docmap tolabs/lab05andlabs/lab04respectively (char I/O was moved before functions/recursion), anddocs/lab05.docadditionally covers scope/storage of variables plus an appendix on splitting a program across multiple.c/.hfiles — material with no counterpart anywhere inlabs/.labs/header.tex— shared LaTeX preamble:fvextraline-breaking for code blocks (without it long terminal transcripts run off the page and get clipped), the brand palette, thefancyhdrrunning header/footer, and the\AtBeginDocumentmasthead that puts the two crests on page 1.\labtitleis injected per lab by the Makefile.assets/—uoa.jpganddit.jpg, referenced from LaTeX via\graphicspathso the same preamble works whether pandoc runs from a lab directory or the repo root.
Writing conventions inside a lab README:
- All prose is in Greek. Match the existing register (second person plural, informal- but-instructional) and keep code identifiers, shell commands and C keywords in English.
- The structural convention lives in
CONTRIBUTING.md§ Οδηγίες συγγραφής and is enforced bytools/lint.py. Read it before restructuring a lab; the summary is that every H2 is one of## Βήμα N: Τίτλος,## Άσκηση N: Τίτλος (file.c),## Για να πάτε παρακάτω (Προαιρετικό)or## Παράρτημα: Τίτλος(always last), and the only badges are(Παλιό θέμα),(Προχωρημένο),(Προαιρετικό)in that order. - Five labs carry a running debugging appendix:
## Παράρτημα: Αποσφαλμάτωση προγραμμάτων (Πράξη Nη)— the "Πράξη" numbering is a single sequence across the book (lab02=1η, lab03=2η, lab07=3η, lab08=4η, lab09=5η), andlint.pyfails if it develops a gap. lab10's appendix is a different genre and carries no Πράξη number. - Math uses
$...$/$$...$$; it is rendered by MathJax on Pages and by xelatex in the PDF. Both must be satisfied. - Short explicit anchors (
<a id="webmail"></a>above a heading) keep section links terse while the heading itself stays descriptive, and survive a retitling.lint.pycounts them as valid anchor targets. - A recurring source of commits is PDF fit: wide tables and long code lines overflow
the
fullpagelayout. Preview withmake build/labNN.pdfbefore assuming Markdown that looks fine on GitHub is fine on paper.
The C files at the repo root (prime.c, collatz.c, maxpath.c, fib.c, encode.c,
decode.c, printchar.c, example1.c, …) plus their compiled binaries and pile.txt
are untracked lecture/demo scratch — worked solutions and live-coding leftovers, not
part of the build. They are not gitignored, so they show up in git status; do not stage
them unless explicitly asked. Compile ad hoc:
gcc -o prime prime.c && ./prime 10001
gcc -o circularprime circularprime.c -lm.github/workflows/publish.yml— on every push tomain(or manual dispatch): auto-increments the patch component of the latest tag, runsmake, and creates a release with that tag on the pushed commit, with everybuild/*.pdfas an asset. Releases are the distribution channel for the handouts; don't create them by hand..github/workflows/kaizen.yml— manual-dispatch-only AI review pass (ethan42/kaizen); not part of the normal build.