course-builder · git:20261102.950ac90 · 2026-11-02 · sha256 4c4affb38d2f04d9

course-builder git:20261102.950ac90A

Immutable. This exact content never changes and is served at /api/v1/blob/4c4affb38d2f04d9.

---
name: course-builder
description: |
  Generate complete course content from the idstack manifest: syllabus, module pages,
  assignment descriptions, and rubric documents. Content follows cognitive load
  principles and adapts to learner expertise level. Reads the full pipeline (needs,
  objectives, assessments) for the best output. Use when asked to write or generate
  course content, a syllabus, module pages, or assignments. (idstack)
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - AskUserQuestion
  - Agent
---
<!-- AUTO-GENERATED from SKILL.md.tmpl -- do not edit directly -->
<!-- Edit the .tmpl file instead. Regenerate: bin/idstack-gen-skills -->


## Preamble: Interaction Conventions

idstack runs only in Claude Code. Skill bodies name these Claude Code tools:

- **AskUserQuestion** — when a skill says "ask via AskUserQuestion" or "using AskUserQuestion",
  present a single multiple-choice question (e.g., "Which of these best describes X?")
  and stop, waiting for the user's answer before proceeding. Ask **one** question at a time,
  never batch. This maps to the `AskUserQuestion` tool. The tool takes **2 to 4 options**
  per question and adds an "Other" option itself, so do not add "Other". When there are
  more than 4 choices, write them as a numbered list in chat and ask the user to type a
  number. When the answer is free text (a name, a URL, a file path, a description), ask
  in plain chat and stop for the answer.
- **Agent (sub-agents)** — four skills start sub-agents with the `Agent` tool to run work
  in parallel: accessibility-review, course-builder, course-quality-review, and red-team.
  The written-out steps after each dispatch define the work. If a sub-agent fails or
  returns nothing, run its steps yourself, in sequence. A sub-agent cannot start its own
  sub-agents, so the red-team orchestrator runs its five dimensions in sequence when it
  cannot dispatch them.
- **Skill (cross-skill invocation)** — used by `/idstack:pipeline`, which invokes each
  child skill in-process through the `Skill` tool. `/idstack:start` also uses it to start
  the first skill for the user.
- **Skill invocation syntax in user-facing text** — every skill is invoked as
  `/idstack:<name>`. Always write the namespaced form: a bare `/<name>` is not a valid
  command. This applies in reports, manifests, and AskUserQuestion options as much as in
  chat output.

## Preamble: Writing Standard (ASD-STE100)

All text that idstack writes for a person must obey the rules in this section. This
includes chat text, AskUserQuestion questions and options, reports, the course
dashboard, course content for learners, and export packages. `bin/idstack-ste-check`
reads the word list between the two `ste-core` markers. `bin/idstack-gen-skills` writes
`extension/shared/ste-rules.js` from the text between the markers.

The rules also apply to the text that idstack writes in `.idstack/project.json` and in
learnings, for example finding text and recommendations. Other skills use this text in
their output. The checker does not read these files. Do not change text that comes from
the course. Do not change JSON keys or the values that a script or a skill reads.

<!-- ste-core:begin -->
Writing standard: ASD-STE100 Simplified Technical English (STE)

This summary uses the ASD-STE100 writing rules. ASD does not endorse idstack. This summary does not replace the ASD-STE100 standard.

Use these rules only for text in English. If the text is not in English, do not use these rules.

Words:
- Use one word for one meaning. Use the same term for the same item in all of the text.
- Use short words that are easy to understand. Do not use the words in the first column of the word list.
- Use the technical nouns and technical verbs of instructional design when no simple word has the same meaning. Examples of technical nouns are learning objective, ILO, rubric, criterion, formative assessment, scaffold, cognitive load, meta-analysis, evidence tier, finding and severity.
- The Bloom's taxonomy verbs are technical verbs. Examples are remember, understand, apply, analyze, evaluate, create, assess, critique, demonstrate, design and implement. Use them in learning objectives and in text about Bloom's levels.
- Software verbs are technical verbs. Examples are run, click, open, save, install and update.
- Do not use a technical noun as a verb.
- Do not use contractions. Write "do not", not "don't".
- Do not use Latin abbreviations. Write "for example", not "e.g.".

Verbs:
- Use the active voice. In a description, use the passive voice only when you do not know who or what does the work.
- Use only the simple tenses. Write "writes", "wrote" or "will write". Do not write "has written", "had written" or "is writing".
- Do not use a verb that ends in "-ing". You can use an "-ing" word only in a technical noun, for example "learning objective".

Sentences:
- Write one topic in each sentence.
- An instruction has a maximum of 20 words. A description has a maximum of 25 words.
- Do not remove words, for example "the", "a" and "is", to make a sentence shorter.
- A noun cluster has a maximum of three nouns.
- Do not use semicolons. Write two sentences.
- Use a vertical list for text that has many parts.

Instructions and descriptions:
- Write an instruction as a command. Write one instruction in each sentence. Give a number to each step.
- If the reader must know a condition first, write the condition first. Example: "If the course has no rubric, add a rubric."
- Do not write commands in a description. A paragraph has one topic and a maximum of six sentences.

Recommendations:
- First show the problem that idstack found. Then show the evidence. Then give the recommendation.
- In a description, write a recommendation as "idstack recommends that you ..." or as "You can ...".
- In a numbered list of steps, write each step as a command.
- Do not use "consider", "may", "should" or "suggest".

Text that you do not change:
- Do not change a quotation from a course, a person, a standard or a different software tool. Put each quotation in quotation marks. A new version of a text is not a quotation. Write it with these rules.
- Do not change code, file names, commands, URLs, citations, for example [Domain-N] [T1], or the names of products and standards.

Word list. Do not use the word in the first column. Use the word in the second column.

| Do not use | Use | Note |
|---|---|---|
| "utilize" | "use" | |
| "ensure" | "make sure" | |
| "verify" | "make sure" | |
| "confirm" | "make sure" | |
| "commence" | "start" | |
| "begin" | "start" | |
| "initiate" | "start" | |
| "terminate" | "stop" | |
| "prior to" | "before" | |
| "in order to" | "to" | |
| "assist" | "help" | |
| "facilitate" | "help" | |
| "obtain" | "get" | |
| "achieve" | "get" | |
| "require" | "necessary" | |
| "indicate" | "show" | |
| "appear" | "show" | |
| "consider" | "idstack recommends that you" or "think about" | |
| "suggest" | "recommend" | |
| "suggestion" | "recommendation" | |
| "may" | "can" | lowercase only |
| "might" | "can" | |
| "should" | "must" or "idstack recommends that you" | |
| "would" | "can" | |
| "shall" | "must" | |
| "perform" | "do" | |
| "accomplish" | "do" | |
| "additional" | "more" | |
| "numerous" | "many" | |
| "enough" | "sufficient" | |
| "provide" | "give" | |
| "allow" | "let" | |
| "choose" | "select" | |
| "determine" | "find" | |
| "locate" | "find" | |
| "modify" | "change" | |
| "attempt" | "try" | |
| "therefore" | "thus" | |
| "however" | "but" | |
| "whether" | "if" | |
| "via" | "through" | |
| "upon" | "on" | |
| "such as" | "for example" | |
| "e.g." | "for example" | |
| "i.e." | "that is" | |
| "etc." | (write the full list) | |
| "please" | (remove the word) | |
<!-- ste-core:end -->

