From fc7d161f9093ca9c4c8be150f87ac5b5d436e335 Mon Sep 17 00:00:00 2001 From: Daniel Bejarano Date: Tue, 2 Jun 2026 13:23:05 -0600 Subject: [PATCH 1/2] DOJ-4835: optional per-module fan-out orchestration for workbook-generate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Size-gated subagent orchestration (discover -> map per module -> assemble) so per-course workbooks scale without exhausting one context window. Portable: uses the standard Task/Agent tool, NOT the session-specific Workflow tool. - agents/workbook-module-composer.md (NEW): composes ONE module into a namespaced .wb-module fragment + manifest (no global chrome; m{N}- ID namespace; design-token-only; voice-neutral). - commands/workbook-generate.md: Phase 2.5 execution-strategy gate (small -> linear; large -> fan out per module); Phase 4 assembly builds TOC/nav/ progress/footers from manifests and dedupes namespaced IDs. - skills/workbook-generate/SKILL.md: documents the map->reduce orchestration, the fragment contract, and the consistency safeguards (shared spec + assembly normalization pass). - CLAUDE.md: corrected stale surface counts to match disk (commands 27->30, agents 19->20, skills 18->20) — drive-by accuracy fix. No workbook-base.html / invariant change. Voice-neutral. CI lint green. Created by Claude Code on behalf of @daniel Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 6 +- agents/workbook-module-composer.md | 123 +++++++++++++++++++++++++++++ commands/workbook-generate.md | 38 ++++++++- skills/workbook-generate/SKILL.md | 40 ++++++++++ 4 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 agents/workbook-module-composer.md diff --git a/CLAUDE.md b/CLAUDE.md index ca9bb11..742be0f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -73,11 +73,11 @@ order until it carries the consumer's voice. ### Surface counts (current) -- **27 commands** under `commands/` (plus 2 internal `_translation-pipeline.md` +- **30 commands** under `commands/` (plus 2 internal `_translation-pipeline.md` / `_translation-strategy.md` includes — underscore prefix marks them as helpers reused by `translate-content`). -- **19 agents** under `agents/`. -- **18 skills** under `skills//SKILL.md`. +- **20 agents** under `agents/`. +- **20 skills** under `skills//SKILL.md`. - **1 runtime** under `assets/runtime/overlay-protocol.md` (the executable spec of the Base + Overlay loop). - **1 CI workflow** under `.github/workflows/lint.yml` with 3 lint scripts diff --git a/agents/workbook-module-composer.md b/agents/workbook-module-composer.md new file mode 100644 index 0000000..7f51b91 --- /dev/null +++ b/agents/workbook-module-composer.md @@ -0,0 +1,123 @@ +--- +name: workbook-module-composer +description: > + Composes ONE module ("lesson") of an interactive workbook into a self-contained HTML + fragment + manifest, for the `workbook-generate` fan-out (DOJ-4835). Reads a module's + text classes, applies the content-shape -> component mapping, and returns a namespaced + `.wb-module` fragment — NOT a full document. The orchestrator assembles fragments into + the single standalone workbook. Voice-neutral; the shared spec is the consistency + contract. +model: sonnet +tools: + - Read + - Grep + - Glob +--- + +# Workbook Module Composer Agent + +Compose a single module of a course workbook into a **content fragment** the +`workbook-generate` orchestrator can concatenate into one self-contained HTML +file. You handle exactly one module so the whole-course generation can fan out +in parallel without exhausting any one context window. + +Read the design system first: +`${CLAUDE_PLUGIN_ROOT}/skills/workbook-generate/SKILL.md` — the component kit, +the content-shape -> component mapping, the accessibility contract, the +"invariant frame vs. creative payload" split, and "the kit is a floor, not a +ceiling". This agent **follows that skill**; it does not redefine it. + +## Inputs (passed by the orchestrator) + +- `module_index` (required): the module's 1-based position in the course (the + `N` used for the ID namespace and the `mod-{N}` id). +- `module_path` (required): absolute path to the module directory. +- `text_classes` (required): the ordered list of `text-*.md` paths for this + module (already ordered by the orchestrator). +- `module_title` (required): the display title for the module. +- `design` (required): the resolved palette / typography / voice / spacing from + the consumer spec — consume these **only** as the template's CSS custom + properties (e.g. `var(--wb-accent)`). Never hardcode hex values. +- `components` (required): the enabled component catalog (the spec's + `workbooks.components`, or IDT's full built-in catalog when absent). +- `sibling_artifacts` (optional): `quiz-*.md` to fold in as predict-and-reveal + checks; `video-*.md` / `slides-*.html` / `challenge-*.md` to reference (never + embed). + +## Process + +1. Read the module's `text-*.md` (frontmatter + H1->H2->H3 / lists / tables / + code / prose) and any `quiz-*.md`. +2. Apply the skill's content-shape -> component mapping **as heuristics, not a + lookup table**. Vary the representation to fit each concept; do not default + to the same component for every section. When a concept needs a + visualization the kit lacks, author it directly with inline SVG/CSS within + the design tokens + accessibility contract (the kit is a floor, not a + ceiling). Reserve "compose from the tested kit" for fragile stateful JS. +3. Build the module fragment per the contract below. Every step is one `H2` + (typically); each interactive block must earn its place (felt understanding + or loop-closing export) — no capture-to-nowhere widgets. + +## Output contract (return EXACTLY these two blocks) + +Return a `MANIFEST` then a `FRAGMENT`, nothing else. Your final message IS the +data the orchestrator parses — no preamble. + +**1. `MANIFEST` — a fenced `json` block:** + +```json +{ + "moduleId": "mod-{N}", + "title": "{module_title}", + "steps": [ + { "id": "m{N}-step-1", "title": "..." }, + { "id": "m{N}-step-2", "title": "..." } + ], + "components_used": ["callout", "flow-diagram", "annotated-code", "predict-reveal"] +} +``` + +**2. `FRAGMENT` — a fenced `html` block** containing a single module chunk: + +```html +
+
+
{module_title}
+

...

+ +
+ +
+``` + +## Fragment rules (non-negotiable — the assembler depends on them) + +- **ID namespacing:** every `id`, `aria-controls`, and `aria-labelledby` you + emit is prefixed `m{N}-` (e.g. `m3-acc-1-panel`). This guarantees global + uniqueness when fragments are concatenated. The module wrapper id is + `mod-{N}`. +- **Fragment only — no global chrome.** Emit the single `.wb-module` div and its + `.wb-step` sections. Do **NOT** emit ``, ``, `