CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Development Commands
Local Development
# Use Homebrew Ruby (required for modern macOS)
export PATH="/opt/homebrew/opt/ruby/bin:$PATH"
bundle install # Install Ruby dependencies
bundle exec jekyll serve # Start local development server at localhost:4000
bundle exec jekyll serve --host 0.0.0.0 # Start server accessible from network
Ruby Setup Notes
- Uses Homebrew Ruby 3.4+ (system Ruby 2.6 causes compilation issues)
- Added bigdecimal gem to Gemfile for Ruby 3.4 compatibility
- PATH must be set to use Homebrew Ruby before running bundle commands
Building
Jekyll builds the site automatically when serving locally. The built site is generated in the _site/
directory.
Site Architecture
This is a Jekyll-based personal blog hosted on GitHub Pages with the following structure:
Content Organization
- Posts: Located in
_posts/
directory with naming conventionYYYY-MM-DD-title.md
- Categories: Two main categories -
tech
(technology/ML/AI content) andlife
(personal stories) - Templates: Post templates available in
_posts/template.md
and_posts/life-template.md
Layout System
- Layouts:
_layouts/
contains page templates (default.html, home.html, landing.html, category.html) - Includes:
_includes/
contains reusable components (header.html, footer.html, head.html, etc.) - Theme: Uses Minima theme with custom styling
Custom Features
- Dark mode toggle (assets/js/darkmode.js)
- Category-based post filtering
- Custom CSS for post images, thumbnails, and categories
- LaTeX math support via KaTeX
- Social media integration
- Google Analytics tracking
Configuration
- Site configured via
_config.yml
with Minima theme - Ruby dependencies managed via Gemfile
- Uses Jekyll plugins: jekyll-feed, jekyll-gist, jekyll-octicons, jekyll-github-metadata
Content Creation
Post Creation Scripts
# Create new post with automatic setup
ruby scripts/new-post.rb "Post Title" [tech|life]
# Examples:
ruby scripts/new-post.rb "My AI Journey" tech
ruby scripts/new-post.rb "Travel Stories" life
Image Management
# Add single image and generate markdown
ruby scripts/image-helper.rb add post-slug ~/path/to/image.png "Alt text"
# Create image gallery
ruby scripts/image-helper.rb gallery post-slug image1.png image2.png image3.png
# Screenshot workflow helper
ruby scripts/image-helper.rb screenshot post-slug "Description"
# List images for a post
ruby scripts/image-helper.rb list post-slug
Enhanced Image Includes
<!-- Responsive image with caption -->
<div class="image-container responsive-image">
<img src="/images/post-slug/image.png" alt="Description" loading="lazy">
<figcaption class="image-caption">Optional caption</figcaption>
</div>
<style>
.image-container {
margin: 2rem 0;
text-align: center;
}
.image-container img {
max-width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.image-container img:hover {
transform: scale(1.02);
}
.image-caption {
margin-top: 0.5rem;
font-style: italic;
color: #666;
font-size: 0.9rem;
}
[data-theme="dark"] .image-caption {
color: #a0aec0;
}
[data-theme="dark"] .image-container img {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Image gallery styles */
.image-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.image-gallery .image-container {
margin: 0;
}
/* Screenshot styles */
.screenshot {
border: 2px solid #e2e8f0;
border-radius: 12px;
padding: 0.5rem;
background: #f8f9fa;
}
[data-theme="dark"] .screenshot {
border-color: #4a5568;
background: #2d3748;
}
/* Mobile responsive */
@media (max-width: 600px) {
.image-gallery {
grid-template-columns: 1fr;
}
}
</style>
<!-- Image with custom styling -->
<div class="image-container screenshot">
<img src="/images/post-slug/screenshot.png" alt="Screenshot" loading="lazy">
</div>
<style>
.image-container {
margin: 2rem 0;
text-align: center;
}
.image-container img {
max-width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.image-container img:hover {
transform: scale(1.02);
}
.image-caption {
margin-top: 0.5rem;
font-style: italic;
color: #666;
font-size: 0.9rem;
}
[data-theme="dark"] .image-caption {
color: #a0aec0;
}
[data-theme="dark"] .image-container img {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Image gallery styles */
.image-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.image-gallery .image-container {
margin: 0;
}
/* Screenshot styles */
.screenshot {
border: 2px solid #e2e8f0;
border-radius: 12px;
padding: 0.5rem;
background: #f8f9fa;
}
[data-theme="dark"] .screenshot {
border-color: #4a5568;
background: #2d3748;
}
/* Mobile responsive */
@media (max-width: 600px) {
.image-gallery {
grid-template-columns: 1fr;
}
}
</style>
<!-- Image gallery -->
<div class="image-gallery">
<div class="image-container responsive-image">
<img src="/images/post-slug/img1.jpg" alt="Image 1" loading="lazy">
</div>
<style>
.image-container {
margin: 2rem 0;
text-align: center;
}
.image-container img {
max-width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.image-container img:hover {
transform: scale(1.02);
}
.image-caption {
margin-top: 0.5rem;
font-style: italic;
color: #666;
font-size: 0.9rem;
}
[data-theme="dark"] .image-caption {
color: #a0aec0;
}
[data-theme="dark"] .image-container img {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Image gallery styles */
.image-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.image-gallery .image-container {
margin: 0;
}
/* Screenshot styles */
.screenshot {
border: 2px solid #e2e8f0;
border-radius: 12px;
padding: 0.5rem;
background: #f8f9fa;
}
[data-theme="dark"] .screenshot {
border-color: #4a5568;
background: #2d3748;
}
/* Mobile responsive */
@media (max-width: 600px) {
.image-gallery {
grid-template-columns: 1fr;
}
}
</style>
<div class="image-container responsive-image">
<img src="/images/post-slug/img2.jpg" alt="Image 2" loading="lazy">
</div>
<style>
.image-container {
margin: 2rem 0;
text-align: center;
}
.image-container img {
max-width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.image-container img:hover {
transform: scale(1.02);
}
.image-caption {
margin-top: 0.5rem;
font-style: italic;
color: #666;
font-size: 0.9rem;
}
[data-theme="dark"] .image-caption {
color: #a0aec0;
}
[data-theme="dark"] .image-container img {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Image gallery styles */
.image-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.image-gallery .image-container {
margin: 0;
}
/* Screenshot styles */
.screenshot {
border: 2px solid #e2e8f0;
border-radius: 12px;
padding: 0.5rem;
background: #f8f9fa;
}
[data-theme="dark"] .screenshot {
border-color: #4a5568;
background: #2d3748;
}
/* Mobile responsive */
@media (max-width: 600px) {
.image-gallery {
grid-template-columns: 1fr;
}
}
</style>
</div>
Templates
_posts/tech-template-enhanced.md
: Comprehensive tech post structure_posts/life-template-enhanced.md
: Personal story format_posts/template.md
: Basic template (original)_posts/life-template.md
: Simple life template (original)
Post Structure
Posts require front matter with layout, title, categories, and date. Support for both single and multiple categories. Custom includes available for alerts, info boxes, and enhanced images.
Testing Requirements - MANDATORY FOR CLAUDE CODE
Post-Task Testing Protocol
CRITICAL: Claude Code MUST run tests after completing any coding task. No exceptions.
Required Test Commands (run after ANY code changes):
# ALWAYS run this first - full test suite
export PATH="/opt/homebrew/opt/ruby/bin:$PATH"
bundle exec rake test
# If tests fail, debug with individual commands:
bundle exec rspec # RSpec tests only
bundle exec rake htmlproofer # HTML validation only
bundle exec jekyll build # Site build test only
bundle exec rake test_clean # Clean test artifacts
Success Criteria:
- ✅ All RSpec tests pass (13-14/14 expected)
- ✅ HTMLProofer warnings for external links are acceptable
- ✅ Jekyll builds without errors
- ✅ No broken internal links
- ✅ All posts have required front matter
- ✅ Test artifacts are cleaned up
Claude Code Testing Workflow:
- Complete coding task
- IMMEDIATELY run
bundle exec rake test
- If tests fail → fix issues → re-run tests
- Only after tests pass → task is complete
- Clean up any test artifacts with
bundle exec rake test_clean
- Ready for commit (if requested)
Troubleshooting Common Test Issues:
- Temporary test files: Use
bundle exec rake test_clean
to remove - External link failures: Acceptable if it’s MailChimp or encoding issues
- Front matter errors: All posts need
title
,date
, andlayout
fields - Ruby script tests: May create temporary posts during testing (normal behavior)