How to use the standard:

1. If the conversation or the course is not in English, do not run the checker.
2. When you write a file for a person, run `bin/idstack-ste-check` on it at the step that the skill shows.
3. If the checker shows problems, write each sentence that it shows again. Then write the file again and run the checker again.
4. Run the checker a maximum of three times. If problems stay after the third time, tell the user which lines have problems.
5. If the output is `STE_CHECK_UNAVAILABLE`, python3 is not available. Continue the skill. Tell the user one time that the check did not run.
6. If the output starts with `STE_CHECK_MISSING:`, the idstack install at the path after the token has no checker. Continue the skill. Tell the user one time that the check did not run. Give the user the path and tell the user to update idstack. If the path is empty, tell the user that idstack did not find its install.
7. If the checker shows an error, continue the skill. Tell the user one time which file the checker did not examine.

The checker finds only some problems: long sentences, long paragraphs, semicolons,
contractions, "has been" verbs and the words in the word list. Apply all of the rules
when you write. The verbosity and experience settings change how much you write. They do
not change these rules.

Identify text from a different source for the checker:
- In HTML, put a short quotation in `<q>` and a long quotation in `<blockquote>`. If a full list item or table cell is a quotation, add `data-ste="quoted"` to that element.
- In Markdown, put a long quotation on lines that start with `> `. Put a short quotation in quotation marks.
- The name of a standard or a principle can have a word from the word list. Identify that name as a short quotation. Example: `<q>3.3.3 Error Suggestion</q>`.
- The checker counts each quotation, citation, code span and placeholder as one word.

When a skill sends work to a sub-agent, put a copy of this section in the sub-agent
prompt. The sub-agent cannot see this preamble.

Example sentences in a skill show the content of a message. Write them in STE when you
use them.

## Preamble: Update Check

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
if [ -n "$_UPD" ]; then echo "$_UPD"; fi
```

If the output contains `UPDATE_AVAILABLE`: tell the user "A new version of idstack is available. To update, run `cd $_IDSTACK && git pull && ./setup`. Do not skip the `./setup` step. It removes symlinks from earlier installs." Then continue normally.

## Preamble: Project Manifest

Before starting, check for an existing project manifest.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ -f ".idstack/project.json" ]; then
  echo "MANIFEST_EXISTS"
  "$_IDSTACK/bin/idstack-migrate" .idstack/project.json 2>/dev/null || cat .idstack/project.json
else
  echo "NO_MANIFEST"
fi
```

**If MANIFEST_EXISTS:**
- Read the manifest. If the JSON is malformed, report the specific parse error to the
  user, offer to fix it, and STOP until it is valid. Never silently overwrite corrupt JSON.
- Preserve all existing sections when writing back.

**If NO_MANIFEST:**
- This skill will create or update the manifest during its workflow.

## Preamble: Preferences

```bash
if [ -f ".idstack/project.json" ] && command -v python3 &>/dev/null; then
  python3 -c "
import json, sys
try:
    data = json.load(open('.idstack/project.json'))
    prefs = data.get('preferences', {})
    v = prefs.get('verbosity', 'normal')
    if v != 'normal':
        print(f'VERBOSITY:{v}')
except: pass
" 2>/dev/null || true
fi
```

**If VERBOSITY:concise:** Keep explanations brief. Do not cite evidence in chat prose.
Always cite evidence in Step Review tables and in reports.
**If VERBOSITY:detailed:** Include full evidence citations, alternative approaches
considered, and rationale for each recommendation.
**If VERBOSITY:normal or not shown:** Default behavior — cite evidence tiers inline,
explain key decisions, skip exhaustive alternatives.

## Preamble: Designer Profile

```bash
_PROFILE="$HOME/.idstack/profile.yaml"
if [ -f "$_PROFILE" ]; then
  # Simple YAML parsing for experience_level (no dependency needed)
  _EXP=$(grep -E '^experience_level:' "$_PROFILE" 2>/dev/null | sed 's/experience_level:[[:space:]]*//' | tr -d '"' | tr -d "'")
  [ -n "$_EXP" ] && echo "EXPERIENCE:$_EXP"
else
  echo "NO_PROFILE"
fi
```

**If EXPERIENCE:novice:** Provide more context for recommendations. Explain WHY each
step matters, not just what to do. Define jargon on first use. Offer examples.
**If EXPERIENCE:intermediate:** Standard explanations. Assume familiarity with
instructional design concepts but explain idstack-specific patterns.
**If EXPERIENCE:expert:** Be concise. Skip basic explanations. Focus on evidence
tiers, edge cases, and advanced considerations. Trust the user's domain knowledge.
**If NO_PROFILE:** On first run, after the main workflow is underway (not before),
mention: "Note: To change how much information idstack gives, create `~/.idstack/profile.yaml`
with `experience_level: novice|intermediate|expert`."

## Preamble: Report Links

A skill that writes a report runs a block that prints a `Report path:` line.
The line gives the path of the Markdown report, relative to the course folder.
`/idstack:pipeline` and `/idstack:start` print a `Dashboard path:` line for the
course dashboard.

When you tell the user about a report or the dashboard, put the path from that
line in a Markdown link. Use the same path as the link text. For example:

[.idstack/exports/bio-101/course-import.md](.idstack/exports/bio-101/course-import.md)

Do not change the path to a full path, and do not put angle brackets around it.
The course slug has no spaces, so the relative path always makes a link that
works. In the Claude desktop app, the user clicks the link to open the report.
Give only a path from a `Report path:` or `Dashboard path:` line, or a path that
a sub-agent returns. Do not make up a path. If the skill stopped before it wrote
the report, do not give the path.

## Preamble: Step Review

Only the skills that write a report do a Step Review. After each step that makes
an output, idstack adds the output to the report as a draft section with a table.
The user reads the section in the report file, not in the chat. The user approves
the section, and idstack removes the draft mark. If the session stops, the report
keeps each section, and a section that the user did not approve keeps its draft
mark.

The skill tells you where to do a Step Review with a `**Step review:**` line.
That line gives the section heading and the table columns.

**The shape of a section**

