Bonus session: Publish a personal website

About 60 minutes. Optional — this session covers a workflow (GitHub Pages publishing) that isn’t a recurring weekly cadence. Skip if you don’t want a personal site or already have one you’re happy with.

Open a Claude Code session in ~/ai-training and hand it this guide:

Read the file at /Users/<you>/ai-training/bonus-website-guide.md (or wherever you saved it) and walk me through the bonus website session.
I've completed the curriculum's core sessions (2.1 through 2.10).

Posture: public, synthetic, or personal data only. A personal website is — by definition — public. The content is yours; the destination is the open web. Don’t put anything on the site you wouldn’t put on your own LinkedIn.


Practice task

Two paths. Pick one.

Path A — Build from scratch (most users)

By the end of the session you will have:

  1. A GitHub repository named <your-username>.github.io.
  2. A single-page personal site in markdown — name, one-paragraph bio, three links — built with pandoc and a minimal template.
  3. The site live at https://<your-username>.github.io within 5–10 minutes of pushing.
  4. A local ~/ai-training/website/ directory mirroring the repo, where you’ll edit going forward.

A real, public, free, DNS-free personal website. The whole thing fits in one HTML file and one GitHub repo.

Path B — Stage edits to an existing site (users who already have a site)

By the end of the session you will have:

  1. A clone of your existing site’s repo at ~/ai-training/website-existing/.
  2. A staging branch with one design change and one content change made by parallel sub-agents (one focused on design — CSS, layout, typography; one focused on content — copy, structure).
  3. A local preview of the staged changes.
  4. A merge of the changes back to main — or, if the changes need iteration, a clean revert and a clear note on what to try differently.

A production version of the path-B flow manages a personal-academic site as a GitHub Pages mirror where design changes (CSS, layout) and content changes (new papers, blog posts, bio updates) are dispatched to separate sub-agents in parallel. Each agent operates on its own branch; the merge is the user’s decision. The split keeps “I want this section restyled” from accidentally rewriting the bio at the same time.


Why GitHub Pages, not a hosting platform

Personal-website tutorials usually push you to a hosting platform — Squarespace, Wix, Webflow, Netlify, Vercel. Each has good arguments. None is the right starting move.

GitHub Pages wins for the first site:

  1. Zero DNS. <username>.github.io is yours the moment the repo exists. No registrar, no nameservers, no waiting for propagation.
  2. Zero cost. Free for public repos, indefinitely.
  3. Source-of-truth is markdown in a Git repo. Iteration is pandoc → push. No content management system, no database.
  4. The skill transfers. Once you can commit + push to a GitHub Pages site, you can commit + push to a Netlify/Vercel/Cloudflare Pages site or any other static host. The plumbing is identical.
  5. No vendor lock-in. Your site is just HTML files. Move them anywhere; nothing breaks.

The trade-off: GitHub Pages doesn’t do server-side anything. No databases, no auth, no forms. For a personal site, you don’t need any of that.

If at some point you want a custom domain, GitHub Pages supports that with one DNS record. You don’t need it on day one.


Step 1: Set up Git (5 minutes — skip if you already use Git)

Verify Git is installed:

git --version

If not, brew install git. Then set your identity:

git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"

The email should match the email on your GitHub account so commits get attributed to you on GitHub.

If you don’t have a GitHub account, create one at github.com — free. Pick a username thoughtfully; it becomes part of your site URL (<username>.github.io).

Set up GitHub auth via the gh CLI:

brew install gh
gh auth login

Follow the prompts. Pick HTTPS, authenticate via web browser. When done, gh auth status shows you logged in.


Step 2: Hand Claude this guide

From inside ~/ai-training, start claude and paste:

Read the file at /Users/<you>/ai-training/bonus-website-guide.md (or wherever you saved it) and walk me through the Reference Sections.
Git is configured and gh CLI is authenticated. I'm taking Path <A or B>.

Claude takes over.


Reference Sections

Claude: walk the user through Path A or Path B based on what they said. Peer-tone. Two rules:

  1. No real bookings of domain names today. If the user wants a custom domain (anything other than <username>.github.io), the right move is to ship the github.io URL first and add the custom domain in a follow-up. Don’t combine the two.
  2. For Path B, dispatch the design and content sub-agents in parallel via the Task tool. The whole point of B is independent operation; don’t run them sequentially.

Design: this session uses Git as the safety net (Session 2.5’s preview formalized today), pandoc round-trip (Session 2.3 generalized to HTML output), and sub-agents (Session 2.6 + 2.7 pattern applied to a different concern). It’s the curriculum’s hosting capstone.


Confirm the setup

Before any web work:

  1. git --version returns a version.
  2. gh auth status shows the user logged in.
  3. The user has a GitHub username they’re happy with (or has created one).
  4. The user has chosen Path A or Path B.

