AGENTS.md
Project purpose
Lex TL;DR is a small Jekyll blog that publishes concise, readable summaries of long-form podcast episodes. The initial focus is the Lex Fridman Podcast; the information architecture must remain able to add other popular podcasters later.
Keep public copy centered on this purpose. Avoid generic positioning such as a journal about ideas, making, or multiple forms unless it directly explains podcast summaries. The homepage should make three points clear:
- The site summarizes long podcast conversations.
- Lex Fridman is the first podcaster covered.
- Other podcasters may be added later.
The production repository is allenlsy/lex-tldr, and GitHub Pages serves it at https://lextldr.com/.
Architecture
- This is a static GitHub Pages-compatible Jekyll site. Do not introduce a CMS, database, user-account system, or application server without an explicit requirement.
_posts/contains published summary variants._drafts/contains unpublished fixtures or work in progress._drafts/spec-routing-example.mdexists to test ordered multi-valuespecrouting; do not publish it accidentally._layouts/contains the shared shell and post presentation._data/collections.ymldefines the collection links displayed as podcasters.collections/contains collection landing pages.index.htmlis the first homepage summary page;page/*/index.htmlcontains the remaining static pagination routes._includes/summary_index.htmlrenders the shared paginated episode list, and_data/summary_pages.ymldefines its routes._includes/seo.htmlrenders canonical, social, multilingual, and JSON-LD metadata;jekyll-sitemapgenerates the public sitemap.search.html,search.json, andassets/js/search.jsprovide static bilingual full-text search; keep search GitHub Pages-compatible and client-side.assets/js/post-toc.jsprogressively builds the article heading tree from renderedh2andh3elements; articles without headings must not show an empty navigation.assets/js/theme.jscontrols the persistent light/dark theme toggle; the first visit follows the operating-system preference and the early inline setup prevents a color flash.assets/css/style.cssis the site stylesheet.CNAMEmust remainlextldr.com, and_config.ymlmust keepurl: "https://lextldr.com"with an emptybaseurlwhile the custom domain is active.
The repository also contains SSSF automation under adws/ and related recipes in justfile. The new-post recipe is the blog-specific exception. Keep other blog work independent from SSSF unless the task explicitly concerns that machinery.
Homepage pagination operates on logical episodes after grouping variants by article_id, never on individual language or spec variants. It offers 20 and 50 episodes per page, with 20 as the default. _data/summary_page_sizes.yml defines the choices, and _data/summary_pages.yml defines their static routes. When the episode count outgrows one of those route sets, add its next page file with the matching summary_page and summary_page_size front matter.
Keep indexable pages self-canonical. Podcast summary variants must emit reciprocal hreflang links, using valid BCP 47 language tags (en and zh-CN) and the English variant as x-default when available. Search is noindex,follow and excluded from the sitemap. Do not add fabricated authors, ratings, images, or other structured data that the page does not substantiate.
Summary and variant model
Treat one podcast episode as one logical article. Every published variant of that summary must share:
article_id: stable slug for the episodearticle_title: shared display titlecollection_id: podcaster collection
Each variant also has:
title: localized display title for that variant; Chinese variants should use a Chinese title whilearticle_titleremains shared across languages. Preserve non-Chinese personal names in their original spelling; use Chinese characters for people whose original name is Chinese.language: currently useenandcnfor the examplevariant_rank: unique, stable ordering within the logical articlepermalink: explicit public routespec: optional ordered YAML list for distinctions beyond language
Language display names live in _data/languages.yml. Templates must use the shared language-label include so every number of variants is supported and known languages show their native names.
When language is the only distinction, omit spec and end the URL after the language:
language: en
variant_rank: 1
permalink: /articles/example-episode/en/
When spec is present, preserve its order and join the values with - in the final URL segment:
language: en
spec:
- short
- audio
variant_rank: 2
permalink: /articles/example-episode/en/short-audio/
Most imported summaries have two variants, en and cn. Episode 440 intentionally has four variants because two distinct source summary sets were imported as ordered short and long specs. Templates must support any number of variants and render cleanly when spec is absent.
Local summary conversion
Content batch tooling lives in the admin/ git submodule (separate repository allenlsy/lex-tldr-admin; fetch it with git submodule update --init after a fresh checkout). The tools resolve the blog root from their own location, so run them from this repository. The just new-post recipe uses scripts/new_post.rb inside this repository and needs no submodule.
admin/convert_pending.py converts pending summary files into Jekyll posts. Place summaries in pending/<collection_id>/ (e.g. pending/lex-fridman/), preview with a dry run, then apply:
python3 admin/convert_pending.py
python3 admin/convert_pending.py --apply
The script derives the episode id, title, and language from the file name and content. The episode number comes from the heading, then the verified video metadata table (VIDEOS), then a live lookup against https://lexfridman.com/podcast (title match plus the YouTube page title), and finally an interactive prompt when nothing else resolves it; the number drives title, article_id, article_title, and permalink. It must remain dry-run by default, must never overwrite a different destination file, and moves converted sources to pending/processed/. Excerpts use the first substantive paragraph of the post body. Chinese variant titles are translated from the shared article_title through an OpenAI-compatible endpoint (default http://127.0.0.1:8000/v1, model Qwen3.6-35B-A3B-MLX-4bit). To regenerate metadata (fill missing excerpts, translate titles) for a date range:
python3 admin/convert_metadata.py --start 2026-08-01 --end 2026-08-31
python3 admin/convert_metadata.py --start 2026-08-01 --end 2026-08-31 --apply
Podcaster collections
Collections represent podcasters in the visible interface. Add a collection entry to _data/collections.yml, add a front-matter-only landing page under collections/ that uses the shared _layouts/collection.html layout, and give all related summary variants the same collection_id. The layout derives the collection number from the _data/collections.yml order.
The first collection is displayed as Lex Fridman Podcast and uses the internal ID lex-fridman. Its /collections/practice-notes/ route is a legacy public URL; preserve that route unless a task includes a deliberate URL migration and compatibility plan.
Public copy and design
- Use “episode,” “summary,” “conversation,” “podcast,” “podcaster,” “language,” and “version” where appropriate.
- Do not describe summaries as unrelated articles or generic ideas in prominent UI copy.
- Keep the editorial visual theme and its responsive behavior unless redesign is requested.
- Preserve accessible navigation, semantic headings, visible focus states, and readable English and Chinese typography.
- Use Jekyll’s
relative_urlfor internal links so routes work locally and at the production domain root.
Local commands
Install dependencies once:
bundle install
Run the regression test:
sh tests/collection_links_test.sh
Build the production site:
bundle exec jekyll build
Preview locally:
bundle exec jekyll serve
List the existing project recipes:
just --list
Create a language-only podcast summary:
just new-post "EPISODE TITLE" en
Preview and convert the pending Lex Fridman summaries:
python3 admin/convert_pending.py
python3 admin/convert_pending.py --apply
The recipe derives the episode ID and URL slug from the title, assigns the next variant rank, and rejects duplicate episode-language variants. Authors must replace the generated placeholder body before publication.
Change workflow
- Inspect
git statusbefore editing. Preserve unrelated user changes. - For behavior changes, add or update a regression test and observe the intended failure before implementation.
- Make the smallest coherent change.
- Run
sh tests/collection_links_test.shandbundle exec jekyll build. - Run
git diff --checkand review the rendered paths or HTML relevant to the change. - Stage only intended files. Do not use broad staging when unrelated files exist.
- Commit and push only when the user requests publication.
Pushing main triggers GitHub Pages. After publishing, verify the Pages workflow succeeds and confirm the changed routes at https://lextldr.com/.
Repository hygiene
- Do not commit
_site/; it is generated output. - Do not commit
.envor expose API keys and credentials. dogfood-output/is untracked QA output and must remain excluded unless explicitly requested.- Do not change or remove historical SSSF files merely to make blog-oriented searches cleaner.
- Prefer explicit post permalinks and stable IDs over inferred routing.