diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ffd0b4d..beff54f 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -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", diff --git a/AGENTS.md b/AGENTS.md index 6c80a2a..b325f69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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: @@ -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, @@ -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 --payload # Canonical manifest write path +bin/idstack-slugify "" # Derive the 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. diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1acde..43973ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 `$`. + +### 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: @@ -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. diff --git a/CLAUDE.md b/CLAUDE.md index acbe061..5e5f34a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 @@ -13,7 +13,7 @@ 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//SKILL.md) bin/idstack-gen-skills --target codex # Regenerate Codex flavor only (dist/codex/skills/idstack-/) @@ -21,8 +21,28 @@ bin/idstack-gen-skills --dry-run # Check if generated files are up to 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 --payload # Canonical manifest write path (atomic, section-scoped) +bin/idstack-slugify "" # Derive the 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 @@ -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: @@ -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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31c9a53..1d66c92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,20 +5,24 @@ 1. Fork the repo and clone your fork 2. Create a branch: `git checkout -b my-skill` 3. Add your skill (see below) -4. Run `./setup` to register it -5. Run `./test/smoke-test.sh` to verify -6. Submit a PR +4. Run `bin/idstack-gen-skills` to generate the skill files from your template +5. Run `./setup` to register it +6. Run the test suite (see [Testing](#testing)) to verify +7. Submit a PR ## How skills work -One directory, one file: +One directory, one source file, one generated file per target: ``` -your-skill/ -└── SKILL.md +skills/your-skill/ +├── SKILL.md.tmpl # Source — this is the file you edit +└── SKILL.md # Generated by bin/idstack-gen-skills (Claude flavor; do not edit) ``` -That's the entire skill. No backend, no config files, no registration step beyond `./setup`. +Plus a Codex flavor at `dist/codex/skills/idstack-your-skill/SKILL.md`, also generated. + +That's the entire skill. No backend, no config files, no registration step beyond `./setup`. Edit the `.tmpl` and regenerate — a hand-edit to `SKILL.md` is overwritten on the next `bin/idstack-gen-skills` run, and the smoke test fails on the drift in the meantime. ### SKILL.md structure @@ -46,19 +50,37 @@ The bare `name` field becomes the slash-command suffix: `name: course-import` is **3. Skill implementation** — the rest of the file is Markdown that defines the skill's workflow, decision trees, and outputs. -**4. Timeline logging** — at the end, a section that logs the session to `.idstack/timeline.jsonl` with skill-specific fields. +**4. `{{MANIFEST_SCHEMA}}` placeholder** — replaced with `templates/manifest-schema.md`. + +**5. `{{IDSTACK_RESOLVE}}` placeholder** — replaced with `templates/snippets/idstack-resolve.sh`. Put this at the top of **every** bash block that calls `$_IDSTACK/bin/...`, not just the first. Bash blocks run in separate shells, so a value derived in an earlier block isn't there in a later one. Skipping it is how `learn` and `course-export` ended up pointing `bin/` calls at a nonexistent directory for marketplace installs. + +**6. Timeline logging** — at the end, a section that logs the session to `.idstack/timeline.jsonl` with skill-specific fields. ### Template system Skills use a template system to share common preamble code. Edit `{skill}/SKILL.md.tmpl`, not `SKILL.md` directly. The generated `SKILL.md` files have an `` header. -After editing a `.tmpl` file or `templates/preamble.md`, regenerate: +After editing a `.tmpl` file, `templates/preamble.md`, `templates/manifest-schema.md`, or `templates/snippets/idstack-resolve.sh`, regenerate: ```bash -bin/idstack-gen-skills +bin/idstack-gen-skills # write the regenerated files +bin/idstack-gen-skills --dry-run # check only — exits non-zero if anything is stale ``` -The smoke test includes a freshness check that fails if any `SKILL.md` is stale. +Commit the regenerated files in the same commit as the template change. The smoke test includes a freshness check that fails if any `SKILL.md` is stale. + +### Embedded Python must run on 3.9 + +Any Python embedded in `templates/preamble.md` or a skill body has to parse on Python 3.9 — that is what macOS ships, and it is the interpreter most designers will hit. An f-string reusing a quote inside its replacement field is legal from 3.12 (PEP 701) and a SyntaxError before it, which is exactly how context recovery stayed silently broken for several releases. `test/test-preamble-python.sh` runs every embedded block on both 3.9 and 3.12. + +### Shared shell libraries + +Logic used by more than one script — or worth a unit test — belongs in `bin/lib/`, sourced by its callers rather than copy-pasted: + +- `bin/lib/version-classify.sh` — version comparison, shared by `setup` and `bin/idstack-doctor` +- `bin/lib/plugin-status.sh` — parses `claude plugin list` down to idstack's own entry + +Point the test at the shipped file, never at a copy of the logic. The version classifier drifted across three PRs while a mirrored copy inside its own test kept passing green. ## The dual-output contract @@ -75,6 +97,8 @@ Phrase recommendations as suggestions ("consider…"), not directives. Cite ever - **Own your section only.** Read the full manifest, modify only the section your skill owns, 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. +- **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 say so inline. Don't convert them, and don't copy the pattern into a skill that owns a single section. +- **Standalone runs need `bin/idstack-migrate --init` first.** On a missing manifest, plain `idstack-migrate` is a no-op, so the merge that follows exits 4 and the skill's results are silently never persisted. `--init` creates a canonical manifest with every section at its default. ## Evidence standards @@ -100,10 +124,26 @@ Use domain codes from `evidence/references.md` (e.g., `[Alignment-14] [T1]`). St ## Testing ```bash -./setup # Register your new skill (auto-detects Claude Code and codex on PATH) -./test/smoke-test.sh # Verify installation across all targets +bin/idstack-gen-skills --dry-run # Generated files up to date? Run this first. +./setup # Register your new skill (auto-detects Claude Code and codex on PATH) +./test/smoke-test.sh # Verify installation across all targets ``` +Eight suites run in CI (`.github/workflows/test.yml`) on every push and pull request. Run whichever ones your change touches locally; CI runs them all: + +| Suite | Covers | +|-------|--------| +| `test/smoke-test.sh` | Install, `SKILL.md` freshness, YAML frontmatter, version agreement across `VERSION` / `plugin.json` / `CHANGELOG.md`, canonical manifest section names, `/idstack:` namespacing, resolve-snippet lockstep, schema migrations, `bash -n` on every script | +| `test/integration-test.sh` | End-to-end run; asserts the suite leaves your working tree untouched | +| `test/test-setup.sh` | `./setup` behavior — flag parsing, scope selection, all three legacy-cleanup shapes, failure handling. Runs against a repo copy with a fake `$HOME` and a stub `claude` | +| `test/test-manifest-merge.sh` | `bin/idstack-manifest-merge` | +| `test/test-version-classifier.sh` | `bin/lib/version-classify.sh` | +| `test/test-plugin-status.sh` | `bin/lib/plugin-status.sh` | +| `test/test-preamble-python.sh` | The preamble's embedded Python, on 3.9 and 3.12 | +| `test/mutation-test.sh` | Reintroduces each known defect into a throwaway copy and asserts the guarding test fails. Add a mutation here whenever you fix a bug — it is what proves your new test would have caught it | + +The CI matrix is ubuntu on Python 3.9 and 3.12, plus macOS on 3.12 for BSD `grep`/`sed`/`awk` differences. `mutation-test.sh` runs once, pinned to 3.9. Do not skip hooks or push with a red suite. + Then test manually: - Claude Code: `/idstack:your-skill` - Codex CLI: `$your-skill` @@ -112,10 +152,15 @@ Then test manually: - **Focused scope** — one skill per PR - **Evidence-backed** — recommendations cite research, not opinions -- **Tested** — smoke test passes, manual test in Claude Code works +- **Tested** — the suite passes, manual test in Claude Code works, and a bug fix ships with both the test that catches it and a mutation in `test/mutation-test.sh` that proves the test works +- **Regenerated** — `bin/idstack-gen-skills --dry-run` is clean, with generated files committed alongside the template change - **Standalone** — skill works without a manifest (ask questions as fallback) - **Pipeline-aware** — if upstream data exists in the manifest, use it to enrich recommendations +## Looking for something to work on? + +[TODOS.md](TODOS.md) is the backlog — deferred work with the reasoning and dependencies attached. [ROADMAP.md](ROADMAP.md) is the user-facing view of the same thing. Read [DESIGN.md](DESIGN.md) before changing anything visual; it is the source of truth for the report stylesheet and the landing page. + ## Questions or feedback? [Fill out this form](https://forms.gle/6LDgDD1M6WWyYvME8) — no GitHub account needed. You can also [open an issue](https://github.com/savvides/idstack/issues). diff --git a/README.md b/README.md index d9a6576..bb429ec 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ idstack: Reading your manifest... I have 12 modules, 6 objectives, ### Top 3 Recommendations 1. Add rubrics to all assessments with elaborated feedback - [Assessment-8] [T1] — Run /learning-objectives to align + [Assessment-8] [T1] — Run /idstack:learning-objectives 2. Design collaborative activities for at least 4 modules [Online-15] [T2] 3. Add learner support section with office hours, tutoring, @@ -94,7 +94,7 @@ You had a course in Canvas. Now you have an evidence-based audit with specific r ## Install — 30 seconds -**Requirement:** [Claude Code](https://claude.ai/code) (desktop app, web app, or CLI). +**Requirement:** [Claude Code](https://claude.ai/code) (desktop app, web app, or CLI) or [OpenAI Codex CLI](https://developers.openai.com/codex/cli). `./setup` detects whichever you have and installs for both if both are present. Paste this into your terminal: @@ -136,25 +136,50 @@ Claude clones the repo, runs setup, and confirms the skills are registered. ``` +
+All setup flags + +```bash +./setup # Auto-detect Claude Code and codex on PATH, install for both +./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 +./setup --keep-legacy # Leave pre-v2.0.1.0 installs in place instead of removing them +``` + +Setup is idempotent — re-run it any time. +
+ You should see: ``` -Installing idstack... - linked: /idstack → /path/to/idstack + regenerated skill files for all targets +Installing idstack (user)... + source: /path/to/idstack + +idstack installed (Claude Code) — scope: user. -idstack installed successfully. + If Claude Code is already running, restart it (plugins load at session start). Usage: /idstack: Have an existing course? - /idstack:course-import → /idstack:course-quality-review + /idstack:course-import -> /idstack:course-quality-review Starting fresh? /idstack:needs-analysis Run the full pipeline: /idstack:pipeline + + All skills: needs-analysis, learning-objectives, assessment-design, + course-builder, course-quality-review, accessibility-review, + red-team, course-export, course-import, pipeline, learn + + More info: https://idstack.org ``` +If you also have Codex CLI on your `PATH`, you'll see an `idstack installed (Codex CLI).` block too, with `$` usage. + ## Your design team idstack turns Claude Code into an evidence-based instructional design team. Each skill is a specialist. All invoked via `/idstack:`. @@ -177,6 +202,8 @@ idstack turns Claude Code into an evidence-based instructional design team. Each Each skill feeds into the next. The project manifest is the thread. +Skill names in the diagram below are shown unprefixed to keep the columns readable. To actually run one, use `/idstack:` in Claude Code or `$` in Codex CLI. + ``` EXISTING COURSE NEW COURSE @@ -270,6 +297,8 @@ Any skill works independently. Run `/idstack:pipeline` to chain them all, or inv | bin/idstack-migrate bin/idstack-timeline-log | | bin/idstack-learnings-log bin/idstack-status | | bin/idstack-slugify bin/idstack-update-check | +| bin/idstack-doctor bin/lib/version-classify.sh | +| bin/lib/plugin-status.sh | +-------------------------------------------------------+ ``` @@ -311,7 +340,7 @@ Every recommendation includes an evidence tier so you know how strong the backin When the skill says "add elaborated feedback to your quizzes," it tells you that's T1 evidence from multiple meta-analyses, not someone's blog post. ### Using skills independently -Any skill works on its own. `/course-quality-review` works without a manifest by asking you questions directly. `/learning-objectives` works without a needs analysis. The pipeline adds context and makes recommendations sharper, but every skill is self-contained. +Any skill works on its own. `/idstack:course-quality-review` works without a manifest by asking you questions directly. `/idstack:learning-objectives` works without a needs analysis. The pipeline adds context and makes recommendations sharper, but every skill is self-contained. ## The evidence base @@ -396,7 +425,7 @@ Have feedback or a feature request? [Fill out this form](https://forms.gle/6LDgD Found a bug? You can also [open an issue on GitHub](https://github.com/savvides/idstack/issues). -Want to add a new skill? See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide. The architecture is simple: create a directory with a SKILL.md file and run `./setup`. +Want to add a new skill? See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide. The architecture is simple: create a directory with a `SKILL.md.tmpl` template, run `bin/idstack-gen-skills` to generate the per-CLI skill files, then `./setup`. ## More diff --git a/ROADMAP.md b/ROADMAP.md index 4305a39..5b41793 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,6 +4,26 @@ What's coming next for idstack. Priorities are shaped by user feedback. [Tell us ## Just shipped +### Course memory, pipeline orchestration, and re-run detection fixed (v3.3.0.0) +- **Welcome-back messages work on stock macOS.** The session-memory code embedded in every skill contained an f-string that is a SyntaxError on any Python below 3.12 — including the 3.9 macOS ships. It failed silently, so context recovery, quality-score trends, and next-step suggestions produced nothing. Fixed, and now exercised on 3.9 in CI so the class of bug can't ship again. +- **`/idstack:pipeline` invokes its child skills correctly.** It was calling them by an unnamespaced name that never resolved in Claude Code. +- **Skills notice previous runs again.** Re-run detection ("update the results or start fresh?") was dead in five skills, which looked up manifest sections that don't exist. +- **Marketplace installs resolve `bin/` correctly.** `learn` and `course-export` missed the marketplace cache — the way most users are installed — so their tool calls pointed at a nonexistent directory. +- **Apostrophes no longer blank the dashboard**, imported courses get a proper next-step suggestion, and `bin/idstack-doctor` can no longer report a disabled install as healthy. +- **Standalone runs persist.** `bin/idstack-migrate --init` creates a canonical manifest, so a skill run outside the pipeline has something to write into instead of silently discarding its results. + +### Test infrastructure and CI (v3.3.0.0, for contributors) +- The suite had never run automatically. GitHub Actions now runs all eight suites on every push and pull request, across ubuntu (Python 3.9 + 3.12) and macOS. +- `./setup` — the primary deliverable — went from zero coverage to 17 behavioral tests. +- `test/mutation-test.sh` reintroduces each fixed defect and asserts its guarding test fails, which is how a test that only appeared to test something gets caught. + +### Install through the Claude Code plugin marketplace (v3.2.0.0) +- `./setup` registers idstack as a Claude Code plugin marketplace and installs from there. Recent Claude Code versions stopped discovering plugins from the bare symlink older setups created, so `/idstack:` commands silently never appeared in the slash picker. If that happened to you, pull the latest and re-run `./setup`. + +### `DESIGN.md` and design-system reconciliation (v3.1.0.0) +- The visual system behind the report stylesheet and the landing page is documented at the repo root in `DESIGN.md` — fonts, colors, spacing, radii, motion, plus anti-patterns and a dated decisions log. Skills, contributors, and reviewers read it before touching anything visual. +- Publication-grade type (Source Serif 4, Public Sans, JetBrains Mono), an ivory palette in place of parchment, sharper card corners, and a second annotation color mirroring the two-pen academic-editor convention. Reports written by older versions still render correctly. + ### Branded HTML reports + per-course export folder (v3.0.0) - **HTML replaces Markdown for the human view.** Every skill that produces findings now writes a branded, self-contained HTML report at `.idstack/exports//.html`. Visual contract: `templates/report.html.tmpl` + `templates/assets/idstack.css` (scholarly serif body, severity-colored finding cards, evidence-tier badges, print-friendly, auto light/dark via `prefers-color-scheme`). Content contract is unchanged — observation → evidence → why-it-matters → suggestion, severity + tier on every finding. - **One folder per course, by name.** All per-course artifacts — every per-skill HTML report, the pipeline `index.html` dashboard, the bundled CSS, and LMS packages (`course-export.imscc`, `scorm-export.zip`) — live under `.idstack/exports//`. The slug is derived from `project_name` via `bin/idstack-slugify` (NFKD-fold, kebab-case, ASCII-safe). Zip the folder to hand the whole deliverable to a stakeholder. @@ -35,23 +55,23 @@ What's coming next for idstack. Priorities are shaped by user feedback. [Tell us - Schema migration v1.4 fixes drifted field names (`red_team_audit.summary.*_count` → `findings_summary.*`, `_import_quality_flags` → `import_metadata.quality_flag_details`). ### idstack v2 — Pipeline orchestrator, intelligence, sub-agents -- **`/idstack pipeline`** — chains all 8 skills automatically. Auto-skips completed skills, shows pipeline status, pause and resume anytime. -- **Namespace refactor** — all skills now invoked via `/idstack ` (e.g., `/idstack needs-analysis`). No more name collisions with other skill packages. +- **`/idstack:pipeline`** — chains all 8 skills automatically. Auto-skips completed skills, shows pipeline status, pause and resume anytime. +- **Namespace refactor** — all skills now invoked via `/idstack:` (e.g., `/idstack:needs-analysis`). No more name collisions with other skill packages. - **Cross-course intelligence** — learnings from one course appear in another. Global store at `~/.idstack/global/learnings.jsonl` with keyword search. -- **`/idstack learn`** — search, delete, promote, and export learnings. -- **Course readiness dashboard** — pre-export gate showing quality/red-team/accessibility status. Integrated into `/idstack course-export`. +- **`/idstack:learn`** — search, delete, promote, and export learnings. +- **Course readiness dashboard** — pre-export gate showing quality/red-team/accessibility status. Integrated into `/idstack:course-export`. - **Designer profile** — `~/.idstack/profile.yaml` with experience level. Skills adapt explanation depth (novice/intermediate/expert). - **Manifest preferences** — schema v1.3 adds verbosity, export format, preferred LMS settings. -- **Sub-agent architecture** — `/idstack red-team` (5 parallel agents), `/idstack accessibility-review` (2 parallel), `/idstack course-quality-review` (3 parallel). Claude Code only, graceful degradation elsewhere. -- **Spec review loop** — `/idstack course-builder` validates alignment via adversarial subagent after generating content. +- **Sub-agent architecture** — `/idstack:red-team` (5 parallel agents), `/idstack:accessibility-review` (2 parallel), `/idstack:course-quality-review` (3 parallel). Claude Code only, graceful degradation elsewhere. +- **Spec review loop** — `/idstack:course-builder` validates alignment via adversarial subagent after generating content. - **IDSTACK_HOME** — all paths portable via env var. Foundation for multi-platform support. ### Bidirectional pipeline + evidence depth (v1.5.1) - All 9 skills now write back to the manifest. Downstream skills get richer input from upstream analysis. -- Score trending: run `/idstack course-quality-review` multiple times and see your score improve over sessions. -- `/idstack accessibility-review` expanded to full WCAG 2.1 AA coverage with course-specific guidance for videos, quizzes, forums, PDFs, and simulations. -- `/idstack red-team` all 5 adversarial dimensions now cite their research evidence. -- `/idstack course-export` shows readiness info (quality, accessibility, red-team scores) before export. +- Score trending: run `/idstack:course-quality-review` multiple times and see your score improve over sessions. +- `/idstack:accessibility-review` expanded to full WCAG 2.1 AA coverage with course-specific guidance for videos, quizzes, forums, PDFs, and simulations. +- `/idstack:red-team` all 5 adversarial dimensions now cite their research evidence. +- `/idstack:course-export` shows readiness info (quality, accessibility, red-team scores) before export. - Schema migration v1.2 with chained upgrades (any version → latest in one pass). ### Course memory (v1.5.0) @@ -65,21 +85,21 @@ What's coming next for idstack. Priorities are shaped by user feedback. [Tell us - Skills check for updates and notify when a new version is available. ### SCORM import and export (v1.4.0) -- `/course-import` now accepts SCORM 1.2/2004 packages from Articulate Rise, Storyline, Adobe Captivate, Lectora, iSpring, and any SCORM-compliant authoring tool -- `/course-export` now generates SCORM 1.2 packages for any LMS or corporate training platform +- `/idstack:course-import` now accepts SCORM 1.2/2004 packages from Articulate Rise, Storyline, Adobe Captivate, Lectora, iSpring, and any SCORM-compliant authoring tool +- `/idstack:course-export` now generates SCORM 1.2 packages for any LMS or corporate training platform - PDF and document file import also added for Rise course exports and syllabi ### Accessibility review + Red team audit (v1.3.0) -- `/accessibility-review` — WCAG 2.1 AA compliance plus Universal Design for Learning (UDL 3.0). Two-tier output: "Must Fix" for legal compliance, "Should Improve" for inclusive design. -- `/red-team` — Adversarial course audit. Assumes the course is broken and tries to prove it. Five dimensions: alignment stress test, evidence verification, cognitive load analysis, learner persona simulation, prerequisite chain integrity. Produces a confidence score. +- `/idstack:accessibility-review` — WCAG 2.1 AA compliance plus Universal Design for Learning (UDL 3.0). Two-tier output: "Must Fix" for legal compliance, "Should Improve" for inclusive design. +- `/idstack:red-team` — Adversarial course audit. Assumes the course is broken and tries to prove it. Five dimensions: alignment stress test, evidence verification, cognitive load analysis, learner persona simulation, prerequisite chain integrity. Produces a confidence score. ## Coming soon -### Gemini CLI support (v2.6) -Add native Gemini CLI as a third target. `.tmpl` → `.toml` transform plus a `gemini-extension.json` manifest. Gemini's built-in `ask_user` tool maps cleanly to the AskUserQuestion concept (drop-in), and inline `!{cmd}` shell interpolation will speed up the manifest-merge call paths. Codex shipped first because its SKILL.md format is a 1:1 match; Gemini needs the file-format transform. +### Gemini CLI support +Add native Gemini CLI as a third target. `.tmpl` → `.toml` transform plus a `gemini-extension.json` manifest. Gemini's built-in `ask_user` tool maps cleanly to the AskUserQuestion concept (drop-in), and inline `!{cmd}` shell interpolation will speed up the manifest-merge call paths. Codex shipped first because its SKILL.md format is a 1:1 match; Gemini needs the file-format transform. Not yet scheduled to a release. -### Marketplace publishing (v2.6) -Publish idstack via `codex plugin marketplace add savvides/idstack` so users don't need to clone the repo. Requires building the proper two-tier marketplace.json + .codex-plugin/plugin.json schema. v2.5 ships with simpler per-skill auto-discovery at `$CODEX_HOME/skills/`, which works without a marketplace. +### Codex marketplace publishing +Publish idstack via `codex plugin marketplace add savvides/idstack` so Codex users don't need to clone the repo. Requires building the proper two-tier marketplace.json + .codex-plugin/plugin.json schema. Codex currently installs through simpler per-skill auto-discovery at `$CODEX_HOME/skills/`, which works without a marketplace. (Claude Code already installs through its marketplace as of v3.2.0.0.) Not yet scheduled to a release. ### More skills Four more skills based on the research synthesis: @@ -99,7 +119,7 @@ Direct API connections to Blackboard, Moodle, and D2L (beyond the IMS Common Car ## The big vision ### Push changes back to your LMS -After `/course-quality-review` identifies issues and `/learning-objectives` generates better objectives, push the improvements directly back to Canvas (and eventually other LMS platforms). No more copy-pasting between a design document and your LMS. The output IS the course. +After `/idstack:course-quality-review` identifies issues and `/idstack:learning-objectives` generates better objectives, push the improvements directly back to Canvas (and eventually other LMS platforms). No more copy-pasting between a design document and your LMS. The output IS the course. This is the 10x goal. It depends on stable import/export, Canvas API write support, conflict handling, and institutional partnerships. It's a ways out, but it's where we're headed. diff --git a/TODOS.md b/TODOS.md index 526a49d..9e1bbe3 100644 --- a/TODOS.md +++ b/TODOS.md @@ -14,7 +14,7 @@ smoke-test catches the regression, new `bin/idstack-doctor` for diagnostics. ## ~~v1.1: Manifest Versioning~~ SHIPPED (v1.2.0) Shipped in v1.2.0. `bin/idstack-migrate` handles schema migrations. -All 7 skill preambles call it automatically. +Every skill preamble calls it automatically (7 skills at the time; 11 now). ## ~~v2: Cross-Domain Quality Checks~~ SHIPPED (v1.2.0) Shipped in v1.2.0. Four checks added to /course-quality-review: @@ -62,13 +62,14 @@ plus a whole-repo symlink at `~/.agents/plugins/idstack/` for in-skill `bin/` re generator (`--target {claude|codex|all}`) emits the Codex flavor under `dist/codex/skills/` with `allowed-tools:` stripped. Concept-name preamble lets the same skill body run in both CLIs. -**Gemini CLI: still pending (v2.6).** `.tmpl` → `.toml` transform, `gemini-extension.json` -manifest, `ask_user` tool mapping. Gemini's built-in structured-question tool is a clean -drop-in for the AskUserQuestion concept. +**Gemini CLI: still pending, not yet scheduled to a release.** `.tmpl` → `.toml` transform, +`gemini-extension.json` manifest, `ask_user` tool mapping. Gemini's built-in +structured-question tool is a clean drop-in for the AskUserQuestion concept. -**Marketplace publishing: still pending (v2.6).** v2.5 uses simpler per-skill auto-discovery; -proper Codex marketplace.json + .codex-plugin/plugin.json packaging would let users do -`codex plugin marketplace add savvides/idstack` without cloning. +**Codex marketplace publishing: still pending, not yet scheduled to a release.** Codex installs +through simpler per-skill auto-discovery; proper Codex marketplace.json + .codex-plugin/plugin.json +packaging would let users do `codex plugin marketplace add savvides/idstack` without cloning. +(Claude Code has installed through its own marketplace since v3.2.0.0.) **Why:** Expands addressable market beyond Claude Code. **Priority:** P2 (Codex done; Gemini next) diff --git a/VERSION b/VERSION index ec285fb..bb32e79 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.0.0 +3.3.0.1 diff --git a/dist/codex/skills/idstack-accessibility-review/SKILL.md b/dist/codex/skills/idstack-accessibility-review/SKILL.md index d8159f4..aaef3b7 100644 --- a/dist/codex/skills/idstack-accessibility-review/SKILL.md +++ b/dist/codex/skills/idstack-accessibility-review/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-assessment-design/SKILL.md b/dist/codex/skills/idstack-assessment-design/SKILL.md index 7d3a224..e56ff9b 100644 --- a/dist/codex/skills/idstack-assessment-design/SKILL.md +++ b/dist/codex/skills/idstack-assessment-design/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-course-builder/SKILL.md b/dist/codex/skills/idstack-course-builder/SKILL.md index 6720128..f3c3b36 100644 --- a/dist/codex/skills/idstack-course-builder/SKILL.md +++ b/dist/codex/skills/idstack-course-builder/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-course-export/SKILL.md b/dist/codex/skills/idstack-course-export/SKILL.md index 6944f24..ced2592 100644 --- a/dist/codex/skills/idstack-course-export/SKILL.md +++ b/dist/codex/skills/idstack-course-export/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-course-import/SKILL.md b/dist/codex/skills/idstack-course-import/SKILL.md index e2d21f9..cc0c7c4 100644 --- a/dist/codex/skills/idstack-course-import/SKILL.md +++ b/dist/codex/skills/idstack-course-import/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-course-quality-review/SKILL.md b/dist/codex/skills/idstack-course-quality-review/SKILL.md index 2e1f37f..a85bb1d 100644 --- a/dist/codex/skills/idstack-course-quality-review/SKILL.md +++ b/dist/codex/skills/idstack-course-quality-review/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-learn/SKILL.md b/dist/codex/skills/idstack-learn/SKILL.md index 3b6d61f..9d6b7a9 100644 --- a/dist/codex/skills/idstack-learn/SKILL.md +++ b/dist/codex/skills/idstack-learn/SKILL.md @@ -244,15 +244,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-learning-objectives/SKILL.md b/dist/codex/skills/idstack-learning-objectives/SKILL.md index 215c0c6..2107b8f 100644 --- a/dist/codex/skills/idstack-learning-objectives/SKILL.md +++ b/dist/codex/skills/idstack-learning-objectives/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-needs-analysis/SKILL.md b/dist/codex/skills/idstack-needs-analysis/SKILL.md index ed7ef86..539b96f 100644 --- a/dist/codex/skills/idstack-needs-analysis/SKILL.md +++ b/dist/codex/skills/idstack-needs-analysis/SKILL.md @@ -245,15 +245,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-pipeline/SKILL.md b/dist/codex/skills/idstack-pipeline/SKILL.md index 86ed5ef..321801b 100644 --- a/dist/codex/skills/idstack-pipeline/SKILL.md +++ b/dist/codex/skills/idstack-pipeline/SKILL.md @@ -244,15 +244,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/dist/codex/skills/idstack-red-team/SKILL.md b/dist/codex/skills/idstack-red-team/SKILL.md index bc0067f..185daa8 100644 --- a/dist/codex/skills/idstack-red-team/SKILL.md +++ b/dist/codex/skills/idstack-red-team/SKILL.md @@ -246,15 +246,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/docs/index.html b/docs/index.html index 6cb7106..8407af8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -44,7 +44,7 @@ "operatingSystem": "macOS, Linux, Windows", "softwareVersion": "3.3.0", "datePublished": "2026-04-20", - "dateModified": "2026-08-04", + "dateModified": "2026-08-05", "offers": { "@type": "Offer", "price": "0", @@ -926,7 +926,7 @@ MIT - v3.3.0.0 — Course memory fixed + v3.3.0.1 — Course memory fixed

Evidence-based instructional design, transparently cited.

108 peer-reviewed studies across 11 research domains. Every recommendation tagged with its evidence tier — T1 meta-analyses and RCTs through T5 expert opinion. Runs in Claude Code, OpenAI Codex CLI, and (soon) Gemini.

@@ -1176,10 +1176,11 @@

v3.3.0.0 — Course memory that actually remembers.

-

August 4, 2026 · v3.3.0.0 · latest

+

August 4, 2026 · v3.3.0.0 · patched by v3.3.0.1

Welcome-back messages work on stock macOS now.

On any Python older than 3.12 — including the 3.9 that macOS ships — the session-memory code inside every skill hit a silent syntax error. No welcome-back summary, no quality-score trend, no suggested next step. Fixed, and now exercised on Python 3.9 in CI so it stays fixed.

Also in this release: /idstack:pipeline invokes its child skills correctly in Claude Code, skills notice previous runs again ("update the results or start fresh?"), imported courses get a proper next-step suggestion, and a course name with an apostrophe no longer blanks the status dashboard. To update: cd into your idstack clone, then git pull && ./setup.

+

Patched in v3.3.0.1 (August 5): skills no longer point you at commands that don't exist. Welcome-back and next-step messages now name the runnable /idstack:<skill> form.

→ All releases on GitHub

diff --git a/skills/accessibility-review/SKILL.md b/skills/accessibility-review/SKILL.md index e639706..bd91c37 100644 --- a/skills/accessibility-review/SKILL.md +++ b/skills/accessibility-review/SKILL.md @@ -254,15 +254,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/assessment-design/SKILL.md b/skills/assessment-design/SKILL.md index 909465a..6a3495a 100644 --- a/skills/assessment-design/SKILL.md +++ b/skills/assessment-design/SKILL.md @@ -253,15 +253,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/course-builder/SKILL.md b/skills/course-builder/SKILL.md index 1aa4f6b..93755bc 100644 --- a/skills/course-builder/SKILL.md +++ b/skills/course-builder/SKILL.md @@ -254,15 +254,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/course-export/SKILL.md b/skills/course-export/SKILL.md index f45f1e5..5579704 100644 --- a/skills/course-export/SKILL.md +++ b/skills/course-export/SKILL.md @@ -254,15 +254,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/course-import/SKILL.md b/skills/course-import/SKILL.md index b25b799..ec58a74 100644 --- a/skills/course-import/SKILL.md +++ b/skills/course-import/SKILL.md @@ -254,15 +254,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/course-quality-review/SKILL.md b/skills/course-quality-review/SKILL.md index b35db8f..f0132dc 100644 --- a/skills/course-quality-review/SKILL.md +++ b/skills/course-quality-review/SKILL.md @@ -254,15 +254,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/learn/SKILL.md b/skills/learn/SKILL.md index 324bd54..c700277 100644 --- a/skills/learn/SKILL.md +++ b/skills/learn/SKILL.md @@ -249,15 +249,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/learning-objectives/SKILL.md b/skills/learning-objectives/SKILL.md index 146393e..9ae7f1f 100644 --- a/skills/learning-objectives/SKILL.md +++ b/skills/learning-objectives/SKILL.md @@ -253,15 +253,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/needs-analysis/SKILL.md b/skills/needs-analysis/SKILL.md index 74d402c..1624405 100644 --- a/skills/needs-analysis/SKILL.md +++ b/skills/needs-analysis/SKILL.md @@ -253,15 +253,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/pipeline/SKILL.md b/skills/pipeline/SKILL.md index 6cc6362..bdb145b 100644 --- a/skills/pipeline/SKILL.md +++ b/skills/pipeline/SKILL.md @@ -253,15 +253,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/skills/red-team/SKILL.md b/skills/red-team/SKILL.md index f8fa417..6c7adef 100644 --- a/skills/red-team/SKILL.md +++ b/skills/red-team/SKILL.md @@ -256,15 +256,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/templates/agent-context.md b/templates/agent-context.md index 6c80a2a..b325f69 100644 --- a/templates/agent-context.md +++ b/templates/agent-context.md @@ -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: @@ -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, @@ -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 --payload # Canonical manifest write path +bin/idstack-slugify "" # Derive the 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. diff --git a/templates/preamble.md b/templates/preamble.md index 213ddf4..9b45c37 100644 --- a/templates/preamble.md +++ b/templates/preamble.md @@ -233,15 +233,15 @@ fi ``` **If QUALITY_TREND is shown:** Synthesize a welcome-back message. Example: "Welcome back. -Quality score trend: 62 -> 68 -> 72 over 3 reviews. Last skill: /learning-objectives." +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 /course-import." +Example: "Welcome back. Last session you ran /idstack:course-import." **If SUGGESTED_NEXT is shown:** Mention the suggested next skill naturally. -Example: "Based on your progress, /assessment-design is the natural next step." +Example: "Based on your progress, /idstack:assessment-design is the natural next step." **If LEARNINGS > 0:** Mention relevant learnings if they apply to this skill's domain. Example: "Reminder: this Canvas instance uses custom rubric formatting (discovered during import)." diff --git a/test/mutation-test.sh b/test/mutation-test.sh index 665d217..5ef7228 100755 --- a/test/mutation-test.sh +++ b/test/mutation-test.sh @@ -100,6 +100,17 @@ sed -i.bak 's|`/idstack:learning-objectives`|`/learning-objectives`|' \ regen expect_fail "bare /skill reference regression" "$WORK/r/test/smoke-test.sh" "$WORK/r" +# 4b. UNBACKTICKED bare /skill in the preamble returns -> smoke-test must fail. +# The guard above matched only backticked refs until v3.3.0.1, so three plain-prose +# examples sat in the preamble's context-recovery section telling the model to say +# "/assessment-design is the natural next step" — a command that does nothing. The +# preamble is spliced into all 22 skill files, so this reached every user. +fresh +sed -i.bak 's|/idstack:assessment-design is the natural next step|/assessment-design is the natural next step|' \ + "$WORK/r/templates/preamble.md" +regen +expect_fail "unbackticked bare /skill in preamble regression" "$WORK/r/test/smoke-test.sh" "$WORK/r" + # 5. pipeline unnamespaced Skill invocation returns -> smoke-test must fail fresh sed -i.bak 's|skill: "idstack:needs-analysis"|skill: "needs-analysis"|' \ diff --git a/test/smoke-test.sh b/test/smoke-test.sh index 7d3dab5..d6f8d8f 100755 --- a/test/smoke-test.sh +++ b/test/smoke-test.sh @@ -165,13 +165,27 @@ done # User-facing skill references must be namespaced /idstack: — the Codex # translation rule strips that prefix; a bare /skill renders as an invalid -# command in both CLIs. (Frontmatter descriptions are exempt; this bans the -# backticked in-body form.) -BARE_SLASH_RE='`/(needs-analysis|learning-objectives|assessment-design|course-builder|course-quality-review|accessibility-review|red-team|course-export|course-import|pipeline|learn)`' +# command in both CLIs. (Frontmatter descriptions are exempt.) +# +# This matched only the backticked form until v3.3.0.1, which let three +# unbackticked examples sit in the preamble's context-recovery section — the +# model copied them and told users to run "/assessment-design", which does +# nothing. The leading class covers a command position: line start, whitespace, +# an opening quote/paren, or a backtick. It deliberately does NOT match a `/` +# preceded by a path character, so `.idstack/exports//red-team.html` +# stays legal, and it can't match `/idstack:` because the skill name +# there does not follow the slash. +BARE_SLASH_RE='(^|[[:space:]"(`])/(needs-analysis|learning-objectives|assessment-design|course-builder|course-quality-review|accessibility-review|red-team|course-export|course-import|pipeline|learn)\b' +# Frontmatter stays exempt: `description:` is prose the CLI shows in a skill +# picker, not a command anyone types. STRIP_FM drops everything through the +# closing `---` so only the body is scanned. Later `---` horizontal rules in +# the body keep incrementing c, which is harmless once c>=2. +STRIP_FM='awk "/^---\$/{c++; next} c>=2"' for skill in $SKILLS; do - check "$skill SKILL.md.tmpl free of bare backticked /skill refs" "! grep -E '$BARE_SLASH_RE' '$IDSTACK_DIR/skills/$skill/SKILL.md.tmpl'" + check "$skill SKILL.md.tmpl body free of bare /skill refs" "! $STRIP_FM '$IDSTACK_DIR/skills/$skill/SKILL.md.tmpl' | grep -qE '$BARE_SLASH_RE'" done -check "preamble free of bare backticked /skill refs" "! grep -E '$BARE_SLASH_RE' '$IDSTACK_DIR/templates/preamble.md'" +# The preamble has no frontmatter — scan the whole file. +check "preamble free of bare /skill refs" "! grep -qE '$BARE_SLASH_RE' '$IDSTACK_DIR/templates/preamble.md'" check "no '/idstack ' space typos in templates" "! grep -rE '/idstack [a-z]' $IDSTACK_DIR/skills/*/SKILL.md.tmpl '$IDSTACK_DIR/templates/preamble.md'" check "pipeline status table uses /idstack: prefixes" "grep -qF '[done] /idstack:needs-analysis' '$IDSTACK_DIR/skills/pipeline/SKILL.md.tmpl'" check "pipeline invokes children with the idstack: namespace" "grep -qF 'skill: \"idstack:needs-analysis\"' '$IDSTACK_DIR/skills/pipeline/SKILL.md.tmpl'"