Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "idstack",
"version": "3.3.0.0",
"version": "3.3.0.1",
"description": "Evidence-based instructional design pipeline. 11 skills backed by peer-reviewed research across 11 domains. Analyze, design, build, review, and export courses with every recommendation citing its evidence tier.",
"author": {
"name": "Philippos Savvides",
Expand Down
57 changes: 55 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ Manifest write rules:
- Use `bin/idstack-manifest-merge` for the write path: section-scoped, atomic (tempfile +
rename), preserves foreign sections, validates against the canonical schema in
`templates/manifest-schema.md`. Inline full-manifest edit is the deprecated fallback.
- **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.

Report write rules:

Expand All @@ -99,12 +106,34 @@ Every skill template follows this pattern:
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. **Timeline logging** (logs session data to `.idstack/timeline.jsonl` on completion)
5. **`{{IDSTACK_RESOLVE}}`** placeholder (replaced by `templates/snippets/idstack-resolve.sh`).
Unlike the other two it 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`, the Codex symlinks, then the
Claude Code marketplace cache. `templates/manifest-schema.md` is spliced verbatim and
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: 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.

### Course memory

Skills log session data to `.idstack/timeline.jsonl` (what skills ran, scores,
Expand Down Expand Up @@ -139,15 +168,39 @@ takes precedence when tiers conflict.

```bash
./setup # Install for the detected CLI(s)
./test/smoke-test.sh # Verify installation and generated artifacts
./setup --local # Install at project scope instead of user scope
./setup --codex / --no-codex # Force or skip the Codex bundle
./setup --keep-legacy # Leave pre-v2.0.1.0 installs in place
bin/idstack-gen-skills # Regenerate skill files for all targets
bin/idstack-gen-skills --target codex # Regenerate Codex flavor only
bin/idstack-gen-skills --dry-run # Check if generated files are up to date
bin/idstack-doctor # Diagnose installs across CLIs
bin/idstack-status # Course health dashboard (run in a project dir)
bin/idstack-status --readiness # Pre-export readiness check only
bin/idstack-migrate # Migrate .idstack/project.json to the latest schema
bin/idstack-migrate --init # Also create a canonical manifest when none exists
bin/idstack-manifest-merge --section <s> --payload <f> # Canonical manifest write path
bin/idstack-slugify "<project name>" # Derive the <course-slug> for .idstack/exports/
```

Tests — all eight run in CI on every push and PR (`.github/workflows/test.yml`,
ubuntu on Python 3.9 + 3.12, macOS on 3.12):

```bash
./test/smoke-test.sh # Install, SKILL.md freshness, frontmatter, version agreement,
# canonical section names, namespacing, resolve-snippet lockstep
./test/integration-test.sh # End-to-end; proves the suite leaves the working tree untouched
./test/test-setup.sh # ./setup behavior: flags, scope, legacy cleanup, failure handling
./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/mutation-test.sh # Reintroduces each fixed defect, asserts its guarding test fails
```

Python 3.9 is the oldest interpreter in the field (macOS system python3) and the
leg that catches modern-only syntax reaching the preamble's embedded scripts.

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

Expand Down
23 changes: 19 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
# Changelog

## v3.3.0.1 (2026-08-05)

To get this fix: `cd` into your idstack clone, then `git pull && ./setup`. Restart Claude Code afterward — plugins load at session start.

### Fixed — skills no longer suggest commands that don't exist

- **Welcome-back and next-step messages named unrunnable commands.** v3.3.0.0 banned bare `/skill` references because they resolve in neither CLI, and fixed them in `bin/idstack-status`. The guard enforcing it matched only backticked refs, so three plain-prose examples in the preamble's context-recovery section survived — and the preamble is spliced into all 22 skill files. The model copied their shape and told users things like "Based on your progress, /assessment-design is the natural next step." Typing that does nothing. Landing inside the context-recovery message v3.3.0.0 had just repaired made it the first thing a user saw once welcome-back messages started working again. Now namespaced; on Codex the existing translation rule renders them as `$<skill>`.

### For contributors

- The smoke-test guard now matches a bare `/skill` in any command position, not only inside backticks, and scans skill bodies with frontmatter still exempt (`description:` is picker prose, not a command). Suite count unchanged at 371.
- `test/mutation-test.sh` gained a case that reintroduces an unbackticked bare reference into the preamble and asserts smoke-test fails: 14 mutations, 14 guarded.

## v3.3.0.0 (2026-08-04)

To get these fixes: `cd` into your idstack clone, then `git pull && ./setup`. Restart Claude Code afterward — plugins load at session start.

### Fixed — course memory, pipeline orchestration, re-run detection

A full audit of the toolchain surfaced a set of bugs that broke user-visible behavior, some since their features shipped:
Expand All @@ -19,14 +34,14 @@ A full audit of the toolchain surfaced a set of bugs that broke user-visible beh
- course-quality-review, course-export, and learning-objectives now write their manifest sections through `bin/idstack-manifest-merge` (atomic, section-scoped, preserves every other section). needs-analysis and course-import keep the Read-modify-Write path — both write several co-owned sections in one pass, which whole-section merge cannot express — and each now documents why.
- `bin/idstack-migrate --init` creates a canonical manifest with every section at its default. Three skills told the user to run `idstack-migrate` to create one when running standalone; it was a no-op on a missing file, so the merge that followed died with exit 4 and standalone results were silently never persisted. The skeleton comes from running the existing migration chain over a minimal seed, so there is no second definition of "canonical".
- learning-objectives reports gained the required "Top recommendations" section; `[Alignment-1]` is now correctly cited as T5.
- Logic that was duplicated or inlined and therefore untestable now lives in `bin/lib/` and is sourced by its callers: `version-classify.sh` (shared by `setup` and `bin/idstack-doctor`) and `plugin-status.sh` (the `claude plugin list` parser). Their unit tests exercise the shipped code rather than a copy — the version classifier had drifted across three PRs while a mirrored test passed green.

### Infrastructure
### For contributors

The audit found the test suite had never run automatically, and that some of it was not testing what it appeared to test. Both are fixed:

- **CI.** New GitHub Actions `test.yml` runs all seven suites on push and PR (ubuntu + macos, Python 3.9 + 3.12 — 3.9 is the leg that catches the context-recovery class of bug). `release.yml` refuses to publish unless the tag, `VERSION`, `plugin.json`, and `CHANGELOG.md` agree and the smoke test passes.
- **`./setup` is now tested** — 16 behavioral tests covering flag parsing, scope selection, all three legacy-cleanup shapes, and failure handling, run against a repo copy with a fake `$HOME` and a stub `claude`. It previously had no coverage at all while the smoke test spent 14 assertions on landing-page CSS.
- Logic that was duplicated or inlined and therefore untestable now lives in `bin/lib/` and is sourced by its callers: `version-classify.sh` (shared by `setup` and `bin/idstack-doctor`) and `plugin-status.sh` (the `claude plugin list` parser). Their unit tests exercise the shipped code rather than a copy — the version classifier had drifted across three PRs while a mirrored test passed green.
- **CI.** New GitHub Actions `test.yml` runs all eight suites on push and PR — seven in a matrix job (ubuntu + macos, Python 3.9 + 3.12 — 3.9 is the leg that catches the context-recovery class of bug), plus the mutation suite in its own job. `release.yml` refuses to publish unless the tag, `VERSION`, `plugin.json`, and `CHANGELOG.md` agree and the smoke test passes.
- **`./setup` is now tested** — 17 behavioral tests covering flag parsing, scope selection, all three legacy-cleanup shapes, and failure handling, run against a repo copy with a fake `$HOME` and a stub `claude`. It previously had no coverage at all while the smoke test spent 14 assertions on landing-page CSS.
- **A mutation suite proves the guards work.** `test/mutation-test.sh` reintroduces each of the 13 defects fixed here into a throwaway copy and asserts the guarding test fails. This is what was missing: the version-classifier suite passed green while testing a local copy of the classifier rather than the shipped code, and `gen-skills` counted a placeholder-less template as neither generated nor failed.
- smoke-test grew from 272 to 371 assertions (version agreement, canonical section names, `/idstack:` namespacing, resolve-snippet lockstep, v1.1 migration, `bash -n` on every script) and prints failure diagnostics instead of a bare FAIL; integration-test proves it leaves the working tree untouched.

Expand Down
40 changes: 37 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## What is idstack

An open source set of skills for evidence-based instructional design. Runs in Claude Code and OpenAI Codex CLI (Gemini CLI on the v2.6 roadmap). Each skill is a SKILL.md file that defines a conversational workflow backed by evidence from peer-reviewed research across 11 domains.
An open source set of skills for evidence-based instructional design. Runs in Claude Code and OpenAI Codex CLI (Gemini CLI is on the roadmap, not yet scheduled). Each skill is a SKILL.md file that defines a conversational workflow backed by evidence from peer-reviewed research across 11 domains.

## Commands

Expand All @@ -13,16 +13,36 @@ An open source set of skills for evidence-based instructional design. Runs in Cl
./setup --local # Install at project scope (./.claude/) instead of user scope
./setup --codex # Force-install the Codex bundle even if codex isn't on PATH
./setup --no-codex # Skip the Codex install
./test/smoke-test.sh # Verify installation, SKILL.md files, YAML frontmatter, migrations
./setup --keep-legacy # Leave pre-v2.0.1.0 installs in place instead of removing them
bin/idstack-gen-skills # Regenerate skill files for all targets (claude + codex)
bin/idstack-gen-skills --target claude # Regenerate Claude flavor only (skills/<name>/SKILL.md)
bin/idstack-gen-skills --target codex # Regenerate Codex flavor only (dist/codex/skills/idstack-<name>/)
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/
```

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

```bash
./test/smoke-test.sh # 371 assertions: install, SKILL.md freshness, frontmatter, version agreement,
# canonical section names, /idstack: namespacing, resolve-snippet lockstep, bash -n
./test/integration-test.sh # End-to-end run; 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-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/mutation-test.sh # Reintroduces each fixed defect and asserts its guarding test fails
```

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
Expand Down Expand Up @@ -70,6 +90,8 @@ Rules for writing the manifest:
- 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:

Expand All @@ -86,10 +108,22 @@ Every skill template follows this pattern:
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. **Timeline logging** (logs session data to `.idstack/timeline.jsonl` on completion)
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`, the Codex symlinks, 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 `AskUserQuestion` / `Agent` / `Skill` as portable concept names so the same body runs in both CLIs), 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.
Expand Down
Loading
Loading