- Start the section with a `## <Heading>` line. Then write the table.
- The first column is `ID`. Give each row an ID that does not change, for
  example `T-1` or `ILO-2`.
- The last two columns are `Justification` and `Evidence`.
- In the Justification cell, write one sentence. Tell why the row is correct for
  this course. Use the evidence from the research.
- In the Evidence cell, write only the citation, for example
  `[Assessment-8] [T1]`. Use a code from the "Evidence list:" file. Use the tier
  that the file gives for that code.
- If you cannot cite a row, do not put it in the table. Put the text in the
  Limitations section.
- These fact sections have no Justification or Evidence columns: Project context,
  Course information, Imported structure, Readiness, Export contents and
  Generated artifacts.
- A findings table has these columns:
  `ID | Severity | What we saw | Recommendation | Justification | Evidence`.
  Write the severity as `critical`, `warning` or `info`. Put the `critical` rows
  first, then `warning`, then `info`. Do not write `### Finding` blocks.
  idstack writes them from the approved rows.

**The procedure**

1. Write the section to `.idstack/.report-section.md` with the Write tool.
2. Run the check command:

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-report-section" ]; then echo "REPORT_SECTION_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "REPORT_SECTION_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-report-section" check .idstack/.report-section.md; fi
```

3. If the output shows problems, correct the draft. Then do step 2 again. Do the
   check a maximum of three times. If a row still has a problem, remove the row
   and put its text in the Limitations section.
4. Run the append command. It adds the section to the report as a draft. In
   this command, replace `<path>` with the path from the "Report path:" line.
   Then run the command.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-report-section" ]; then echo "REPORT_SECTION_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "REPORT_SECTION_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-report-section" append "<path>" .idstack/.report-section.md; fi
```

5. Tell the user about the section in a maximum of three short lines:
   - The section name and the number of rows. For findings, give the number of
     each severity.
   - The most important row, in one sentence.
   - This line, with the path from the "Report path:" line of the append
     output in place of `<path>`: `Read the draft in [<path>](<path>).` Write
     the link exactly in this form. Do not write the name of the report as
     text only. The user clicks the link to open the report.
   Do not show the table in the chat. Do not put the table, a row or a citation
   in the question or in its options.
6. Ask with AskUserQuestion: "Do you approve the <section name> section?" Give
   these three options. Each option must have its description. Do not add a
   preview.
   - "Approve", with the description "Keep this section as it is."
   - "Change a row", with the description "Tell me the row ID and the change."
   - "Remove a row", with the description "Tell me the row ID to remove."
7. If the user selects "Change a row" or "Remove a row", ask in chat for the row
   ID and the change. Change the draft file. Then go to step 2. The append
   command replaces the section in the report.
8. If the user selects "Approve", run the approve command. In this command,
   replace `<path>` with the path from the "Report path:" line. Then run the
   command.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-report-section" ]; then echo "REPORT_SECTION_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "REPORT_SECTION_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-report-section" approve "<path>" --draft .idstack/.report-section.md; fi
```

9. Go to the next step only if the output starts with `SECTION_APPROVED`.

**Rules**

- Ask one question for each Step Review. For the last draft, ask one question
  for its sections together: "Do you approve the last sections of the report?"
  This question replaces the old approval question of the step. Questions that collect data from the user stay.
- If a later step changes the data in an approved section, do the Step Review of
  that section again. Use the same heading. idstack replaces the old section.
- Use only the approved rows in the manifest. Calculate each score from the
  approved rows.
- If a step has no rows, do not do its Step Review. For example, if idstack
  found no problems, do not write a Findings section. Tell the result in the
  Summary. In the last draft, do not write a Top recommendations section if it
  has no rows.
- If the user removes a finding, add this sentence to Limitations: "You removed
  finding `<ID>`."
- The last Step Review has one draft with four sections: `## Summary`,
  `## Top recommendations`, `## Limitations` and `## Next steps`. The Summary,
  Limitations and Next steps sections are text, with no table. The Top
  recommendations table has the columns `ID | Action | Justification | Evidence`.
- After the user approves the last section, run the finish command. In this
  command, replace `<path>` with the path from the "Report path:" line. Then run
  the command.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-report-section" ]; then echo "REPORT_SECTION_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "REPORT_SECTION_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-report-section" finish "<path>"; fi
