Date: October 18, 2025 Migrated by: Claude (Anthropic AI Assistant) Duration: ~2 hours
This document chronicles the complete migration of Carlo Ciliberto's GitHub Pages personal website from a custom HTML/CSS/JavaScript implementation to the AcademicPages Jekyll template with automated publication management.
-
Migrated to AcademicPages Template
- Professional academic website template based on Jekyll
- Fork of Minimal Mistakes theme
- Responsive design with mobile support
- Built-in theme support (light/dark modes)
-
Automated Publication Management
- Fetched 74 publications from Google Scholar automatically
- Created reusable Python scripts for future updates
- Publications stored as individual markdown files
- Easy to maintain and update
-
Created Backup
- Original site backed up to
backup-original-sitegit branch - Original files moved to
old_site_backup/directory - No data loss - full rollback capability
- Original site backed up to
-
Automation Scripts Created
fetch_scholar_pubs.py- Fetches publications from Google Scholarsetup_site.py- Converts publications to Jekyll markdown formatUPDATE_PUBLICATIONS.md- User documentation
-
Docker-based Development Environment
- Resolved local Ruby/Jekyll compatibility issues
- Reproducible local preview environment
- Easy to maintain and update
Problem:
LoadError: cannot load such file -- nokogiri/nokogiri
Root Cause:
- System Ruby 2.6 on macOS couldn't load the nokogiri native extension
- Nokogiri is a C-based Ruby gem that needs to match system architecture
- Pre-compiled gem binary (
x86_64-darwin) was incompatible with system - Likely due to macOS system Ruby being outdated or architecture mismatch
Attempts Made:
- ✗
bundle pristine nokogiri- Didn't resolve the issue - ✗ Reinstalling nokogiri locally - Permission errors with system Ruby
- ✗ Using different bundler versions - Still encountered loading errors
Final Solution:
- Used Docker to bypass all local Ruby/gem issues
- Docker provides Ruby 3.2 environment with all dependencies correctly compiled
- Modified
docker-compose.yamlto runbundle installbefore Jekyll
Why This Worked:
- Docker provides a consistent, isolated environment
- Ruby 3.2 in Docker with properly compiled native extensions
- No reliance on system Ruby or local gem installations
Problem:
undefined method `untaint' for "/usr/src/app":String (NoMethodError)
Root Cause:
- Local
Gemfile.lockwas generated with Bundler 1.17.2 - Docker image had Bundler 2.4.19 (newer version)
- Bundler 1.17.2 uses
String#untaintmethod which was removed in Ruby 3.2 - The
untaintmethod was deprecated in Ruby 2.7 and removed in Ruby 3.0+
Solution:
- Deleted old
Gemfile.lockfile - Let Docker regenerate it with compatible Bundler 2.4.19
- New lockfile compatible with Ruby 3.2
Command Used:
rm Gemfile.lock
docker compose up # Regenerates Gemfile.lockLesson Learned:
- Gemfile.lock should be regenerated when changing Ruby versions significantly
- Old bundler versions are incompatible with modern Ruby (3.x)
Problem Sequence:
File to import not found or unreadable: theme/default dark_light
Evolution of Attempts:
-
First Attempt:
site_theme: "default dark"- Error:
File to import not found or unreadable: theme/default dark_light - The template was looking for
theme/default dark_light.scss
- Error:
-
Second Attempt:
site_theme: "default_dark"- Error:
File to import not found or unreadable: theme/default_dark_light - Template appends
_lightsuffix for dual-theme system
- Error:
-
Correct Solution:
site_theme: "default"- The template has a dual-theme system that automatically handles light/dark modes
- Available theme files:
_default_light.scssand_default_dark.scss - Setting
site_theme: "default"allows the theme to switch between both
Available Themes:
default(has_default_light.scssand_default_dark.scss)air(has_air_light.scssand_air_dark.scss)
Lesson Learned:
- AcademicPages uses a dual-theme system with automatic light/dark mode switching
- Don't specify the
_darkor_lightsuffix in configuration - The template handles the theme switching logic internally
User Question: "Why do we need Ruby/Jekyll at all?"
Answer:
Jekyll is the static site generator that GitHub Pages uses by default. Here's why:
-
GitHub Pages Integration:
- GitHub Pages has native Jekyll support built-in
- When you push to your repository, GitHub automatically runs Jekyll
- Converts markdown + templates → complete HTML website
-
Why Not Just HTML?:
- Managing 74 individual publication pages in pure HTML would be tedious
- Jekyll uses templates + markdown = easier maintenance
- Change one template file → affects all publication pages
-
Why Ruby?:
- Jekyll is written in Ruby (historical choice by GitHub)
- Ruby has a rich ecosystem of static site generation tools
- Bundler (Ruby's package manager) handles all dependencies
-
The Workflow:
Markdown files → Jekyll (Ruby) → HTML/CSS/JS → Web Browser -
Local Development:
- Needed to preview the site before pushing to GitHub
- Required running Jekyll locally → needed Ruby environment
- Docker solved this by providing isolated Ruby environment
Key Insight: You don't need to understand Ruby. You just need:
- Python scripts to fetch/format publications (✓ using
uv) - Docker to run Jekyll for local preview (✓
docker compose up) - GitHub Pages to build the production site (✓ automatic)
Compared Templates:
- François-Xavier Briol: Uses AcademicPages ✓
- Benjamin Guedj: Uses AcademicPages ✓
- Marc Deisenroth: Uses Hugo Blox Builder
Decision: AcademicPages
- Same as 2 out of 3 example sites
- Proven in academia
- Simpler than Hugo (no Go toolchain needed)
- Native GitHub Pages support
- Large community and documentation
Alternatives Considered:
- ✗ System Ruby - Too old (2.6), gem conflicts
- ✗ rbenv/rvm - Additional Ruby version manager complexity
- ✗ Homebrew Ruby - Still potential gem conflicts
- ✓ Docker - Isolated, reproducible, no local conflicts
Docker Benefits:
- Same environment as production (Ruby 3.2)
- No conflicts with system Ruby
- Easy to replicate on any machine
- One command:
docker compose up
| File | Purpose |
|---|---|
fetch_scholar_pubs.py |
Fetches publications from Google Scholar using scholarly library |
setup_site.py |
Converts JSON publications to Jekyll markdown files |
UPDATE_PUBLICATIONS.md |
User documentation for updating publications |
CLAUDE.md |
This file - technical documentation of migration |
_publications/*.md |
74 individual publication markdown files |
_pages/about.md |
Updated biography page |
Gemfile.lock |
Regenerated with Bundler 2.4.19 for Ruby 3.2 |
| File | Changes Made |
|---|---|
_config.yml |
- Updated personal information (name, bio, affiliation) - Set theme to "default"- Updated social links (Google Scholar, GitHub) - Fixed avatar path to images/carlo_ciliberto.jpg |
docker-compose.yaml |
Modified command to run bundle install before jekyll serve |
Gemfile |
Temporarily disabled jemoji during troubleshooting (later re-enabled) |
| Source | Destination |
|---|---|
index.html, *.css, *.js, papers/, old/ |
old_site_backup/ |
carlo_ciliberto.jpg |
Copied to images/carlo_ciliberto.jpg |
# 1. Fetch latest publications
uv run python fetch_scholar_pubs.py
# 2. Regenerate publication markdown files
uv run python setup_site.py
# 3. Preview locally
docker compose up
# Visit http://localhost:4000
# 4. Commit and push
git add _publications/ _config.yml
git commit -m "Update publications from Google Scholar"
git push origin master# Start local preview
docker compose up
# Visit http://localhost:4000 in browser
# Make changes to files
# Jekyll auto-regenerates (watch mode enabled)
# Stop server
docker compose downChange Colors/Styling:
- Edit
_sass/theme/_default_dark.scssfor dark mode - Edit
_sass/theme/_default_light.scssfor light mode
Change Navigation:
- Edit
_data/navigation.yml
Update Biography:
- Edit
_pages/about.md
Add Teaching/Talks:
- Create markdown files in
_teaching/or_talks/directories
- System Ruby versions vary by OS
- Native gem compilation is error-prone
- Solution: Use Docker for reproducible environments
- Theme configuration wasn't clearly documented
- Had to inspect SASS files to understand theme system
- Tip: Look at actual theme files in
_sass/theme/
- Lockfiles are version-specific
- Don't commit lockfiles across major Ruby version changes
- Regenerate when moving between environments
- Google Scholar API eliminated manual publication entry
- Python scripts (uv) + Jekyll (Docker) = good separation of concerns
- Update 74 publications in < 1 minute vs. hours of manual work
- Despite local complexity, GitHub Pages builds flawlessly
- Their servers have correct Ruby/Jekyll setup
- Local preview is optional but helpful
Check:
- Image file exists in
images/directory _config.ymlhas correct path:avatar: "images/carlo_ciliberto.jpg"- Restart Docker container:
docker compose down && docker compose up
Try:
# Remove all containers and rebuild
docker compose down
docker compose up --buildCheck:
- Run
uv run python fetch_scholar_pubs.py - Verify
/tmp/scholar_publications.jsonwas created - Run
uv run python setup_site.py - Check
_publications/directory has files - Restart Jekyll:
docker compose down && docker compose up
Verify:
_config.ymlhassite_theme: "default"(not"default_dark")- Check browser console for CSS errors
- Clear browser cache
- Check
_sass/theme/directory has theme files
Option 1 - Git Branch:
git checkout backup-original-site
git push origin backup-original-site:master --forceOption 2 - Local Backup:
cp -r old_site_backup/* .
git add -A
git commit -m "Rollback to original site"
git push| Task | Time |
|---|---|
bundle install (first time) |
~30 seconds |
bundle install (cached) |
~5 seconds |
| Jekyll build (74 publications) | ~4 seconds |
| Jekyll incremental rebuild | ~1 second |
| Metric | Value |
|---|---|
| Docker image size | ~500 MB |
Generated _site folder |
~15 MB |
| Publication JSON | ~97 KB |
-
Automated Scheduled Updates
- Set up GitHub Actions to run
fetch_scholar_pubs.pyweekly - Auto-commit and push if new publications found
- Set up GitHub Actions to run
-
Publication Metadata Enrichment
- Add DOI links automatically
- Fetch abstracts if missing
- Add paper thumbnails/figures
-
Theme Customization
- Create custom color scheme
- Add UCL branding
- Customize fonts
-
Additional Sections
- Add blog posts
- Add project showcases
- Add teaching materials
If you encounter issues:
- Check this documentation first
- Review
UPDATE_PUBLICATIONS.mdfor user-facing instructions - Consult the AcademicPages Issues
- For publication fetching: Check Scholarly Library Issues
End of Documentation
This migration was completed successfully with all goals achieved. The site is now easier to maintain, professionally designed, and fully automated for publication updates.