Remove em-dashes from the wiki generator + README #95

Merged
claude merged 1 commits from fix/no-slop-wiki-generator into main 2026-06-22 23:25:31 -04:00
2 changed files with 45 additions and 31 deletions
+34 -20
View File
@@ -2,33 +2,34 @@
### The Toolchain Around AI Coding ### The Toolchain Around AI Coding
A living course for IT professionals who are comfortable in an AI chat window and starting to build A living course for IT professionals who are comfortable in an AI chat window and starting to build
real software with it but are still copy-pasting between the chat and their files. The goal is to real software with it, but who are still copy-pasting between the chat and their files. The goal is
replace that loop with durable engineering workflows: version control, collaboration, CI/CD, to replace that loop with durable engineering workflows: version control, collaboration, CI/CD,
runners, and the tools that extend AI into real systems. runners, and the tools that extend AI into real systems.
> **Thesis:** the model is the cheap, swappable part. The workflow around it is the skill that > **Thesis:** the model is the cheap, swappable part. The workflow around it is the skill that
> lasts. This course is deliberately model- and vendor-agnostic whichever LLM you use, the > lasts. This course is deliberately model- and vendor-agnostic: whichever LLM you use, the
> scaffolding is the same. > scaffolding is the same.
This repo *is* the course, and it also dogfoods the course: it's version-controlled, it commits its This repo *is* the course, and it also dogfoods the course: it's version-controlled, it commits its
own AI instructions file ([`AGENTS.md`](AGENTS.md), the subject of Module 5), and each module is own AI instructions file ([`AGENTS.md`](AGENTS.md), the subject of Module 5), and each module is
built on a branch and merged through review — exactly the motion the modules teach. built on a branch and merged through review, the same motion the modules teach.
--- ---
## Read it as a book ## Read it as a book
The lessons are rendered into the **[Wiki](https://git.jpaul.io/justin/ai-workflow-course/wiki)** as a navigable textbook (unit-by-unit The lessons render into the **[Wiki](https://git.jpaul.io/justin/ai-workflow-course/wiki)** as a
sidebar, one page per module). The wiki is generated from `modules/` and kept in sync navigable textbook (unit-by-unit sidebar, one page per module, prev/next links). The wiki is
automatically it's build output, so read it there but **edit the lessons here in `modules/`**. generated from `modules/` and kept in sync automatically; it's build output, so read it there but
See [`tools/`](tools/) for the generator and the sync workflows. **edit the lessons here in `modules/`**. See [`tools/`](tools/) for the generator and the sync
workflows.
--- ---
## Who this is for ## Who this is for
IT professionals who are fluent in an AI chat window and comfortable with ops concepts — **not IT professionals who are fluent in an AI chat window and comfortable with ops concepts. Not
beginners.** If you already paste code between a chat tab and your editor and feel the friction, you beginners. If you already paste code between a chat tab and your editor and feel the friction, you
are the audience. You will not be taught what a variable is; you will be taught the engineering are the audience. You will not be taught what a variable is; you will be taught the engineering
scaffolding that makes AI-assisted work safe, shareable, and repeatable. scaffolding that makes AI-assisted work safe, shareable, and repeatable.
@@ -42,11 +43,11 @@ units, plus a capstone finale.
| Unit | Modules | Theme | | Unit | Modules | Theme |
|------|---------|-------| |------|---------|-------|
| **1 Get out of the chat window** | 17 | The local foundation: version control, committing the AI's config, getting the AI editing real files safely. | | **1: Get out of the chat window** | 17 | The local foundation: version control, committing the AI's config, getting the AI editing real files safely. |
| **2 Make it shareable, reviewable, recoverable** | 812 | The team layer: hosting, issues, review, collaboration, recovery. | | **2: Make it shareable, reviewable, recoverable** | 812 | The team layer: hosting, issues, review, collaboration, recovery. |
| **3 Automate the checking and shipping** | 1319 | The pipeline: tests, CI, security scanning, containers, secrets, delivery, runners. | | **3: Automate the checking and shipping** | 1319 | The pipeline: tests, CI, security scanning, containers, secrets, delivery, runners. |
| **4 Extend the AI into your systems** | 2023 | The frontier: MCP, skills, securing them, existing codebases. | | **4: Extend the AI into your systems** | 2023 | The frontier: MCP, skills, securing them, existing codebases. |
| **5 AI in the loop** | 2427 | Agents inside the pipeline, from assistive to autonomous, plus the evals that make it trustworthy. | | **5: AI in the loop** | 2427 | Agents inside the pipeline, from assistive to autonomous, plus the evals that make it trustworthy. |
| **Capstone** | finale | One real feature taken end to end. | | **Capstone** | finale | One real feature taken end to end. |
**Durable core vs. expansion zone.** Modules 114 are the stable foundation. From Module 15 onward **Durable core vs. expansion zone.** Modules 114 are the stable foundation. From Module 15 onward
@@ -58,17 +59,29 @@ the reasoning behind the sequencing.
--- ---
## How git works in this course
You don't memorize git commands here. Modules 13 have you run the basics by hand so you build
intuition (the AI is still in a browser chat). Module 4 puts the AI in your editor/CLI, and from
there you **direct the AI to do the git work** (commit, branch, merge, revert) and verify the
result. Think arithmetic by hand first, then a calculator. You learn that git is critical and how it
works; the AI drives the keystrokes.
---
## Format and conventions ## Format and conventions
- **Written lessons + interactive labs.** Every module is a README you read *and* a lab you run at - **Written lessons + interactive labs.** Every module is a README you read *and* a lab you run at
the keyboard. There are no quizzes; there's a "you're done when…" check. the keyboard. There are no quizzes; there's a "you're done when…" check.
- **Run labs on your own machine, any OS.** No sandbox or cloud account required. Where a lab needs - **Run labs on your own machine, any OS.** No sandbox or cloud account required. Where a lab needs
code, it leans on **Python or shell** picked per lab, kept as small as possible. The *concepts* code, it leans on **Python or shell**, picked per lab, kept as small as possible. The *concepts*
are language-agnostic; the labs just need something concrete to run. are language-agnostic; the labs just need something concrete to run.
- **Claude Code as the worked example.** Commands and labs use Claude Code as the concrete agent
(`claude --version # sub your own agent`); the concepts stay model- and tool-agnostic.
- **GitHub is the default, not the requirement.** Hosting examples use GitHub because nearly - **GitHub is the default, not the requirement.** Hosting examples use GitHub because nearly
everyone will encounter it, but the course is provider-neutral and includes an optional everyone will encounter it, but the course is provider-neutral and includes an optional
**self-hosted-forge track** for on-prem and air-gapped environments. **self-hosted-forge track** for on-prem and air-gapped environments.
- **Self-checks only.** No grading, no certification each module ends at a concrete done-criterion. - **Self-checks only.** No grading, no certification; each module ends at a concrete done-criterion.
--- ---
@@ -77,7 +90,7 @@ the reasoning behind the sequencing.
``` ```
ai-workflow-course/ ai-workflow-course/
README.md # this file README.md # this file
AGENTS.md # committed AI instructions dogfoods Module 5 (vendor-neutral name) AGENTS.md # committed AI instructions; dogfoods Module 5 (vendor-neutral name)
the-workflow-syllabus.md # the full course plan (source of truth for structure) the-workflow-syllabus.md # the full course plan (source of truth for structure)
handoff.md # build-context notes for the authoring sessions handoff.md # build-context notes for the authoring sessions
_TEMPLATE.md # the shape every module follows _TEMPLATE.md # the shape every module follows
@@ -98,5 +111,6 @@ ai-workflow-course/
## Status ## Status
Planning is complete (27 modules + capstone). Authoring is in progress, built in dependency-chain All 27 modules and the capstone are written and reviewed. The lessons render to the
order. Modules 12 are drafted as the reference exemplars; the rest follow. [Wiki](https://git.jpaul.io/justin/ai-workflow-course/wiki) as a textbook, kept in sync from
`modules/` by CI. Blog drafts for jpaul.me live under [`blog/`](blog/).
+11 -11
View File
@@ -3,11 +3,11 @@
Host-agnostic: this writes Markdown into a target wiki working directory. A thin Host-agnostic: this writes Markdown into a target wiki working directory. A thin
per-host CI wrapper clones the host's `<repo>.wiki.git`, runs this script, then per-host CI wrapper clones the host's `<repo>.wiki.git`, runs this script, then
commits and pushes. The same script feeds both the Gitea and GitHub wikis only commits and pushes. The same script feeds both the Gitea and GitHub wikis; only
the `--host` URL flavor and the CI wrapper differ. the `--host` URL flavor and the CI wrapper differ.
The wiki is GENERATED BUILD OUTPUT. Never hand-edit it; edit modules/ and let CI The wiki is GENERATED BUILD OUTPUT. Never hand-edit it; edit modules/ and let CI
re-render. Labs are NOT copied into the wiki lesson pages link to the runnable re-render. Labs are NOT copied into the wiki; lesson pages link to the runnable
files back in the main repo. Each page gets prev/next navigation so the wiki reads files back in the main repo. Each page gets prev/next navigation so the wiki reads
like a textbook. like a textbook.
@@ -24,11 +24,11 @@ from pathlib import Path
# Unit structure (module numbers), from the syllabus. Drives the textbook nav. # Unit structure (module numbers), from the syllabus. Drives the textbook nav.
UNITS = [ UNITS = [
("Unit 1 Get out of the chat window", range(1, 8)), ("Unit 1: Get out of the chat window", range(1, 8)),
("Unit 2 Make it shareable, reviewable, recoverable", range(8, 13)), ("Unit 2: Make it shareable, reviewable, recoverable", range(8, 13)),
("Unit 3 Automate the checking and shipping", range(13, 20)), ("Unit 3: Automate the checking and shipping", range(13, 20)),
("Unit 4 Extend the AI into your systems", range(20, 24)), ("Unit 4: Extend the AI into your systems", range(20, 24)),
("Unit 5 AI in the Loop", range(24, 28)), ("Unit 5: AI in the Loop", range(24, 28)),
] ]
@@ -48,7 +48,7 @@ def first_h1(text: str, fallback: str) -> str:
def short_title(h1: str) -> str: def short_title(h1: str) -> str:
"""'Module 1 The Copy-Paste Problem' -> 'The Copy-Paste Problem'.""" """'Module 1: The Copy-Paste Problem' -> 'The Copy-Paste Problem'."""
m = re.match(r"^Module\s+\d+\s*[—:-]\s*(.+)$", h1) m = re.match(r"^Module\s+\d+\s*[—:-]\s*(.+)$", h1)
return m.group(1).strip() if m else h1 return m.group(1).strip() if m else h1
@@ -78,7 +78,7 @@ def rewrite_repo_file_links(body: str, web_base: str, branch: str, host: str) ->
def banner(source_path: str, source_url: str) -> str: def banner(source_path: str, source_url: str) -> str:
return ( return (
f"> 📖 _This page is generated from [`{source_path}`]({source_url}). " f"> 📖 _This page is generated from [`{source_path}`]({source_url}). "
f"**Edit the source, not the wiki** edits here are overwritten on the next sync. " f"**Edit the source, not the wiki**; edits here are overwritten on the next sync. "
f"Run the hands-on labs from the repo, linked inline._\n" f"Run the hands-on labs from the repo, linked inline._\n"
) )
@@ -153,7 +153,7 @@ def main() -> int:
cap_title = None cap_title = None
if cap.exists(): if cap.exists():
body = cap.read_text(encoding="utf-8") body = cap.read_text(encoding="utf-8")
cap_title = first_h1(body, "Capstone The Full Loop") cap_title = first_h1(body, "Capstone: The Full Loop")
seq.append({"page": "capstone", "label": cap_title, "body": body, "slug": None}) seq.append({"page": "capstone", "label": cap_title, "body": body, "slug": None})
# --- pass 2: write each page with banner + prev/next nav -------------- # --- pass 2: write each page with banner + prev/next nav --------------
@@ -212,7 +212,7 @@ def main() -> int:
home.append("") home.append("")
home.append( home.append(
"\n---\n> 📖 _This wiki is generated from the " "\n---\n> 📖 _This wiki is generated from the "
f"[course repo]({args.web_base}) edit `modules/` there, not these pages._" f"[course repo]({args.web_base}); edit `modules/` there, not these pages._"
) )
(out / "Home.md").write_text("\n".join(home) + "\n", encoding="utf-8") (out / "Home.md").write_text("\n".join(home) + "\n", encoding="utf-8")