This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Academic personal website for Moritz Seebacher (PhD student, ifo Institute / LMU Munich). Hosted on GitHub Pages at https://moritzseebacher.github.io. Repository: github.com/moritzseebacher/moritzseebacher.github.io. Research focus: education & labor economics, using LinkedIn data to study skills, social networks, and career trajectories.
This repository is public. It is served at https://moritzseebacher.github.io, and its
full history is readable by anyone, including files deleted in a later commit.
Nothing describing Moritz’s preferences may be committed here. Not in a doc, not in a
comment, not in a variable name, not in a test fixture, not in a .pyc. Specifically:
Where it goes instead: F:\Academic Website\job_market_2026\, which is deliberately
outside this repository. Preference material is local only and known to Claude — it is
not tracked by git anywhere, not in this repo and not in another one.
The job market tooling is untracked on purpose. .claude/commands/jm-scan.md,
.claude/scripts/jm_*.py, .claude/job-market-*.md and __pycache__/ live on disk so the
/jm-scan command still works, but they are in .gitignore and must stay there. Do not
git add -f them. Do not “restore” them on the grounds that they look like missing code.
Before committing anything, check. If a change touches the job market workflow, confirm
git status shows no job-market path staged. When in doubt, ask rather than commit.
mmistakes/minimal-mistakes)assets/css/main.scss)_includes/footer/custom.html)jekyll-include-cache, jekyll-sitemap, jekyll-seo-tagpython .claude/scripts/site_check.py # Pre-push validation (no Ruby needed; see fallback below)
bundle exec jekyll serve # Local dev server (http://localhost:4000)
bundle exec jekyll build # Build static site to _site/
Always run site_check.py before pushing. It needs only Python and catches the
breakages that actually occur when editing this site by hand: nav anchors that no longer
resolve, links to files that do not exist, orphan PDFs left in the repo root, unbalanced
<details>/<div> tags, blank lines that break kramdown’s tight-list rule, and paper
action rows whose PDF link is in the wrong position. Exit code 1 means do not push.
python is not on PATH on every machine this repo is edited from, and on the remote ifo
server it is not on PATH at all. Do not conclude that Python is unavailable and skip
site_check.py — the checker is the only pre-push validation there is.
python, python3, or py on PATH.Z:\PromotionProject\git_moritz\python_environment\jobtitles_env\python.exe
— a project venv on the ifo network drive, verified working on 4 Sep 2026 (Python 3.10.19).
It runs site_check.py and cv_audit.py fine; they use only the standard library.
cv_audit.py additionally shells out to pdftotext, which must be on PATH; without it
the audit blocks rather than passing unverified.Same order applies to cv_audit.py and any other script in .claude/scripts/.
A Gemfile is committed for local preview via the github-pages gem, which pins the same
dependency versions GitHub Pages uses server-side. Ruby is not installed on the current
machine, so the Gemfile has not been exercised — bundle install will need running once
before jekyll serve works. Deployment does not depend on it: Pages builds with its own
dependency set and ignores the repo’s Gemfile.
moseeb98.github.io/
├── _config.yml # Jekyll config, author profile, theme settings
├── _data/navigation.yml # Top nav bar entries (all anchor links to index.md)
├── _includes/footer/custom.html # Mobile nav JS fix (moves nav items to hidden-links)
├── assets/css/main.scss # Custom SCSS overrides (avatar sizing, mobile layout)
├── index.md # Main page — all content sections live here
├── Seebacher-Moritz_2023_7_ret_pass_format.jpg # Profile photo (served from root)
├── Seebacher_Career_Effects_Online_Social_Networks.pdf # Job market paper (stable filename)
├── Multidimensional_Skills_LinkedIn_IZA_DP17896.pdf # Working paper PDF (stable filename)
└── CV_Academic_Moritz_Seebacher_MM_YY_English.pdf # CV (built from LaTeX, served from root)
Single-page academic site — all content lives on the index page:
index.md — All content lives here as sections with anchor IDs: #job-market-paper, #publications, #working-papers, #work-in-progress, #policy-papers-non-refereed, #cv._data/navigation.yml — Defines main nav (top bar) and sections sidebar nav, both pointing to anchors on the index page._config.yml — Author profile (name, avatar, bio, email, LinkedIn), theme skin (default), plugins, locale, timezone.assets/css/main.scss — Responsive avatar/sidebar layout overrides (see below)._includes/footer/custom.html — JavaScript that runs on mobile (≤800px) to force all nav items into the Minimal Mistakes hidden-links dropdown, ensuring the … toggle works correctly.Each entry is a Markdown bullet:
- [Paper Title](https://url-to-paper) (with Co-Author Name)
<small><strong>Venue Name</strong>, Volume X (Year), pages.</small>
<br> that separates the title/authors from the citation.<small><strong>Venue</strong>, details.</small>.Every entry at working-paper stage or beyond (publications, working papers) carries a
collapsible abstract. Non-refereed policy papers do not. The job market paper is the
exception in the other direction: its abstract is expanded by default
(<details ... open>), but it collapses like the rest.
What goes public, and at which stage (Moritz, revised 16 Sep 2026). A work-in-progress
project is listed once Moritz has decided it will become a paper and wants the collaboration
visible — as a title-only entry with coauthors and no action row (the promotions project
with Dorn and Woessmann is the example). An abstract is added once the coauthors have agreed
on one (the alumni project). Projects still at the idea, outline, or grant-review stage
(misreporting, AI and labor) stay off the site even though the research statement names them:
the statement goes to a committee, the site is public, and they are deliberately not the same
list. Work-in-progress entries never link to a PDF. Whatever is listed here is listed in the
CV in the same words, and cv_audit.py (rule R37) checks every title on both sides.
Status notes. An entry that has a draft but no public PDF carries
<span class="paper-note">Draft available upon request</span> directly after the abstract
toggle (alumni project, 16 Sep 2026). The same words go into the CV’s outlet slot, and rule
R37 fails if one side has the tag and the other does not. Drop the tag the day the PDF goes
up.
Every abstract sits inside a <div class="paper-actions"> row, whether or not the entry has a
PDF. The <details> holds only its <summary>; the abstract text is a sibling
<span class="abstract-text">:
- [Paper Title](https://url) (with Co-Author)
<small><strong>Venue</strong>, details.</small>
<div class="paper-actions"><details class="abstract"><summary>Abstract</summary></details><a class="paper-pdf" href="/File_Name.pdf">PDF</a><span class="abstract-text">Full abstract text…</span></div>
<details> is what makes that possible: the <details> stays
button-width so the PDF button sits beside it rather than being pushed to the right-hand
edge, and the text, a flex sibling with a 100% basis, wraps onto its own full-width row.<div> — the list item must stay “tight”. A blank line makes
kramdown wrap the item in <p>, which invalidly nests a block element inside a paragraph.ageskill → age-skill).assets/css/main.scss under --- COLLAPSIBLE PAPER ABSTRACTS --- and
--- PAPER ACTION ROW ---.Publications and working papers with an ungated PDF in the repo root carry a PDF button in the
action row, directly after the abstract toggle (see above for the markup).
PDF, for every entry. Version status (accepted manuscript vs. published
version) is carried by a notice on the file itself, not by the link text.Links are distinguished by colour only — the theme’s hover underline is switched off in
assets/css/main.scss under --- LINKS ---.
Use ## Title {#anchor-id} so navigation links (/#anchor-id) resolve correctly.
CV PDF, job market paper PDF, and profile photo are served from the repo root (no subdirectory).
Unlike the CV, the JMP PDF keeps a stable filename — Seebacher_Career_Effects_Online_Social_Networks.pdf — so that links shared on the job market never break. New drafts are dated in the paper itself, not in the filename.
When a new draft arrives (every step, every time — updating the CV is part of this workflow, not a separate task):
Seebacher_Career_Effects_Online_Social_Networks.pdf with the new PDF, keeping the filename unchanged. Do not add a dated copy to the repo root.index.md (pdftotext -f 1 -l 1 <pdf> -) — the title in the ## Job Market Paper heading and the abstract-text span must match the PDF verbatim. When the abstract changed, take the new text from the paper’s main.tex, not from pdftotext, to avoid line-break artifacts.tex/cv.tex in the application package, then rebuild and re-sync the website copy with .\build.ps1 web (see CV update workflow below). Rules R37 (title) and R38 (abstract, verbatim) in .claude/scripts/cv_audit.py enforce both.site_check.py and cv_audit.py; any failure means fix it first and re-run. A stale abstract on the site or in the CV is a blocker, not a follow-up.The CV is built from LaTeX, not Word (changed 10 September 2026). The source is
tex/cv.tex in the application package, which lives outside this repository with the rest of
the job market material. One source produces two PDFs:
| Build | Output | Carries the referees? |
|---|---|---|
.\build.ps1 core |
pdf\Seebacher_CV.pdf |
Yes — sent with applications and to the letter writers |
.\build.ps1 web |
the dated CV_Academic_*.pdf in this repo root |
Yes — the same PDF under the dated name |
Since 16 September 2026 the two copies are the same document. All four letter writers
agreed to be listed publicly, so the References section (names, affiliations, email addresses)
is on the website CV. The page itself lists no referees (Moritz, same day): the CV is the
one place, so index.md gets no References section and no referee mailto: link. Until then
the website build defined \publicCV, which dropped the block; that switch is gone.
build.ps1 web refuses to copy a CV that does not carry all four referees.
Never hand-edit the PDF in this repo root. It is overwritten by the next build.ps1 web.
Edit tex/cv.tex and rebuild.
When updating the CV:
tex/cv.tex in the application package..\build.ps1 core (the copy that goes to committees and letter writers) and
.\build.ps1 web (the public copy). The web command copies the public PDF here under a
filename dated to the current month, deletes the superseded one, and relinks index.md if
the month rolled over.site_check.py and cv_audit.py. cv_audit.py is the gate that matters: it reads the
published PDF and fails if its References section is missing or short of four referees,
if index.md links a referee address, if the Fields line, a paper title or the draft-status
tag disagrees with index.md, or if an abstract is not verbatim in both.The Word documents in the repo root are superseded and are kept only as history. They are
git-ignored and no longer feed anything; cv_audit.py warns while they are still there.
Desktop (≥1024px): Sidebar avatar is circular, 85% of sidebar width, portrait crop (aspect-ratio: 5/6, object-position: 50% 15%).
Mobile (≤800px): Two-column CSS grid — photo fills the left column, name/bio and contact links stack in the right column. Avatar is rectangular (no border-radius, object-fit: contain). The … button replaces the hamburger icon; the footer JS moves all nav items to the hidden-links dropdown.
Push to main branch → GitHub Pages builds and deploys automatically. No CI/CD config needed.
Repository: https://github.com/moritzseebacher/moritzseebacher.github.io
Live site: https://moritzseebacher.github.io