@erclx/aitk 0.99.1 → 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "0.99.1",
4
+ "version": "0.100.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: claude-teach
3
+ description: Scope boundary for learning a subject across sessions, and the split between the disposable lesson and the durable reference page
4
+ ---
5
+
6
+ # Claude teach requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, a session asked to teach a subject answers in the conversation, so everything it produced dies with the session and the next one starts from nothing. It teaches from recall rather than from a source, so the learner is handed claims nothing was read for and cannot tell which ones. It picks the next topic from the subject's own order rather than from what the learner got wrong, so it teaches past a gap it never measured. It asks nothing about what the learner already knows, so difficulty has no floor and the session lands either below or far above them.
11
+
12
+ It also produces one output where two are needed. A page written to be worked through once and a page written to be looked up later have different lifetimes and different readers, and merging them yields material that is disposable and gets kept, or durable and carries a quiz nobody can promote. Writing the durable half in a format the authoring gates do not read costs a conversion at the moment it matters most, which is the moment someone tries to promote it.
13
+
14
+ A session that does record something records the wrong thing. It writes what was taught rather than what the learner retrieved, and a tally of errors carries none of the misconception a later session would work against.
15
+
16
+ Two failures land specifically on where the folder sits. A workspace resolved against the current directory forks into a copy per linked worktree, so the learning records split and no session sees the whole history. A body naming only the destination path reports success and loses the write, because the file-editing tools refuse a main-root path from a linked worktree and offer a worktree copy instead.
17
+
18
+ ## Must
19
+
20
+ - Hold the workspace at the main worktree root, so one learner has one history rather than one per worktree
21
+ - Name the write route for a main-root path from a linked worktree, since a body naming only the destination reports a success that did not happen
22
+ - Settle the learner's starting point by asking, so difficulty sits above a measured floor
23
+ - Research the subject from sources before teaching it, and record what was read and what was found and not opened
24
+ - Place each lesson from the learning records rather than from the subject's order, and open with retrieval on the last wrong answer
25
+ - Split the output by lifetime, sending the worked-through half to lessons and the looked-up half to reference pages in the format the authoring gates read
26
+ - Record the wrong answer itself rather than the count, since that is what the next session places the learner from
27
+ - Report progress against the mission's success lines, so a mission can be called finished
28
+
29
+ ## Must not
30
+
31
+ - Teach from recall without saying which claims rest on it
32
+ - Write outside the workspace folder, which is what a promotion pass owns rather than this skill
33
+ - Open a second workspace on a subject an existing one already covers
34
+ - Renumber a workspace folder, a lesson, or a learning record, since the number is cited by files already written
35
+
36
+ ## Guards
37
+
38
+ - No subject named and no existing workspace matching, stop rather than opening a workspace with nothing to learn
39
+
40
+ ## Out of scope
41
+
42
+ - Promoting a durable page out of the workspace, which is a judgment about public prose and belongs to a separate surface
43
+ - The command surface and the records backup for the folder, which resolve the root in-process and carry the workspace off one disk
44
+ - What a lesson renders as and how a quiz behaves once rendered, which the lesson-craft reference shapes and a rendering layer executes
45
+ - Deciding when to fire. The skill is user-invoked through `disable-model-invocation`, so opening a workspace is the learner's call rather than a description match.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: claude-teach
3
+ description: Opens and runs a learning workspace on one subject, holding a mission, resources, numbered lessons, reference pages, a glossary, and learning records that survive across sessions. Use when asked to "teach me X", "open a learning workspace", "I want to learn X", "quiz me on this", "continue the lesson", or "resume my workspace on X". Do NOT use to write project documentation, which belongs to the surface owning that document, and do NOT use to answer one question, which is an ordinary reply.
4
+ disable-model-invocation: true
5
+ argument-hint: <subject to learn, or the topic of the workspace to resume>
6
+ ---
7
+
8
+ # Claude teach
9
+
10
+ Run a learning workspace on one subject across sessions. The workspace holds what the learner has been through, so a session weeks later resumes from the folder rather than from the conversation.
11
+
12
+ The shape of the workspace is fixed by `.claude/standards/teach.md`, or `${CLAUDE_SKILL_DIR}/../../standards/teach.md` when the project does not have that file. Read it before writing anything into the folder. The pedagogy sits in `${CLAUDE_SKILL_DIR}/references/pedagogy.md` and the lesson craft in `${CLAUDE_SKILL_DIR}/references/lesson-craft.md`.
13
+
14
+ ## Guards
15
+
16
+ - If the invocation names no subject and no existing workspace matches, stop: `❌ No subject. Invoke with the subject to learn, or the topic of a workspace to resume.`
17
+ - Never trust recall for what the subject says. Research first, cite what was read, and say what was not.
18
+ - Write nothing outside the workspace folder. A durable page stays in `reference/` until a promotion pass moves it, and this skill runs no promotion.
19
+ - Do not open a second workspace on a subject one already covers. Resume that one.
20
+
21
+ ## Step 0: resolve the workspace root
22
+
23
+ Workspaces live at the main worktree root, never inside a linked worktree. A copy per worktree forks the learning records, and the learner is one person.
24
+
25
+ ```bash
26
+ git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-
27
+ ```
28
+
29
+ Fall back to the current directory when that reports nothing. Workspaces sit under `<main-root>/.claude/teach/`.
30
+
31
+ From a linked worktree the file-editing tools refuse every path under that root and offer a worktree copy instead, which is a second file no later session reads. Never take that redirect. Create a file as one plain shell command carrying a heredoc, and change a file that already exists by reading it and writing it back whole through the same route.
32
+
33
+ ## Step 1: open or resume
34
+
35
+ List the folders under the workspace root. A folder whose topic matches the invocation is a resume, and anything else is a new workspace.
36
+
37
+ On a resume, read `MISSION.md`, the highest-numbered learning record, and `GLOSSARY.md`. Those three carry where the learner stopped and what they got wrong. Report the mission's success lines with what is already met before teaching anything.
38
+
39
+ On a new workspace, settle the starting point first, by asking rather than by assuming. Difficulty with no floor under it teaches nobody, and the mission cannot be written without it.
40
+
41
+ Then take the ordinal from the highest one present, incremented, create the folder as `<nn>-<topic>`, and write all three files the standard requires: `MISSION.md` to the template it carries, `RESOURCES.md` with whatever Step 2 read, and `GLOSSARY.md`, empty of terms until a lesson defines one. A workspace missing any of the three fails its own conformance check the moment anything walks it.
42
+
43
+ ## Step 2: research before teaching
44
+
45
+ Read the subject from sources rather than from recall. Record every source in `RESOURCES.md` with its link, and list under a leads heading anything found and not opened.
46
+
47
+ A claim nothing was read for is the failure this step exists against. Where no source is reachable, say so in the lesson and mark what rests on recall.
48
+
49
+ ## Step 3: place the learner
50
+
51
+ Pick the next lesson from the learning records rather than from the subject's own order. The target is the band immediately past what the learner can already do unaided, which `${CLAUDE_SKILL_DIR}/references/pedagogy.md` states in full.
52
+
53
+ Open with retrieval on what the last session got wrong, before anything new. A learner who cannot retrieve the previous lesson is not ready for the next one, and moving on anyway buys fluency that decays.
54
+
55
+ ## Step 4: write the lesson and the reference
56
+
57
+ Two outputs with two lifetimes, and the split decides the format.
58
+
59
+ - A lesson goes to `lessons/<nnnn>-<slug>.html`, self-contained, carrying its own quiz and the feedback for each answer. It links the shared stylesheet under `assets/` rather than restating styles, and the first lesson in a workspace writes that stylesheet before linking it. A lesson is disposable and is never promoted.
60
+ - A reference page goes to `reference/<slug>.md`, written for a reader with no learner in it. This is the half that survives the workspace, so it is written in markdown to pass the authoring gates a promotion would put it through.
61
+
62
+ Add every term the lesson defines to `GLOSSARY.md`, in the entry shape the standard fixes.
63
+
64
+ Follow `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` for what makes a lesson worth returning to. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct.
65
+
66
+ ## Step 5: record what happened
67
+
68
+ Write `learning-records/<nnnn>-<slug>.md` before the session ends, carrying the lessons covered, what the learner retrieved unaided, what they got wrong with the wrong answer itself, and what to revisit.
69
+
70
+ Record the wrong answer rather than the count. The next session places the learner from this file, and a tally carries no misconception to work against.
71
+
72
+ Then restate the mission's success lines with what is now met. A mission whose lines are all met is finished, and saying so is what closes a workspace.
73
+
74
+ ## Output
75
+
76
+ ```plaintext
77
+ ✅ <opened|resumed> .claude/teach/<nn>-<topic>/
78
+ Lesson: .claude/teach/<nn>-<topic>/lessons/<nnnn>-<slug>.html
79
+ Reference: .claude/teach/<nn>-<topic>/reference/<slug>.md
80
+ Record: .claude/teach/<nn>-<topic>/learning-records/<nnnn>-<slug>.md
81
+ Progress: <n> of <m> success lines met
82
+ ```
83
+
84
+ Omit the reference line where the lesson produced no durable page. Emit every path from the project root, in the form the project's instruction file sets.
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: Lesson craft reference
3
+ description: Typography, restraint, quiz construction, and what makes a lesson worth returning to
4
+ ---
5
+
6
+ # Lesson craft reference
7
+
8
+ Judgment rather than shape. The workspace standard fixes where a lesson sits and what it is named, and this file covers what makes one worth opening twice.
9
+
10
+ ## One course, not a pile of pages
11
+
12
+ A workspace accumulates lessons over weeks. The learner reads them as one body of material, so a lesson that invents its own look reads as someone else's work.
13
+
14
+ - Write the shared stylesheet into the workspace assets on the first lesson, and link it from every lesson after
15
+ - Promote anything used a second time into that stylesheet. A second use makes it a component of the course.
16
+ - Keep the structural furniture identical across lessons: where the title sits, where the quiz sits, what a correct answer looks like
17
+ - Do not restate styles inside a lesson. A local override is a decision the next lesson has to either copy or contradict.
18
+
19
+ ## Typography
20
+
21
+ The learner is reading, so the reading surface is the product.
22
+
23
+ - Set body text at a comfortable reading size with generous line height, and hold the measure to roughly 65 to 75 characters
24
+ - Use one typeface for prose and one for code, and no others
25
+ - Build hierarchy from size and weight rather than from color. Color that carries meaning fails for a reader who cannot see it.
26
+ - Give code blocks room. Cramped code is the part of a lesson a learner skips.
27
+
28
+ ## Restraint
29
+
30
+ Every element competes with the material for attention.
31
+
32
+ - Cut any decoration that carries no information
33
+ - Use at most one accent color, reserved for the thing the learner acts on
34
+ - Do not animate anything the learner did not trigger
35
+ - Prefer whitespace over rules and boxes to separate sections
36
+
37
+ ## Quiz construction
38
+
39
+ The quiz is the retrieval, so a leak in its construction turns it into a reading test.
40
+
41
+ - Write every option to the same length, in words and in characters. A longer option reads as the considered one.
42
+ - Vary which position holds the correct answer, and never let the order follow the order the material was taught in
43
+ - Make each wrong option a misconception someone actually holds. An obviously wrong option removes itself and shrinks the question.
44
+ - Write feedback for every option, including the correct one, saying why rather than whether
45
+ - Give feedback after the attempt, never alongside the question
46
+
47
+ ## What makes a lesson worth returning to
48
+
49
+ - The worked example is complete. A learner returning for the example finds the whole thing rather than a fragment they have to reconstruct.
50
+ - The lesson states what it assumes. A returning reader can tell in one line whether they are in the right place.
51
+ - The hard part is named as the hard part. Material that flattens everything to one difficulty gives a returning reader nothing to navigate by.
52
+ - Nothing depends on the session it was written in. A lesson referring to what was discussed is unreadable a week later.
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Pedagogy reference
3
+ description: Fluency against storage strength, retrieval practice, spacing, interleaving, the zone of proximal development, and where difficulty helps
4
+ ---
5
+
6
+ # Pedagogy reference
7
+
8
+ The rules a lesson is built from. Read this before picking what to teach next, not while writing the markup.
9
+
10
+ ## Fluency is not storage strength
11
+
12
+ A learner who follows an explanation smoothly has demonstrated that the explanation was clear. That is fluency, and it decays within days. Storage strength is whether the material can be retrieved later without the explanation present, and the two move independently.
13
+
14
+ The practical consequence is that a lesson cannot report its own success. Only a later retrieval can, which is why the learning record exists and why every session opens by testing the last one rather than by reviewing it.
15
+
16
+ - Treat a learner's confidence as evidence about the lesson, never about their retention
17
+ - Never advance on the strength of a smooth session. Advance on a retrieval the learner passed unaided.
18
+
19
+ ## Retrieval practice
20
+
21
+ Pulling an answer out of memory strengthens it far more than reading it again. Recognition is the weak form: a learner who picks the right option from four has done less work than one who produced the answer from nothing.
22
+
23
+ - Ask before telling. Open with the question, then teach into the gap the attempt exposes.
24
+ - Prefer a question the learner has to produce an answer to over one they select from
25
+ - Let the learner fail an attempt before correcting it. A failed retrieval followed by the answer beats being told first.
26
+ - Do not cue the answer in the question. A question restating the material tests reading rather than memory.
27
+
28
+ ## Spacing
29
+
30
+ The same total time spread across days beats the same time in one sitting. Forgetting between sessions is the mechanism rather than the cost, because effortful retrieval is what strengthens the trace.
31
+
32
+ - Revisit a topic after the learner has begun to forget it, not while it is still fresh
33
+ - Widen the gap each time a topic is retrieved correctly, and shorten it after a miss
34
+ - Name what to revisit and roughly when in the learning record, so the next session has a schedule rather than a guess
35
+
36
+ ## Interleaving
37
+
38
+ Mixing related topics within a session beats finishing one before starting the next. Blocked practice inflates in-session performance and hurts what survives it, because the learner stops having to work out which approach a problem calls for.
39
+
40
+ - Mix topics inside a session once the learner has a foothold in each
41
+ - Keep problems in a mixed set close enough that telling them apart is the work
42
+ - Do not interleave a topic the learner has never seen. Interleaving discriminates between things already known.
43
+
44
+ ## The zone of proximal development
45
+
46
+ The productive band is what the learner cannot do alone and can do with support. Below it the session is review, and above it the support carries the whole task and nothing transfers.
47
+
48
+ - Compute the band from the learning records rather than from the subject's own order
49
+ - Target the first thing the last record shows the learner could not do unaided
50
+ - Withdraw support as the learner succeeds, and restore it on a miss rather than repeating the lesson
51
+ - Where the records show nothing, ask. A guessed starting point misses in both directions.
52
+
53
+ ## Where difficulty helps and where it hurts
54
+
55
+ Difficulty is not uniformly good. It helps skill acquisition, where the learner is building a procedure they will execute, and it hurts knowledge acquisition, where the learner is taking on facts and structure they do not have yet.
56
+
57
+ - Introduce new facts and structure in their clearest form, with worked examples and no invented obstacles
58
+ - Add difficulty once the learner is practicing rather than acquiring: withhold the worked step, vary the surface of the problem, delay the feedback
59
+ - Never confuse a hard explanation with a hard problem. A confusing explanation adds load that teaches nothing.
60
+
61
+ ## Sourcing
62
+
63
+ Parametric recall is confident where it is wrong, and a learner cannot audit it. Every claim in a lesson traces to something read.
64
+
65
+ - Read the subject from sources before teaching, and record each one with its link
66
+ - Mark any claim resting on recall as resting on recall, in the lesson itself
67
+ - List a source found and not opened as a lead, and never cite it
@@ -7,7 +7,7 @@ description: Validating the session records under .claude/ and the standards cor
7
7
 
