CLAUDE.md

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

Project Overview

Jekyll 4 static blog deployed to GitHub Pages at sameerbajaj.com. Features blog posts, book notes, and a tools/projects showcase. SEO and organic search are primary traffic drivers — prioritize proper metadata, performance, and discoverability.

Critical Workflow Rules

Common Commands

# Local development (user runs this, not you)
bundle exec jekyll serve --livereload --config _config.yml,_config-dev.yml

# Faster dev modes via npm (see DEVELOPMENT.md for details)
npm run dev:full           # Full fidelity
npm run dev:fast-design    # CSS/layout work (limit_posts: 10)
npm run dev:fast-content   # Writing only (fastest, skips tools/books pages)

# Production build
bundle exec jekyll build

# Clean build cache
bundle exec jekyll clean

# HTML validation
bundle exec rake  # Runs HTMLProofer on _site/

# Image optimization
uv run scripts/optimize-images.py [--dry-run] [--force]
uv run scripts/optimize-images.py --responsive [--sizes 400,800,1200]

# Search engine indexing
npm run submit:all    # Submit URLs to Google + Bing
npm run submit:google
npm run submit:bing

Ruby 3.2.2 via rbenv. Always use rbenv Ruby, not system Ruby.

Architecture

Layout inheritance chain

compress.html → default.html → page.html → post.html
                                          → book_notes.html
                                          → other_notes.html
                                          → posts_all.html

default.html is the main shell — it owns <head>, JSON-LD structured data, Open Graph/Twitter meta tags, dark mode init script, and critical CSS inlining. Everything ultimately wraps in compress.html for HTML minification.

Content types

Config layering

Configs are layered via --config flag. Later files override earlier ones:

Environment-gated behavior

Several things change based on jekyll.environment == "production" (set automatically by GitHub Pages):

/* Micro perf: text rendering and font synthesis */ body{ text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; font-synthesis-weight: none; font-synthesis-style: none; }

@import “pages/home-blog-projects”; @import “pages/page”; @import “pages/post”;

@import “components/author”; @import “components/disqus”; @import “components/footer”; @import “components/header”; @import “components/nav”; @import “components/others”; @import “components/pagination”; @import “components/related”; @import “components/share”; @import “components/side-by-side”; @import “components/social-links”; @import “components/spoiler”; @import “components/toc”; @import “components/books”; @import “components/newsletter”; @import “components/floating-actions”; @import “components/home-hero”; @import “components/tag-filter”; @import “pages/tools”; `

CSS / Dark mode system

The stylesheet compiles from _includes/style.scss, which imports all SCSS partials. The import order matters — _sass/base/variables-css.sass must come first.

Dark mode uses CSS custom properties defined in _sass/base/variables-css.sass under :root (light) and html.dark-mode (dark). Never hardcode colors — always use var(--background-color), var(--text-color), etc. For cases where CSS variables aren’t sufficient, use .dark-mode .component selectors. See docs/DARK_MODE_GUIDE.md for the full variable reference and patterns.

The dark mode toggle is in assets/js/dark-mode.js with localStorage persistence. A blocking inline script in default.html <head> applies the class before first paint to prevent flash.

Custom font: Signifier (woff2), preloaded in <head>.

Newsletter popup

Controlled by show_newsletter_popup in _config.yml. The flag is emitted as a <meta> tag in default.html and read by newsletter.js via window.siteConfig. This flag only controls the JS modal popup, not the inline post newsletter section (`<div class="post-newsletter" id="postNewsletter" data-cta-location="post_footer">

Enjoyed this? Get notified when I post something new.

</div> `).

Front Matter Conventions

Blog posts:

---
title: "Post Title"
layout: post
date: YYYY-MM-DD HH:MM
last_modified_at: YYYY-MM-DD HH:MM  # Bump when substantially revising (signals freshness to Google)
image: /assets/images/filename.webp  # OG image; fallback: image_url → first <img> in content → site avatar
description: "SEO description (used for meta tags, ~150-160 chars)"
excerpt: "Preview text shown in post listings"
tags: [tag1, tag2]
category: blog
author: sameerbajaj
---

Book notes add: book_title, book_author, book_url, book_thoughts, rating (out of 10), date_read, star (featured flag).

Tools (_data/tools.yml): title, description, url, category, launch_date, pinned, image.

Image Handling

CI/CD

GitHub Actions workflows in .github/workflows/:

Documentation

Detailed guides in docs/:

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora