if err ≠ nil

a blog about my projects, Kubernetes and Go by Alexej Kubarev

CLAUDE.md

CLAUDE.md

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

Overview

This is a Jekyll-based personal blog and vanity URL host for Go packages, deployed to GitHub Pages at alexejk.io. Ruby version is pinned to 3.4.7 (see .ruby-version).

Commands

# Install dependencies
bundle install

# Serve locally with live reload
bundle exec jekyll serve

# Build static site to _site/
bundle exec jekyll build

Architecture

Content

  • _posts/ — Blog posts in Markdown with YAML front matter. Filename format: YYYY-MM-DD-slug.md. Default layout is post, permalink is /article/:title/.
  • _drafts/ — Unpublished drafts (not included in builds unless --drafts flag is used).
  • about.md, archive.html, index.html — Top-level pages.

Go Vanity URLs

go-imports/ contains one Markdown file per Go package (e.g. go-xmlrpc.md). Each file only needs a repo: front matter key specifying the GitHub repo name. The go-imports layout and permalink: /:basename are applied via _config.yml defaults, so the file go-imports/foo.md becomes alexejk.io/foo and serves the correct go-import and go-source meta tags.

To add a new Go vanity URL, create go-imports/<package-name>.md:

---
repo: <github-repo-name>
---

Optionally add branch: <branch> to override the default (master).

Layouts

  • default.html — Base HTML shell with <head> and <footer> includes.
  • post.html — Blog post layout (extends default).
  • page.html — Generic page layout (extends default).
  • go-imports.html — Minimal HTML that only emits go-import/go-source meta tags and a redirect; no site chrome.

Styling

SCSS partials in _sass/ are compiled via styles.scss. Key partials: _variables.scss, _base.scss, _type.scss, _code.scss, _syntax.scss (Rouge syntax highlighting).

Plugins (active in GitHub Pages)

jekyll-feed (atom.xml), jekyll-seo-tag, jekyll-sitemap, jekyll-relative-links, jekyll-paginate (5 posts/page).

Writing Blog Posts

Use the /blog-post command to create a new post from a rough idea, or to resume one saved in _drafts/. The command is defined in .claude/commands/blog-post.md and orchestrates the full workflow:

  1. Clarify — targeted questions if the idea is too vague (skipped if clear)
  2. Outline — numbered section list shown for approval before any writing
  3. Draft — full post written in the blog’s established voice
  4. Critic review — a separate agent checks the draft for AI slop, vague claims, and voice breaks; feedback is applied before you see the result
  5. Iterate — adjust based on your feedback until satisfied
  6. Save — writes to _posts/YYYY-MM-DD-<slug>.md on approval; promotes and deletes the draft if one existed

Saving and resuming drafts: At any point after the idea is established, say “save draft” to save the current state to _drafts/<slug>.md. Resume later with /blog-post resume <slug> (or just /blog-post resume to see a list). The draft file stores the current phase and notes in front matter keys (_draft_phase, _draft_notes) that Jekyll silently ignores.

Blog voice (summary)

The existing posts establish a clear style. New posts must match it:

  • Opens with personal motivation/context (“While working on… I came across…”)
  • First-person and opinionated throughout — the author has a take
  • Light, dry humor used sparingly
  • Every claim backed by concrete code/config/output
  • ### headers, short paragraphs, no transitional filler
  • Conclusion expresses genuine opinion, not a recap

Post front matter

---
title: "Post Title"
categories: [Go, DevOps]
---

categories uses existing values where possible: Go, DevOps, Kubernetes, Projects, Random. No date, layout, or author fields are needed — these are set by _config.yml defaults.