8
8
  ## Validate
9
9
 
10
- `aitk records validate <kind>` reports where a file and the standard governing it disagree. Four kinds are gitignored folders under `.claude/`: `plans`, `groundwork`, `intake`, and `memory`. The fifth is `standards`, the authoring corpus, which is tracked and installed rather than scratch.
10
+ `aitk records validate <kind>` reports where a file and the standard governing it disagree. Five kinds are gitignored folders under `.claude/`: `plans`, `groundwork`, `intake`, `memory`, and `teach`. The sixth is `standards`, the authoring corpus, which is tracked and installed rather than scratch.
11
11
 
12
12
  ```bash
13
13
  aitk records validate plans
@@ -25,17 +25,18 @@ It reads and never writes, and the reason splits by kind. A session record is pe
25
25
 
26
26
  `standards` reads the authoring root at `standards/` where it exists and the installed copy at `.claude/standards/` otherwise. The authoring root wins because the installed tree is generated from it in the toolkit, where a fix written to the copy is discarded by the next regen. A project that consumed the corpus holds only the second, so one precedence serves both. The walk stays flat, matching install and the catalog, so `standards/bundled/` is out of range: its members are named for the skill that reads them rather than for a path they govern.
27
27
 
28
- Nothing fires it automatically. The four record folders are gitignored, so the standards-audit hook exits early on them and any check reading changed files from git never lists one. The corpus is tracked and still unreached, since the markdown audit reads content across the files git lists and rules on no filename. The verb runs at the moment a session claims the record is finished, which is the same placement `aitk tasks validate` takes over the board.
28
+ Nothing fires it automatically. The five record folders are gitignored, so the standards-audit hook exits early on them and any check reading changed files from git never lists one. The corpus is tracked and still unreached, since the markdown audit reads content across the files git lists and rules on no filename. The verb runs at the moment a session claims the record is finished, which is the same placement `aitk tasks validate` takes over the board.
29
29
 
30
30
  ### What each kind checks
31
31
 
32
- | Kind | What it reports |
33
- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
- | `plans` | A filename that is not `feature-<slug>.md`, a missing `# Feature:` heading, a missing required section, a files-to-touch entry naming no file or saying nothing about one, and a question carrying no suggestion or no answer slot |
35
- | `groundwork` | A track with no `README.md` or no `01-current-state.md`, a file missing `title` or `description`, a `README.md` with no `date` as `YYYY-MM-DD`, an unnumbered file, and a track holding a decision without its handoff or the reverse |
36
- | `intake` | A dump with no `00-overview.md`, the same frontmatter and numbering checks, an item missing any of `Problem`, `Fix`, `Worth it`, or `You`, and an item carrying `Open` with no `Suggested` |
37
- | `memory` | A filename whose prefix names none of the four types, an entry missing `title`, `description`, or `category`, a `category` disagreeing with that prefix, a title repeating the filename, and a rule-bearing body missing a part |
38
- | `standards` | A standard missing `title` or `description`, an absent `## Scope` section, a scope section carrying no `Does not govern:` list, a statement anchoring nothing, and a filename naming no part of the path the statement governs |
32
+ | Kind | What it reports |
33
+ | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
+ | `plans` | A filename that is not `feature-<slug>.md`, a missing `# Feature:` heading, a missing required section, a files-to-touch entry naming no file or saying nothing about one, and a question carrying no suggestion or no answer slot |
35
+ | `groundwork` | A track with no `README.md` or no `01-current-state.md`, a file missing `title` or `description`, a `README.md` with no `date` as `YYYY-MM-DD`, an unnumbered file, and a track holding a decision without its handoff or the reverse |
36
+ | `intake` | A dump with no `00-overview.md`, the same frontmatter and numbering checks, an item missing any of `Problem`, `Fix`, `Worth it`, or `You`, and an item carrying `Open` with no `Suggested` |
37
+ | `memory` | A filename whose prefix names none of the four types, an entry missing `title`, `description`, or `category`, a `category` disagreeing with that prefix, a title repeating the filename, and a rule-bearing body missing a part |
38
+ | `standards` | A standard missing `title` or `description`, an absent `## Scope` section, a scope section carrying no `Does not govern:` list, a statement anchoring nothing, and a filename naming no part of the path the statement governs |
39
+ | `teach` | A workspace folder carrying no two-digit ordinal, an absent `MISSION.md`, `RESOURCES.md`, or `GLOSSARY.md`, a file missing `title` or `description`, a mission with no `date` as `YYYY-MM-DD` or no `## Success looks like` section, an unnumbered learning record, and a reference page opening with an ordinal |
39
40
 