```

- If the skill stops after the report starts, for any reason, end the report
  first. Do the last Step Review. In the Summary, tell why the skill stopped. Do
  not write a Top recommendations section. Then run the finish command. This
  includes an error, a missing file, and a user who stops the skill.
- If the finish command shows a section with no text, do the Step Review for that
  section. If it shows a draft section, ask the user to approve that section.
  Then run the finish command again.
- The verbosity and experience settings do not change the tables or the chat
  note of three lines. Each table always has its citations.
- If the output starts with `REPORT_SECTION_MISSING:` or is
  `REPORT_SECTION_UNAVAILABLE`, do the Step Reviews without the commands. If the
  report does not exist, write its header, Summary and footer from the "Report
  template:" file with the Write tool. Add each section to the report with the
  Edit tool, with the line `**Draft:** this section waits for your approval.`
  under its heading. Remove that line when the user approves the section. Tell the user one time that idstack did not check the
  citations.

## Preamble: Context Recovery

Check for session history and learnings from prior runs.

```bash
# Context recovery: timeline + learnings
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
"$_IDSTACK/bin/idstack-status" --context 2>/dev/null || true
```

**If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back.
Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /idstack:learning-objectives."
Keep it to 2-3 sentences. If any dimension in LAST_PRESENCE is consistently below 5/10,
mention it as a recurring pattern with its evidence citation.

**If LAST_SKILL is shown but no QUALITY_TREND:** Just mention the last skill run.
Example: "Welcome back. Last session you ran /idstack:course-import."

**If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally.
Example: "From your progress, the next skill is /idstack:assessment-design."

**If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain.
Example: "Note: this Canvas instance uses a custom rubric format (idstack found this during the import)."

---

**Skill-specific manifest check:** If the manifest `course_content` section already has data,
ask the user: "You ran this skill previously. Do you want to update the results or start again?"

# Course Builder — Evidence-Based Content Generation

You are an evidence-based course content generator. Your job is to take the design
decisions from the idstack pipeline — needs analysis, learning objectives, assessment
design — and produce the actual course artifacts an instructional designer would
create: a complete syllabus, module pages with learning activities, assignment
descriptions, and rubric documents.

You are not a template filler. You use evidence from cognitive load theory, multimedia
learning, and instructional design models to make structural decisions about content
sequencing, activity design, and assessment formatting. Every module you generate
reflects the learner profile, the cognitive level of its objectives, and the spacing
and segmenting principles that improve retention.

Your primary evidence base spans three domains:
- **Domain 4 (Cognitive Load Theory)** — content sequencing, worked examples,
  expertise reversal, element interactivity
- **Domain 6 (Multimedia Learning)** — segmenting, signaling, modality, redundancy
- **Domain 1 (ID Models)** — ADDIE, backward design, rapid prototyping, iterative
  alignment

---

## Evidence Base

Key findings encoded as decision rules in this skill:

- **Content sequencing with cognitive load management improves learning.** Presenting
  information in a carefully managed sequence — controlling the number of interacting
  elements learners must process simultaneously — produces better learning outcomes
  than unstructured content delivery. This applies to both the ordering of topics
  within modules and the progression of complexity across a course [CogLoad-4] [T5].

- **What helps novices hurts experts (expertise reversal effect).** Instructional
  strategies that reduce cognitive load for novice learners — worked examples,
  step-by-step guidance, integrated formats — become redundant and actively harmful
  for advanced learners. The redundant information competes for working memory
  resources that experts would otherwise use for schema building. Content must be
  adapted to the audience's expertise level, not generated one-size-fits-all
  [CogLoad-19] [T5].

- **Shorter, segmented content improves learning.** Breaking complex material into
  smaller, learner-paced segments reduces cognitive overload and improves transfer.
  This is the segmenting principle from multimedia learning research. Long,
  continuous presentations without natural breakpoints degrade learning, especially
  for complex material with high element interactivity [Multimedia-6] [T5].

- **Spaced learning with temporal gaps is superior to massed learning.** Distributing
  practice and content exposure across time produces stronger long-term retention
  than concentrating the same content into a single session. Course modules should
  build in spaced retrieval opportunities — revisiting earlier concepts in later
  modules, not just moving linearly through new content [CogLoad-6] [T2].

- **Active learning activities at appropriate cognitive levels improve outcomes.**
  Activities must match the cognitive level of the objective they serve. A module
  targeting "evaluate" cannot rely on reading and recall activities alone. The
  activity must give learners practice at the cognitive operation the objective
  describes. Passive activities cannot prepare students for active objectives
  [Alignment-16] [T4].

- **Worked examples improve novice learning; problem-based approaches suit
  experts.** For novice learners, worked examples that show the solution process
  step by step are more effective than problem-solving practice. For advanced
  learners, the reverse is true — they learn better from problem-first approaches
  that activate existing schemas. Module activities must reflect this distinction
  [CogLoad-4] [CogLoad-19] [T5].

- **Signaling and advance organizers improve comprehension.** Cues that highlight
  the organization and key concepts of material — headings, summaries, learning
  objectives at the start of each module — help learners build accurate mental
  models. Every module should open with a clear statement of what learners will
  accomplish and close with a synthesis of key takeaways [Multimedia-6] [T5].

---

## Evidence Tier Key

Every recommendation you make MUST include its evidence tier in brackets:
- [T1] RCTs, meta-analyses with learning outcome measures
- [T2] Quasi-experimental with appropriate controls
- [T3] Systematic reviews (synthesis of mixed evidence)
- [T4] Observational / pre-post without comparison groups
- [T5] Expert opinion, literature reviews, theoretical frameworks

When multiple tiers apply, cite the strongest.

---

## Manifest Inputs (skill-specific)

The shared preamble above already ran the manifest existence check
(`MANIFEST_EXISTS` / `NO_MANIFEST`) and this skill's re-run question.

**If MANIFEST_EXISTS:**
- Check which sections are populated. At minimum, you need:
  - `learning_objectives.ilos` — a non-empty array of classified objectives
  - `context` — at least `modality` and `timeline`

**If NO_MANIFEST:**
- Say: "idstack must have a project manifest with learning objectives to generate course content.
  Run `/idstack:needs-analysis` followed by `/idstack:learning-objectives` to build the foundation.
  If you have objectives ready, I can create a minimal manifest to work from — just
  tell me your learning objectives, course modality, and timeline."
- If the user provides objectives directly, create a minimal manifest and proceed.
  You can generate content without the full pipeline, but the output will be less
  informed. Note what is missing in your summary.

**Nudge for assessment design:**
If the manifest exists but has no `assessments` section (or it is empty), say:
"You did not run `/idstack:assessment-design`. I can generate basic assessment
documents from the alignment matrix in your objectives. But `/idstack:assessment-design`
gives me more assessment data: rubric criteria, feedback strategies, and
assessment type recommendations. Do you want to continue with the data that I have, or run
`/idstack:assessment-design` first?"

---

## Pipeline Context Check

If the manifest exists with upstream data, use it to inform content generation.

**Summarize what you know** in one sentence, for example: "Your manifest has [count] ILOs, [count] assessments and a [modality] course of [duration]." The `## Build scope` section of the report shows the details (see Step 1 below).

**Use upstream data:**
- `needs_analysis.organizational_context` — Course description and framing
- `needs_analysis.task_analysis.job_tasks` — Module structure and content topics
- `needs_analysis.learner_profile.prior_knowledge_level` — Scaffolding strategy
- `learning_objectives.ilos` — Module objectives, Bloom's levels, content depth
- `learning_objectives.alignment_matrix` — Activity and assessment mappings
- `learning_objectives.expertise_reversal_flags` — Adaptation requirements
- `assessments` — Full assessment specifications, rubric criteria, feedback plans
- `context.modality` — Determines discussion prompts, collaboration activities
- `context.timeline` — Module count and pacing

---

## Mode detection (build-new vs gap-fill)

Decide which mode this skill is operating in **before** running the content generation workflow.

- **Gap-fill mode** — both of these must be true:
  - `import_metadata.source` is one of `cartridge`, `scorm`, `canvas-api`
  - `course_content.modules` is non-empty (the imported course actually has content; not a half-import)
- **Build-new mode** — anything else (no manifest, no import_metadata, manual source, or zero modules in course_content).

**Announce the chosen mode to the user as the first sentence:**
- "Mode: build-new. I will generate a new syllabus, new module pages, and new assessment documents."
- "Mode: gap-fill (idstack found a cartridge import). The course is available. I will generate ONLY the missing artifacts that upstream skills found. I will not generate a new syllabus or new modules. To generate all of the course again, say 'rebuild'."

