CLAUDE.md · git:20260830.97236cb · 2026-08-30 · sha256 bb90800603b6a988

CLAUDE.md git:20260830.97236cbA

Immutable. This exact content is served forever at /api/v1/blob/bb90800603b6a988.

# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What is idstack

An open source set of skills for evidence-based instructional design. Runs in Claude Code. Each skill is a SKILL.md file that defines a conversational workflow backed by evidence from peer-reviewed research across 11 domains.

## Commands

```bash
./setup              # Install idstack — registers the plugin with Claude Code
./setup --local      # Install at project scope (./.claude/) instead of user scope
./setup --keep-legacy # Leave pre-v2.0.1.0 installs in place instead of removing them
bin/idstack-gen-skills                     # Regenerate skills/<name>/SKILL.md from the .tmpl sources
bin/idstack-gen-skills --dry-run           # Check if generated files are up to date
bin/idstack-doctor                         # Diagnose plugin install (presence, manifest version, legacy-install conflicts)
bin/idstack-status                         # Course health dashboard (run in a project dir)
bin/idstack-status --readiness             # Pre-export readiness check only
bin/idstack-migrate                        # Migrate an existing .idstack/project.json to the latest schema
bin/idstack-migrate --init                 # Also create a canonical manifest when none exists (standalone skill runs)
bin/idstack-manifest-merge --section <s> --payload <f>   # Canonical manifest write path (atomic, section-scoped)
bin/idstack-slugify "<project name>"       # Derive the <course-slug> used for .idstack/exports/
bin/package-extension.sh                   # Package Chrome extension into build/ for Web Store distribution
```

Tests (run in CI on every push and PR — see `.github/workflows/test.yml`):

```bash
./test/smoke-test.sh              # 362 assertions: install, SKILL.md freshness, frontmatter, version agreement,
                                  # canonical section names, /idstack: namespacing, resolve-snippet lockstep, bash -n,
                                  # Claude-Code-only invariant (no dist/, no AGENTS.md, no retired-CLI references)
./test/integration-test.sh        # 51 behavioral tests across the bin/ scripts; also proves the suite
                                  # leaves the working tree untouched
./test/test-setup.sh              # 17 behavioral tests for ./setup (flags, scope, legacy cleanup, failure handling)
./test/test-doctor.sh             # 13 behavioral tests for bin/idstack-doctor's PROBLEM/WARNING branches
./test/test-status.sh             # 22 tests for bin/idstack-status, incl. the --readiness export gate
./test/test-manifest-merge.sh     # bin/idstack-manifest-merge unit tests
./test/test-version-classifier.sh # bin/lib/version-classify.sh unit tests
./test/test-plugin-status.sh      # bin/lib/plugin-status.sh unit tests
./test/test-preamble-python.sh    # Runs the preamble's embedded python on 3.9 and 3.12
./test/test-extension.sh          # Chrome Extension packaging and static analysis tests
./test/test-responsive-landing.js # Responsive/mobile invariants for docs/index.html, as CSS text (node; via smoke-test)
./test/test-rendered-landing.js   # Renders docs/index.html in headless Chrome and asserts the outcome:
                                  # no sideways scroll, 44px touch targets, column counts (node + Chrome)
python3 test/check-evidence-cards.py . # Verifies landing page evidence cards match evidence/references.md
python3 test/check-doc-accuracy.py .   # Verifies documentation accuracy across version strings, binaries, flags, and links
./test/mutation-test.sh           # Reintroduces each fixed defect and asserts its guarding test fails
```

