CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

Lewis Blake’s personal/professional website (statistician, ML/optimization background), hosted at www.lewisblake.com via GitHub Pages (repo: lewisblake/lewisblake.github.io). Built with Jekyll, forked from AcademicPages, which itself forks the Minimal Mistakes theme. The theme is fully vendored into this repo (not pulled via remote_theme), so _layouts, _includes, and _sass are all directly editable.

Local development

No Ruby/Jekyll needs to be installed on the host — everything runs in a container.

# First time / after Gemfile changes
docker build -t jekyll-site .          # scripts say `podman`, but plain `docker` works identically
                                        # (same CLI syntax) if podman isn't installed

# Start/stop/manage
./jekyll.sh start     # serve at http://localhost:4000, live-reloads on file changes
./jekyll.sh stop
./jekyll.sh restart
./jekyll.sh status     # recent logs
./jekyll.sh logs       # follow logs
./jekyll.sh shell       # shell inside the container
./setup.sh              # convenience wrapper: builds image if missing, starts server

The scripts hardcode podman; swap in docker if that’s what’s installed (as of this writing, docker is available and podman is not). If invoking Docker directly instead of via jekyll.sh:

docker run -d -p 4000:4000 -p 35729:35729 -v "$(pwd):/site:Z" --name jekyll-server jekyll-site

There is no automated test suite or linter — verification means building the site and checking pages render correctly (visually and via curl/HTTP status).

Deployment

Deployed via GitHub Pages’ legacy “deploy from a branch” build (Settings → Pages → Source), not GitHub Actions. This means:

  • Jekyll version is whatever the github-pages gem in the Gemfile pins (currently Jekyll 3.10 — old, but this is GitHub’s own build environment and is not something to “fix” casually).
  • Only plugins on GitHub Pages’ whitelist can be used (see plugins: in _config.yml: jekyll-paginate, jekyll-sitemap, jekyll-gist, jekyll-feed, jekyll-redirect-from).
  • A GitHub Actions-based deploy was tried and reverted by deliberate choice — the owner prioritizes “keep it working with minimal upkeep” over engineering flexibility. Don’t re-propose migrating the deploy mechanism or bumping the Jekyll version unless asked; both were explicitly weighed and declined.
  • If Actions is ever revisited: ruby/setup-ruby’s bundler-cache: true installs gems into vendor/bundle/ inside the repo, and Jekyll’s default source: . will then try to build the vendored gem source as site content (this broke the build once — a Jekyll gem’s own _posts template file has an unparsable ERB placeholder date). vendor is already in _config.yml’s exclude: list to guard against this regardless.

_config.yml’s url must stay https://www.lewisblake.com (matching CNAME) — GitHub Pages 301s the apex domain to www, so canonical tags/sitemap/feed should point at www directly, not the apex.

Content architecture

Content lives in Jekyll collections, each with output: true and its own permalink in _config.yml:

  • _talks, _publications, _publications_technotes, _publications_posters — filename convention YYYY-MM-DD-slug.md.
  • _teaching — courses taught.
  • _pages — standalone pages (about/home, cv, projects, publications index, contact, etc.). The home page is _pages/about.md (permalink: /).
  • _data/authors.yml, _data/navigation.yml, _data/ui-text.yml — site-wide author/nav/string data referenced via site.data.* in Liquid templates.
  • markdown_generator/ — Jupyter notebooks/scripts that historically bulk-generated _talks/_publications entries from TSV files. Content is now maintained by hand; these are not part of the build.

Styling

assets/css/main.scss is the entry point; it @imports theme partials from _sass/ in a specific order (base → layout → components). Custom additions layered on top of the stock theme, all imported at the end of main.scss:

  • _animations.scss — restrained fade/slide-in entrance animations (respects prefers-reduced-motion). Don’t add more without reason; this was a deliberate “just enough” ceiling.
  • _dark-mode.scss — dark theme via [data-theme="dark"] attribute + CSS custom properties (--link-color, --border-color, etc.), toggled by assets/js/dark-mode.js (vanilla JS, reads/writes localStorage['theme'], independent of the jQuery bundle below).
  • _skills-badges.scss — styles the .skill-tag pill elements on the About page (see below).

Font Awesome is fully self-hosted (vendored SCSS + woff files in assets/fonts/), but _includes/head.html also loads Font Awesome 5.15.4 from cdnjs. This looks redundant but isn’t: the vendored copy is an old version (5.5.0) missing some brand icons actually used in the sidebar (e.g. fa-orcid), so the CDN link is a deliberate, SRI-pinned fallback. Don’t remove it without first checking every fa-/fab fa- icon used in _includes/_data against _sass/vendor/font-awesome/_icons.scss.

JavaScript

assets/js/main.min.js is a pre-built, minified bundle (jQuery 1.12.4 core + plugins + _main.js), assembled by the uglify/build:js npm script in package.json. Node/npm is not installed in the Docker dev image — editing assets/js/_main.js or the plugin files under assets/js/plugins/ will not take effect until someone rebuilds the bundle with Node available elsewhere. Every plugin currently bundled is in active use (_main.js calls all of them): fitVids (video embeds), Stickyfill (sticky author sidebar polyfill), smoothScroll (anchor links), magnificPopup (image lightboxes), and greedy-nav (collapsing mobile menu). None of it is dead code to trim.

Images

Check dimensions/file size before adding images, especially page headers/banners — this repo has shipped multi-megabyte, camera-resolution images as page banners before (a 5991×2350, 4.5MB JPEG mislabeled with a .png extension was used as the homepage hero for some time). Resize to roughly 2× the largest on-page display size and compress before committing.

Skill tags

The About page’s “Technical Skills” section (_pages/about.md) uses local <span class="skill-tag"> elements, not img.shields.io badge images — this was a deliberate change to drop 14 external network requests per page load and keep the visual style consistent with the rest of the site. Follow the same pattern (plain <div class="skill-tags"><span class="skill-tag">Name</span>...</div>) rather than reintroducing shields.io images.