40
41
  The half-closed track is the groundwork check a reader cannot run by eye. A folder holding `06` without `07` reads as closed to anyone scanning filenames while the file a returning session actually opens is absent.
41
42
 
@@ -89,7 +89,7 @@ The plan's shape is fixed by `.claude/standards/plan.md`: the section list, the
89
89
 
90
90
  An execution that picks other than the suggestion rewrites the `- Suggested:` line as `overridden at execution to <pick>,` followed by the measurement that moved it, and leaves the slot blank. That fixed phrase is how a reader of the archived plan tells an override from a suggestion the execution accepted, since an authored suggestion often carries a number of its own. The same deviation takes one line in the open task's `## Findings`, which is the register that survives the plan being archived. A deviation from a question somebody already answered goes back to whoever answered it instead, since a filled slot is a decision already made.
91
91
 
92
- `aitk records validate plans` reports where a plan and that standard disagree: a filename that is not `feature-<slug>.md`, a missing required section, a files-to-touch entry naming no file, and a question carrying a suggestion with no answer slot. The same verb takes `groundwork`, `intake`, and `memory`, which are governed the same way and were unreachable for the same reason. Nothing fires it automatically, because all four folders are gitignored and every check the repository runs reads changed files from git. It reports and never writes, since the folders are per-machine scratch with no history to recover a wrong repair from.
92
+ `aitk records validate plans` reports where a plan and that standard disagree: a filename that is not `feature-<slug>.md`, a missing required section, a files-to-touch entry naming no file, and a question carrying a suggestion with no answer slot. The same verb takes `groundwork`, `intake`, `memory`, and `teach`, which are governed the same way and were unreachable for the same reason. Nothing fires it automatically, because all five folders are gitignored and every check the repository runs reads changed files from git. It reports and never writes, since the folders are per-machine scratch with no history to recover a wrong repair from.
93
93
 
