This repository contains the source files for levineuwirth.org in their entirety and is automatically updated whenever the website is rebuilt. https://levineuwirth.org
Go to file
Levi Neuwirth 7ca937d98c Fix audit HIGHs/MEDs in build code
- ArchiveIndex: guard rawIndex/rawState with doesFileExist so a fresh
  clone (gitignored data/ JSONs absent) degrades to empty instead of
  crashing — the behavior the module doc already promised (AUDIT §1.2)
- Commonplace: decode YAML via encodeUtf8, not Char8.pack, which
  truncates codepoints above 0x7F (AUDIT §3.2)
- Stats: DayOfWeek is ISO-numbered (Mon=1..Sun=7); dowOf and weekStart
  assumed Mon=0..Sun=6, clipping every Sunday cell outside the heatmap
  viewBox and starting weeks on Sunday (AUDIT §3.1)
- Site: epistemicEntry now honors the proved/proven confidence sentinel
  like Contexts.overallScoreField (AUDIT §2.6)
- Contexts: affiliationField returns noResult instead of an empty list,
  so essays without affiliation no longer render an empty meta row
  (AUDIT §2.7)

Verified: full site build passes; proved page gets score=100 in
epistemic-meta.json; empty .meta-affiliation gone; heatmap rows
y=22..94 all inside the 104-high viewBox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:21:30 -04:00
archive Add link archive system: snapshots, backlinks, link-rot 2026-05-23 10:06:33 -04:00
build Fix audit HIGHs/MEDs in build code 2026-06-10 09:21:30 -04:00
content auto: 2026-05-26T15:50:02Z [skip ci] 2026-05-26 11:50:02 -04:00
data Internal audit 2026-05-07 17:20:27 -04:00
nginx Add link archive system: snapshots, backlinks, link-rot 2026-05-23 10:06:33 -04:00
static Branding: traced logo mark, regenerated favicons, og-image 2026-06-09 18:57:34 -04:00
templates Branding: traced logo mark, regenerated favicons, og-image 2026-06-09 18:57:34 -04:00
tools embed.py: split page vs paragraph embedding models 2026-06-09 18:57:43 -04:00
.env.example States/Context/Embeddings fixes 2026-04-26 11:22:57 -04:00
.gitignore embed.py: split page vs paragraph embedding models 2026-06-09 18:57:43 -04:00
.python-version GPG signing, embedding pipeline, visualization filter, search timing, sig popups 2026-03-20 20:14:49 -04:00
ARCHIVE.md Add link archive system: snapshots, backlinks, link-rot 2026-05-23 10:06:33 -04:00
AUDIT-2026-06-09.md Add 2026-06-09 repository audit findings 2026-06-09 18:57:43 -04:00
AUDIT.md Add AUDIT.md 2026-05-07 15:07:48 -04:00
HOMEPAGE.md affiliation, cabal helper script 2026-03-26 08:14:50 -04:00
LICENSE Add MIT License to the project 2026-03-15 19:02:33 +00:00
MARKS.md Marks I 2026-05-07 23:51:14 -04:00
Makefile Stamp the site-wide build time post-render 2026-05-23 12:05:28 -04:00
PHOTOGRAPHY.md Spec dilemma 2026-05-01 21:22:01 -04:00
README.md nginx: ship security baseline, reference vhost, and tighter cache 2026-05-07 15:08:03 -04:00
WRITING.md embed.py: split page vs paragraph embedding models 2026-06-09 18:57:43 -04:00
cabal.project initial deploy! whoop 2026-03-17 21:56:14 -04:00
cabal.project.freeze Refreeze after system update: distributive 0.6.3 et al. 2026-06-09 18:57:25 -04:00
levineuwirth.cabal Add link archive system: snapshots, backlinks, link-rot 2026-05-23 10:06:33 -04:00
pyproject.toml embed.py: split page vs paragraph embedding models 2026-06-09 18:57:43 -04:00
uv.lock embed.py: split page vs paragraph embedding models 2026-06-09 18:57:43 -04:00

README.md

levineuwirth.org

Personal site of Levi Neuwirth — essays, blog posts, poetry, fiction, and music. Built with Hakyll and Pandoc, with a custom build system in build/ and a Haskell + JS + Python toolchain.

Quickstart

make build              # one-shot production build into _site/
make dev                # dev build (drafts visible) + local server on :8000
make watch              # cabal-watch rebuild (drafts visible)
make clean              # cabal run site -- clean
make deploy             # clean → build → sign → push → rsync to VPS

make build always runs make clean implicitly when invoked from make deploy. For day-to-day work, prefer make dev (which serves the site on http://localhost:8000) or make watch (rebuilds on save without a server).

Run make build any time you add or replace binary assets (JPEG/PNG figures, PDFs, music assets). make dev and make watch skip the convert-images.sh / pdf-thumbs preprocessing steps, so a fresh JPEG will have no .webp companion and a fresh PDF will have no thumbnail until a full make build regenerates them. Once the companions exist they survive subsequent make dev runs.

Optional features

  • Similar-links and embeddings. tools/embed.py precomputes page-level embeddings for the "Related" block. To enable:

    uv sync                 # creates .venv with sentence-transformers, faiss-cpu
    

    The build silently skips embedding when .venv is absent.

  • Client-side semantic search. Downloads a quantized ONNX model used by static/js/semantic-search.js (run once; files are gitignored):

    make download-model
    
  • Image conversion. make build calls tools/convert-images.sh to produce .webp companions next to every JPEG/PNG. Requires cwebp (libwebp on Arch, webp on Debian/Ubuntu).

  • PDF thumbnails. make pdf-thumbs generates first-page thumbnails for PDFs in static/papers/ using pdftoppm (poppler on Arch, poppler-utils on Debian/Ubuntu). Skipped silently when missing.

Configuration

.env (gitignored, copy from .env.example) holds the GitHub PAT and the VPS rsync target consumed by make deploy. Never commit it.

Repository layout

  • build/ — Haskell build system (Hakyll rules, Pandoc filters, contexts). See build/Filters/ for the Pandoc AST transforms (sidenotes, wikilinks, transclusion, score embedding, viz, …).
  • content/ — authored Markdown (essays, blog, poetry, fiction, music).
  • templates/ — Hakyll/Pandoc HTML templates.
  • static/ — CSS, JS, fonts, images, vendored PDF.js.
  • tools/ — Python tooling (embeddings, importers) and shell scripts.
  • data/ — generated and source data (commonplace.yaml, annotations.json, bibliographies, similar-links.json).
  • nginx/ — vhost snippets shipped to the VPS (security-headers.conf, static-assets.conf, popup-proxy.conf). The live vhost on the VPS is the source of truth; see nginx/vhost.conf.example for the canonical structure and the include order these snippets expect.

Architecture pointers

  • build/Site.hs is the Hakyll rules entry point.
  • build/Patterns.hs defines canonical content patterns shared by Backlinks, Authors, Tags, and Site.
  • build/Compilers.hs wires the Pandoc filter chain into Hakyll.
  • build/Filters/Images.hs does WebP <picture> wrapping; requires the .webp companions produced by tools/convert-images.sh.

License

See LICENSE.