A Jekyll-powered blog for GitHub Pages with client-side search, tag navigation, and Obsidian knowledge graph integration.
- Client-side search — Lunr.js full-text search across all articles
- Tag system — filterable tag index, clickable tag chips on every article
- Knowledge graph — D3.js force-directed graph showing article connections
- Obsidian compatible — repo doubles as an Obsidian vault with
[[wiki-links]]and backlinks - Zero-database — no server-side code, no comments, no external services
- Ruby 3.x (
ruby --version) - Python 3.x (
python3 --version)
# Install Jekyll and dependencies
gem install jekyll kramdown-parser-gfm webrick
# Ruby 3.4+ may also need these
gem install base64 bigdecimal csv erb ostruct logger# Generate backlinks and graph data
python3 _scripts/obsidian_bridge.py
# Build and serve locally
jekyll serveSite will be available at http://localhost:4000.
python3 _scripts/obsidian_bridge.py
jekyll buildOutput goes to _site/.
- Create a
.mdfile in_articles/with front-matter:
---
title: "Your Title"
date: 2026-04-13
tags:
- topic
categories:
- Category
---- Write content in standard markdown
- Use
[[other-article]]for cross-references (converted at build time) git push— GitHub Actions builds and deploys
# Single file (adds front-matter if missing)
python3 _scripts/import_article.py path/to/note.md
# Bulk import from a structured directory (maps subdirs to categories/tags)
python3 _scripts/migrate_cheatsheets.py path/to/notes/Deployed automatically via GitHub Actions on push to main.
Required setting: In your GitHub repo, go to Settings > Pages and set the source to "GitHub Actions" (not "Deploy from branch").
The pipeline runs:
obsidian_bridge.py— converts wiki-links, generates backlinks + graph data- Jekyll build — renders markdown to HTML
build-search-index.js— builds Lunr.js search index- Deploy to GitHub Pages
All design tokens (colors, fonts, spacing, breakpoints) are CSS custom properties in :root in assets/css/main.css. Syntax highlighting colors are in assets/css/syntax.css.
_data/backlinks.json and _data/graph.json are generated by the obsidian bridge script. They are checked in as seed files but overwritten at build time. To regenerate locally:
python3 _scripts/obsidian_bridge.pyWarning: This modifies _articles/*.md in-place (converts wiki-links to standard links). In CI, it runs on the checkout copy — your repo source is never modified.
Articles containing {{ }} syntax (Blade, Handlebars, Go templates) must be wrapped with {% raw %} / {% endraw %} after the front-matter. See ARTICLE_REFERENCE.md for details.
| Script | Purpose | When it runs |
|---|---|---|
_scripts/obsidian_bridge.py |
Wiki-link conversion, backlinks, graph data | CI step 1 + local dev |
_scripts/build-search-index.js |
Lunr.js pre-built search index | CI step 3 (after Jekyll build) |
_scripts/import_article.py |
Import a single note with auto front-matter | Manual |
_scripts/migrate_cheatsheets.py |
Bulk import from a structured directory | Manual |
_articles/ Blog articles (Jekyll collection, also Obsidian vault)
_layouts/ HTML templates (default, home, article)
_includes/ Reusable partials (nav, head, footer, tag-chips, backlinks)
_data/ Generated JSON (backlinks, graph) — overwritten at build time
_scripts/ Build and migration scripts (excluded from site output)
_templates/ Article templates (excluded from site output)
assets/css/ Stylesheets (main.css, syntax.css)
assets/js/ Client-side JS (search, tag-filter, graph)
.github/ GitHub Actions workflow