94
94
  `aitk records push` carries these folders off the disk they live on, and `aitk records pull` brings them back. Eight of them are backed: `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `task-archive`, and `tasks`. The history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree, so every path a task file cites stays where it is.
95
95
 
@@ -278,8 +278,9 @@ This section is the corpus the coverage claim is measured against: every name `a
278
278
  | -------------------------- | ------------------------------------------------------------------------------ |
279
279
  | `aitk:toolkit-cli` | Before a sync or install, to learn what it overwrites, merges, or leaves alone |
280
280
  | `aitk:youtube-transcripts` | When a video transcript is wanted in the repo as context |
281
+ | `aitk:claude-teach` | To learn a subject across sessions, in a workspace that holds the progress |
281
282
 
282
- Both rows answer a question rather than mark a point in a project's life, so a phase above would send a reader to the wrong group.
283
+ Every row answers a question rather than marking a point in a project's life, so a phase above would send a reader to the wrong group.
283
284
 
284
285
  ## Feedback routing
285
286
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "0.99.1",
4
+ "version": "0.100.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -10,9 +10,10 @@ import { gitEnv } from '@/git-env'
10
10
  * enclosing repository already. The list is spelled out rather than read off
11
11
  * that group so adding an ignore entry cannot silently enlarge the payload.
