CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Install dependencies (first time or after Gemfile changes)
bundle install
# Serve locally with live reload at http://localhost:4000
bundle exec jekyll serve --livereload
# Production build (output to _site/)
bundle exec jekyll build
# CI build (matches what GitHub Actions runs)
bundle exec appraisal jekyll build --future --config _config_ci.yml,_config.yml
# Create new content
./scripts/new_post.sh "Article Title"
./scripts/new_formation_module.sh "Module Title"
# Generate English translation skeleton from a French file
python scripts/generate_en_translation.py _posts/YYYY-MM-DD-mon-article.md
Alternatively, source setup_aliases.sh to get jekyll_serve, new_article, new_formation_module shorthand aliases.
Architecture
Generator: Jekyll with the Beautiful Jekyll theme (v6.0.1). The theme is loaded as a gem, so most layout/include overrides live in _layouts/ and _includes/ locally.
Site structure (after the refactor):
- Showcase — two flat entries, no dropdown. The homepage (
/,/en/) is the DataStories view; Dev projects live at/projects/dev/(+/en/mirror). Each tile links straight to a deployed application (new tab), never to an internal write-up. The catalogue is_data/showcase.yml, rendered by_includes/showcase_grid.html, styled byassets/css/showcase.css. - Blog (
/blog/,/en/blog/) — the single editorial feed. Everything written lives in_posts/: articles, project write-ups, hackathons. No sub-sections, no thematic split. - Formation IA (
/formation-ia/) — a self-contained mini-site with its own layout, CSS and sub-pages (mini-cours, newsletter, participer, ressources). It is not part of the blog and not in the navbar: it is reached through its showcase tile.
Adding a showcase entry: append to _data/showcase.yml — url (the live app), image, category (dev |
datastories, omit to show only on the homepage), and fr:/en: blocks with title + subtitle. Set internal: true for an on-site target (no new tab). Use label: when the target is not a playable demo (e.g. a code repository). |
Collections (defined in _config.yml):
_posts/— All editorial content, output at/blog/:title/(FR) and/en/blog/<slug>/(EN)_formation_ia/— AI training modules, output at/formation-ia/:path/(unchanged)_projects/— empty, kept declared only so the collection stays available; the showcase uses_data/showcase.yml, not this collection
Listing: _includes/post_list.html is the single source for the blog feed (used by /blog/, /en/blog/ and both homepages); it renders each item through _includes/post_preview.html. Never duplicate listing logic between a page and a layout.
Redirects: URL changes go through jekyll-redirect-from (redirect_from: in front matter). Old published URLs must be kept verbatim there, typos included.
Bilingual (FR/EN) system:
- Default language is French (
lang: frin_config.yml) - Each piece of content has a paired
-envariant withlang: en - FR and EN files share a
translation_keyfront matter field to link them - FR permalinks use
/blog/<slug>/, EN permalinks use/en/blog/<slug>/(explicit in front matter) - Navigation is duplicated in
_data/navigation.ymlunderfr:anden:keys scripts/generate_en_translation.pyauto-generates the EN skeleton (front matter + slug) from a FR source file
Front matter conventions:
# French post
lang: fr
translation_key: my-article # must match EN pair
permalink: /blog/my-article/
# English paired post
lang: en
translation_key: my-article
permalink: /en/blog/my-article/
AI chat widget: configured via mistral_api_url in _config.yml, proxied through a Cloudflare Worker. Widget markup lives in _includes/ai_chat_widget.html, JS in assets/js/.
CI/CD: .github/workflows/ci.yml — builds on Ubuntu with Ruby 3.3, uses appraisal for multi-version testing, uploads the _site/ artifact to GitHub Pages. The _config_ci.yml overlay sets the correct baseurl for the Pages environment.
Content Generation — Traduction EN (_projects/ et _posts/)
Pour traduire une fiche projet ou un article du français vers l’anglais, procéder en deux étapes :
1. Générer la coquille EN
Lancer le script de génération sur le fichier FR source :
python scripts/generate_en_translation.py _posts/YYYY-MM-DD-mon-article.md
# ou
python scripts/generate_en_translation.py _projects/YYYY-MM-DD-mon-projet.md
Le script crée le fichier EN appairé (suffixe -en) avec :
- Le front matter pré-rempli (
lang: en,translation_keyidentique au FR,permalinken/en/...) - Le slug et le titre adaptés
- Le corps du fichier laissé tel quel (en français) pour servir de base à la traduction
2. Traduire le corps en anglais
Ouvrir le fichier EN généré et traduire uniquement le corps Markdown :
- Respecter la structure narrative du fichier FR : conserver l’ordre, les niveaux de titres (
##,###), les listes, les images et les liens. - Adapter le ton pour un public anglophone : éviter la traduction littérale, privilégier une formulation idiomatique et naturelle en anglais.
- Ne pas modifier le front matter :
title,subtitle,permalink,translation_key,lang,feature-image,tags,daterestent ceux générés par le script. - Ne pas modifier les URLs (liens externes, images Cloudinary, ancres internes) : elles doivent rester strictement identiques à celles du fichier FR.
- Conserver les blocs de code, les emojis et les éléments de mise en forme à l’identique.
Content Generation — Fiches projet (_projects/)
Quand on te demande de créer une fiche projet pour ce site, tu dois obligatoirement suivre ces conventions avant d’écrire quoi que ce soit.
Informations Ă collecter si manquantes
- Titre du projet
- Sous-titre (1 phrase de résumé)
- Date de publication (format YYYY-MM-DD, par défaut : date du jour)
- URL image de couverture (Cloudinary de préférence — ne jamais inventer une URL)
- Tags (voir conventions ci-dessous)
- Version EN prévue ? (pour le champ
translation_key)
Frontmatter obligatoire
---
layout: project
title: "Titre du projet"
subtitle: "Une phrase qui résume le projet."
feature-image: "https://res.cloudinary.com/dvlzgmjzb/image/upload/..."
tags: [tag-1, tag-2, tag-3]
author: Héric Libong
date: "YYYY-MM-DD"
lang: fr
translation_key: project-slug-du-projet # omettre si pas de version EN
---
Conventions de tags
- Tout en minuscule, kebab-case :
data-visualisation,formule-1 - 3 Ă 8 tags par projet
- Toujours inclure les langages/outils principaux
- Tags fréquents :
python,javascript,django,fastapi,docker,data-visualisation,dataviz,nlp,scraping,api,formule-1,fastf1,d3js,pandas,github-pages,hackathon
Nommage du fichier
Format strict : YYYY-MM-DD-titre-en-kebab-case.md
Destination : _projects/
Structure narrative du corps
Dans cet ordre :
-
Origine du projet — pourquoi ce projet existe, quel problème il résout. Ton narratif, 2-4 paragraphes. Pas de bullet points.
- Sources de données (si projet data) — liste avec nom en gras
- description courte du rĂ´le de chaque source.
-
Présentation du projet — ce que l’outil fait concrètement. Sous-sections
###autorisées. Captures d’écran si URL fournie. - Stack technique (si applicable) — deux sous-sections :
- Côté données (libs Python, pipeline)
- Côté front (HTML/CSS/JS, framework, hébergement)
-
État du projet — en cours / terminé / archivé + prochaines étapes.
- Liens utiles — démo publique + code source GitHub.
Workflow complet
- Lire le README du projet si fourni
- Collecter les informations manquantes (image, tags, date)
- Produire le fichier directement dans
_projects/avec le bon nom - Confirmer le chemin exact du fichier créé