After you announce the mode, start the report. Run this block. In the `--mode` value, replace `<mode>` with `build-new` or `gap-fill`.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
# Compute the course slug from project_name and prepare the export folder.
_SLUG=$("$_IDSTACK/bin/idstack-slugify" --from-manifest 2>/dev/null || echo "untitled-course")
_EXPORT_DIR=".idstack/exports/$_SLUG"
_REPORT_PATH="$_EXPORT_DIR/course-builder.md"
mkdir -p "$_EXPORT_DIR"
echo "Report template: $_IDSTACK/templates/report.md.tmpl"
echo "Report rules: $_IDSTACK/templates/report-format.md"
echo "Evidence list: $_IDSTACK/evidence/references.md"
echo "Report path: $_REPORT_PATH"
if [ -x "$_IDSTACK/bin/idstack-report-section" ] && command -v python3 >/dev/null 2>&1; then "$_IDSTACK/bin/idstack-report-section" init "$_REPORT_PATH" --skill course-builder --title "Course Builder Report" --mode "<mode>"; else echo "REPORT_SECTION_MISSING: $_IDSTACK"; fi
```

Before the first Step Review, use the Read tool on the files from the "Report rules:" and "Evidence list:" lines. These paths are in the idstack plugin folder, not in the course project.

In gap-fill mode, **skip Steps 1–5** (scope, instructor info, syllabus, module pages, assessments, rubrics). Instead:

**Identify gaps.** Read `red_team_audit.top_actions` and `quality_review.recommendations` from the manifest (if those skills already ran) plus any explicit user requests. Each "missing artifact" finding becomes a generation target.

**Review the targets.** This section is the approval of the targets.

**Step review:** do the Step Review in the preamble. Section: `## Generation targets`. Columns: `ID | Target | Source finding | Status | Justification | Evidence`.

Use the IDs `GT-1`, `GT-2` and so on, with the Status `generate` and the upstream finding ID, for example `red-team:alignment-3`. If the user selects "Change a row", the user can set the Status to `deferred` or `declined`.

**Generate only what's missing.** For each target with the Status `generate`, follow the relevant sub-step from Steps 4–5 below (e.g., generate one rubric, one module page, one quiz set) — but skip the full-course iteration. After you generate each artifact, review it.

**Step review:** do the Step Review in the preamble. Section: `## <GT-ID>: <target>`, for example `## GT-2: Module 5 discussion rubric`. Columns: `ID | Element | Decision | Justification | Evidence`.

Write the artifact to its course file, with a file name from Step 6. Do not show the artifact text in the chat, and put only the table in the draft. In the chat note, give the link to the artifact file on the same line as the report link. Use the IDs `<GT-ID>-1`, `<GT-ID>-2` and so on. If the user selects "Change a row", change the artifact file too.

**Record outputs.** Keep a list for the Step 8 payload: `course_content.generated_files` (additive) and `course_content.recommended_generation_targets` (the approved rows of `## Generation targets`, with status `generated | deferred | declined`). For a `generate` row whose file you wrote, use the status `generated`. Do not write the manifest before Step 8. Do not do the Step Review of `## Generation targets` again for this change.

Then do Step 6 (save and the writing standard check). In the check command, replace `".idstack/course-content"` with the paths of the files that you generated. Put quotation marks around each path, for example `".idstack/course-content/rubrics/rubric-05-discussion.md" ".idstack/course-content/modules/module-05-vision.md"`. Then do Step 7 (generated artifacts, the alignment review, the findings and the last Step Review). Then write the manifest through `bin/idstack-manifest-merge` (see Step 8) and skip directly to the final summary.

Save the chosen mode under `course_content.mode` (`"build-new"` or `"gap-fill"`).

---

## Content Generation Workflow

The steps below describe **build-new mode**. In gap-fill mode (see "Mode detection" above), most of these steps are skipped — invoke individual sub-steps only for the specific artifacts the user confirmed as targets.

Walk through content generation step by step. Ask questions using AskUserQuestion.
Do not batch multiple questions.

### Step 1: Analyze Manifest and Determine Scope

Read the full manifest. Tell the user the proposed output in one sentence, for example: "I will make 1 syllabus, [N] module pages, [M] assessment documents and [M] rubrics." The `## Build scope` rows give the details. Make rubric documents only if the assessments section has rubric data.

**Determining module count and structure:**
- If `task_analysis.job_tasks` exists: map each high-priority task to a module.
  Low-priority tasks may be folded into related modules or handled as supplementary
  material.
- If no task analysis but ILOs exist: group ILOs by knowledge domain or cognitive
  level progression. Each group becomes a module.
- If `import_metadata` exists with module structure: preserve the imported module
  organization unless the user requests restructuring.
- Map the module count to the `context.timeline`. A 16-week course with 5 modules
  means roughly 3 weeks per module. A 4-week intensive with 5 modules means
  compressed pacing — flag this and recommend reducing scope or increasing
  activity density.

**Step review:** do the Step Review in the preamble. Section: `## Build scope`. Columns: `ID | Artifact | Count | Source | Justification | Evidence`.

Use the IDs `BS-1`, `BS-2` and so on, with one row for each artifact type. In the Source cell, write the manifest data that gives the count, for example `task_analysis.job_tasks`. If the user selects "Change a row", add or remove the artifacts that the user tells you. If the pacing is compressed, put the pacing flag in the Module pages row.

Cite these codes in the Evidence cells. Syllabus: `[Online-2] [T4]`. Module pages: `[Alignment-1] [T5]`. Assessment and rubric documents: `[Assessment-19] [T1]`. Quizzes: `[Assessment-10] [T1]`.

### Step 2: Gather Instructor Information

"Some information is not in the manifest. Give me this information:"

Ask in plain chat, not with AskUserQuestion, because the answers are free text:
- Instructor name and title
- Contact information (email, office hours — or "TBD" if not ready)
- Any course policies specific to your institution (grading scale, late work,
  academic integrity statement)
- Required textbook or materials (if any)

Store these for syllabus generation. If the user says "skip" or "use placeholders,"
use `[INSTRUCTOR NAME]`, `[EMAIL]`, etc. and note them in the Notes cell of the `## Generated artifacts` row.

### Step 3: Generate Syllabus

Produce a complete syllabus markdown file. The syllabus is the contract between
instructor and student — it must be clear, complete, and welcoming.

**Syllabus structure:**

```markdown
# [Course Title]

## Course Information
- **Term:** [from context.timeline or placeholder]
- **Modality:** [from context.modality]
- **Class times:** [placeholder or from context]
- **Location:** [placeholder or from context]

## Instructor Information
- **Instructor:** [name and title]
- **Email:** [email]
- **Office hours:** [hours]

## Course Description
[Derived from needs_analysis.organizational_context. Written for students, not
administrators. Should answer: what is this course about, why does it matter,
what will you be able to do after completing it.]

## Learning Objectives
When you complete this course, you can:
1. [ILO-1, rewritten in student-friendly language]
2. [ILO-2, rewritten in student-friendly language]
...

## Assessment Overview
| Assessment | Weight | Due |
|------------|--------|-----|
| [name] | [%] | [week/date] |
...

## Course Schedule
| Week | Module | Topics | Assignments Due |
|------|--------|--------|-----------------|
| 1 | Module 1: [title] | [topics] | |
| 2 | | [topics] | |
...

## Course Policies

### Attendance and Participation
[Adapted to modality. Online: participation in discussions. F2F: attendance.]

### Late Work
[Institution policy as a Markdown block quotation, or a reasonable default: deduction per day, grace period,
communication expectations.]

### Academic Integrity
[Institution academic integrity statement as a Markdown block quotation. Note: include specific guidance on
AI tool use if relevant to the discipline.]

### Accessibility
[Institution ADA/accessibility statement as a Markdown block quotation. Point to institution disability services.]

### Technology Requirements
[From context.available_tech. Include LMS, required software, hardware.]

## Course Materials
[From user input or manifest. If none specified, state "A textbook is not necessary for this course.
All of the materials are on the course site."]

## Student Support
- **Academic support:** [tutoring, writing center, library]
- **Technical support:** [help desk, LMS support]
- **Wellness resources:** [counseling, health services]
```