12
12
  *
13
- * `RECORD_KINDS` in `validate.ts` overlaps this on four names and carries one
13
+ * `RECORD_KINDS` in `validate.ts` overlaps this on five names and carries one
14
14
  * more that no backup reaches. The two lists differ on purpose: one is what a
15
- * standard governs, this is what a disk loss would take.
15
+ * standard governs, this is what a disk loss would take, and `standards` is
16
+ * tracked so a backup would carry a second copy of committed files.
16
17
  */
17
18
  export const BACKED_FOLDERS = [
18
19
  'groundwork',
@@ -23,6 +24,7 @@ export const BACKED_FOLDERS = [
23
24
  'review',
24
25
  'task-archive',
25
26
  'tasks',
27
+ 'teach',
26
28
  ] as const
27
29
 
28
30
  /** Holds the records history beside the folders it tracks, ignored by the enclosing repository. */
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'node:fs'
1
+ import { existsSync, statSync } from 'node:fs'
2
2
  import { readdir, readFile } from 'node:fs/promises'
3
3
  import { join } from 'node:path'
4
4
  import { parseFrontmatter, readField } from '@/indexes/frontmatter'
@@ -10,6 +10,7 @@ export const RECORD_KINDS = [
10
10
  'intake',
11
11
  'memory',
12
12
  'standards',
13
+ 'teach',
13
14
  ] as const
14
15
 
15
16
  export type RecordKind = (typeof RECORD_KINDS)[number]
@@ -29,6 +30,7 @@ const FOLDERS_BY_KIND: Readonly<Record<RecordKind, readonly string[]>> = {
29
30
  intake: [join('.claude', 'intake')],
30
31
  memory: [join('.claude', 'memory')],
31
32
  standards: ['standards', join('.claude', 'standards')],
33
+ teach: [join('.claude', 'teach')],
32
34
  }
33
35
 
34
36
  /**
@@ -106,7 +108,7 @@ export function isRecordKind(value: string): value is RecordKind {
106
108
  /**
107
109
  * Whether a kind's folder is shared session scratch at the main worktree root.
108
110
  *
109
- * The four record folders are, so every session validates the records every
111
+ * The five record folders are, so every session validates the records every
110
112
  * other session reads. The corpus is tracked instead, so a linked worktree holds
111
113
  * its own edited copy, and defaulting that kind to the main root would report on
112
114
  * a tree the session never touched and say nothing about which one it read.
@@ -566,6 +568,174 @@ async function checkDump(dir: string, slug: string): Promise<Finding[]> {
566
568
  return [...findings, ...perCluster.flat()]
567
569
  }
568
570
 
571
+ const TEACH_MISSION = 'MISSION.md'
572
+ const TEACH_RESOURCES = 'RESOURCES.md'
573
+ const TEACH_GLOSSARY = 'GLOSSARY.md'
574
+ const TEACH_REFERENCE = 'reference'
575
+ const TEACH_RECORDS = 'learning-records'
576
+
577
+ const TEACH_SUCCESS = /^##[ \t]+Success looks like[ \t]*$/
578
+ const WORKSPACE_NAME = /^\d{2}-[a-z0-9]+(-[a-z0-9]+)*$/
579
+ const NUMBERED_RECORD = /^\d{4}-[a-z0-9]+(-[a-z0-9]+)*\.md$/
580
+ /**
581
+ * A kebab slug that does not open with an ordinal. The lookahead rejects a
582
+ * leading run of digits followed by a hyphen and nothing else, so a subject
583
+ * whose own name starts with a digit still passes.
584
+ */
585
+ const REFERENCE_NAME = /^(?!\d+-)[a-z0-9]+(-[a-z0-9]+)*\.md$/
586
+
587
+ /** The two fields every markdown file in a workspace carries. */
588
+ async function checkTeachFile(
589
+ dir: string,
590
+ slug: string,
591
+ file: string,
592
+ subject: string,
593
+ ): Promise<Finding[]> {
594
+ const frontmatter = parseFrontmatter(await readFile(join(dir, file), 'utf8'))
595
+
596
+ const missing = ['title', 'description'].filter(
597
+ (field) => !readField(frontmatter, field),
598
+ )
599
+
600
+ if (missing.length === 0) return []
601
+
602
+ return [
603
+ finding(
604
+ 'frontmatter-incomplete',
605
+ slug,
606
+ subject,
607
+ `carries no ${missing.join(' and no ')}.`,
608
+ ),
609
+ ]
610
+ }
611
+
612
+ /**
613
+ * One markdown subfolder of a workspace. `lessons/` and `assets/` are never
614
+ * reached, because a lesson is generated markup carrying no frontmatter and a
615
+ * walk over it would report every one as malformed.
616
+ */
617
+ async function checkTeachSubfolder(
618
+ dir: string,
619
+ slug: string,
620
+ folder: string,
621
+ name: RegExp,
622
+ message: string,
623
+ ): Promise<Finding[]> {
624
+ const path = join(dir, folder)
625
+
626
+ // Tested as a directory rather than for presence. Every other walk in this
627
+ // module takes its path from `listFolders`, and this one is built from a
628
+ // fixed name, so a workspace holding a plain file called `reference` would
629
+ // reach `readdir` and take the whole run down with `ENOTDIR`.
630
+ if (!statSync(path, { throwIfNoEntry: false })?.isDirectory()) return []
631
+
632
+ const files = await listMarkdown(path)
633
+
634
+ const malformed = files
635
+ .filter((file) => !name.test(file))
636
+ .map((file) =>
637
+ finding('name-malformed', slug, `${folder}/${file}`, message),
638
+ )
639
+
640
+ const perFile = await Promise.all(
641
+ files.map((file) => checkTeachFile(path, slug, file, `${folder}/${file}`)),
642
+ )
643
+
644
+ return [...malformed, ...perFile.flat()]
645
+ }
646
+
647
+ async function checkWorkspace(dir: string, slug: string): Promise<Finding[]> {
648
+ const findings: Finding[] = []
649
+
650
+ if (!WORKSPACE_NAME.test(slug)) {
651
+ findings.push(
652
+ finding(
653
+ 'name-malformed',
654
+ slug,
655
+ slug,
656
+ 'is not named NN-<topic> with a two-digit ordinal, so a listing sorts alphabetically rather than by when each workspace opened.',
657
+ ),
658
+ )
659
+ }
660
+
661
+ const files = await listMarkdown(dir)
662
+
663
+ if (!files.includes(TEACH_MISSION)) {
664
+ findings.push(
665
+ finding(
666
+ 'index-missing',
667
+ slug,
668
+ TEACH_MISSION,
669
+ 'is absent, so the workspace states no subject and no success to finish against.',
670
+ ),
671
+ )
672
+ }
673
+
674
+ for (const required of [TEACH_RESOURCES, TEACH_GLOSSARY]) {
675
+ if (!files.includes(required)) {
676
+ findings.push(
677
+ finding(
678
+ 'section-missing',
679
+ slug,
680
+ required,
681
+ 'is required and the workspace carries no such file.',
682
+ ),
683
+ )
684
+ }
685
+ }
686
+
687
+ const perFile = await Promise.all(
688
+ files.map((file) => checkTeachFile(dir, slug, file, file)),
689
+ )
690
+ findings.push(...perFile.flat())
691
+
692
+ if (files.includes(TEACH_MISSION)) {
693
+ const text = await readFile(join(dir, TEACH_MISSION), 'utf8')
694
+
695
+ if (!hasOpeningDate(parseFrontmatter(text)?.raw ?? '')) {
696
+ findings.push(
697
+ finding(
698
+ 'date-malformed',
699
+ slug,
700
+ TEACH_MISSION,
701
+ 'carries no date field as YYYY-MM-DD, so the workspace states no opening day.',
702
+ ),
703
+ )
704
+ }
705
+
706
+ if (
707
+ !linesOutsideFences(text).some((line) => TEACH_SUCCESS.test(line.trim()))
708
+ ) {
709
+ findings.push(
710
+ finding(
711
+ 'section-missing',
712
+ slug,
713
+ '## Success looks like',
714
+ 'is absent, so the mission names no observable thing the learner will be able to do.',
715
+ ),
716
+ )
717
+ }
718
+ }
719
+
720
+ return [
721
+ ...findings,
722
+ ...(await checkTeachSubfolder(
723
+ dir,
724
+ slug,
725
+ TEACH_REFERENCE,
726
+ REFERENCE_NAME,
727
+ 'is not named <slug>.md as a kebab slug opening with no ordinal, so a page looked up rather than worked through implies an order no reader follows.',
728
+ )),
729
+ ...(await checkTeachSubfolder(
730
+ dir,
731
+ slug,
732
+ TEACH_RECORDS,
733
+ NUMBERED_RECORD,
734
+ 'is not numbered NNNN-<slug>.md, so the records carry no read order.',
735
+ )),
736
+ ]
737
+ }
738
+
569
739
  const MEMORY_INDEX = 'index.md'
570
740
  const MEMORY_FIELDS = ['title', 'description', 'category'] as const
571
741
 
@@ -872,6 +1042,22 @@ export function checkStandard(name: string, text: string): Finding[] {
872
1042
  return [...findings, ...checkStandardName(name, scope.statement)]
873
1043
  }
874
1044
 
1045
+ /**
1046
+ * The three kinds whose records are folders rather than files. Keyed by kind so
1047
+ * a seventh arrives as an entry here and the compiler names the walk it owes,
1048
+ * where a ternary chain would silently fall through to whichever branch is last.
1049
+ */
1050
+ const FOLDER_CHECK: Readonly<
1051
+ Record<
1052
+ Exclude<RecordKind, 'plans' | 'memory' | 'standards'>,
1053
+ (dir: string, slug: string) => Promise<Finding[]>
1054
+ >
1055
+ > = {
1056
+ groundwork: checkTrack,
1057
+ intake: checkDump,
1058
+ teach: checkWorkspace,
1059
+ }
1060
+
875
1061
  function refuse(reason: ValidateRefusal, message: string): ValidateRefused {
876
1062
  return { ok: false, reason, message }
877
1063
  }
@@ -939,7 +1125,7 @@ export async function validateRecords(
939
1125
  }
940
1126
 
941
1127
  const folders = await listFolders(dir)
942
- const check = kind === 'groundwork' ? checkTrack : checkDump
1128
+ const check = FOLDER_CHECK[kind]
943
1129
  const perFolder = await Promise.all(
944
1130
  folders.map((slug) => check(join(dir, slug), slug)),
945
1131
  )
@@ -26,5 +26,6 @@ Reference docs for consistent authoring across the toolkit and target projects.
26
26
  - [Slug reference](slug.md): Transform from a git branch name to a slug, and the three responses to an empty result
27
27
  - [Standard reference](standard.md): Shape and content rules for authoring a standard
28
28
  - [Tasks reference](tasks.md): Folder layout, filename convention, readiness groups, and content rules for .claude/tasks/
29
+ - [Teach reference](teach.md): Workspace layout, ordinal naming, frontmatter, and the mission, learning-record, and glossary formats for a learning workspace
29
30
  - [Versioning reference](versioning.md): Phase label vs semver discipline across tasks, PRs, reviews, issues, commits, and tags
30
31
  - [Wireframe reference](wireframes.md): Shape and content rules for .claude/wireframes/<surface>.md files
@@ -0,0 +1,155 @@
1
+ ---
2
+ title: Teach reference
3
+ description: Workspace layout, ordinal naming, frontmatter, and the mission, learning-record, and glossary formats for a learning workspace
4
+ ---
5
+
6
+ # Teach reference
7
+
8
+ Applies to a learning workspace at `.claude/teach/<nn>-<topic>/`. One workspace holds one subject studied across sessions, and it carries both halves of what studying produces: the durable reference material a reader consults later, and the disposable lessons a learner works through once.
9
+
10
+ The folder is gitignored. Its markdown half is written in a format the authoring gates read, so a page promoted out of it later needs no conversion.
11
+
12
+ ## Scope
13
+
14
+ Governs a learning workspace under `.claude/teach/<nn>-<topic>/`: folder layout, ordinal naming, frontmatter, and the mission, learning-record, and glossary formats.
15
+
16
+ Does not govern:
17
+
18
+ - What a lesson teaches, how it sequences difficulty, and what makes one worth returning to, which belong to the surface driving the workspace
19
+ - Where a durable page goes once it leaves the workspace, which belongs to the routing test the destination surface states
20
+ - One question measured in depth before anyone can plan against it: `groundwork.md`
21
+ - A dump of many findings filed by domain, each carrying its own verdict: `intake.md`
22
+ - Voice and word choice: `prose.md`
23
+ - Headings, punctuation, and file references: `markdown.md`
24
+ - When a workspace opens at all, and the procedure that runs one, which belong to the surface driving it
25
+
26
+ ## What a working workspace looks like
27
+
28
+ A workspace works when a session returning after weeks can resume from the folder alone:
29
+
30
+ - Which subject is being learned, and what will the learner be able to do when the mission is finished?
31
+ - Which sources stand behind the material, and which were found and never opened?
32
+ - What has the learner already been through, and what did they get wrong?
33
+ - Which pages here are durable reference material, and which are disposable?
34
+
35
+ A workspace failing these is non-conforming even when it satisfies every shape rule below.
36
+
37
+ ## Folder name
38
+
39
+ - Name the folder `<nn>-<topic>`, a two-digit zero-padded ordinal followed by a kebab-case topic slug.
40
+ - Take the ordinal from the highest one already present, incremented. A listing then sorts by when each workspace opened rather than alphabetically.
41
+ - Use two digits on the folder and four inside it. A person opens far fewer workspaces than one workspace holds lessons.
42
+ - Never renumber an existing folder. The ordinal is the order it opened, and a later reader cites it by that name.
43
+
44
+ ## Layout
45
+
46
+ | Path | Holds | Required |
47
+ | --------------------- | ------------------------------------------------------ | -------- |
48
+ | `MISSION.md` | The subject, the learner's starting point, and success | Always |
49
+ | `RESOURCES.md` | Sources read and sources found but not opened | Always |
50
+ | `GLOSSARY.md` | Terms the subject defines, one entry each | Always |
51
+ | `NOTES.md` | Session scratch that belongs to no other file | Optional |
52
+ | `reference/<slug>.md` | Durable reference pages, the promotable half | Optional |
53
+ | `learning-records/` | Numbered records of what the learner was taken through | Optional |
54
+ | `lessons/` | Numbered lessons, generated and disposable | Optional |
55
+ | `assets/` | Files several lessons share, including the stylesheet | Optional |
56
+
57
+ Only the markdown half answers to a conformance check: `MISSION.md`, `RESOURCES.md`, `GLOSSARY.md`, `NOTES.md`, `reference/`, and `learning-records/`. A lesson is generated markup that nothing downstream cites, so this standard fixes its filename and its location and says nothing about what it contains.
58
+
59
+ ## Frontmatter
60
+
61
+ Every markdown file carries `title` and `description`. `MISSION.md` carries one field the others do not.
62
+
63
+ - `title` (required): what the file covers, in sentence case
64
+ - `description` (required): one line naming what a reader gets from it
65
+ - `date` (required, `MISSION.md` only): the day the workspace opened, as `YYYY-MM-DD`
66
+
67
+ Date the workspace once rather than every file. A per-file date leaves every other file stale the first time one is edited, and the opening date never rots.
68
+
69
+ ## File naming
70
+
71
+ - Number a lesson and a learning record `0001` upward, as `<nnnn>-<slug>.html` and `<nnnn>-<slug>.md`. The number is read order and never changes.
72
+ - Name a reference page for its subject alone, with no number. A reference page is looked up rather than worked through, so an ordinal on one implies an order no reader follows.
73
+ - Keep one shared stylesheet under `assets/` and link it from every lesson. A lesson restating its own styles makes a workspace read as a pile of one-offs rather than as one course.
74
+
75
+ ## MISSION.md
76
+
77
+ Fixes what the workspace is for. Everything else in the folder answers to it.
78
+
79
+ - A one-line statement of the subject
80
+ - A `## Starting point` section stating what the learner already knows, so difficulty has a floor to sit above
81
+ - A `## Success looks like` section listing specific observable things the learner will be able to do
82
+ - A `## Out of scope` section naming what this workspace deliberately does not cover
83
+
84
+ Write each success line as something a learner can be asked to do rather than something they will understand. A line nobody can test is a line nothing can report progress against.
85
+
86
+ ## Learning records
87
+
88
+ One record per session the learner worked through, holding what happened rather than what was taught.
89
+
90
+ - The lessons covered, by number
91
+ - What the learner retrieved correctly without help
92
+ - What they got wrong, and what the wrong answer was
93
+ - What to revisit, and roughly when
94
+
95
+ Record the wrong answer rather than the fact of an error. A wrong answer names the misconception, and the count alone names nothing.
96
+
97
+ ## GLOSSARY.md
98
+
99
+ One entry per term the subject defines, sorted alphabetically.
100
+
101
+ - Lead each entry with the term as a bolded span, then the definition in one or two sentences
102
+ - Define the term without using it
103
+ - Name the lesson or reference page where the term first appears
104
+ - Keep an entry to the meaning. Worked detail belongs on a reference page.
105
+
106
+ ## RESOURCES.md
107
+
108
+ Splits what was read from what was found.
109
+
110
+ - List every source that stands behind the material, each with a link
111
+ - List under a leads heading any source found and not opened, and never cite one
112
+ - Say which claims in the workspace rest on which source
113
+
114
+ A source found and not read is listed as a lead because a link attached to a page nobody opened is worse than no link. Listing it still pays, since it stops a later session searching for what this one already surfaced.
115
+
116
+ ## Conventions
117
+
118
+ - Write the markdown half in the format the authoring gates read, so a page promoted later needs no conversion.
119
+ - Keep a reference page free of the learner. A page carrying a second person or a quiz is a lesson wearing the wrong extension, and it cannot be promoted.
120
+ - Revise a file the subject has moved under rather than appending a second version narrating the change.
121
+
122
+ ## Anti-patterns
123
+
124
+ - **The mission with no test.** Success stated as understanding rather than as a task leaves nothing able to say the mission is finished.
125
+ - **The lesson filed as reference.** A page written to be worked through once sits in `lessons/`, and putting it in `reference/` puts disposable output in the half that gets promoted.
126
+ - **The record that counts errors.** A tally of how many were missed carries none of the misconception, which is the only part a later session can act on.
127
+ - **The date left in the body.** A frontmatter field and a sentence both claiming the opening date resolve to whichever a reader happens to hit, and only one of them is readable by a walker.
128
+ - **The renumbered folder.** Closing a gap in the ordinals moves every name a reader or a record already cited.
129
+
130
+ ## Template
131
+
132
+ ```markdown
133
+ ---
134
+ title: <Subject>
135
+ description: <one line naming what a learner gets from this workspace>
136
+ date: <YYYY-MM-DD>
137
+ ---
138
+
139
+ # <Subject>
140
+
141
+ <One line stating the subject.>
142
+
143
+ ## Starting point
144
+
145
+ <What the learner already knows.>
146
+
147
+ ## Success looks like
148
+
149
+ - <a specific thing the learner will be able to do>
150
+ - <a specific thing the learner will be able to do>
151
+
152
+ ## Out of scope
153
+
154
+ - <what this workspace deliberately does not cover>
155
+ ```