Path A — Build from scratch

Step A1 — Initialize the repo (5 minutes)

In ~/ai-training/:

mkdir -p website
cd website
git init
gh repo create <username>.github.io --public --source=. --remote=origin

The <username>.github.io repo name is magic — GitHub Pages auto-publishes the contents of this repo to that URL with no further config.

Verify:

git remote -v

Should show origin pointing at https://github.com/<username>/<username>.github.io.


Step A2 — Write the site (15 minutes)

A personal site is one page. Three things on it: who you are, what you do, where to find you. Resist the urge to add more on day one.

Create website/index.md:

---
title: <Your name>
---

# <Your name>

<One paragraph. What you do, what you're working on, who'd benefit
from contacting you. Three to five sentences. No bullet points.>

## Recent work

- [<Project / paper / talk>](<URL>) — one-line description.
- [<Project / paper / talk>](<URL>) — one-line description.
- [<Project / paper / talk>](<URL>) — one-line description.

## Contact

- Email: <email>
- <other channel>: [<handle>](<URL>)

Claude: build this with the user as a real conversation. Push back on hand-wavy phrasings. “I work in tech” is too vague; “I write about distributed systems and run a small consultancy” is workable. The bio is the part that takes longest; don’t rush it.

Now a minimal HTML template at website/_template.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$title$</title>
<style>
  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
         Helvetica, Arial, sans-serif; line-height: 1.55;
         max-width: 640px; margin: 60px auto; padding: 0 20px;
         color: #1a1a1a; background: #fff; }
  h1 { font-size: 32px; margin-bottom: 8px; font-weight: 600; }
  h2 { font-size: 18px; margin-top: 36px; font-weight: 600;
       color: #555; }
  p { margin: 12px 0; }
  a { color: #0366d6; text-decoration: none; }
  a:hover { text-decoration: underline; }
  ul { padding-left: 20px; }
  li { margin: 8px 0; }
</style>
</head>
<body>
$body$
</body>
</html>

Build:

pandoc website/index.md -s --template=website/_template.html -o website/index.html
open website/index.html

The site opens in a browser as a local file. Read it together. Iterate index.md and re-run pandoc until the page is what the user wants.

Claude: the template is loadbearing but boring. The first version of any personal site should be ugly-fast rather than slow-pretty. Resist the temptation to write more CSS today.


Step A3 — Publish (5 minutes)

Add a .gitignore so the markdown source stays out of the published site only if you want HTML-only published. For first launch, push everything:

echo "*.swp" > website/.gitignore
echo "*.bak" >> website/.gitignore

Commit and push:

cd website
git add index.md _template.html index.html .gitignore
git commit -m "Initial personal site"
git branch -M main
git push -u origin main

GitHub Pages auto-publishes the repo’s main branch root. Within 1–5 minutes, https://<username>.github.io serves the site.

gh repo view --web

opens the GitHub repo in a browser. The “Pages” section in repo settings shows the live URL once published. Click it; the live site loads.

Tell the user: “That’s a real, public, free personal website. The URL is yours. You can give it to people.”


Step A4 — Iteration loop (5 minutes)

The publish loop from here on is three commands:

pandoc website/index.md -s --template=website/_template.html -o website/index.html
git -C website add . && git -C website commit -m "<what changed>"
git -C website push

Wait 1–2 minutes; the live site updates.

Save this as a slash command at .claude/commands/publish-site.md:

Run the website rebuild and push:

  cd ~/ai-training/website
  pandoc index.md -s --template=_template.html -o index.html
  git add index.html
  if git diff --cached --quiet; then
      echo "No HTML changes; nothing to publish."
      exit 0
  fi
  git commit -m "Site update"
  git push

Then tell me when the push completes.

Now /publish-site from any Claude session in ~/ai-training/ re-publishes.


Path B — Stage edits to an existing site

Step B1 — Clone and branch (3 minutes)

Clone the existing site’s repo into ~/ai-training/:

cd ~/ai-training
gh repo clone <user>/<existing-site-repo> website-existing
cd website-existing
git checkout -b staging

Verify the existing repo builds locally — open index.html in a browser, confirm it looks like the live site.


Step B2 — Dispatch parallel sub-agents (15 minutes)

In Claude:

Two changes to make to this site:

  1. Design change: <what the user wants restyled — e.g.
     "tighten line-height, larger title, narrower content width">
  2. Content change: <what the user wants edited — e.g.
     "add a new paper to the Recent Work section, update bio
     to reflect role change">

Dispatch TWO sub-agents IN PARALLEL using the Task tool, with
distinct prompts:

Agent A — design (model: sonnet)
  Prompt: "You are working in /Users/<you>/ai-training/website-existing
  on the staging branch. Make ONLY the design change described:
  <design change>. Edit CSS / template / layout files. Do NOT touch
  content files (index.md, posts/, content/). When done, return:
  list of files modified, a one-paragraph summary of what changed,
  and any decisions you made that the user should review."

Agent B — content (model: sonnet)
  Prompt: "You are working in /Users/<you>/ai-training/website-existing
  on the staging branch. Make ONLY the content change described:
  <content change>. Edit content / markdown / data files. Do NOT
  touch CSS, templates, or layout. When done, return: list of files
  modified, a one-paragraph summary of what changed, any decisions
  you made that the user should review."

Wait for both to complete, then summarize what each did.

Claude: actually dispatch both in parallel. The whole point of the split is independent operation. Sequential dispatch loses the speedup AND introduces accidental coupling.

Each agent commits its changes on the staging branch. Read the summaries. The split should be visible in the diffs:

git -C website-existing diff main..staging --stat

Design changes touch CSS / templates; content changes touch markdown. If the diff shows design files in the content commits or vice versa, the split broke — re-dispatch the offending agent with a tighter scope.


Step B3 — Local preview (5 minutes)

Build locally (depends on the existing site’s build system; if pandoc-based, same as Path A):

cd website-existing
<existing build command>
open _site/index.html  # or wherever build output lands

Read the staged version. Both changes should be visible. If something looks wrong, tell Claude what — Claude either revises the relevant agent’s work or drops the change.


Step B4 — Merge or revert (2 minutes)

If both changes look right:

git -C website-existing checkout main
git -C website-existing merge staging
git -C website-existing push origin main

Site updates within minutes.

If only one change is right:

git -C website-existing checkout main
git -C website-existing cherry-pick <commit-hash-of-the-good-change>
git -C website-existing push origin main

If neither is right, drop the staging branch entirely and start over:

git -C website-existing checkout main
git -C website-existing branch -D staging

The site is unchanged; nothing was published; the experiment cost you 15 minutes. That’s the value of the staging discipline.


Micro-skills introduced

Name these out loud:


Wrapping up the bonus session

Three things to try this week (or month):

  1. Iterate on the site once a week for a month. A new line in the bio, a new link, a small CSS tweak. The publish loop should feel like a 30-second move; if it’s not, something in your setup is wrong (probably auth or working directory) — fix it now while it’s fresh.
  2. Add one piece of content. A blog post, a paper PDF link, a presentation. Site that updates is more valuable than a static one.
  3. Resist the redesign. The first version is ugly; that’s correct. Wait three months before any major redesign. Most early redesigns are tinkering for its own sake.

Feedback.

The user submits feedback at https://docs.google.com/forms/d/e/1FAIpQLSfsdkBKr6WCM_EZR3_0lXCgwjlCfINqgCS2rUbi7crKPewriw/viewform.

Claude: paste the URL into chat. The form mirrors the questions below. Collect answers conversationally first, then have the user click through and submit.

  1. On a 1–5 scale, how useful did this session feel?
  2. Did GitHub Pages feel like the right starting platform, or did it feel under-featured?
  3. The pandoc + template approach — does it match how you’d want to maintain a site, or do you want a heavier framework?
  4. (Path A) Going from “no site” to “live site” in one session — did it click, or did the publish step feel unstable?
  5. (Path B) The design/content split via parallel sub-agents — did the agents stay in their lanes, or did the split feel artificial?
  6. What confused you most this session?
  7. Anything you’d want a follow-up bonus session to cover (custom domain, a blog system, comments, analytics)?

Tell the user: “Bonus session is opt-in; feedback helps shape future material if you want to share it.”


Good to know

Personal sites should look unfinished. A site that’s “done” is a site that’s stale. Visible incrementalism — “added a new paper this week” — beats a frozen artifact.

HTML and CSS are not scary. A personal site needs maybe 30 lines of CSS to look fine. You don’t need a framework, a build system, or a theme. The Path A template above is enough.

Custom domains are a follow-up, not a launch step. Get the github.io URL working first. Add a custom domain (e.g. yourname.com) later — it’s one DNS record at the registrar plus one file in the repo. Don’t combine the two.

Don’t move to a heavyweight platform. “I want to be able to edit my site from my phone” is the path that ends with a Wordpress install, six plugins, and a year of maintenance. The markdown + Git pattern is editable from anywhere with a text editor. Resist.

Domain and email are separate decisions. Owning yourname.com doesn’t mean you need you@yourname.com. Buying email hosting is a separate purchase; most people don’t need it.

The skill transfers. Once you can commit + push to GitHub Pages, you can do the same with any static-hosting platform. Netlify, Vercel, Cloudflare Pages — the workflow is identical. Pick GitHub Pages today; pick whichever you want for the next site.