`test/test-helper.sh` is not a suite — it is sourced by every **bash** suite that runs assertions itself and owns the shared `PASS`/`FAIL`/`TOTAL` counters and the `check()` assertion (`test-extension.sh` is the exception: it delegates to node and asserts nothing of its own). Do not add a local counter block to a bash suite; smoke-test fails on one, and a mutation proves that guard works. The node suites (`test-extension.sh`'s eight unit tests, `test/test-responsive-landing.js`, and `test/test-rendered-landing.js`) cannot source it; they accumulate their own problems and report a count, which is the same contract in another language.

CI matrix: ubuntu (Python 3.9 + 3.12) and macOS (3.12). 3.9 is the leg that catches modern-only Python syntax reaching the preamble's embedded scripts — it is what macOS ships. `mutation-test.sh` runs once, pinned to 3.9.

No build step for users. No dependencies beyond bash (python3 recommended for full features). Skills are plain Markdown files.

## Architecture

### Skills

Each skill is a directory with a template and generated file:

```
{skill-name}/
├── SKILL.md.tmpl  # Source: YAML frontmatter + {{PREAMBLE}} + workflow
└── SKILL.md       # Generated by bin/idstack-gen-skills (do not edit directly)
```

11 skills total. The 8-skill linear pipeline is the canonical sequence; `/idstack:course-import` joins it when there's an existing course to start from, and `/idstack:learn` is a cross-project memory utility that runs outside the pipeline. All invoked via `/idstack:<skill>`:

```
/idstack:pipeline (orchestrates the 8-skill linear chain, auto-skips completed)

/idstack:needs-analysis → learning-objectives → assessment-design → course-builder → course-quality-review → accessibility-review → red-team → course-export
                                    ↑
/idstack:course-import ─────────────┘

/idstack:learn (manage cross-project learnings)
```

Any skill also works standalone (asks questions directly if no manifest exists).

### Project manifest and reports — the dual-output contract

Every skill that produces findings writes **both**:

1. **JSON section** in `.idstack/project.json` — system state for downstream skills, the pipeline orchestrator, and `bin/idstack-status`.
2. **HTML report** at `.idstack/exports/<course-slug>/<skill>.html` — the human view, branded and self-contained. Visual contract: `templates/report.html.tmpl` + `templates/assets/idstack.css`. Content contract: `templates/report-format.md`. The skill writes the relative path back into its section's `report_path` field.

The HTML is what the instructional designer reads (open in any browser; the folder is self-contained, with CSS bundled). The JSON is for the system. The two stay in sync: every finding in the report corresponds to a finding in the manifest's structured arrays.

`<course-slug>` is derived from the manifest's `project_name` via `bin/idstack-slugify` (NFKD-fold, lowercase, kebab-case, ASCII-safe; empty input → `untitled-course`). All per-course artifacts — every per-skill HTML report, the pipeline `index.html` dashboard, and LMS packages (`course-export.imscc`, `scorm-export.zip`) — live under the same `.idstack/exports/<course-slug>/` folder, so the deliverable is self-describing when zipped, emailed, or handed off.

`/idstack:pipeline` produces `.idstack/exports/<course-slug>/index.html` — the cross-cutting course dashboard. It surfaces readiness scores, top issues that recur across multiple skills, evidence themes, links to every per-skill report, and where to start. Regenerated on every pipeline run (including partial runs and explicit re-runs when all skills are already complete).

Rules for writing the manifest:

- Validate JSON on read. If malformed, report and stop. Never silently overwrite.
- Own your section only. Read full manifest, modify only your skill's section, preserve everything else.
- Update the `updated` timestamp on every write.
- Use `bin/idstack-manifest-merge` for the write path: it's section-scoped, atomic (tempfile + rename), preserves foreign sections, and validates against the canonical schema in `templates/manifest-schema.md`. Inline full-manifest `Edit` is the deprecated fallback only.
- **The one documented exception:** `needs-analysis` and `course-import` keep the Read-modify-Write path because each writes several co-owned sections in one pass, which whole-section merge cannot express. Both state why inline. Don't "fix" them to use the merge tool, and don't copy their pattern into a single-section writer.
- Running standalone, call `bin/idstack-migrate --init` before merging. On a missing manifest plain `idstack-migrate` is a no-op, so the merge that follows exits 4 and the results are silently never persisted.

Rules for writing the report:

- Follow the **visual contract** in `templates/report.html.tmpl` and the **content contract** in `templates/report-format.md` — observation → evidence → why-it-matters → suggestion, with severity (`critical|warning|info`) and evidence tier (`T1`–`T5`) on every finding. Use the CSS hooks the stylesheet styles: `<article class="finding sev-{severity}">`, `<span class="sev-badge sev-{severity}">`, `<span class="tier-badge tier-T{N}">`, `<cite class="citation">[Domain-N] [TN]</cite>`.
- Every skill that writes a report copies `$_IDSTACK/templates/assets/idstack.css` into `.idstack/exports/<course-slug>/assets/idstack.css` so the folder is self-contained when zipped or moved.
- Phrase recommendations as suggestions ("consider…"), not directives. idstack is a collaborator.
- Cite every recommendation. Findings without a `[Domain-N] [Tier]` citation belong in *Limitations* or *Notes*, not *Findings*.

### SKILL.md.tmpl structure

Every skill template follows this pattern:

1. **YAML frontmatter** with `name`, `description`, and `allowed-tools` fields.
2. **`{{PREAMBLE}}`** placeholder (replaced by `templates/preamble.md` during generation)
3. **Workflow** (Markdown defining the conversational flow, decision trees, outputs)
4. **`{{MANIFEST_SCHEMA}}`** placeholder (replaced by `templates/manifest-schema.md`)
5. **`{{IDSTACK_RESOLVE}}`** placeholder (replaced by `templates/snippets/idstack-resolve.sh`). Unlike the other two, this one appears many times per template — once at the top of every bash block that calls `$_IDSTACK/bin/...`. Bash blocks run in separate shells, so `_IDSTACK` must be re-derived in each; the snippet is the single definition of that resolution order (`CLAUDE_PLUGIN_ROOT`, `IDSTACK_HOME`, then the Claude Code marketplace cache). `templates/manifest-schema.md` is spliced verbatim and so writes the resolution out longhand — smoke-test keeps the two in lockstep.
6. **Timeline logging** (logs session data to `.idstack/timeline.jsonl` on completion)

The shared preamble includes: interaction conventions (defines how skills use `AskUserQuestion`, `Agent`, and `Skill`), update check, manifest check, preferences check, designer profile check, and context recovery (reads timeline + learnings for welcome-back messages and pipeline guidance).

Python embedded in the preamble must parse on Python 3.9 — the version macOS ships. `test/test-preamble-python.sh` runs every embedded block on 3.9 and 3.12; a syntax error there dies silently at runtime, which is how context recovery stayed broken for several releases.

### Shared shell libraries

Logic used by more than one script — or that deserves a unit test — lives in `bin/lib/` and is sourced by its callers rather than inlined:

- `bin/lib/version-classify.sh` — version comparison, shared by `setup` and `bin/idstack-doctor`
- `bin/lib/plugin-status.sh` — parses `claude plugin list` output into idstack's own entry

Test the shipped file, never a copy. The version classifier drifted across three PRs while a mirrored copy in its test passed green.

### Course memory

Skills log session data to `.idstack/timeline.jsonl` (what skills ran, scores, dimensions) and `.idstack/learnings.jsonl` (project-specific discoveries). The context recovery preamble reads these on session start to provide continuity across conversations.

### Evidence standards

Every recommendation in a skill must cite its evidence tier using domain codes from `evidence/references.md`:

| Tier | Meaning |
|------|---------|
| T1 | Meta-analyses, RCTs |
| T2 | Quasi-experimental with controls |
| T3 | Systematic reviews of mixed evidence |
| T4 | Observational, no comparison group |
| T5 | Expert opinion, theoretical frameworks |

Format: `[DomainCode-Number] [Tier]` (e.g., `[Alignment-14] [T1]`). Stronger evidence takes precedence when tiers conflict.

### Interaction pattern

- Ask one structured question at a time, using the `AskUserQuestion` tool. The preamble's "Interaction Conventions" section defines this protocol.
- Never batch multiple questions
- Skills must work without a manifest (fallback to asking questions directly)
- Write next-step text in the namespaced form, `/idstack:foo`. A bare `/foo` does not resolve, and smoke-test fails on one

## Skill routing

When working in this repo, route user requests to the appropriate idstack skill:

- New course / fresh design → `/idstack:needs-analysis` (or `/idstack:pipeline` to chain all 8)
- Existing course (Canvas, Blackboard, Moodle, D2L cartridge, SCORM, PDF) → `/idstack:course-import`
- Bloom's classification, learning objectives, ILO development → `/idstack:learning-objectives`
- Rubrics, assessment design, formative checkpoints, feedback strategy → `/idstack:assessment-design`
- Generate course content (syllabus, modules, assignments) → `/idstack:course-builder`
- Quality audit (Quality Matters + Community of Inquiry) → `/idstack:course-quality-review`
- WCAG 2.1 AA + UDL accessibility review → `/idstack:accessibility-review`
- Adversarial pre-launch audit (5 dimensions, confidence score) → `/idstack:red-team`
- Package for LMS (IMS Common Cartridge, Canvas API, SCORM) → `/idstack:course-export`
- Search, prune, promote, or export cross-project learnings → `/idstack:learn`

Skills are auto-discovered by Claude Code via the plugin manifest at
`.claude-plugin/plugin.json`.

## Design system

Always read `DESIGN.md` (repo root) before making any visual or UI decision in this project. All font choices, colors, spacing, border radii, motion timing, and aesthetic direction are defined there. Do not deviate without explicit user approval and a corresponding update to `DESIGN.md`.

When generating HTML reports, the report stylesheet at `templates/assets/idstack.css` is the canonical implementation of `DESIGN.md`. Any update to `DESIGN.md` should be reflected there (and in `docs/index.html` for landing-page tokens) in the same PR.