feat(course): build out all 27 modules, capstone, scaffold, and conventions
Scaffold the course repo and author the full curriculum in dependency-chain order, following the settled build decisions in handoff.md. - Scaffold: course README, vendor-neutral AGENTS.md (dogfoods Module 5), _TEMPLATE.md (the fixed 9-section module shape), root .gitignore, ship config. - Modules 1-2: reference exemplars (locked for tone/depth/lab style). - Modules 3-27: full lessons + runnable labs, each following the template, respecting the chain, vendor/model-agnostic, with "feel the pain" labs. - Module 8 hosting comparison web-researched and date-stamped (as of 2026-06-22), not written from memory; expansion-zone modules carry Verify-before-publish. - Capstone: the full loop end to end on the running tasks-app example. Lab code syntax-checked (Python/shell/YAML); every module has the 7 core template sections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Agent prompt — issue #42, branch `feature/42-count`
|
||||
|
||||
Run this in the `tasks-app-42-count` worktree. This agent's work is genuinely parallel with #43
|
||||
(docs) — different files — and deliberately collides with #44 (clear) at `cli.py`'s dispatch chain.
|
||||
|
||||
---
|
||||
|
||||
You are working in this worktree only. Do not touch any other folder.
|
||||
|
||||
**Task:** Add a `count` command to `cli.py` that prints the number of *pending* (not-done) tasks.
|
||||
|
||||
- Add a new `elif command == "count":` branch to the dispatch in `main()` in `cli.py`.
|
||||
- Use the existing `TaskList.pending()` method from `tasks.py` — do not change `tasks.py`.
|
||||
- Print just the integer, e.g. `3`.
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- `python cli.py count` prints the number of pending tasks and exits 0.
|
||||
- No other files change. (`README.md`, `CHANGELOG.md`, and `tasks.py` are owned by other agents —
|
||||
stay out of them.)
|
||||
|
||||
When done, stop. The human commits, pushes, and opens the PR.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Agent prompt — issue #43, branch `feature/43-docs`
|
||||
|
||||
Run this in the `tasks-app-43-docs` worktree. This agent owns documentation only — different files
|
||||
from every other agent in the fleet, so it merges cleanly no matter what the others do. This is what
|
||||
a *genuinely* parallel split looks like: disjoint files, no shared interface.
|
||||
|
||||
---
|
||||
|
||||
You are working in this worktree only. Do not touch any other folder, and do not edit `cli.py` or
|
||||
`tasks.py` — code is owned by other agents.
|
||||
|
||||
**Task:** Document the `tasks-app` and start a changelog.
|
||||
|
||||
- In `README.md`, add a "Commands" section documenting the existing commands: `add <title>`, `list`,
|
||||
and `done <index>`. Show an example invocation for each.
|
||||
- Create `CHANGELOG.md` with a "Keep a Changelog"–style `## [Unreleased]` section and an `### Added`
|
||||
list. (Other agents are adding commands in parallel; leave a placeholder line noting that new
|
||||
commands are landing — the human will reconcile the exact list at merge.)
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- `README.md` documents the three existing commands accurately.
|
||||
- `CHANGELOG.md` exists and is valid markdown.
|
||||
- No code files change.
|
||||
|
||||
When done, stop. The human commits, pushes, and opens the PR.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Agent prompt — issue #44, branch `feature/44-clear`
|
||||
|
||||
Run this in the `tasks-app-44-clear` worktree. **This agent deliberately collides with #42.** Both
|
||||
add a new `elif` to the same dispatch chain in `cli.py` — same file, same region. That's the
|
||||
agent-vs-agent merge conflict the lab wants you to predict in Part A and resolve in Part C. It is not
|
||||
a mistake in the lab; it is the lesson. Two agents on the same file is a *joint*, not a seam.
|
||||
|
||||
---
|
||||
|
||||
You are working in this worktree only. Do not touch any other folder.
|
||||
|
||||
**Task:** Add a `clear` command to `cli.py` that removes all tasks.
|
||||
|
||||
- Add a new `elif command == "clear":` branch to the dispatch in `main()` in `cli.py`.
|
||||
- It should empty the task list and save, then print `cleared`.
|
||||
- Reuse the existing `load()` / `save()` helpers. Do not change `tasks.py`.
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- `python cli.py clear` removes all tasks and prints `cleared`.
|
||||
- `python cli.py list` afterward shows `(no tasks yet)`.
|
||||
|
||||
When done, stop. The human commits, pushes, and opens the PR — and should expect a conflict against
|
||||
`feature/42-count` at merge.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Module 26 lab — tear down the fleet after the work has merged.
|
||||
#
|
||||
# Removes each worktree and prunes stale records. Refuses to remove a worktree with uncommitted
|
||||
# work (Git's safety) — commit or merge first. Run from inside your tasks-app repo.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
FLEET=(
|
||||
"../tasks-app-42-count"
|
||||
"../tasks-app-43-docs"
|
||||
"../tasks-app-44-clear"
|
||||
)
|
||||
|
||||
git rev-parse --git-dir >/dev/null 2>&1 || { echo "not a git repo" >&2; exit 1; }
|
||||
|
||||
for path in "${FLEET[@]}"; do
|
||||
if [ -d "$path" ]; then
|
||||
echo "remove: $path"
|
||||
git worktree remove "$path" # fails if dirty — that's intentional; commit first
|
||||
fi
|
||||
done
|
||||
|
||||
git worktree prune
|
||||
echo
|
||||
echo "Fleet torn down. Remaining worktrees:"
|
||||
git worktree list
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Module 26 lab — fan work out across a fleet of worktrees.
|
||||
#
|
||||
# Creates one worktree per issue, each on its own issue-named branch. main is left untouched
|
||||
# and reserved as the integration point. Run from inside your tasks-app repo.
|
||||
#
|
||||
# This is Module 7's `git worktree add` repeated with a naming convention. The convention is the
|
||||
# point: branch name carries the issue number, folder name mirrors the branch.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Each entry: "<worktree-folder> <branch>". Edit to match your coordination plan.
|
||||
FLEET=(
|
||||
"../tasks-app-42-count feature/42-count"
|
||||
"../tasks-app-43-docs feature/43-docs"
|
||||
"../tasks-app-44-clear feature/44-clear"
|
||||
)
|
||||
|
||||
if [ ! -d .git ] && ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "error: run this from inside your tasks-app git repo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for entry in "${FLEET[@]}"; do
|
||||
# shellcheck disable=SC2086
|
||||
set -- $entry
|
||||
path="$1"; branch="$2"
|
||||
if git worktree list --porcelain | grep -q "branch refs/heads/$branch"; then
|
||||
echo "skip: $branch already checked out in a worktree"
|
||||
continue
|
||||
fi
|
||||
echo "fan-out: $path (branch $branch)"
|
||||
git worktree add "$path" -b "$branch"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Fleet is up. main is reserved for integration — no agent works there."
|
||||
git worktree list
|
||||
@@ -0,0 +1,45 @@
|
||||
# Coordination plan — Module 26 lab
|
||||
|
||||
This is the artifact orchestration runs on. With one agent, the plan lived in your head. With a
|
||||
fleet, it has to live here — because your head doesn't scale and it forgets (Module 2).
|
||||
|
||||
Fill the **Status** column as you go, and answer the questions at the bottom. The plan is the
|
||||
deliverable, not the code.
|
||||
|
||||
---
|
||||
|
||||
## The fleet
|
||||
|
||||
| Issue | Branch | Worktree | Files owned | Depends on | Status |
|
||||
|-------|--------|----------|-------------|------------|--------|
|
||||
| #42 count | `feature/42-count` | `tasks-app-42-count` | `cli.py` (dispatch + new fn) | — | queued |
|
||||
| #43 docs | `feature/43-docs` | `tasks-app-43-docs` | `README.md`, `CHANGELOG.md` | — | queued |
|
||||
| #44 clear | `feature/44-clear` | `tasks-app-44-clear` | `cli.py` (dispatch + new fn) | — | queued |
|
||||
|
||||
`main` is reserved as the integration point. No agent works in the main worktree.
|
||||
|
||||
---
|
||||
|
||||
## Part A — Predict the conflicts BEFORE you launch
|
||||
|
||||
Read the "Files owned" column. Which pairs are genuinely parallel, and which will collide at merge?
|
||||
Write your prediction here, then watch it come true in Part C.
|
||||
|
||||
- Genuinely parallel (disjoint files, no shared interface): _______________________
|
||||
- Will collide at merge (and on which file/line): _______________________________
|
||||
- If you wanted to avoid the collision, what would you change? (serialize one? scope it to a
|
||||
different file?) _____________________________________________________________
|
||||
|
||||
---
|
||||
|
||||
## Part D — Score the orchestration honestly
|
||||
|
||||
- **Did parallel beat sequential?** Agent wall-clock (overlapping) + your serial review time +
|
||||
conflict resolution, vs. "I'd have done these three myself, in order."
|
||||
Answer: ______________________________________________________________________
|
||||
|
||||
- **Which split was worth it and which wasn't?**
|
||||
Answer: ______________________________________________________________________
|
||||
|
||||
- **Where was the bottleneck?** (Almost certainly your review queue, not the agents. Name it.)
|
||||
Answer: ______________________________________________________________________
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Module 26 lab — fleet dashboard.
|
||||
#
|
||||
# Prints every worktree, its branch, and how much work is in flight (uncommitted changes +
|
||||
# commits ahead of main). Your "where is every agent?" view in one command. Run from anywhere
|
||||
# inside the repo.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
git rev-parse --git-dir >/dev/null 2>&1 || { echo "not a git repo" >&2; exit 1; }
|
||||
|
||||
printf "%-32s %-22s %-10s %s\n" "WORKTREE" "BRANCH" "AHEAD" "DIRTY?"
|
||||
printf "%-32s %-22s %-10s %s\n" "--------" "------" "-----" "------"
|
||||
|
||||
git worktree list --porcelain | awk '/^worktree /{wt=$2} /^branch /{print wt"\t"$2}' \
|
||||
| while IFS=$'\t' read -r wt ref; do
|
||||
branch="${ref#refs/heads/}"
|
||||
name="$(basename "$wt")"
|
||||
# commits on this branch not yet in main
|
||||
ahead="$(git -C "$wt" rev-list --count main.."$branch" 2>/dev/null || echo "?")"
|
||||
# any uncommitted changes in this worktree?
|
||||
if [ -n "$(git -C "$wt" status --porcelain 2>/dev/null)" ]; then dirty="yes"; else dirty="no"; fi
|
||||
printf "%-32s %-22s %-10s %s\n" "$name" "$branch" "$ahead" "$dirty"
|
||||
done
|
||||
Reference in New Issue
Block a user