00-planning β 04-post-training
._TEMPLATE/
you copy to start the next one, an _ARCHIVED/
you park old stuff in, and a CLAUDE.md
that makes the convention machine-readable.<angle-bracket-slots>
, and "done" is a grep
that returns nothing.I had course material scattered across repos β planning notes here, marketing copy there, facilitator run-sheets in a third place. Every new course started from a blank page, and I re-invented the folder layout each time. So I collapsed everything into one monorepo with a single rule: every course has the identical shape.
The insight isn't "use folders" β it's that a course has a lifecycle, and numbered folders make that lifecycle the primary axis instead of file type. Plan it, sell it, teach it, run it, follow up. Five stages, always in order:
| Folder | Stage | What lives here |
|---|---|---|
00-planning/ |
||
| Prepare | Syllabus (source of truth), specs | |
01-marketing/ |
||
| Sell | Positioning master + channel assets | |
02-content/ |
||
| Teach | Modules, one file each | |
03-delivery/ |
||
| Run | Run-sheet, pre-flight checklist, fallback plan | |
04-post-training/ |
||
| Follow up | Feedback form, follow-up email, post-mortem |
The numeric prefix isn't decoration. It forces sort order to match the actual workflow, so the folder listing reads like the process itself. Same reason migration files are timestamped β order is information.
<course>/
00-planning/ -> derives everything below
01-marketing/
02-content/
03-delivery/
04-post-training/ --. post-mortem findings
|
^------------------' feed back into 00..03
That loop at the end matters: the post-mortem doesn't sit in a graveyard folder. Its findings flow back into the syllabus, the run-sheet, the marketing. The structure runs the same feedback loop it's supposed to teach.
_TEMPLATE/
: a course starts as a copy Starting a new course is one line:
cp -r _TEMPLATE my-new-course
The template is the full lifecycle skeleton with the writing already stubbed. What you must fill is marked as <angle-bracket-slots>
β <course-name>
, <promise-one-liner>
, and so on. Everything not in a slot is standing structure you keep.
The part I like most is the definition of done. A course is ready when this returns nothing:
grep -rn '<' --include='*.md' .
No slot hits = no unfilled blanks. It turns "is this finished?" from a judgment call into a command with an exit code β the same instinct as a failing test. If I were wiring this into CI, that grep becomes the assertion.
_ARCHIVED/
: park it, don't delete it
Retired formats and old campaigns go into _ARCHIVED/
, in dated subfolders with a note on why it was retired and what replaced it. One rule keeps it honest: nothing live may reference anything in there. If a live file still links to it, it isn't archived β it's just moved.
Why keep it at all? Because a retired price, a killed campaign style, or an abandoned format is a recorded decision. Deleting it loses the "we already tried that, here's why it didn't work." Git history technically has it, but nobody spelunks reflog for a pricing decision.
CLAUDE.md
: the convention, machine-readable
The last piece is a CLAUDE.md
at the root that spells out the layout, the naming rules, and the standing decisions. It's written for an AI coding agent, but the real value is broader: it's the one file where the convention lives as text instead of as tribal knowledge in my head. Any collaborator β human or agent β reads one file and knows where things go.
The pattern generalizes past courses. Any repeatable body of work with a lifecycle β client engagements, product launches, incident write-ups β benefits from the same three moves: one fixed shape, a copy-to-start template with a grep-checkable done state, and a parking lot for retired decisions. Consistency you can grep
beats consistency you have to remember.