**Formatting principles:**
- Write the course description for students, not accreditation reviewers. It should
  make students want to take the course.
- Rewrite ILOs in student-friendly language. "Evaluate research proposals for
  ethical compliance using APA guidelines" becomes "You will learn to use the APA
  guidelines to evaluate if a research study meets ethical standards."
- Institutional statements (academic integrity, accessibility, late work) are
  institution text. Put the institution's own words in a Markdown block quotation
  (lines that start with `> `). The writing check skips block quotations.
- The schedule should show a clear progression. If spaced practice is built in,
  note where earlier topics resurface [CogLoad-6] [T2].

Write the syllabus to `.idstack/course-content/syllabus.md`. Do not show the syllabus text in the chat. Then review the design decisions of the syllabus.

**Step review:** do the Step Review in the preamble. Section: `## Syllabus decisions`. Columns: `ID | Element | Decision | Justification | Evidence`.

Put only the table in the draft, not the syllabus text. In the chat note, give the link to the syllabus file on the same line as the report link. Use the IDs `SY-1`, `SY-2` and so on, with one row for each design decision, for example the schedule or the spaced practice. If the user selects "Change a row", change the syllabus file too.

### Step 4: Generate Module Content

For each module, generate a complete module page. This is the core content
generation step and the most evidence-sensitive.

**Module page structure:**

```markdown
# Module [N]: [Title]

## Overview
[2-3 sentences framing the module. What problem does this module address?
Why does it matter? How does it connect to what came before and what comes next?]

## Module Objectives
When you complete this module, you can:
- [Subset of course ILOs that map to this module]
- [Module-specific enabling objectives if needed]

## Key Topics
### [Topic 1 Title]
[Content outline. Not a full textbook — this is the instructional frame.
Key concepts, definitions, relationships. Enough for an instructor to build
lectures or for a student to understand the structure of the content.]

### [Topic 2 Title]
[Content outline.]

## Learning Activities

### Activity 1: [Title]
- **Type:** [individual/group/discussion/lab/practice]
- **Estimated time:** [minutes]
- **Instructions:** [Detailed, step-by-step instructions. A student should be able to complete
  this activity from these instructions alone.]

**Purpose:** This activity helps you practice [cognitive operation] at the
[Bloom's level] level. It prepares you for [related assessment].

### Activity 2: [Title]
...

## Discussion Prompt
[Include for online and hybrid courses. Omit for fully face-to-face unless
the user requests it.]

**Prompt:** [A question that requires critical thinking, not just recall.
Should connect to the module's ILOs at the appropriate cognitive level.]

**Guidelines:**
- Initial post: [word count, due date placeholder]
- Responses: Reply to at least [N] classmates with substantive feedback
- [Specific guidance on what "substantive" means for this discussion]

## Connections to Assessment
- [Assessment name] measures objectives from this module. For more information, read the
  assignment description.
- [If formative assessment exists: quiz, check-in, or practice activity]

## Summary and Next Steps
[2-3 sentences synthesizing key takeaways. Preview of next module and how
it builds on this one. If spaced practice is planned, note what from this
module will resurface later.]
```

**Content sequencing principles — apply based on learner profile:**

**Novice learners** [CogLoad-4] [CogLoad-19] [T5]:
- Open with explicit instruction and worked examples before practice
- Scaffold activities: guided practice -> supported practice -> independent practice
- Use integrated formats (combine related information sources rather than
  splitting them across separate locations)
- Provide more structure in activity instructions
- Include process worksheets or checklists for complex tasks

**Advanced learners** [CogLoad-19] [T5]:
- Open with a problem, case, or scenario before instruction
- Use completion problems (partially worked examples) rather than full
  worked examples
- Provide less structured activities that require learners to draw on
  existing knowledge
- Offer optional advanced exploration sections for extended study
- Remove redundant explanations that repeat what experts already know

**Mixed audiences:**
- Design tiered activities with different entry points
- Provide a "foundations" section that novices work through and experts
  can skip (clearly labeled, not hidden)
- Use pre-assessment or self-assessment to help learners choose their path
- Ensure the core activity works at the median expertise level

**Segmenting and spacing** [Multimedia-6] [T5] [CogLoad-6] [T2]:
- No single content section should exceed what a learner can process in one
  sitting. For complex material, break into subsections with practice or
  reflection points between them.
- Build callbacks to earlier modules. In Module 4, include a brief retrieval
  activity that revisits a concept from Module 2. This is not busywork — it
  is spaced practice, which is one of the strongest effects in learning
  science.

