From 4198ee6baafd3c0783140b6b18751041b3920254 Mon Sep 17 00:00:00 2001 From: Valentin Schmidt Date: Sun, 30 Aug 2026 10:13:51 +0200 Subject: [PATCH 1/5] fix: make thesis-finder frontmatter valid strict YAML An unquoted ": " inside the description ("multi-session continuity: detects prior searches") parses as a nested mapping under a strict YAML reader. Claude Code's lenient parser and our regex-based bundlers never noticed, but external installers do: `npx skills add` skipped the entry point and offered an install that dangles at the first hand-off. Replaced with an em dash rather than quoting the value, so the frontmatter regexes in the bundle scripts are untouched. Added a test that yaml.safe_load's every shipped SKILL.md frontmatter across skills/, .claude/skills/ and .codex/skills/; pyyaml joins the dev extra for it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A5VtwCJkmfxRtTAa1gQ7bA --- pyproject.toml | 1 + skills/tests/test_skill_package.py | 23 +++++++++++++++++++++++ skills/thesis-finder/SKILL.md | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 76cb670..c8eb90b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ license = "MIT" [project.optional-dependencies] dev = [ "pytest>=8", + "pyyaml>=6", ] eval = [ "deepeval", diff --git a/skills/tests/test_skill_package.py b/skills/tests/test_skill_package.py index b36ea43..1946718 100644 --- a/skills/tests/test_skill_package.py +++ b/skills/tests/test_skill_package.py @@ -5,6 +5,8 @@ import re from pathlib import Path +import pytest + SKILLS_DIR = Path(__file__).resolve().parents[1] REPO_ROOT = SKILLS_DIR.parent @@ -85,6 +87,27 @@ def test_skill_frontmatter_is_portable_and_trigger_rich() -> None: assert set(fields) == {"name", "description"} +def test_every_shipped_skill_frontmatter_parses_as_strict_yaml() -> None: + """External installers (e.g. `npx skills add`) parse frontmatter with a strict YAML + reader and silently skip a skill whose frontmatter fails. An unquoted `: ` inside a + description is enough to drop the entry point from an install.""" + yaml = pytest.importorskip("yaml") + + skill_files = [skill_dir / "SKILL.md" for skill_dir in _skill_dirs()] + for agent_dir in (REPO_ROOT / ".claude" / "skills", REPO_ROOT / ".codex" / "skills"): + skill_files.extend(sorted(path for path in agent_dir.glob("*/SKILL.md") if not path.parent.is_symlink())) + + for skill_md in skill_files: + _, _, rest = skill_md.read_text(encoding="utf-8").partition("---\n") + frontmatter, separator, _ = rest.partition("\n---") + assert separator, f"{skill_md} has no closing frontmatter delimiter" + try: + parsed = yaml.safe_load(frontmatter) + except yaml.YAMLError as error: + raise AssertionError(f"{skill_md} frontmatter is not valid YAML: {error}") from error + assert parsed["name"] and parsed["description"] + + def test_referenced_skill_resources_exist() -> None: reference_pattern = re.compile(r"`(references/[^`]+)`") diff --git a/skills/thesis-finder/SKILL.md b/skills/thesis-finder/SKILL.md index f16ed0f..8ea2aa8 100644 --- a/skills/thesis-finder/SKILL.md +++ b/skills/thesis-finder/SKILL.md @@ -1,6 +1,6 @@ --- name: thesis-finder -description: Single entry point for thesis discovery. Helps a student sharpen what kind of thesis fits them and then find where to write it. Builds the student profile through an inline interview if not yet present, then routes to university chair discovery (find-university-chairs), company thesis discovery (find-company-thesis-options), or both, based on student choice. Records the student's own thesis self-understanding before and after the search. Supports multi-session continuity: detects prior searches and resumes without re-interviewing. Use when a student wants to find where to write their thesis — no prior skill invocation needed. +description: Single entry point for thesis discovery. Helps a student sharpen what kind of thesis fits them and then find where to write it. Builds the student profile through an inline interview if not yet present, then routes to university chair discovery (find-university-chairs), company thesis discovery (find-company-thesis-options), or both, based on student choice. Records the student's own thesis self-understanding before and after the search. Supports multi-session continuity — detects prior searches and resumes without re-interviewing. Use when a student wants to find where to write their thesis — no prior skill invocation needed. --- # Thesis Finder From f79546ae0c4920edf96e4def7690710f8bb77cd0 Mon Sep 17 00:00:00 2001 From: Valentin Schmidt Date: Sun, 30 Aug 2026 10:13:51 +0200 Subject: [PATCH 2/5] chore: hide maintainer-only skills from external installers create-thesis-sim-student and run-thesis-simulations drive the local simulation suite and mean nothing to a student. Installers that scan .claude/skills/ were listing them alongside the ten public skills; metadata.internal is the documented opt-out and Claude Code still loads them locally. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A5VtwCJkmfxRtTAa1gQ7bA --- .claude/skills/create-thesis-sim-student/SKILL.md | 2 ++ .claude/skills/run-thesis-simulations/SKILL.md | 2 ++ .codex/skills/create-thesis-sim-student/SKILL.md | 2 ++ .codex/skills/run-thesis-simulations/SKILL.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.claude/skills/create-thesis-sim-student/SKILL.md b/.claude/skills/create-thesis-sim-student/SKILL.md index 77f3a06..9cb6c35 100644 --- a/.claude/skills/create-thesis-sim-student/SKILL.md +++ b/.claude/skills/create-thesis-sim-student/SKILL.md @@ -1,6 +1,8 @@ --- name: create-thesis-sim-student description: Create new repo-local thesis-finder simulation student commands. Use when asked to add, scaffold, draft, or generate a new simulated thesis-finder student persona for Claude and Codex. +metadata: + internal: true --- # Create Thesis Simulation Student diff --git a/.claude/skills/run-thesis-simulations/SKILL.md b/.claude/skills/run-thesis-simulations/SKILL.md index 21ce448..aa17056 100644 --- a/.claude/skills/run-thesis-simulations/SKILL.md +++ b/.claude/skills/run-thesis-simulations/SKILL.md @@ -1,6 +1,8 @@ --- name: run-thesis-simulations description: Run and evaluate all repo-local thesis-finder simulation commands. Use when asked to run the thesis simulation suite, evaluate thesis-finder personas, execute all thesis-sim commands, or produce conversation and rating artifacts. +metadata: + internal: true --- # Run Thesis Simulations diff --git a/.codex/skills/create-thesis-sim-student/SKILL.md b/.codex/skills/create-thesis-sim-student/SKILL.md index 77f3a06..9cb6c35 100644 --- a/.codex/skills/create-thesis-sim-student/SKILL.md +++ b/.codex/skills/create-thesis-sim-student/SKILL.md @@ -1,6 +1,8 @@ --- name: create-thesis-sim-student description: Create new repo-local thesis-finder simulation student commands. Use when asked to add, scaffold, draft, or generate a new simulated thesis-finder student persona for Claude and Codex. +metadata: + internal: true --- # Create Thesis Simulation Student diff --git a/.codex/skills/run-thesis-simulations/SKILL.md b/.codex/skills/run-thesis-simulations/SKILL.md index 21ce448..aa17056 100644 --- a/.codex/skills/run-thesis-simulations/SKILL.md +++ b/.codex/skills/run-thesis-simulations/SKILL.md @@ -1,6 +1,8 @@ --- name: run-thesis-simulations description: Run and evaluate all repo-local thesis-finder simulation commands. Use when asked to run the thesis simulation suite, evaluate thesis-finder personas, execute all thesis-sim commands, or produce conversation and rating artifacts. +metadata: + internal: true --- # Run Thesis Simulations From 691aab15ce66f188734188e9afc284397a90e20c Mon Sep 17 00:00:00 2001 From: Valentin Schmidt Date: Sun, 30 Aug 2026 10:13:51 +0200 Subject: [PATCH 3/5] docs: document the one-command skills-CLI install Route C gains an optional Step 0: `npx skills add Tue-StudyOS/study-os-thesis --skill '*'` installs all ten skills into any of ~70 skills-directory clients. The manual copy route and the release archives are unchanged and stay the fallback for anyone without Node. Both caveats are stated: --skill '*' is mandatory because a partial pick breaks the name-based hand-offs, and the CLI tracks main unless a @skills-vX.Y.Z tag is appended. Also corrects the README's "dependency-free (pytest only)" claim now that pyyaml is a dev dep. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A5VtwCJkmfxRtTAa1gQ7bA --- CHANGELOG.md | 15 +++++++++------ INSTALL.md | 32 +++++++++++++++++++++++++++++++- README.md | 17 ++++++++++++++++- STATUS.md | 20 ++++++++++++++++++++ 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be99546..e6deaee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,10 @@ This project follows Semantic Versioning for the released skill package: ### Added -- ... +- One-command install for skills-directory clients: `npx skills add + Tue-StudyOS/study-os-thesis --skill '*'` (third-party Vercel `skills` CLI), documented as + Route C Step 0 in INSTALL.md. The release archives and the manual copy route are unchanged. +- Test: every shipped `SKILL.md` frontmatter must parse under a strict YAML reader. ### Changed @@ -21,16 +24,16 @@ This project follows Semantic Versioning for the released skill package: ### Fixed -- ... +- `thesis-finder`'s frontmatter description contained an unquoted `: `, which made it + invalid YAML. Strict parsers — including the `skills` CLI — skipped the entry-point skill + silently, leaving an install that dangles at the first hand-off. +- Repo-local maintainer skills (`create-thesis-sim-student`, `run-thesis-simulations`) are + marked `metadata.internal`, so external installers no longer offer them to students. ### Removed - ... -### Breaking Changes - -- None. - ## [2.1.0] - 2026-08-20 **This release adds two new ways to install the same skills.** Until now the only shape was diff --git a/INSTALL.md b/INSTALL.md index c03b8be..c57547e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -28,7 +28,7 @@ outside the skills folder. | | Route A — Claude app | Route B — ChatGPT, Gemini, or any chat | Route C — Claude Code, Codex, Gemini CLI | |---|---|---|---| | For | Claude Pro/Max users | Anyone else, including free ChatGPT and Gemini | People already working in a terminal agent | -| Install | Upload **one zip** | Attach **one file**, paste one text block | Copy **ten folders** into a directory | +| Install | Upload **one zip** | Attach **one file**, paste one text block | One command, or copy **ten folders** into a directory | | Terminal needed | No | No | Yes | All three run the same searches and produce the same output. Whichever you pick, @@ -93,6 +93,35 @@ works, but nothing is remembered once that chat ends. they call each other. A partial install fails at the first hand-off. (Routes A and B have no such trap — everything travels in one artifact.) +## Step 0 — The one-command shortcut (optional) + +If you have **Node 22.20 or newer**, one command installs all ten skills into the client you +use — Claude Code, Codex, Cursor, OpenCode and some seventy others: + +```bash +npx skills@latest add Tue-StudyOS/study-os-thesis --skill '*' --agent claude-code -g +``` + +- `--skill '*'` is **not optional**. Without it you are asked to pick from a list, and any + pick short of all ten hits the hand-off trap above. +- `--agent` names your client — `claude-code`, `codex`, `cursor`, … Leave the flag out and it + asks you. +- `-g` installs for your whole account (`~/.claude/skills/`). Drop it and the skills land in + the current folder only (`./.claude/skills/`), which is what you want if you keep one + directory per thesis search. +- The command tracks `main`. To pin a release instead, append the tag to the repository name: + `Tue-StudyOS/study-os-thesis@skills-v2.1.0`. + +Restart your client afterwards and continue at **Run it**. + +`skills` is a third-party installer made by Vercel, not part of this project. It downloads +this repository and copies the ten folders from `skills/` into your client's skills +directory — by hand, that is exactly Steps 1 and 2 below, and the result is the same files. +If you would rather not run an unfamiliar installer, or you have no Node, just start at +Step 1. + +--- + ## Step 1 — Get the files Download the latest release archive from @@ -232,6 +261,7 @@ single step is the difference between continuing and starting over. | **Routes A/B:** it asks the full interview again on a later visit | The chat was not started inside the project/GPT/Gem, or the session file was never added to it | Open a chat inside the container holding your session file and type `thesis-finder` again. If no session file was ever saved, the interview has to be redone. | | **Route B:** it answers from general knowledge instead of following the instructions | The document was attached but the instructions block was never pasted in | Paste the block from `-----BEGIN INSTRUCTIONS-----` into the container's instructions field. Without it the assistant has no reason to open the document. | | **Route C:** agent finds *some* skills but breaks partway ("I don't have a skill called `discover-university-candidates`"), or the folder listing looks wrong | Wrong folder level, or a partial install | The path must be `/thesis-finder/SKILL.md`, **not** `/study-os-thesis-skills-vX.Y.Z/thesis-finder/SKILL.md`. Move the contents up one level and make sure **all** skill folders are there. | +| **Route C:** `npx skills` refuses to start, or warns `EBADENGINE` | Node is older than 22.20, or missing entirely | Skip Step 0 and install by hand from Step 1 — same files, no Node needed. | | Results are thin, generic, or the agent says it cannot verify anything | No web access, or search quota exhausted | Confirm web search is enabled in your client and that you have quota left. These skills cannot work offline — everything they output is verified live, by design. | --- diff --git a/README.md b/README.md index 3a8d2ee..3256dbc 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,21 @@ what the target client can load, not by preference. | **ChatGPT, Gemini** — Projects, Custom GPTs, Gems | `thesis-finder-portable-vX.Y.Z.md` + `-instructions-vX.Y.Z.txt` | One document, named sections | Neither loads Agent Skills at all. Their containers hold an instructions box and a handful of files. | | **Any chat, nothing installed** | the same portable `.md` | Attach and type `thesis-finder` | Works, but nothing is remembered after the chat ends. | +**Or install straight from this repo.** Any client that reads a skills directory can also +skip the release archive and pull `skills/` directly with the third-party +[`skills`](https://github.com/vercel-labs/skills) CLI: + +```bash +npx skills@latest add Tue-StudyOS/study-os-thesis --skill '*' --agent claude-code -g +``` + +It copies the same ten folders into that client's skills directory — the archive route by +other means. Two consequences: it tracks `main` unless a release tag is appended +(`…/study-os-thesis@skills-v2.1.0`), and `--skill '*'` is required, because a partial pick +breaks the name-based hand-offs. The CLI parses frontmatter with a strict YAML reader and +silently drops any skill that fails it, so `skills/*/SKILL.md` frontmatter is +`yaml.safe_load`-clean and tested as such. + ### Why three and not one Each client breaks the previous form in a specific way: @@ -184,7 +199,7 @@ independent reference list at all and says so to the student at run time. ## Quality gates -Tests are dependency-free (`pytest` only) and run from the repo root: +Tests need only `pytest` and `pyyaml`, and run from the repo root: ```bash python -m pip install -e ".[dev]" diff --git a/STATUS.md b/STATUS.md index 0065155..d8b928b 100644 --- a/STATUS.md +++ b/STATUS.md @@ -370,6 +370,26 @@ architecture-tagged. W optional. ## Log +- **2026-08-30** — **One-command install via the Vercel `skills` CLI — and the frontmatter bug + it exposed.** Branch `feat/skills-cli-install`. `npx skills add Tue-StudyOS/study-os-thesis` + already worked against our layout without any change: the CLI scans `skills//SKILL.md`, + which is what we ship. Running it revealed that it found **11 skills and skipped + `thesis-finder`** — the entry point — with a YAML parse error. Cause: `Supports multi-session + continuity: detects prior searches` in the frontmatter description. An unquoted `: ` inside a + plain scalar is a nested mapping to a strict YAML reader. Claude Code's lenient parser and our + own regex-based bundlers never noticed; `yaml.safe_load` fails on it too. Every external + installer would therefore have handed students exactly the partial install INSTALL.md warns + about. Fixed with an em dash (no quoting, so the bundler regexes are untouched), guarded by a + new strict-YAML test over `skills/`, `.claude/skills/`, and `.codex/skills/` — verified to + fail when the colon is put back. `pyyaml` added to the `dev` extra for it, and the README's + "dependency-free (`pytest` only)" claim corrected. Also marked the two maintainer-only skills + (`create-thesis-sim-student`, `run-thesis-simulations`) `metadata.internal`, which the CLI + honours: the public listing went 12 → 10, and Claude Code still loads them locally. Documented + as Route C **Step 0** in INSTALL.md plus a README paragraph, with the two caveats that matter: + `--skill '*'` is mandatory (partial picks break the hand-offs) and the CLI tracks `main` + unless a `@skills-vX.Y.Z` tag is appended. Routes A, B, and the manual Route C copy are + untouched — no files moved, no frontmatter quoted, no build script changed. + - **2026-08-20 (d)** — **Task AP: degree programs resolved by rule, not by lookup. The catalog was already lying.** Branch `feat/degree-program-discovery`, off `main`. From cc5b49cc437c87909f8a69918eaa1725b93504cb Mon Sep 17 00:00:00 2001 From: Valentin Schmidt Date: Sun, 30 Aug 2026 10:20:58 +0200 Subject: [PATCH 4/5] docs: correct how a release is pinned with the skills CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing the published branch rather than only the local tree showed the `repo@tag` shorthand parses but silently ignores the ref — every such install gets the default branch. The tag has to be spelled out as a URL path (`/tree/skills-vX.Y.Z`), which in turn cannot express a ref containing a slash. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A5VtwCJkmfxRtTAa1gQ7bA --- CHANGELOG.md | 2 ++ INSTALL.md | 6 ++++-- README.md | 8 +++++--- STATUS.md | 8 ++++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6deaee..f8fe347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project follows Semantic Versioning for the released skill package: - One-command install for skills-directory clients: `npx skills add Tue-StudyOS/study-os-thesis --skill '*'` (third-party Vercel `skills` CLI), documented as Route C Step 0 in INSTALL.md. The release archives and the manual copy route are unchanged. + Pinning a release requires the tag as a URL path (`/tree/skills-vX.Y.Z`); the `repo@tag` + shorthand is accepted but ignored. - Test: every shipped `SKILL.md` frontmatter must parse under a strict YAML reader. ### Changed diff --git a/INSTALL.md b/INSTALL.md index c57547e..177e954 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -109,8 +109,10 @@ npx skills@latest add Tue-StudyOS/study-os-thesis --skill '*' --agent claude-cod - `-g` installs for your whole account (`~/.claude/skills/`). Drop it and the skills land in the current folder only (`./.claude/skills/`), which is what you want if you keep one directory per thesis search. -- The command tracks `main`. To pin a release instead, append the tag to the repository name: - `Tue-StudyOS/study-os-thesis@skills-v2.1.0`. +- The command tracks `main`. To pin a release instead, give the full URL with the tag in it — + `npx skills@latest add https://github.com/Tue-StudyOS/study-os-thesis/tree/skills-v2.1.0 + --skill '*' --agent claude-code -g`. The shorter `repo@tag` form is accepted but the tag is + ignored, so you silently get `main`. Restart your client afterwards and continue at **Run it**. diff --git a/README.md b/README.md index 3256dbc..897fb4a 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,11 @@ npx skills@latest add Tue-StudyOS/study-os-thesis --skill '*' --agent claude-cod ``` It copies the same ten folders into that client's skills directory — the archive route by -other means. Two consequences: it tracks `main` unless a release tag is appended -(`…/study-os-thesis@skills-v2.1.0`), and `--skill '*'` is required, because a partial pick -breaks the name-based hand-offs. The CLI parses frontmatter with a strict YAML reader and +other means. Two consequences: `--skill '*'` is required, because a partial pick breaks the +name-based hand-offs, and the CLI installs the **default branch** — pinning a release needs +the tag spelled out as a URL path +(`add https://github.com/Tue-StudyOS/study-os-thesis/tree/skills-v2.1.0`), since the shorter +`repo@tag` form parses but ignores the tag. The CLI parses frontmatter with a strict YAML reader and silently drops any skill that fails it, so `skills/*/SKILL.md` frontmatter is `yaml.safe_load`-clean and tested as such. diff --git a/STATUS.md b/STATUS.md index d8b928b..9047a56 100644 --- a/STATUS.md +++ b/STATUS.md @@ -386,8 +386,12 @@ architecture-tagged. W optional. (`create-thesis-sim-student`, `run-thesis-simulations`) `metadata.internal`, which the CLI honours: the public listing went 12 → 10, and Claude Code still loads them locally. Documented as Route C **Step 0** in INSTALL.md plus a README paragraph, with the two caveats that matter: - `--skill '*'` is mandatory (partial picks break the hand-offs) and the CLI tracks `main` - unless a `@skills-vX.Y.Z` tag is appended. Routes A, B, and the manual Route C copy are + `--skill '*'` is mandatory (partial picks break the hand-offs) and the CLI installs the + **default branch**. The `repo@tag` shorthand parses but silently ignores the tag — caught + by testing the published branch rather than only the local tree; pinning needs the tag as + a URL path (`/tree/skills-v2.1.0`), and refs containing `/` are misparsed there. Verified + end-to-end over the network against the fixed tree: 10 skills, `thesis-finder` present, + no skip warning. Routes A, B, and the manual Route C copy are untouched — no files moved, no frontmatter quoted, no build script changed. - **2026-08-20 (d)** — **Task AP: degree programs resolved by rule, not by lookup. The From 4d79bebc10ac562f213869114b2f75bdb641d22e Mon Sep 17 00:00:00 2001 From: Valentin Schmidt Date: Sun, 30 Aug 2026 11:08:05 +0200 Subject: [PATCH 5/5] fix: address Copilot review on the skills-CLI install PR Import yaml directly in the strict-YAML frontmatter test so a missing pyyaml fails the suite instead of silently skipping the gate, and install pyyaml in the codex-evals workflow, which was the only job not installing the dev extra. Move the pinned-install command into a fenced block; inline code cannot span lines, so it rendered broken and could not be copied. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01HmFo5RDAjNo6DPPDAEH9vg --- .github/workflows/codex-multiturn-evals.yml | 2 +- INSTALL.md | 11 +++++++---- skills/tests/test_skill_package.py | 3 +-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codex-multiturn-evals.yml b/.github/workflows/codex-multiturn-evals.yml index 0da3666..187c04c 100644 --- a/.github/workflows/codex-multiturn-evals.yml +++ b/.github/workflows/codex-multiturn-evals.yml @@ -52,7 +52,7 @@ jobs: python-version: "3.13" - name: Install deterministic test dependencies - run: python -m pip install pytest + run: python -m pip install pytest pyyaml - name: Install optional DeepEval dependency if: ${{ inputs.run_deepeval }} diff --git a/INSTALL.md b/INSTALL.md index 177e954..c6b3140 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -109,10 +109,13 @@ npx skills@latest add Tue-StudyOS/study-os-thesis --skill '*' --agent claude-cod - `-g` installs for your whole account (`~/.claude/skills/`). Drop it and the skills land in the current folder only (`./.claude/skills/`), which is what you want if you keep one directory per thesis search. -- The command tracks `main`. To pin a release instead, give the full URL with the tag in it — - `npx skills@latest add https://github.com/Tue-StudyOS/study-os-thesis/tree/skills-v2.1.0 - --skill '*' --agent claude-code -g`. The shorter `repo@tag` form is accepted but the tag is - ignored, so you silently get `main`. +- The command tracks `main`. To pin a release instead, give the full URL with the tag in it: + + ```bash + npx skills@latest add https://github.com/Tue-StudyOS/study-os-thesis/tree/skills-v2.1.0 --skill '*' --agent claude-code -g + ``` + + The shorter `repo@tag` form is accepted but the tag is ignored, so you silently get `main`. Restart your client afterwards and continue at **Run it**. diff --git a/skills/tests/test_skill_package.py b/skills/tests/test_skill_package.py index 1946718..cfebd06 100644 --- a/skills/tests/test_skill_package.py +++ b/skills/tests/test_skill_package.py @@ -6,6 +6,7 @@ from pathlib import Path import pytest +import yaml SKILLS_DIR = Path(__file__).resolve().parents[1] @@ -91,8 +92,6 @@ def test_every_shipped_skill_frontmatter_parses_as_strict_yaml() -> None: """External installers (e.g. `npx skills add`) parse frontmatter with a strict YAML reader and silently skip a skill whose frontmatter fails. An unquoted `: ` inside a description is enough to drop the entry point from an install.""" - yaml = pytest.importorskip("yaml") - skill_files = [skill_dir / "SKILL.md" for skill_dir in _skill_dirs()] for agent_dir in (REPO_ROOT / ".claude" / "skills", REPO_ROOT / ".codex" / "skills"): skill_files.extend(sorted(path for path in agent_dir.glob("*/SKILL.md") if not path.parent.is_symlink()))