From 389ac2e460c0e578b0758cf58b9fcfeb61c45add Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 22 Jun 2026 23:21:09 -0400 Subject: [PATCH] style(no-slop): remove every em-dash + banned words across all modules + capstone Apply the no-ai-slop standard (now binding in AGENTS.md): the em-dash character is banned outright (restructured, not blind-replaced), plus the banned word/phrase list (delve, leverage, robust, seamless, truly, unlock, etc.). 0 em-dashes remain in modules + capstone; the only "robust" left is the planted M10 ai-change.patch trap. Module H1 titles use a colon separator. All deliberate teaching devices preserved; labs compile/parse (py/sh/yaml/json); no junk. AGENTS.md updated with the hard no-slop rules. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT --- AGENTS.md | 15 +- capstone/README.md | 20 +-- modules/01-the-copy-paste-problem/README.md | 32 ++-- .../lab/starter/README.md | 8 +- .../lab/starter/cli.py | 2 +- .../README.md | 32 ++-- .../lab/gitignore-starter | 4 +- .../03-version-control-for-words/README.md | 68 ++++---- .../lab/adr-template.md | 12 +- .../lab/runbook-template.md | 6 +- .../README.md | 112 ++++++------ .../lab/verify.sh | 4 +- modules/05-commit-the-ai-config/README.md | 50 +++--- .../lab/instructions-file-starter.md | 12 +- .../README.md | 74 ++++---- .../lab/make-conflict.sh | 4 +- .../README.md | 100 +++++------ .../lab/agent-a-prompt.md | 2 +- .../lab/agent-b-prompt.md | 2 +- .../lab/cleanup-worktrees.sh | 2 +- .../lab/setup-worktrees.sh | 2 +- modules/08-remotes-and-hosting/README.md | 132 +++++++------- .../lab/verify-backup.sh | 8 +- .../09-issues-and-the-task-layer/README.md | 106 ++++++------ .../lab/example-issues.md | 32 ++-- .../lab/issue-template.md | 10 +- .../README.md | 14 +- .../lab/ai-diff-review-checklist.md | 16 +- .../lab/tasks-app/cli.py | 2 +- .../lab/tasks-app/tasks.py | 2 +- .../README.md | 62 +++---- .../lab/issue.md | 4 +- .../lab/pr-body.md | 4 +- .../12-revert-reset-and-recovery/README.md | 102 +++++------ .../lab/bad-clear-snippet.py | 4 +- modules/13-testing-in-the-ai-era/README.md | 44 ++--- .../lab/tasks-app/README.md | 10 +- .../lab/tasks-app/tasks.py | 2 +- modules/14-continuous-integration/README.md | 66 +++---- .../lab/ci-starter.yml | 8 +- .../lab/gitlab-ci-starter.yml | 6 +- .../lab/test_tasks.py | 4 +- modules/15-security-scanning/README.md | 104 +++++------ .../15-security-scanning/lab/ci-security.yml | 4 +- modules/15-security-scanning/lab/config.py | 8 +- .../15-security-scanning/lab/requirements.txt | 6 +- .../15-security-scanning/lab/security-scan.sh | 8 +- .../README.md | 70 ++++---- .../lab/Dockerfile | 12 +- .../lab/dockerignore-starter | 8 +- .../README.md | 52 +++--- .../lab/starter/.env.example | 2 +- .../lab/starter/sync.py | 4 +- .../README.md | 102 +++++------ .../lab/cd-starter.yml | 6 +- .../lab/deploy.sh | 12 +- .../lab/serve.py | 4 +- .../README.md | 112 ++++++------ .../lab/inspect-runner.sh | 10 +- .../lab/whoami-runner.yml | 12 +- .../README.md | 22 +-- .../lab/tasks_mcp_server.py | 10 +- .../README.md | 24 +-- .../lab/add-command-skill.md | 20 +-- .../lab/tasks-app/cli.py | 2 +- .../README.md | 88 +++++----- .../lab/README.md | 8 +- .../lab/audit.sh | 8 +- .../lab/suspicious-skill/SKILL.md | 2 +- .../lab/suspicious-skill/tools/sync.py | 6 +- .../README.md | 78 ++++----- .../lab/orient.py | 20 +-- .../lab/skills/map-this-repo.md | 4 +- .../lab/skills/safe-change.md | 14 +- modules/24-assistive-agents/README.md | 74 ++++---- .../lab/ai-review.sample.json | 4 +- .../24-assistive-agents/lab/label-taxonomy.md | 32 ++-- .../24-assistive-agents/lab/review-rubric.md | 6 +- modules/24-assistive-agents/lab/reviewer.py | 8 +- .../24-assistive-agents/lab/sample-issue.md | 2 +- modules/24-assistive-agents/lab/triage.py | 14 +- modules/25-autonomous-agents/README.md | 62 +++---- modules/25-autonomous-agents/lab/.gitignore | 6 +- .../25-autonomous-agents/lab/agent-job.yml | 20 +-- .../25-autonomous-agents/lab/agent_runner.py | 42 ++--- .../lab/issue-delete-command.md | 6 +- .../README.md | 162 +++++++++--------- .../lab/agent-prompts/agent-42-count.md | 8 +- .../lab/agent-prompts/agent-43-docs.md | 8 +- .../lab/agent-prompts/agent-44-clear.md | 4 +- .../lab/cleanup.sh | 6 +- .../lab/fan-out.sh | 4 +- .../lab/orchestration-plan.md | 14 +- .../lab/status.sh | 2 +- modules/27-evals/README.md | 98 +++++------ .../lab/candidates/swapped_model/tasks.py | 4 +- modules/27-evals/lab/eval_set.py | 2 +- modules/27-evals/lab/llm_judge.py | 4 +- modules/27-evals/lab/run_eval.py | 4 +- 99 files changed, 1324 insertions(+), 1315 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 026dca1..ee5c348 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -61,9 +61,18 @@ then use a calculator. Direct, concrete, rigorous. Reframe ops instincts the reader already has toward AI-assisted work. No motivational filler. When in doubt, show the command and what goes wrong without it. -**No slop.** Don't write like an AI. Avoid "prose" (say "writing", "words", or "docs"), "unlock", -"leverage" as filler, "delve", "dive in", "seamless", "in today's fast-paced", "it's worth noting". -Don't lean on em-dashes — at density they read as a machine tell; vary the punctuation. +**No slop (hard rules).** Don't write like an AI. + +- **No em-dash character (`—`) anywhere.** Use a semicolon, a period, a comma, or restructure the + sentence. This is absolute; self-check every edit by searching for `—` and removing each one. +- **Banned words:** "prose" (say "writing"/"words"/"docs"), delve, leverage, utilize, foster, + bolster, underscore, unveil, streamline, robust, comprehensive, pivotal, seamless, significantly, + extremely, truly, unlock, "dive in". +- **Banned openers/transitions:** Furthermore, Moreover, That being said, In today's world, + It's worth noting, When it comes to. +- No hollow "this is important" statements, no intensifier standing in for a number, no weasel + hedges ("may potentially", "can help to"), no dramatic/teasing headings (a heading names its + content). End claims on a concrete, checkable fact. ## Conventions for labs diff --git a/capstone/README.md b/capstone/README.md index 5f9b752..9d48256 100644 --- a/capstone/README.md +++ b/capstone/README.md @@ -1,4 +1,4 @@ -# Capstone — The Full Loop +# Capstone: The Full Loop > **One feature, taken end to end, with every module doing its job in sequence.** This is the finale: > not new material, but proof that the twenty-seven pieces you learned separately are actually one @@ -127,13 +127,13 @@ swappable part; the workflow is the durable skill*), and you just lived it inste ## Hands-on lab -**Lab language:** shell + Python, on the `tasks-app` repo. You'll direct Claude Code (`claude` — sub +**Lab language:** shell + Python, on the `tasks-app` repo. You'll direct Claude Code (`claude`; sub your own agent) to do the git and the edits (M4); you make the calls and verify each result. **You'll need:** the `tasks-app` repo in the prerequisite state above, Claude Code (or your own agent), your forge account, and a working Docker install. -### Part A — Issue and branch (M9, M6, M11) +### Part A: Issue and branch (M9, M6, M11) 1. File the issue on your forge. Title: *"Task due dates + `overdue` command + `/overdue` endpoint."* In the body, write the acceptance criteria as you'd hand them to a contributor you don't trust to @@ -157,7 +157,7 @@ agent), your forge account, and a working Docker install. git branch # the new branch exists and is checked out ``` -### Part B — Implement with the AI (M4, M5) +### Part B: Implement with the AI (M4, M5) 3. Give Claude Code the issue, not a vague wish: @@ -179,9 +179,9 @@ agent), your forge account, and a working Docker install. ``` > *Verify-before-publish: refresh the example due dates so the "future" one is still in the future - > at publish time — a hardcoded near-future date silently inverts this assertion once it passes.* + > at publish time; a hardcoded near-future date silently inverts this assertion once it passes.* -### Part C — Tests (M13) +### Part C: Tests (M13) 5. Have the AI extend `test_tasks.py`, then **read the test names** and confirm the boundaries are actually covered. If "due today" and "no due date" aren't each their own test, tell the AI to add @@ -198,7 +198,7 @@ agent), your forge account, and a working Docker install. git status # nothing stray left uncommitted ``` -### Part D — PR, CI, security, review (M10, M11, M14, M15, M19) +### Part D: PR, CI, security, review (M10, M11, M14, M15, M19) 6. Tell the AI to push the branch and open the PR, with `Closes #47` in the description. Then verify on the forge that the PR exists, targets `main`, and carries the closing keyword: @@ -220,7 +220,7 @@ agent), your forge account, and a working Docker install. AI fix it on the branch, let CI re-run, and review again. Catching this *here*, before merge, is the entire point of the gate. -### Part E — Merge and deploy (M11, M16, M18, M17) +### Part E: Merge and deploy (M11, M16, M18, M17) 9. With CI green and the diff honest, squash-merge. Issue #47 closes itself. @@ -235,7 +235,7 @@ agent), your forge account, and a working Docker install. reproducible artifact (M16), configured from the environment (M17), behind a self-rolling-back health check (M18). -### Part F — Rehearse recovery (M12) +### Part F: Rehearse recovery (M12) 11. **Have the AI sync local `main` first.** The squash-merge in step 9 happened on the forge, so the new commit lives only on the remote and your local `main` is one behind. Tell the AI to pull @@ -264,7 +264,7 @@ agent), your forge account, and a working Docker install. --- -## Stretch variant — run the same feature the Unit 5 way (optional) +## Stretch variant: run the same feature the Unit 5 way (optional) The main loop kept you in the driver's seat, directing each step. Now run the **identical** feature with autonomous agents *inside* the pipeline and watch how much of the loop keeps running when you diff --git a/modules/01-the-copy-paste-problem/README.md b/modules/01-the-copy-paste-problem/README.md index 648a965..bfcf43e 100644 --- a/modules/01-the-copy-paste-problem/README.md +++ b/modules/01-the-copy-paste-problem/README.md @@ -1,4 +1,4 @@ -# Module 1 — The Copy-Paste Problem +# Module 1: The Copy-Paste Problem > **You can already get an AI to write good code. The thing that's failing you is everything around > the code.** This module names that gap honestly and gets your workspace ready to close it. @@ -8,7 +8,7 @@ ## Prerequisites None. This is the orientation module. You need to be comfortable using an AI chat assistant and have -a machine you can install software on — that's the whole entry requirement. +a machine you can install software on. That's the whole entry requirement. If you've never opened a terminal, this course will stretch you, but it won't lose you: every command is shown and explained. @@ -47,7 +47,7 @@ For a single file you're poking at for an afternoon, this is fine. The friction results are real. The problem isn't that this loop is *bad*. It's that the loop **doesn't scale along the two axes every real project grows on: more than one file, and more than one day.** -### Seam 1 — More than one file +### Seam 1: More than one file The moment your project is two files instead of one, the chat window loses the thread. You paste in `cli.py`, ask for a change, and the AI confidently edits it. But the change actually needed to touch @@ -59,17 +59,17 @@ You become the integration layer. Every change is a manual diff you perform in y what's in the chat and what's on disk. That's slow, and worse, it's *error-prone in a way you can't see*: there's no record of what actually changed. -### Seam 2 — More than one day +### Seam 2: More than one day Close the chat tab, come back tomorrow, and the AI's entire working memory is gone. It doesn't know what you decided yesterday, which approach you rejected, or why that one function looks weird (you had a reason). The context that lived in the conversation evaporated when the session ended. -So you re-explain. You re-paste. You reconstruct yesterday from memory — and your memory is worse +So you re-explain. You re-paste. You reconstruct yesterday from memory, and your memory is worse than you think. The project's real state lives on your disk, but the chat has no way to read your disk, so every session starts cold. -### Seam 3 — No undo, no record, no safety +### Seam 3: No undo, no record, no safety This is the quiet one, and it's the most dangerous. The AI confidently makes a mess. It deletes a function you needed, "refactors" something into a subtly broken state, rewrites a file you'd carefully @@ -138,13 +138,13 @@ purpose** so you recognize it later. > **One command name, the whole course through:** whichever of `python` / `python3` just printed a > 3.10+ version is the command to use in *every* lab from here on. The labs are written with -> `python`; if that's "command not found" on your machine — common on current macOS and default -> Debian/Ubuntu, where Python is installed only as `python3` — read it as `python3` (and `pip3` +> `python`; if that's "command not found" on your machine (common on current macOS and default +> Debian/Ubuntu, where Python is installed only as `python3`), read it as `python3` (and `pip3` > wherever a lab uses `pip`). This note holds course-wide; we won't repeat it. ### Get the course materials -Everything you'll run in this course lives in one repo. Grab it once, up front — no tools required +Everything you'll run in this course lives in one repo. Grab it once, up front; no tools required beyond a web browser: 1. Open the course's home page, **`https://git.jpaul.io/justin/ai-workflow-course`**, and use its @@ -159,7 +159,7 @@ You now have every module's files locally, including this one's under > *A cleaner, **updatable** way to get the repo, `git clone`, arrives in **Module 8**, once you've > learned Git (Module 2). A one-time ZIP is all you need today; don't reach for `clone` yet.* -### Part A — Stand up the project +### Part A: Stand up the project 1. Make a working directory and copy in the starter app from this module's `lab/starter/` folder: @@ -170,9 +170,9 @@ You now have every module's files locally, including this one's under # tasks.py cli.py README.md ``` - (Copy them however you like — drag-and-drop in your editor's file explorer is fine.) + (Copy them however you like; drag-and-drop in your editor's file explorer is fine.) - > **On Windows:** these labs' shell snippets are written for bash — run them from **Git Bash** or + > **On Windows:** these labs' shell snippets are written for bash; run them from **Git Bash** or > **WSL** and they work as-is. In native PowerShell a few POSIX-only commands differ; here, `mkdir > -p` becomes `New-Item -ItemType Directory -Force`. @@ -188,9 +188,9 @@ You now have every module's files locally, including this one's under You should see your task listed. **This is your "real local project, an editor, and a terminal."** That's the Module 1 setup goal, complete. -### Part B — Feel the seams +### Part B: Feel the seams -Now reproduce each failure deliberately. Keep the AI strictly in the **browser chat** — no +Now reproduce each failure deliberately. Keep the AI strictly in the **browser chat**; no editor-integrated tools yet (those arrive in Module 4). This is the "before" picture on purpose. 1. **Seam 1 (multiple files).** First mark a task done so there's something to hide. Run `python @@ -215,7 +215,7 @@ editor-integrated tools yet (those arrive in Module 4). This is the "before" pic (fragile, gone once you close the file) and the chat history (if you can find the right message). There is no checkpoint. -You just manually reproduced the three problems the rest of Unit 1 removes. Hold onto that feeling — +You just manually reproduced the three problems the rest of Unit 1 removes. Hold onto that feeling; it's the motivation for everything that follows. --- @@ -239,7 +239,7 @@ Be honest about the limits of this module's claims: **You're done when:** -- You can run `python cli.py list` in your terminal and see output — your project, editor, and +- You can run `python cli.py list` in your terminal and see output; your project, editor, and terminal are working together. - You can name the three seams where copy-paste breaks (more than one file, more than one day, no undo) without looking back at the lesson. diff --git a/modules/01-the-copy-paste-problem/lab/starter/README.md b/modules/01-the-copy-paste-problem/lab/starter/README.md index 3b041ea..d963b11 100644 --- a/modules/01-the-copy-paste-problem/lab/starter/README.md +++ b/modules/01-the-copy-paste-problem/lab/starter/README.md @@ -1,7 +1,7 @@ -# Demo app — `tasks` +# Demo app: `tasks` A deliberately tiny command-line task tracker. It exists to be *changed by an AI*, so it's small -enough to read in a minute but real enough to have more than one file — which is exactly where the +enough to read in a minute but real enough to have more than one file, which is exactly where the copy-paste workflow starts to hurt. This is the running example for **Module 1** (where you feel the copy-paste problem) and **Module 2** @@ -9,8 +9,8 @@ This is the running example for **Module 1** (where you feel the copy-paste prob ## Files -- `tasks.py` — the core logic (`Task`, `TaskList`). -- `cli.py` — the command-line front end. Reads/writes `tasks.json`. +- `tasks.py`: the core logic (`Task`, `TaskList`). +- `cli.py`: the command-line front end. Reads/writes `tasks.json`. ## Run it diff --git a/modules/01-the-copy-paste-problem/lab/starter/cli.py b/modules/01-the-copy-paste-problem/lab/starter/cli.py index 7cac167..36a7af8 100644 --- a/modules/01-the-copy-paste-problem/lab/starter/cli.py +++ b/modules/01-the-copy-paste-problem/lab/starter/cli.py @@ -4,7 +4,7 @@ Run it: python cli.py add "write the lesson" python cli.py list -State is kept in tasks.json next to this file. It's intentionally minimal — the point of this app +State is kept in tasks.json next to this file. It's intentionally minimal; the point of this app is to be a realistic-but-small thing you change with an AI, not a product. """ diff --git a/modules/02-version-control-as-a-safety-net/README.md b/modules/02-version-control-as-a-safety-net/README.md index 847246a..4078474 100644 --- a/modules/02-version-control-as-a-safety-net/README.md +++ b/modules/02-version-control-as-a-safety-net/README.md @@ -1,4 +1,4 @@ -# Module 2 — Version Control as a Safety Net +# Module 2: Version Control as a Safety Net > **Version control is undo for the AI, and it's the AI's memory between sessions.** This is the one > module that makes every riskier thing in the rest of the course safe to attempt. @@ -7,7 +7,7 @@ ## Prerequisites -- **Module 1** — you have a real local project (`tasks-app`), an editor, and a terminal, and you've +- **Module 1**: you have a real local project (`tasks-app`), an editor, and a terminal, and you've felt the three seams where copy-paste breaks. This module installs the fix for the third seam (no undo, no record) and, surprisingly, the second (no memory across time) as well. @@ -41,7 +41,7 @@ why." You can compare any two checkpoints, and you can return to any of them. That's it. Everything else (branches, remotes, merges) is built on "snapshots you can move between." For now we only need the local core: `init`, `commit`, `diff`, `log`, `restore`. -### Reframe 1 — Commits are undo for the AI +### Reframe 1: Commits are undo for the AI Module 1's third seam was: when the AI makes a mess, you have no checkpoint to return to. A commit *is* that checkpoint. The workflow becomes: @@ -75,7 +75,7 @@ the last commit. That's the everyday AI-undo. (Returning to an *older* commit, r the reflog are recovery topics with their own module (Module 12) once you've got remotes and PRs to make them meaningful. Here we only need "undo back to my last checkpoint.") -### Reframe 2 — The repo is durable memory the AI can read +### Reframe 2: The repo is durable memory the AI can read This is the part most people miss, and it directly fixes Module 1's *second* seam. @@ -87,10 +87,10 @@ were we?" entirely from ground truth by reading Git: | Command | What it tells a cold session | |---------|------------------------------| -| `git status` | What's changed but **not yet committed** — including brand-new files Git isn't tracking yet. The "in-flight, unsaved" picture. | -| `git diff` | The **actual line-level edits** sitting uncommitted. Not a summary — the real changes. | -| `git log --oneline` | What's already **committed and settled** — the project's decision history. | -| `git log main..HEAD` + the ahead/behind line in `git status` | How this branch compares to `main` and to the remote — the **not-yet-shared** work. (Fully meaningful once you have branches and a remote, Modules 6 and 8 — but the habit starts here.) | +| `git status` | What's changed but **not yet committed**, including brand-new files Git isn't tracking yet. The "in-flight, unsaved" picture. | +| `git diff` | The **actual line-level edits** sitting uncommitted. Not a summary; the real changes. | +| `git log --oneline` | What's already **committed and settled**: the project's decision history. | +| `git log main..HEAD` + the ahead/behind line in `git status` | How this branch compares to `main` and to the remote: the **not-yet-shared** work. (Fully meaningful once you have branches and a remote, Modules 6 and 8, but the habit starts here.) | Together those cover every state a change can be in: **untracked, uncommitted, committed, and not-yet-pushed.** That's the entire surface area of "what's going on in this project," and a fresh @@ -138,7 +138,7 @@ Everything above is standard Git. What's *specific* to AI-assisted work: [git-scm.com](https://git-scm.com) or your package manager), the `tasks-app` folder from Module 1, and your AI assistant. -> **How you work with the AI in this lab — still the browser.** You haven't moved the AI into your +> **How you work with the AI in this lab: still the browser.** You haven't moved the AI into your > editor yet; that's **Module 4** ("Getting the AI Out of the Browser"), and it comes *after* this > one on purpose. The whole point of this module is to install the safety net **first**: you only > let an AI edit your real files directly once you can see and revert exactly what it did. So for now, @@ -148,14 +148,14 @@ and your AI assistant. > Module 1, and that friction is exactly what Module 4 removes. You'll appreciate it more for having > felt it one more time with a net underneath you. -### Part A — First checkpoint +### Part A: First checkpoint 1. In your project folder, initialize the repo and make the first commit: ```bash cd ~/ai-workflow-course/tasks-app git init -b main # start the repo with its first branch named "main" (Git 2.28+) - git status # everything shows as "untracked" — Git sees the files but isn't saving them yet + git status # everything shows as "untracked"; Git sees the files but isn't saving them yet ``` > **Why `-b main`, and what if your Git is older.** Stock Git still names the first branch @@ -177,7 +177,7 @@ and your AI assistant. **You now have a net.** Everything after this is recoverable. -### Part B — A change you can see and trust +### Part B: A change you can see and trust 3. Get `cli.py` in front of your AI first. The browser chat can't see your disk, so you have to hand it the file: run `cat cli.py` and copy the output, or copy the contents straight from your editor. @@ -199,7 +199,7 @@ and your AI assistant. git commit -m "Add count command" ``` -### Part C — Recover from a mess (the whole point) +### Part C: Recover from a mess (the whole point) 5. Now let the AI make a mess on purpose. Ask it to *"aggressively refactor `tasks.py`"* and paste the result over your file **without reading it**. Run the app. Maybe it's broken, maybe it's @@ -209,7 +209,7 @@ and your AI assistant. ```bash git status # shows tasks.py as modified - git restore tasks.py # discard the change — back to your last commit, byte for byte + git restore tasks.py # discard the change; back to your last commit, byte for byte git diff # empty: nothing changed. you're clean. python cli.py list # works again ``` @@ -218,14 +218,14 @@ and your AI assistant. *This is the safety net.* Internalize how cheap that just was; that cheapness is what lets you say yes to riskier AI work for the rest of the course. -### Part D — The repo as the AI's memory +### Part D: The repo as the AI's memory 7. Make one more committed change and one *uncommitted* change, so the project has real state: ```bash # (with the AI) add a "help" command, then: git add . && git commit -m "Add help command" - # (with the AI) start a "delete " command but DON'T commit it — leave it modified + # (with the AI) start a "delete " command but DON'T commit it; leave it modified ``` 8. Open a **brand-new AI chat** (or clear the context). Paste it nothing about the project. Instead, diff --git a/modules/02-version-control-as-a-safety-net/lab/gitignore-starter b/modules/02-version-control-as-a-safety-net/lab/gitignore-starter index a59332a..ea1cd2f 100644 --- a/modules/02-version-control-as-a-safety-net/lab/gitignore-starter +++ b/modules/02-version-control-as-a-safety-net/lab/gitignore-starter @@ -3,10 +3,10 @@ # A .gitignore tells Git which files to leave untracked. The rule of thumb: version the things a # human (or AI) authors, ignore the things a machine generates. For our tasks-app: -# Runtime state — generated by running the app, not authored. Not something you want in history. +# Runtime state, generated by running the app, not authored. Not something you want in history. tasks.json -# Python bytecode caches — generated, never edited by hand. +# Python bytecode caches: generated, never edited by hand. __pycache__/ *.pyc diff --git a/modules/03-version-control-for-words/README.md b/modules/03-version-control-for-words/README.md index 803ec69..1bb7c4f 100644 --- a/modules/03-version-control-for-words/README.md +++ b/modules/03-version-control-for-words/README.md @@ -1,4 +1,4 @@ -# Module 3 — Version Control for Words, Not Just Code +# Module 3: Version Control for Words, Not Just Code > **The safest place to practice Git is on words, and it happens to be a genuinely useful skill on > its own.** Branch an Architecture Decision Record (ADR), let the AI draft it, read the diff, merge @@ -8,14 +8,14 @@ ## Prerequisites -- **Module 1** — you have the `tasks-app` project, an editor, and a terminal. -- **Module 2** — you can `init`, `commit`, read a `diff`, and `restore`. This module adds two new +- **Module 1:** you have the `tasks-app` project, an editor, and a terminal. +- **Module 2:** you can `init`, `commit`, read a `diff`, and `restore`. This module adds two new verbs to that vocabulary: `branch` and `merge`. They're introduced here, in the lowest-stakes setting possible (a markdown file), and picked up again for real code work in - **Module 6 — Branches: Sandboxes for Experiments**. + **Module 6 (Branches: Sandboxes for Experiments)**. You're still working the way you did in Modules 1–2: **AI in a browser tab, copy-paste into the -file.** Editor-integrated AI is Module 4. That's deliberate — practicing branch/merge on documents +file.** Editor-integrated AI is Module 4. That's deliberate; practicing branch/merge on documents is exactly the low-risk on-ramp that makes the copy-paste friction tolerable one more time. --- @@ -51,8 +51,8 @@ them in code: back to the version that was correct an hour ago. `runbook-final-v2-ACTUAL-use-this.docx` is what "no undo" looks like when it metastasizes. -Git fixes all three for documents the same way it fixes them for code — *if* the documents are in a -format Git can actually work with. That "if" is the whole argument. +Git fixes all three for documents the same way it fixes them for code, but only *if* the documents +are in a format Git can actually work with. That "if" is the whole argument. ### Why plain text wins: the diff is line-based @@ -72,7 +72,7 @@ you exactly that: That is a perfect change record. A reviewer reads it in two seconds. Two people can edit different sections and Git merges them automatically, because the changes touch different lines. -Now do the same edit in a `.docx`. A Word document isn't text — it's a zipped bundle of XML, styles, +Now do the same edit in a `.docx`. A Word document isn't text; it's a zipped bundle of XML, styles, and metadata. Git happily tracks it, but it can't diff it meaningfully. Ask for the diff and you get: ``` @@ -80,7 +80,7 @@ Binary files a/runbook.docx and b/runbook.docx differ ``` That's it. That's the entire change record: *something* changed. You can't see *what*, you can't -review it, and you can't merge two people's edits — Git will force you to pick one whole file and +review it, and you can't merge two people's edits; Git will force you to pick one whole file and throw the other away. The version history exists and is **completely useless**. `.pptx` is worse, because slide decks are even more structure and even less text. @@ -96,16 +96,16 @@ The honest counterpoint, where binary formats still earn their place, is in *Whe You don't need to convert everything. These are the high-value targets, all naturally plain text: -- **READMEs** — how to run the thing. Already markdown by convention; you saw `tasks-app/README.md` +- **READMEs:** how to run the thing. Already markdown by convention; you saw `tasks-app/README.md` in Module 1. -- **ADRs (Architecture Decision Records)** — short documents that capture *one* decision: the +- **ADRs (Architecture Decision Records):** short documents that capture *one* decision: the context, the choice, and the consequences. The point is to make the *reasoning* survive the meeting. An ADR lives next to the code, gets versioned with it, and answers "why is it like this?" long after everyone's forgotten. -- **Runbooks** — the step-by-step for an operational task (deploy, restore, rotate a key, respond to +- **Runbooks:** the step-by-step for an operational task (deploy, restore, rotate a key, respond to an alert). These get edited under pressure, which is exactly when you want clean history and undo. -- **Changelogs** — what changed in each release. A markdown `CHANGELOG.md` is the standard. -- **Specs / PRDs** — what you're going to build and why, before you build it. +- **Changelogs:** what changed in each release. A markdown `CHANGELOG.md` is the standard. +- **Specs / PRDs:** what you're going to build and why, before you build it. For this audience the ADR is the easiest win: small, structured, high-value, and the kind of thing that *never* gets written because it feels like overhead, right up until the AI drafts it for you in @@ -136,14 +136,14 @@ Two new-command notes for this audience: - **`git switch -c `** creates and moves onto a branch. (Older docs and muscle memory use `git checkout -b `; `switch` is the newer, clearer verb for the same thing. Either works.) -- **`git diff` shows nothing for a brand-new file** until Git is tracking it — new files are +- **`git diff` shows nothing for a brand-new file** until Git is tracking it; new files are "untracked," and `git diff` only compares *tracked* changes. That's why the loop above does `git add` *then* `git diff --staged` (also spelled `--cached`): staging tells Git "track this," and - `--staged` shows you what's staged. For a new file the diff is all-additions, which is fine — you're + `--staged` shows you what's staged. For a new file the diff is all-additions, which is fine; you're still reading every line before it lands. Because this is one document on its own branch, the merge is trivial: nothing else touched `main` -while you worked, so Git **fast-forwards** — it just slides `main` up to your branch with no +while you worked, so Git **fast-forwards**; it just slides `main` up to your branch with no conflict. That clean case is the whole reason we practice here first. What happens when two branches edit the *same lines* (a merge conflict) is a real skill, and it gets its own treatment in **Module 6**, on code, where the stakes make it worth the depth. Practice the happy path now; the @@ -155,7 +155,7 @@ Most Git hosts (GitHub, GitLab, Gitea, and others) ship a **wiki** alongside eac looks like a web app: you click "New Page," type in a box, hit save. It feels like a different kind of thing from your code. -It isn't. On essentially every one of these hosts, **the wiki is itself a Git repository** — a +It isn't. On essentially every one of these hosts, **the wiki is itself a Git repository**, a separate repo, usually addressable as something like `your-project.wiki.git`, full of markdown files. Every page is a `.md` file. Every "save" in the web UI is a commit. The web editor is just a convenience layer over `git commit`. @@ -174,7 +174,7 @@ wearing a web UI.) Here's why this module is more than "learn Git on easy mode": - **LLMs are native markdown writers.** Markdown is arguably the *most* fluent output format these - models have — they were trained on oceans of it, and they reach for it by default. Asking an AI to + models have; they were trained on oceans of it, and they reach for it by default. Asking an AI to "write an ADR for this decision" or "turn these rough notes into a runbook" plays directly to its strengths. The output is genuinely good and genuinely in the right format, with zero conversion. - **"Draft it, branch it, diff it, merge it" works today.** You don't need new tools, a new model, or @@ -209,7 +209,7 @@ zero. - The ADR template from this module's `lab/adr-template.md` (and `lab/runbook-template.md` if you want to do the variant at the end). -### Part A — Branch for the document +### Part A: Branch for the document 1. Confirm you're starting clean, then create a branch for the ADR: @@ -222,7 +222,7 @@ zero. You're now working on a copy. Nothing you do here touches `main` until you merge. -### Part B — Let the AI draft the ADR +### Part B: Let the AI draft the ADR 2. Make a home for decision records: @@ -250,7 +250,7 @@ zero. stretch before Module 4 removes it.) The file has to exist on disk before the next part can stage it. -### Part C — Review the diff before you accept it +### Part C: Review the diff before you accept it 5. A brand-new file is untracked, so `git diff` shows nothing yet. Stage it, then review: @@ -272,7 +272,7 @@ zero. git log --oneline # your new checkpoint, on this branch ``` -### Part D — Make a one-line edit and see the line-based diff +### Part D: Make a one-line edit and see the line-based diff 7. Edit one sentence in the ADR (tighten a line, fix a claim, whatever). Save, then: @@ -288,14 +288,14 @@ zero. git commit -m "Tighten ADR 0001 rationale" ``` -### Part E — Merge it into main +### Part E: Merge it into main 8. First, switch back to `main` and prove the document isn't there yet. You created the whole `docs/adr/` directory on the branch, so on `main` it doesn't exist: ```bash git switch main - ls docs/adr/ # error: "No such file or directory" — it's only on the branch + ls docs/adr/ # error: "No such file or directory", only on the branch git log --oneline # and your ADR commits aren't here either ``` @@ -317,7 +317,7 @@ zero. You just ran the complete branch → draft → diff → commit → merge loop on a real document, with the AI doing the writing and you doing the reviewing. That's the loop the rest of the course runs on. -### Optional — do it again as a runbook +### Optional: do it again as a runbook Repeat the loop on a different branch (`git switch -c docs/runbook-restore`) using `runbook-template.md` from this module's `lab/` folder: ask the AI to write a runbook for "restore the @@ -330,7 +330,7 @@ on next run. Same five parts. Doing it twice is what turns the commands into ref - **Line-based diffs punish reflowed paragraphs.** Git diffs *lines*. If you (or the AI) rewrap a paragraph so every line shifts, the diff shows the whole paragraph as changed even if you altered - three words — the clean diff degrades toward `.docx`-style noise. The fix the technical-writing + three words; the clean diff degrades toward `.docx`-style noise. The fix the technical-writing world uses is **semantic line breaks**: write one sentence (or one clause) per line, so edits stay local and diffs stay surgical. Worth knowing the AI will *not* do this by default; you can ask it to. @@ -339,8 +339,8 @@ on next run. Same five parts. Doing it twice is what turns the commands into ref it just can't show you what changed inside them. Diagrams-as-code (text formats that render to pictures) sidestep this, but that's beyond this module. - **Word and PowerPoint still exist for reasons.** A pixel-precise client deliverable, a slide deck - with heavy layout, a document a non-technical stakeholder must edit in a tool they already know — - these are real constraints. The argument isn't "markdown for everything." It's "anything that needs + with heavy layout, a document a non-technical stakeholder must edit in a tool they already know. + These are real constraints. The argument isn't "markdown for everything." It's "anything that needs history, review, or multiple authors is paying a steep tax in a binary format." Pick the targets where that tax actually bites: runbooks, ADRs, specs, changelogs. - **Merge conflicts are real; you just didn't hit one.** This lab fast-forwarded because nothing else @@ -348,10 +348,10 @@ on next run. Same five parts. Doing it twice is what turns the commands into ref That's a genuine skill, deferred to **Module 6** on purpose so you learn it where the stakes make it matter. - **The wiki-clone aha needs a remote.** You can *see* that a host's wiki is a Git repo now, but - cloning it, editing locally, and pushing back requires remotes — **Module 8**. The realization is + cloning it, editing locally, and pushing back requires remotes, which is **Module 8**. The realization is yours today; the round trip waits a few modules. - **The AI writes confident fiction.** It will produce a fluent ADR with a rationale that sounds - exactly like something a senior engineer wrote — and is sometimes simply made up. The format makes + exactly like something a senior engineer wrote, and is sometimes simply made up. The format makes the document reviewable; it does not make the document *true*. Reading the diff is necessary, not sufficient. You still have to know whether the reasoning is right. @@ -363,12 +363,12 @@ on next run. Same five parts. Doing it twice is what turns the commands into ref - Your `tasks-app` repo has an `docs/adr/0001-*.md` on `main`, authored by the AI and reviewed by you, arrived there via a branch and a merge. -- You created a branch, committed to it, merged it back, and deleted it — and `git log --oneline` on +- You created a branch, committed to it, merged it back, and deleted it; `git log --oneline` on `main` shows the ADR commits. - You can explain, to a skeptical colleague, why the team's runbooks shouldn't be `.docx` files on a - shared drive — using the line-based-diff argument, not just "markdown is nicer." + shared drive, using the line-based-diff argument, not just "markdown is nicer." - You know that your Git host's wiki is itself a Git repo, and what that implies. When branch/diff/commit/merge feels routine on a document, you're ready for **Module 4**, where the AI -finally comes out of the browser and starts editing your files directly — a step that's only safe +finally comes out of the browser and starts editing your files directly, a step that's only safe because you can now branch, diff, and revert exactly what it does. diff --git a/modules/03-version-control-for-words/lab/adr-template.md b/modules/03-version-control-for-words/lab/adr-template.md index fd9648d..6c2ba96 100644 --- a/modules/03-version-control-for-words/lab/adr-template.md +++ b/modules/03-version-control-for-words/lab/adr-template.md @@ -1,8 +1,8 @@ -# ADR NNNN — +# ADR NNNN: - **Status:** proposed | accepted | superseded by ADR-XXXX - **Date:** YYYY-MM-DD @@ -32,10 +32,10 @@ -- **