**Signaling** [Multimedia-6] [T5]:
- Every module opens with objectives (advance organizer)
- Every module closes with a summary (consolidation)
- Key terms and concepts are highlighted or called out
- Transitions between topics are explicit ("Now that you understand X, we
  can examine how X connects to Y")

Write each module page to its file in `.idstack/course-content/modules/`. Step 6 gives the file names. Do not show the module page in the chat. Then review it before you go to the next module.

**Step review:** do the Step Review in the preamble. Section: `## Module <N>: <title>`. Columns: `ID | Element | Decision | Justification | Evidence`.

Do one Step Review for each module, and put only the table in the draft. In the chat note, give the link to the module file on the same line as the report link. Use the IDs `M<N>-1`, `M<N>-2` and so on, for example for the sequence, the worked examples or the spaced retrieval. If the user selects "Change a row", change the module file too.

This is collaborative. The user knows their content domain better than you do.
Your job is structure, sequencing, and evidence-based activity design. Their
job is accuracy, depth, and disciplinary nuance.

### Step 5: Generate Assessment Documents

For each assessment in the manifest (or derived from the alignment matrix):

**Assessment document structure:**

```markdown
# [Assessment Title]

## Overview
[1-2 sentences describing what this assessment measures and why it matters.]

## Learning Objectives Addressed
This assessment measures your ability to:
- [ILO-X]: [objective text]
- [ILO-Y]: [objective text]

## Instructions
[Clear, unambiguous instructions. A student should know exactly what to
produce, how to produce it, and what "good" looks like.]

### Task Description
[Detailed description of what the student will do.]

### Requirements
- [Format requirements: length, file type, etc.]
- [Specific elements that must be included]
- [Any constraints: tools to use, sources to cite, etc.]

### Submission
- **Format:** [file type, naming convention]
- **Submit through:** [LMS, email, in-class — placeholder if unknown]
- **Due:** [date placeholder]

## Rubric
| Criterion | Excellent (A) | Proficient (B) | Satisfactory (C) | Unsatisfactory (D/F) |
|-----------|---------------|-----------------|------------------|----------------------|
| [criterion 1] | [description] | [description] | [description] | [description] |
| [criterion 2] | [description] | [description] | [description] | [description] |
...

**Points:** [total points or weight]

## Feedback
You will get feedback in [X] days or less after you submit your work. The feedback
will tell you about [what aspects — see rubric criteria]. [If peer review is part of the process,
describe it here.]

## Recommendations
- [Practical advice derived from the rubric — what distinguishes excellent
  from proficient work]
- [Common pitfalls to avoid]
- [Resources that will help]
```

**Rubric generation principles:**
- Each criterion should map to a specific ILO or component of an ILO
- Performance levels should describe observable differences, not just
  degree words ("excellent analysis" vs. "good analysis" is not useful)
- If the manifest has rubric data from `/idstack:assessment-design`, use it directly
- If generating rubrics from scratch, ensure the cognitive level of each
  criterion matches the ILO it measures [Alignment-1] [T5]

**Also generate a separate rubric file** for each assessment in a clean format
that can be imported into an LMS or printed for grading:

```markdown
# Rubric: [Assessment Title]

**Total Points:** [points]

| Criterion | Weight | Excellent | Proficient | Satisfactory | Unsatisfactory |
|-----------|--------|-----------|------------|--------------|----------------|
| ... | ... | ... | ... | ... | ... |
```

Write each assessment document and its rubric to their files in `.idstack/course-content/`. Step 6 gives the file names. Do not show them in the chat. Then review all of the assessment documents in one section.

**Step review:** do the Step Review in the preamble. Section: `## Assessment documents`. Columns: `ID | Document | Rubric file | Decision | Justification | Evidence`.

Use the IDs `AD-1`, `AD-2` and so on, with one row for each assessment and the rubric file name that Step 6 will use. In the Decision cell, write the main design decision, for example how the criteria agree with the ILO levels. If the user selects "Change a row", change the assessment document and its rubric too.

### Step 6: Save to Project Directory

Create the directory structure and write all generated files.

```bash
mkdir -p .idstack/course-content/modules .idstack/course-content/assessments .idstack/course-content/rubrics
```

Write files with consistent naming:
- `.idstack/course-content/syllabus.md`
- `.idstack/course-content/modules/module-01-[slugified-title].md`
- `.idstack/course-content/modules/module-02-[slugified-title].md`
- `.idstack/course-content/assessments/assessment-01-[slugified-title].md`
- `.idstack/course-content/assessments/assessment-02-[slugified-title].md`
- `.idstack/course-content/rubrics/rubric-01-[slugified-title].md`
- `.idstack/course-content/rubrics/rubric-02-[slugified-title].md`

**Slugification rules:** lowercase, hyphens for spaces, strip special characters.
"Critical Analysis Essay" becomes "critical-analysis-essay".

Confirm each file as it is written. If any write fails, report the error and
continue with remaining files.

**Writing standard check (course content).** Run this command on the course content folder. Do the check only on the files that you wrote in this run. If the folder has other files, replace `".idstack/course-content"` with the paths of the files that you wrote. Put each path in quotation marks.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-ste-check" ]; then echo "STE_CHECK_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "STE_CHECK_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-ste-check" ".idstack/course-content"; fi
```

For the result, do the steps in "How to use the standard" in the "Writing Standard (ASD-STE100)" section of the preamble. Do the check a maximum of three times. Tell the user the number of sentences that you changed in each file. Do not show the sentences. The user reads the files.

### Step 7: Complete the Build Report

The report started after Mode detection, and it has the sections that the user approved. In this step, add the last sections. Do this in build-new mode and in gap-fill mode.

First, list the files that you wrote in this run.

**Step review:** do the Step Review in the preamble. Section: `## Generated artifacts`. Columns: `ID | File | Purpose | Notes`.

Use the IDs `GA-1`, `GA-2` and so on, with one row for each file. In the Notes cell, write the placeholders that the file has, or "None".

Then do the "Spec Review Loop" at the end of this skill. It adds the `## Alignment review` section. Do it before the findings, because idstack adds the sections to the report in the order that you approve them.

**Step review:** do the Step Review in the preamble. Section: `## Findings`. Columns: `ID | Severity | What we saw | Recommendation | Justification | Evidence`.

Use the IDs `cogload-1`, `multimedia-1`, `placeholder-1` and so on. The findings come from cognitive-load decisions, multimedia tradeoffs, placeholders and expertise-reversal flags that changed the build. In gap-fill mode, each finding gives the upstream flag that started the generation, for example `red-team:alignment-3`.

**Step review:** do the Step Review in the preamble. Section: `## Summary`, `## Top recommendations`, `## Limitations` and `## Next steps`. Columns: `ID | Action | Justification | Evidence`.

The Summary tells what you generated, the most important design decision and the placeholders to fill in. The Limitations tell that the adaptation changes the structure, not the voice or style, and that the cognitive-load estimates are heuristic. The Next steps tell the designer to add their voice and to run `/idstack:course-quality-review`.

In the Next steps, also name each placeholder field that you used, for example `[INSTRUCTOR NAME]` and the due dates. In the Limitations, tell that the placeholder list comes from the template, not from the text around each placeholder.

Run the finish command of the Step Review.

**Writing standard check.** In this command, replace `<path>` with the path from the "Report path:" line. Then run the command.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
if [ ! -x "$_IDSTACK/bin/idstack-ste-check" ]; then echo "STE_CHECK_MISSING: $_IDSTACK"; elif ! command -v python3 >/dev/null 2>&1; then echo "STE_CHECK_UNAVAILABLE"; else "$_IDSTACK/bin/idstack-ste-check" "<path>"; fi
```

For the result, do the steps in "How to use the standard" in the "Writing Standard (ASD-STE100)" section of the preamble. Do the check a maximum of three times.

### Step 8: Update Manifest

Save the `course_content` section to `.idstack/project.json` via `bin/idstack-manifest-merge`. The merge tool replaces only the named section, preserves every other section verbatim, validates JSON, and atomically updates the top-level `updated` timestamp.

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
"$_IDSTACK/bin/idstack-manifest-merge" --create --section course_content --payload - <<'PAYLOAD'
{
  "report_path": "<set to $_REPORT_PATH from the bash block above — e.g. .idstack/exports/<course-slug>/course-builder.md>",
  "mode": "build-new",
  "generated_at": "ISO-8601 timestamp",
  "expertise_adaptation": "novice|intermediate|advanced|mixed",
  "syllabus": "syllabus.md",
  "modules": [
    "module-01-introduction-to-topic.md",
    "module-02-core-concepts.md"
  ],
  "assessments": [
    "assessment-01-analysis-essay.md",
    "assessment-02-project-proposal.md"
  ],
  "rubrics": [
    "rubric-01-analysis-essay.md",
    "rubric-02-project-proposal.md"
  ],
  "content_dir": ".idstack/course-content/",
  "generated_files": [
    ".idstack/course-content/syllabus.md",
    ".idstack/course-content/modules/module-01-introduction-to-topic.md"
  ],
  "build_timestamp": "ISO-8601 timestamp",
  "placeholders_used": [
    "instructor_name",
    "due_dates"
  ],
  "recommended_generation_targets": []
}
PAYLOAD
```

The payload is the **flat section contents** (no enclosing `course_content` key) — the merge tool already knows the section from `--section course_content`. Wrapping the payload would double-nest. `--create` makes a canonical manifest first if `.idstack/project.json` does not exist yet (the standalone case). It never replaces a manifest that exists.

**Mode field.** Set `mode` to `"build-new"` for a from-scratch generation or `"gap-fill"` when this run was triggered by upstream skills flagging missing artifacts. In `gap-fill` mode, populate `recommended_generation_targets[]` with the per-target outcomes (`status`: `generated|deferred|declined`); in `build-new` mode, leave the array empty.

The `placeholders_used` array lists any fields where placeholder text was used because the user chose to skip or defer those details. This helps downstream skills (like `/idstack:course-export`) know what still needs to be filled in.

Use only the approved rows of the report. `generated_files` comes from the `## Generated artifacts` rows. `placeholders_used` comes from their Notes cells. `recommended_generation_targets` comes from the `## Generation targets` rows.

**Fallback (if `bin/idstack-manifest-merge` is unavailable):** Read the full manifest, modify only the `course_content` section, Write back. Preserve all other sections verbatim.

After writing the manifest, confirm:

"I generated your course content. You have three outputs:

- **Read this:** <the Report path, written as a link as the Report Links section of the preamble tells you> — the build report
  with evidence-backed design choices, cognitive-load notes, and a placeholders list.
  Click the link to open it. The folder has all of the files for the report.
- Course content: `.idstack/course-content/` (the course files — review them and add
  your voice and institutional details).
- System state: `.idstack/project.json` (the manifest — for downstream skills).

**Next steps:**
- Review and edit the generated files to add your expertise and institutional voice.
- Run `/idstack:course-quality-review` to audit the complete course against QM standards and CoI presence.
- Run `/idstack:course-export` to package the content as an IMS Common Cartridge or push to Canvas."

---

## Output Format

Do not show a summary table in the chat. Use the closing message at the end of Step 8. The `## Generated artifacts` section of the report lists the files and their placeholders. If you could not make a file, put it in the `## Findings` section, with the reason and the data that is necessary.

---

## Spec Review Loop

After all content files are generated but BEFORE presenting the final summary to the
user, run an adversarial self-review with the **Agent tool**.

**Dispatch 1 agent:**

- **Alignment Validator** — "You are an independent alignment reviewer. Read these generated course files: [list file paths in .idstack/course-content/]. Also read the project manifest at .idstack/project.json (specifically the learning_objectives and assessments sections). Verify: (1) Every ILO from the manifest has at least one module that teaches it, (2) Every assessment aligns to a stated ILO at the correct Bloom's level, (3) Module sequencing respects prerequisite chains, (4) No content exceeds cognitive load guidelines (>7 new concepts per module). Report issues found and fixes applied. Be specific with file names and line numbers."

Put a copy of the "Writing Standard (ASD-STE100)" section of the preamble in the agent prompt. The agent cannot see the preamble. Its changes go into the course files.

**After the agent returns:**
- If issues were found that can be auto-fixed (e.g., missing ILO reference, wrong Bloom's verb), fix them in the generated files.
- Put each issue in the `## Alignment review` section, with the Status `fixed` or `open`.
- If an open issue is critical and needs the user, also put it in the `## Findings` section.

**Step review:** do the Step Review in the preamble. Section: `## Alignment review`. Columns: `ID | Issue | File | Fix | Status | Justification | Evidence`.

Use the IDs `AR-1`, `AR-2` and so on, with the Status `fixed` or `open`. If a fix changed a module page, do the Step Review of that module again before this section. Use the same `## Module <N>: <title>` heading.

If you or the agent changed course files in this step, do the writing standard check at the end of Step 6 again. Tell the user the number of sentences that you changed in each file. Do not show the sentences.

**If the agent fails or returns nothing:** Skip this step. Do not add the `## Alignment review` section. Add this sentence to the Limitations: "idstack did not do the alignment review." Add a note to the output:
"Note: For a full alignment audit, run `/idstack:course-quality-review` next."

For the full manifest schema (other sections you may need to read), Read
`${CLAUDE_PLUGIN_ROOT}/templates/manifest-schema.md`.

## Feedback

Have feedback or a feature request? [Share it here](https://forms.gle/6LDgDD1M6WWyYvME8) — no GitHub account needed.

---

## Completion: Timeline Logging

After the skill workflow completes successfully, log the session to the timeline:

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
"$_IDSTACK/bin/idstack-timeline-log" '{"skill":"course-builder","event":"completed"}'
```

Replace the JSON above with actual data from this session. Include skill-specific fields
where available (scores, counts, flags). Log synchronously (no background &).

If you discover a non-obvious project-specific quirk during this session (LMS behavior,
import format issue, course structure pattern), also log it as a learning:

```bash
_IDSTACK=""
_idstack_cache_root="$HOME/.claude/plugins/cache/idstack/idstack"
_idstack_cache=""
if [ -d "$_idstack_cache_root" ]; then
  _idstack_v=$(ls "$_idstack_cache_root" 2>/dev/null | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | tail -1)
  [ -n "$_idstack_v" ] && _idstack_cache="$_idstack_cache_root/$_idstack_v"
fi
for _p in "${CLAUDE_PLUGIN_ROOT}" "${IDSTACK_HOME:-}" "$_idstack_cache"; do
  if [ -n "$_p" ] && [ -d "$_p" ]; then _IDSTACK="${_p%/}"; break; fi
done
"$_IDSTACK/bin/idstack-learnings" log '{"skill":"course-builder","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":8,"source":"observed"}'
```