This guide is built to be handed to an AI assistant, which then walks you through it one step at a time. Claude Code in a terminal, Claude Desktop, and Codex all work. Save this page to your machine, open a fresh assistant session, give it this file, and paste this:
Walk me through the bonus website session one step at a time.
Give me only the current step. Stop after each step and wait for me to say it's done.
Before each step, check whether it's already done on this machine, and skip it if it is.
Tell me what each command does before I run it.
Start at the beginning.
Then work through it together. Tell the assistant when a step is finished, or paste the error when one isn’t.
Assistant: the rules below govern this whole session. They override any default habit of reading a document and summarizing it.
CLAUDE.md or
AGENTS.md records which one; if it does not, ask once and
do not ask again. Where a step below has a ### Claude Code
version and a ### Codex version, deliver only theirs and do
not mention the other exists. Everywhere else the work is identical, so
say “your assistant” rather than assuming Claude. This is about the tool
the learner installs and works in, not about which assistant is reading
this guide.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.
Run this from ~/ai-training, the working directory you
made in Session 2.1.
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.
Two paths. Pick one.
By the end of the session you will have:
<your-username>.github.io.https://<your-username>.github.io within 5–10 minutes
of pushing.~/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.
By the end of the session you will have:
~/ai-training/website-existing/.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).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.
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:
<username>.github.io
is yours the moment the repo exists. No registrar, no nameservers, no
waiting for propagation.pandoc → push. No content management system,
no database.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.
Already done? Run git --version and
gh auth status. If git prints a version and
gh auth status shows you logged in, this step is finished.
Skip to Step 2.
Verify Git is installed:
git --version
What this does. git --version prints
the installed version, confirming Git is on your PATH.
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"
What this does. Git tracks your files as a series of
snapshots called commits. git config --global sets the name
and email attached to every commit you make on this machine, which is
what lets GitHub credit them to your account once you push.
Worth knowing. Because Git keeps every snapshot,
committing before you let an AI edit a file gives you an undo button. If
an edit goes wrong, git restore . throws away the
uncommitted damage and restores every file to the last commit.
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
What this does. brew install gh
installs GitHub’s own command-line tool, which can create repositories,
clone them, and open pull requests without leaving the terminal.
gh auth login connects it to your GitHub account, the same
account your commits will be attributed to. Everything gh
does here, you could also click through on github.com, but running it
from the terminal is what lets an AI assistant drive it too.
Follow the prompts. Pick HTTPS, authenticate via web browser. When
done, gh auth status shows you logged in.
Step 1 was yours. The rest runs through Claude. If you haven’t handed
it this guide yet, follow “How to run this session” at the top. From
inside ~/ai-training, start claude, give it
this file, and add one line so it knows where you are:
Git is configured and gh CLI is authenticated. I'm taking Path <A or B>.
This tells Claude which path you’re on and that Git and GitHub auth are already done, so it can skip straight into the Reference Sections instead of rechecking Step 1.
Claude takes over.
Claude: walk the user through Path A or Path B based on what they said. Peer-tone. Two rules:
<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.Design: this session uses Git as the safety net (Session 2.3’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.
Before any web work:
git --version returns a version.gh auth status shows the user logged in.Already done? Run
gh repo view <username>.github.io, replacing
<username> with yours. If it returns repo details
instead of an error, this step is finished. Skip to Step A2.
In ~/ai-training/:
mkdir -p website
cd website
git init
gh repo create <username>.github.io --public --source=. --remote=origin
What this does. mkdir -p and
cd set up and enter the working folder, same pattern as
Session 2.1. git init turns this folder into the Git
repository your identity from Step 1 will commit to.
gh repo create uses the gh CLI you
authenticated in Step 1 to create the matching GitHub repo and connects
this folder to it as 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
What this does. git remote -v lists the
repo’s remotes, confirming origin points at the GitHub repo
gh repo create just made.
Should show origin pointing at
https://github.com/<username>/<username>.github.io.
Already done? Run
ls website/index.md website/_template.html. If both exist
and you’re happy with them, this step is finished. Skip to Step A3.
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
What this does. Same pandoc-plus-template pattern as
Session 2.3, retargeted to HTML output. open launches the
result in your default browser.
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.
Already done? Open
https://<username>.github.io in a browser, replacing
<username> with yours. If your site is already live
there, this step is finished. Skip to Step A4.
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
What this does. Same echo redirect
pattern as Session 2.1: > creates the file with one
line, >> appends a second line without wiping the
first.
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
What this does. git add stages the
files you want in the next snapshot. git commit saves that
snapshot to your local repository, with the message describing what
changed. git branch -M main names your default branch
main, which is what GitHub expects. git push
uploads your commits to the origin remote, the step that
actually makes them show up on GitHub.
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
What this does. gh repo view --web
opens the repo’s GitHub page in your 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.”
Already done? Run
ls .claude/commands/publish-site.md from
~/ai-training. If it already exists, this step is finished.
Skip straight to using /publish-site.
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
What this does. Same pandoc-build-commit-push loop
as Step A3, chained with && and run with
-C website so it works from any directory.
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.
Already done? Run
ls ~/ai-training/website-existing and
git -C ~/ai-training/website-existing branch --show-current.
If the folder exists and the current branch is already
staging, this step is finished. Skip to Step B2.
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
What this does. gh repo clone downloads
the existing repo the same way gh repo create set one up in
Path A, cloning instead of creating.
git checkout -b staging creates a new branch called
staging and switches to it, so nothing you do next touches
main until you decide to merge it.
Verify the existing repo builds locally — open
index.html in a browser, confirm it looks like the live
site.
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.
Paste this whole block at once. It hands Claude both change descriptions plus the parallel-dispatch instruction in one shot, so it can launch both sub-agents immediately instead of waiting for a follow-up message.
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
What this does.
git diff main..staging --stat lists which files differ
between the two branches without printing the full diff, so you can see
whether design and content stayed in their own files.
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.
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
What this does. cd enters the repo, the
build command is whatever the existing site already uses to turn source
into HTML, and open previews the result in your
browser.
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.
If both changes look right:
git -C website-existing checkout main
git -C website-existing merge staging
git -C website-existing push origin main
What this does. checkout main switches
back to the main branch, merge staging folds the staged
commits into it, and push uploads the merged result to
GitHub the same way Path A’s push did.
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
What this does. cherry-pick takes just
one commit from staging and replays it onto
main, so you keep the change that worked without pulling in
the one that didn’t.
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
What this does. checkout main returns
you to the main branch, and branch -D staging deletes the
staging branch and its commits for good.
Worth knowing. -D force-deletes the
branch even though it has commits that were never merged into
main. That’s fine here, since neither change passed review,
and main itself is never touched, so this only throws away
the experiment, not the published site.
The site is unchanged; nothing was published; the experiment cost you 15 minutes. That’s the value of the staging discipline.
Name these out loud:
<username>.github.io is the magic repo name. No
registrar, no DNS, no waiting. The skill transfers to Netlify, Vercel,
Cloudflare Pages — the plumbing is identical..docx,
retargeted to HTML. The template is one file; iteration is fast.staging; merge to main only after local
preview. The cost of staging is one extra command; the cost of
publishing a broken site is “everyone sees it.”/publish-site as a slash command. The
3-command publish loop becomes one slash command. Friction goes from
“remember the commands” to “type the slash.”Three things to try this week (or month):
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.
Tell the user: “Bonus session is opt-in; feedback helps shape future material if you want to share it.”
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.