Release v0.3.0 - #19
Merged
Merged
Conversation
Complete implementation of the whet CLI tool — a multi-platform installer for expert AI coding agent skills. Encompasses all 6 development phases: Phase 1 - Foundation: YAML frontmatter for SKILL.md files, skill.toml metadata, pixi→uv migration, dynamic test discovery Phase 2 - CLI + Adapters: Typer CLI (add/remove/list/search/info/install), Claude Code, Google Antigravity, Cursor, GitHub Copilot adapters Phase 3 - Gap Filling Wave 1: FastAPI, AWS SageMaker, Hugging Face skills, DevOps/Infra agent, Data Engineer agent Phase 4 - Settings Engine + Doctor: settings generate/apply/diff with merge support, 10 health checks in doctor command Phase 5 - Scaffolding: whet init with string.Template rendering, cv-inference-service and pytorch-training-project archetype templates Phase 6 - Distribution + Polish: whet update command, Gradio and Kubernetes skills, release workflow, repo rename to whet Content inventory: - 30 skills (CV/ML, infrastructure, experiment tracking, code quality) - 6 agents (Expert Coder, ML Engineer, DevOps/Infra, Data Engineer, Code Review, Test Engineer) - 6 archetypes (pytorch-training, cv-inference, data-pipeline, library-package, model-zoo, research-notebook) - 203 tests passing, ruff clean, mypy strict clean Also includes: - Rename all references from ai-cv-claude-skills to whet - CI workflows updated for main/develop branching model - Tag-triggered release workflow (PyPI trusted publishing + GitHub Releases) - justfile task runner replacing pixi tasks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add proper type annotations to _install_to and _get_adapter in install.py (fixes no-untyped-call errors under --strict) - Add mypy overrides for typer (no stubs), yaml, and tomli modules - Disable untyped-decorator warnings for whet.cli.* (Typer decorators) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- `whet install` now installs both skills (30) and agents (6) by default - Add --skills-only and --agents-only flags for granular control - Add --with-settings / -s flag to apply settings template with merge - Add discover_agents() to registry loader (reuses Skill model) - Settings merge uses existing engine (preserves user customizations) Closes #4 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- load_existing() now extracts only permissions.allow, ignoring extra keys like defaultMode, hooks, statusLine that exist in real settings - write_settings() preserves all existing keys in the file, only updating permissions.allow (non-destructive merge) - Fixes crash when merging into ~/.claude/settings.json with hooks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - `whet target <platform>` and `whet config target <value>` now persist the selection to `~/.config/whet/config.json` - All 8 CLI call sites switched from `WhetConfig()` (hardcoded Claude default) to `WhetConfig.load()` (reads from disk, falls back to defaults) - `whet target` (no args) now shows the current persisted target alongside auto-detection ## Test plan - [x] 203 tests pass (`uv run pytest tests/ -v`) - [x] mypy strict passes (`uv run mypy src/whet/ tests/ --strict`) - [x] ruff clean (`uv run ruff check . && uv run ruff format --check .`) - [x] Manual: `whet target antigravity` → `whet config` shows `target: antigravity` - [x] Manual: `whet target claude` → `whet install --global` uses `~/.claude/skills` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…y trigger descriptions (#6) P0/P1 cleanup from the skill-library review. **32 skills** total. ## What changed ### 1. Trim bloat (progressive disclosure) All **19 SKILL.md bodies over Anthropic's 500-line guideline** are now under it — restated "what is X" prose and near-duplicate code blocks removed, every distinct pattern/gotcha/anti-pattern kept. | Skill | Before | After | |---|---|---| | kubernetes | 776 | 480 | | onnx | 720 | 499 | | abstraction-patterns | 687 | 464 | | matplotlib | 675 | 452 | | github-actions | 632 | 412 | | pypi | 616 | 335 | | …13 more | — | all <500 | Avg SKILL.md 551 → ~440 lines; ~2.2k net lines removed. (Next step, not in this PR: split survivors into thin index + `references/`.) ### 2. New skills (real coverage gaps) - **model-evaluation** — detection mAP/IoU, confusion matrices, per-class + per-size breakdowns, threshold selection, per-slice failure analysis, eval-as-CI gate. Built on **`supervision`** (`import supervision as sv`), the detection-native library already used alongside RF-DETR/YOLOX, with `torchmetrics` retained for classification/calibration. Feeds GSD's `eval-planner`; previously only generic `testing` existed. - **pydantic-ai** — typed LLM/VLM structured outputs; VLM-in-the-loop auto-labeling (Gemini/Moondream → validated detections). The supervision usage was verified against **0.29.1** and encodes the real traps: import from `supervision.metrics` (the top-level `sv.MeanAveragePrecision` is deprecated for 0.31.0 and inconsistent with pycocotools); `MetricTarget.MASKS` is silently ignored by mAP in released versions (it scores boxes — use pycocotools for mask mAP); don't pre-filter confidence before mAP; `-1` is an "absent" sentinel, not a score. ### 3. `pydantic-strict` → `pydantic` Renamed for a simpler name and broader scope (strict remains the default stance). Updates the dir, docs page, nav, archetype refs, and all `skill.toml` cross-refs — no dangling references. ### 4. Pushy "use-when" descriptions Every skill's `description:` rewritten as a third-person, trigger-first "Use this skill when…" with keyword coverage and explicit disambiguation between adjacent skills (code-quality vs pre-commit vs vscode; docker-cv vs kubernetes vs gcp; pydantic vs pydantic-ai; mlflow vs wandb vs tensorboard). ### 5. Env manager: pixi stays canonical Kept **pixi** as the ML env manager (handles CUDA/system deps beyond Python). Incidental run-commands are tool-agnostic (`pytest`, not `pixi run pytest`); dependency installs use `pixi add`. ### 6. No vertex-ai skill — folded into `gcp` instead A separate `vertex-ai` skill was **duplicating** the `gcp` skill, which already covers Vertex AI training jobs (custom + custom-container, GPU selection reference, prebuilt containers) alongside GCS and Artifact Registry. Instead, `gcp` gains the one genuinely non-obvious bit: > **Retrieving Artifacts After Training** — the training VM is ephemeral, so write to `AIP_MODEL_DIR` and explicitly sync artifacts down when the job ends. ## Verification - `uv run pytest tests/` → **213 passed** - `uv run ruff check .` → clean - `uv run ruff format --check .` → clean ## Notes for review - The `pydantic` rename touches archetype `.toml` skill lists and cross-refs — worth a glance that nothing dangles. - Worth sanity-checking the trimmed skills you use most (pytorch-lightning, onnx, fastapi) for anything cut that you wanted kept. - `model-evaluation`'s supervision snippets assume `sv.DetectionDataset.from_coco`; swap to `from_yolo` if that matches your loader. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Follows [#6](#6) (merged). Result: **32 skills, 0 agents.** ## Why remove the agents They were never Claude Code subagents. Four independent pieces of evidence: 1. **4 of 6 had no YAML frontmatter** — `expert-coder`, `ml-engineer`, `code-review`, `test-engineer` began directly with an H1. They installed with the heading as their entire description (`expert-coder: Expert Coder Agent`) and were effectively untriggerable. The two that worked were the two that happened to have frontmatter. 2. **All 6 installed to `.claude/skills/`, not `.claude/agents/`.** `discover_agents()` returned `Skill` objects; there was no `Agent` model anywhere in `src/`. 3. **`agent.toml` was never parsed** — only a doctor check and a test asserted the file existed. The `advisory`/`blocking` field was read exactly once, by a test. 4. **Both "blocking" `action.yml` files were broken** — they ran `pixi run` against a repo with no `pixi.toml` (whet itself uses uv), and no workflow referenced them. Content-wise ~77% of their 3,047 lines duplicated existing skills. Because they were written independently they *diverged*: `test-engineer` timed GPU inference without `cuda.synchronize()` (meaningless) while `skills/testing` does it correctly; `expert-coder` recommended `logging.getLogger` against the repo's own Loguru mandate. GSD already ships 33 correctly-formatted subagents. **GSD owns agency; whet owns domain knowledge — and knowledge is a skill.** ## Promoted to a skill - **`skills/data-pipelines`** (481 lines) from `data-engineer` — storage-format decision matrix, **group-aware leakage-preventing splitting** (frames from one match must not straddle splits), schema evolution/migration, Great Expectations suites. ## Also removed (per review) - **`dvc`** — not part of the workflow. Removed the skill, its docs page, nav entry, archetype/`skill.toml` references, and rewrote prose that pointed at it. Where DVC appeared as a *generic* data-versioning concept, the guidance is now tool-neutral (object storage plus a versioned/content-hashed manifest) rather than naming an unused tool. - **`cv-model-selection`** — not wanted. ## Salvaged before deletion | From | To | |---|---| | devops-infra containerization tree | `docker-cv` | | devops-infra deployment tree ("is K8s right?") | `kubernetes` | | devops-infra CI/CD tree | `github-actions` | | test-engineer coverage thresholds + naming convention | `testing` | ## Removed plumbing `agents/`, `docs/agents/`, `discover_agents()`, `--agents-only`/`--skills-only`, `agents_dir` config, the two doctor agent checks (remaining checks renumbered 1–8), `tests/test_agents.py`, and the agents nav/how-to sections. ## Verification - `uv run pytest tests/` → **192 passed** - `uv run ruff check .` / `ruff format --check .` → clean - `uv run mypy src/whet/ tests/ --strict` → clean - `uv run mkdocs build --strict` → clean (caught and fixed dangling agent links) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
) **Stacked on [#7](#7 — base is `p1-agents-to-skills`, so review #7 first. ## 1. Progressive disclosure Split the 21 skills over 450 lines into a thin `SKILL.md` index plus topic-organized `references/` loaded on demand. A SKILL.md loads fully into context when triggered and **stays there for the session**, so every line is a recurring token cost. Anthropic's guidance is that SKILL.md should read like a table of contents. **Always-resident lines: 14,930 → 7,122** across 32 skills, with ~10k lines relocated into **115 reference files**. Content was *relocated, not trimmed*. | Skill | Index before → after | |---|---| | onnx | 503 → 120 | | opencv | 502 → 131 | | kubernetes | 496 → 125 | | pytorch-lightning | 485 → 125 | | testing | 479 → 103 | | wandb | 477 → 121 | | gcp | 477 → 116 | | aws-sagemaker | 455 → 132 | | …13 more | all → 95–143 | Each index keeps the 80%-case patterns, conventions, and anti-patterns inline, then ends with a `## Deep dives` list giving every reference a *"read this when…"* trigger. Rules enforced: **one level deep** (no reference links to another reference), TOC on any reference over 100 lines, descriptive filenames, frontmatter byte-for-byte unchanged. ## 2. Installer support (required — otherwise the links 404) Without this, the deep-dive links would break exactly the way the external `interface-design` skill's currently do: - `Skill.references_dir` / `reference_files()` / `read_flattened()` - **Claude + Antigravity** adapters copy `references/` on install - **Cursor + Copilot** store one flat file, so references are **inlined** rather than lost ## 3. Install tiers New `tier` field in `skill.toml`. `tier = "extra"` marks a skill as opt-in, skipped unless `whet install --include-extras`. Marked extra: **aws-sagemaker, kubernetes, gradio, huggingface, mlflow** — real skills, but no evidence they're in the flagship workflow, so they no longer dilute the default trigger surface. ## 4. Documentation CLAUDE.md now documents the description formula (trigger-first, pushy, with disambiguation), the progressive-disclosure layout and its rules, and the tier system. `docs/skills/index.md` gains an Install Tiers section and marks extras. Also documents the **`interface-design` companion**: whet ships no general product-UI ruleset (`gradio` is ML demos only), so that external skill is the recommended pairing — with a note that its `references/` must be present or its deep-dive links won't resolve. ## Verification - `uv run pytest tests/` → **192 passed** - `uv run ruff check .` / `ruff format --check .` → clean - `uv run mypy src/whet/ tests/ --strict` → clean - `uv run mkdocs build --strict` → clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…' skills) (#9) ## Problem `whet install` copies skills but never removes ones deleted upstream. After the recent cleanup, **8 deleted skills were still installed** and still being loaded by Claude Code: ``` code-review data-engineer devops-infra dvc expert-coder ml-engineer pydantic-strict test-engineer ``` So the broken "agents" (the ones with no frontmatter), the removed `dvc`, and a stale `pydantic-strict` sitting next to the new `pydantic` were all still live. The repo was clean; the installed copies were not. ## Why this isn't just `rm -rf` A skills directory is **shared**. `~/.claude/skills/` here holds 104 skills — most of them GSD's, plus `interface-design` and hand-written ones. A prune that removed "anything not in whet's `skills/`" would delete all of them. So prune is **manifest-scoped**: - Each install writes `.whet-manifest.json` into the target directory, recording which skills whet owns there. - Prune only ever removes names from that manifest → skills owned by other tools are **invisible** to it. - Orphans are computed against the **unfiltered** source set, so a skill merely skipped by `--category` or by the `extra` tier is never mistaken for a deleted one. - Without `--prune`, orphans are **reported, not touched**. - A corrupt or missing manifest yields an empty owned-set, which **fails safe** — prune is authorized to remove nothing. ## Usage ```bash whet install --prune ``` Installs predating the manifest are invisible to prune by design (whet has no record it owns them); clear those once with `whet remove <name>`. ## Tests 10 new tests in `tests/test_manifest.py`, including the two that matter: - `test_find_orphans_ignores_skills_whet_did_not_install` — the GSD/interface-design protection - `test_find_orphans_ignores_filtered_but_existing_skills` — an `extra` skill skipped this run is not an orphan - plus corrupt-manifest and wrong-shape tolerance **202 passed**; ruff, `mypy --strict`, and `mkdocs build --strict` clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…10) ## The headline bug `cv-inference-service` is named for it, described as a *"FastAPI + ONNX deployment service"*, and tagged `fastapi` — but **never required the `fastapi` skill**. Generating that archetype gave you ONNX and Docker with no serving-layer guidance. Flagged in the round-1 review, not yet fixed. ## The pattern behind it Several archetypes predate skills added during the cleanup, so they scaffold a project that never pulls in the skill written for that exact job: | Archetype | Change | |---|---| | `cv-inference-service` | **+ `fastapi`** (required), + `model-evaluation` (recommended) | | `data-processing-pipeline` | **+ `data-pipelines`** (required) — the skill built precisely for ETL, storage formats, and leakage-free splitting | | `pytorch-training-project` | + `model-evaluation`, + `data-pipelines` (recommended) | | `model-zoo` | + `model-evaluation` (recommended) — it's tagged *"benchmarks"* | | `research-notebook` | + `model-evaluation` (recommended) | A training archetype with no evaluation story was the other real gap: you could scaffold a full PyTorch project and never be pointed at mAP, frozen test sets, or slice analysis. ## Also verified No archetype lists an `extra` tier skill (`aws-sagemaker`, `kubernetes`, `gradio`, `huggingface`, `mlflow`) as **required** — that would force an opt-in skill onto every generated project. ## Verification - `uv run pytest tests/` → **192 passed** - `whet doctor` → all skill dependencies resolve - `mkdocs build --strict` → clean Scope is deliberately limited to `archetype.toml` skill lists. The broader archetype audit (templates, staleness, whether 6 archetypes earn their keep) is a separate PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Third pillar of the library review. Skills (#6, #8) and agents (#7) were audited and fixed; the 6 archetypes had never been reviewed. An audit that actually **rendered** each one and ran the toolchain against the output found they were in worse shape than either. ## Why it went unnoticed **Nothing ever rendered an archetype in CI.** The tests checked README length and file existence — which is exactly how `cv-inference-service` shipped for months without the `fastapi` skill. Every bug below was invisible to a green build. ## What was broken **4 of 6 archetypes generated nothing.** `whet init` fell through to a 4-file stub; `model-zoo` and `research-notebook` produced *byte-identical* output apart from one description string. `research-notebook` shipped no `notebooks/` directory — the one thing its name promises. **The 2 with templates produced projects that did not run:** | Archetype | Failure | |---|---| | `pytorch-training-project` | **Zero runtime dependencies declared** — couldn't import its own entry point. Crashed on the first training step (`batch["image"]` against `FakeData`, which yields tuples). **Hydra was a required skill but entirely absent**, so documented CLI overrides silently did nothing — worse than crashing. Failed its own `ruff` gate. | | `cv-inference-service` | Named for ONNX, requires the `onnx` skill, shipped **no `onnxruntime`, no inference engine, no `/predict`** — its request/response schemas were dead code. `Dockerfile` COPY'd a `uv.lock` that doesn't exist, so `docker build` failed. | And the docs described a different product than the code: every README said `pixi`, every template said `uv`; all six listed a `pixi.toml` no template shipped. ## What this PR does **Templates: 19 files → 125.** All six now render into a project that passes its own gates. - **pytorch-training-project** — deps declared; tuple unpacking; a real `@hydra.main` driving Pydantic configs; `transforms.py` and `configs/trainer/debug.yaml` added; 13 tests including a genuine `fast_dev_run`. A *second* latent crash surfaced during verification and was fixed: the `LazyLinear` head left `configure_optimizers` iterating uninitialized params. - **cv-inference-service** — real ONNX Runtime engine, wired `/predict`, pixi-based Dockerfile, and the app starts cleanly with **no model artifact present** (covered by a test, so the suite needs no weights). - **data-processing-pipeline** — group-aware, leakage-preventing splits (split on video/match/scene, never the row) with a disjointness assertion. - **library-package** — the packaging furniture the README promised: `LICENSE`, `CHANGELOG.md`, `py.typed`, entry point. - **model-zoo** — model-card schema + **sha256-verified** weight fetch, with a test proving a corrupted file is rejected. - **research-notebook** — an actual `notebooks/` dir with a valid `.ipynb`, plus `nbstripout` so outputs stay out of git. **The guardrails are the real point:** - `tests/test_archetype_templates.py` renders every archetype through whet's **real** `render_template` and asserts the generated project has no unsubstituted placeholders, parses, passes `ruff`, **declares every package it imports**, and has src-layout + tests. That import-vs-dependency check catches the "zero dependencies declared" class of bug without installing torch. - `tests/test_archetypes.py` — archetype skills resolve to real skills, no `extra`-tier skill sits in `required`, `required` is non-empty. - New **`archetypes` CI job** running both suites. **Staleness swept** — the deleted Code Review / Test Engineer agents were still referenced in 5 archetype READMEs, `docs/archetypes/index.md`, `master-skill`, and two guides (`code-review.yml` → a plain `ci.yml`). Templates now use pixi consistently with tool-agnostic run commands; all `uv` references dropped from generated projects. ## Verification - `uv run pytest tests/` → **250 passed** - `uv run ruff check .` / `ruff format --check .` → clean - `uv run mypy src/whet/ tests/ --strict` → clean - `uv run mkdocs build --strict` → clean ## Notes for review - Deliberately **not** in this PR: further skill-composition additions the audit suggested (no archetype pulls in `pixi` despite every README opening with `pixi install`; `pydantic-ai` is referenced by zero archetypes). Kept separate to keep this diff to "make the templates work." - Each archetype still has up to three conflicting directory trees documented (archetype README vs docs page vs actual `template/`). Worth a follow-up making `template/` the single source of truth. - Two caveats from template verification: mypy on a real 3.11 interpreter can trip over current numpy stubs (`--python-version 3.12` is clean); and pixi warns that `[project]` is deprecated in favor of `[workspace]` — left as-is because `skills/pixi/SKILL.md` documents `[project]` repo-wide, so changing it should be coordinated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The two P0 items from the review's remaining-work list. ## 1. `whet init` didn't install the archetype's skills It rendered the template, then **printed** `whet add ...` for you to run yourself. That matters because an archetype's value over a plain folder copy **is** the skill set it composes — so leaving installation as homework made the `[skills]` list advisory. It's also why the audit concluded `whet init X` ≈ `whet add <X's skills>` + four boilerplate files. Now: ```bash whet init pytorch-training-project # + required skills whet init pytorch-training-project --with-recommended # + recommended too whet init pytorch-training-project --no-skills # files only ``` Verified end to end — `whet init cv-inference-service` installs its 6 required skills into the new project's `.claude/skills/`, **including their `references/`** (23 reference files), so the progressive-disclosure deep-dive links resolve in the scaffolded project rather than 404ing. A name in `archetype.toml` that no longer resolves is reported rather than silently skipped. ## 2. `docs/archetypes/*.md` had become the stale copy All six pages still documented `uv run ...`. #11 corrected the archetype READMEs and templates to pixi with tool-agnostic run commands, which left the **published docs site** as the wrong half of the README/docs/template split: | Page | Was | |---|---| | cv-inference-service | `uv run uvicorn ...` | | pytorch-training-project | `uv run python -m my_project.train` (×3) | | library-package | `uv run pip install -e ".[dev]"`, `uv run test`, `uv run python -m build` | | research-notebook | `uv run jupyter lab`, `uv run pytest --nbmake` | | model-zoo, data-processing-pipeline | `uv run python ...` (×5) | Now consistent with what the templates actually ship. `grep` for `uv run` / `code-review.yml` across `docs/archetypes/` returns nothing. ## Verification - `uv run pytest tests/` → **255 passed** (4 new: install, references travel, `--no-skills`, `--with-recommended`) - `ruff check` / `ruff format --check` / `mypy --strict` / `mkdocs build --strict` → all clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
P1 from the review. Archetype composition had drifted from what the templates ship, so a generated project used tools nothing had taught the agent about. Every change below is grounded in **what each rendered template actually contains** — I rendered all six and read their real dependencies rather than working from a wishlist. ## The gaps | Change | Evidence | |---|---| | **`pixi` → required on all 6** | Every template ships a `pixi.toml` and every generated README opens with `pixi install` — yet **0 of 6** archetypes composed the skill explaining it. | | **`code-quality` → required on the 5 lacking it** | All six configure ruff + mypy strict in their `pyproject.toml`. | | **`testing` → required on research-notebook** | It ships `tests/`. | | **`pydantic-ai` → recommended on data-processing-pipeline** | VLM-assisted labeling is a natural extension of a dataset pipeline, and it was referenced by **zero** archetypes. | | `abstraction-patterns`, `library-review` → recommended on library-package | Both are precisely the subject of publishing a library. | | `onnx`, `gcp` → recommended on pytorch-training-project | Its README promises export; Vertex is the training target. | | `tensorrt` → recommended on model-zoo | Listed as an extension point in its README. | ## Two corrections the audit missed Found by inspecting rendered dependencies rather than the READMEs: - **`model-zoo`** *required* `pytorch-lightning` and `onnx`, but its template deliberately keeps torch **optional** (real deps: `pydantic`, `pyyaml`, `loguru`, `httpx`). Both moved to recommended, so `required` means "needed to run." - **`research-notebook`** *required* `pytorch-lightning` while its template has **no torch at all** (real deps: `numpy`, `matplotlib`, `pydantic`, `loguru`). Moved to recommended. ## What stops it drifting again A new test ties composition to the template: if a template ships `pixi.toml` or `tests/`, or configures ruff/mypy, the archetype **must** require the matching skill. Composition can no longer silently diverge from what the generated project uses. ## Deliberately not added The audit also suggested `opencv` on cv-inference-service and `matplotlib` on data-processing-pipeline. Both templates use neither (`cv-inference-service` uses pillow; the data pipeline ships no plotting), so adding them would be noise. `kubernetes` was skipped for the same reason — the k8s claims were trimmed from that README in #11. ## Verification - `uv run pytest tests/` → **257 passed** (1 new composition test) - `whet doctor` → all skill dependencies resolve - ruff / format / `mypy --strict` / `mkdocs build --strict` → clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Current pixi deprecates the `project` field. Parsing any of our generated manifests emitted: ``` WARN The `project` field is deprecated. Use `workspace` instead. ╭─[pixi.toml:1:1] 1 │ ╭─▶ [project] ``` Two independent template agents hit this while verifying their work in #11, which means it was reaching the user of **every scaffolded project**. ## Changed - `skills/pixi/SKILL.md` + both reference files (`manifest-reference.md`, `project-templates.md`) - All **6** archetype template `pixi.toml` manifests - `[tool.pixi.project]` → `[tool.pixi.workspace]` for the pyproject-based variant ## Deliberately surgical `[project]` also means the **PEP 621 table** in `pyproject.toml`, which is entirely unrelated and must not be renamed. Left untouched: - `skills/pypi/SKILL.md` and `skills/master-skill/SKILL.md` — PEP 621 packaging metadata - The `# pyproject.toml` example *inside* the pixi manifest reference — same file, different meaning I checked each occurrence's surrounding context rather than doing a blanket find-and-replace, and asserted the expected line content before rewriting it. ## Verification Rendered all six archetypes and ran `pixi task list` in each: | | deprecation warnings | |---|---| | before | 6 / 6 | | after | **0 / 6** | Plus `uv run pytest tests/` → **251 passed**; ruff and `mkdocs build --strict` clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Final P2 item. These nine were already **under** the 500-line ceiling, so no rule was broken — but a `SKILL.md` stays resident for the whole session once triggered, so those lines cost on every turn that composes them. ## Result **Library-wide always-resident lines: 7,122 → 4,523** (16,500 before the review began — a 73% cut overall). Reference files: 115 → 155. Content was **relocated, not trimmed**. | Skill | Before → After | | Skill | Before → After | |---|---|---|---|---| | library-review | 450 → **116** | | github-actions | 425 → **120** | | loguru | 442 → **152** | | master-skill | 418 → **145** | | code-quality | 438 → **157** | | pre-commit | 379 → **112** | | github-repo-setup | 434 → **120** | | docker-cv | 362 → **143** | | vscode | 430 → **114** | | | | ## What stayed inline Skills that own a **canonical artifact** keep it in the index, because other skills and all six archetype templates defer to them: - **`code-quality`** — the ruff/mypy `pyproject` blocks (`pre-commit` and `github-actions` point here for the standards themselves) - **`docker-cv`** — the multi-stage pixi Dockerfile that every archetype template follows - **`github-actions`** — the standard pixi setup block, since later examples abbreviate it as `# ...pixi setup...` - **`loguru`** — `setup_logging()` and the mandatory "never `print()` / never `logging.getLogger`" rule - **`master-skill`** — the initialization steps and archetype list ## Left unsplit deliberately `pypi` (338), `model-evaluation` (272), and `pydantic-ai` (206) are already index-sized. Splitting them would add indirection without reducing anything meaningful. ## Verification - **Frontmatter byte-identical** for all nine (diffed against `git show HEAD:`) — descriptions are the trigger surface, so they must not drift. - Every reference over 100 lines opens with a table of contents. - **One level deep holds** — `grep` for `references/` inside reference files returns nothing, so no reference links to another. - `uv run pytest tests/` → **251 passed**; ruff, format, `mypy --strict`, `mkdocs build --strict` all clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The last item on the review's tail. ## The problem Each archetype's directory tree was hand-maintained in **two** places — the archetype README and the published docs page — so both drifted independently of the actual template. #11 and #15 corrected the archetype READMEs, which left **the docs pages as the only stale copy**. They documented **78 files no template generates**: | Page | Ghosts | |---|---| | data-processing-pipeline | 21 (`base.py`, `dataset.py`, `download.py`, `configs/`, …) | | cv-inference-service | 13 (`serve.py`, `predictor.py`, `preprocessing.py`, `schemas/`, `docker-compose.yml`, …) | | model-zoo | 13 (`MODEL_CARD.md`, `benchmarks/`, `model_configs.py`, …) | | library-package | 11 (`helpers.py`, `module.py`, `api/`, `guides/`, …) | | pytorch-training-project | 10 (`datamodule.py`, `detector.py`, `metrics.py`, `coco.yaml`, …) | | research-notebook | 10 (three example notebooks, `utils.py`, `plots.py`, …) | ## The fix **Regenerated every `docs/archetypes/*.md` tree directly from the rendered template**, so each now describes exactly what `whet init` produces. **78 → 0** documented-but-absent files. Also normalized placeholder syntax across the archetype READMEs. Three different spellings were in use: - `${var}` — correct, what `string.Template` substitutes - `{{var}}` — **inert**; the engine never substitutes it, so `cv-inference-service`'s README was actively misleading - `<var>` — invented All now use `${var}`. ## Guards Three tests so the trees can't silently drift again: - `test_readme_tree_matches_template` - `test_docs_page_tree_matches_template` - `test_readme_uses_real_placeholder_syntax` I verified the tree guard actually bites by planting a ghost entry — it failed with `model-zoo README documents files its template does not ship: ['ghost_file.py']` — then restored the file. ## Verification - `uv run pytest tests/` → **279 passed** (3 new guards) - ruff / format / `mypy --strict` / `mkdocs build --strict` → clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## Correcting an overclaim
I previously said body length was defended by CI. **It was not.** The
only length assertion in the suite was a `>500` **character** *floor* in
`test_skills_completeness.py`. The 500-**line** ceiling, the
progressive-disclosure structure, and description quality had **no guard
at all**.
They were passing because they'd just been fixed by hand — which is
precisely the state that rots. A scorecard that holds only because
someone recently tidied up isn't a scorecard, it's a snapshot.
## What this adds
`tests/test_skill_hygiene.py` — one check per scorecard rule, each tied
to a failure this library actually had:
| Guard | The failure it prevents |
|---|---|
| Body ≤ 500 lines | 19 of 30 skills once averaged **551** lines |
| Cited `references/...` exist | The deep-dive-404 failure mode |
| No orphaned reference files | Unreachable files that only cost tokens
|
| References one level deep | Nested refs cause partial reads |
| TOC on references >100 lines | Partial read must still reveal scope |
| Descriptions trigger-first | They were topic summaries ("Covers X, Y,
Z") — these under-trigger |
| Descriptions third person | First person hurts discovery |
| Descriptions within listing budget | Overflow silently truncates
matching keywords |
| Split skills link their deep dives | An index that doesn't route is
just a shorter skill |
## One subtlety worth reviewing
The third-person check **strips quoted user utterances first**. A
description listing what a user might *say* — `"set up my editor"` — is
doing keyword coverage, not speaking in first person, and that phrasing
is actively encouraged. Without the strip, `vscode` failed on good
practice.
## Every guard was proven to bite
Rather than trusting green, I planted a regression for each and observed
the failure, then reverted:
```
loguru/SKILL.md cites reference files that do not exist: ['references/does-not-exist.md']
loguru description is not trigger-first ... Got: structured logging for cv/ml. covers sinks, json, levels...
pypi/SKILL.md is 539 lines (limit 500). Move detail into references/ ...
```
## Verification
- `uv run pytest tests/` → **536 passed**
- ruff / format / `mypy --strict` → clean
- Wired into the `archetypes` CI job as "Enforce skill-authoring rules"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The last open item from the review's scorecard. ## Why these two Both sit closest to the "restates what Claude already knows" line — the rule that a skill should encode knowledge the model *lacks*, since every loaded line is a recurring cost. - **`vscode`** — `settings.json`, `launch.json`, extension lists. Standard editor configuration. - **`github-repo-setup`** — `gh repo create --public --license MIT`, branch-protection calls. The tool's documented interface. Neither is CV/ML domain knowledge, which is the value whet exists to supply. Contrast with `model-evaluation` knowing that `MetricTarget.MASKS` is silently ignored by supervision's mAP, or `data-pipelines` knowing to split on video rather than frame — knowledge that prevents a specific expensive mistake. ## Why demote rather than delete They *do* carry non-obvious content worth keeping: - remote-SSH GPU setup and devcontainer `--gpus` / `--shm-size` - the branch-protection JSON payload, and the rule that required status checks must match job names exactly Both are already thin indexes (**114** and **120** lines). `extra` keeps them one flag away — `whet install --include-extras` — while the default trigger surface stays focused. **Default install is now 25 core skills; 7 opt-in.** ## Verified safe to demote - **No archetype** lists either as `required` or `recommended` — so this can't trip the "archetype must not force an opt-in skill" guard. - The only cross-references are **disambiguation clauses in descriptions** (`"editor integration in vscode"`, `"see github-repo-setup"`), not dependencies. Those read correctly whether or not the skill is installed — they mark a scope boundary either way. ## Verification - `uv run pytest tests/` → **279 passed** - `whet doctor` → all skill dependencies resolve - ruff + `mkdocs build --strict` → clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bump version to 0.3.0 and add a CHANGELOG. Version note: PyPI already carries 0.2.1 while both main and develop declared 0.1.0, and the repository has no git tags — 0.2.1 was published outside the tag-triggered workflow. Releasing from 0.1.0 would build a package older than what is already live, so this bump goes past it. 0.3.0 rather than 0.2.2 because the release is breaking: the agents concept and the --agents-only/--skills-only flags are removed, two skills are deleted, one is renamed, and whet init changes behaviour. Below 1.0.0, breaking changes ship in a minor bump. 536 tests pass; ruff, format, mypy --strict, and mkdocs --strict clean. uv build produces whet-0.3.0 wheel and sdist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Caught by installing the built wheel into a clean venv and running the CLI outside any checkout, which is what a user actually does. `whet list` printed "No skills found" and `whet doctor` reported a missing skills directory. Two causes: - [tool.hatch.build.targets.wheel] packaged only src/whet. The bundled content was listed for the sdist but never the wheel, so the published artifact was the CLI with none of the product: 36 files, zero SKILL.md. - skills_dir, archetypes_dir, and the settings templates resolved via Path(__file__).parents[3], which is the repository root in a checkout but points outside site-packages once installed. Fixes: - Force-include skills/, archetypes/, and settings/ into the wheel under whet/_data/. The wheel goes from 36 files to 430 — 32 SKILL.md, 155 reference files, 125 archetype template files. - Add whet.core.paths.bundled_dir(), which prefers the packaged copy and falls back to the repo layout so a source checkout still works with no build step. - Drop the stale agents/ entry from the sdist include list. Verified end to end: installing the wheel in a clean venv and running outside the repo now lists 32 skills, passes doctor, and `whet init cv-inference-service` scaffolds a project with 8 skills and 43 reference files installed. Adds tests/test_packaging.py so this cannot ship broken again, including a check that packaging never references a directory that no longer exists. 541 tests pass; ruff, format, mypy --strict, mkdocs --strict clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
main carried a squash commit (7ee1eaa, 'Release v0.1.0') that was never merged back into develop, so the same files were added independently on both sides and git saw ~100 add/add conflicts. Resolved with -s ours: main's content is a strict subset of this branch, and every file present only on main is a reviewed deletion — the agents/ tree and its docs (removed in #7), skills/dvc, and skills/pydantic-strict (renamed to pydantic). Nothing unique is discarded. Recording main as a parent reconciles the histories so future develop -> main merges are clean.
Branch protection on main requires a status check named 'docs', but nothing could ever produce it: - docs.yml only triggered on push to main, so it never ran on a pull request - its jobs were named build/deploy, so even when it did run it reported 'build' and 'deploy' — never 'docs' The result was circular: merging to main required a check that only a push to main could produce. PR #19 sat with three green checks and a fourth that was not pending but simply absent. - Rename the build job to `docs` so it satisfies the required context. - Add a pull_request trigger for main and develop. - Gate artifact upload and the deploy job to pushes on main, so PRs build the docs without touching GitHub Pages. - Build with --strict on PRs. This is the check that caught the dangling agent-page links rather than letting them ship. - Key concurrency by ref so parallel PR doc builds do not queue behind one another. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ortizeg
added a commit
that referenced
this pull request
Jul 24, 2026
Companion to **[#19](#19. Merge this **after** #19 lands. ## Why this is required, not housekeeping `develop` is currently missing four things that only exist on the release branch — and one of them is a live bug: | Missing from develop | Impact | |---|---| | **The packaging fix** (`force-include`, `core/paths.py`) | **A wheel built from develop today ships zero skills.** `uv tool install whet` would produce a CLI that reports "No skills found". | | `tests/test_packaging.py` | Nothing on develop would *catch* that regression. | | Version bump to 0.3.0 | develop still declares `0.1.0`, behind the published 0.2.1. | | `CHANGELOG.md` | Would be lost on the next release. | ## It also fixes the divergence permanently This is precisely the mistake that caused #19's ~100 add/add conflicts: `main` received a squash commit (`7ee1eaa`, "Release v0.1.0") that was **never merged back into develop**, so both branches recreated the same files independently from their shared ancestor. Skipping this back-merge would repeat that exactly — `main` would hold the release commits, `develop` would not, and the next release would conflict all over again. Merging here brings `7ee1eaa` into develop's ancestry so all three branches finally share history. ## Verification Merged cleanly — **no conflicts**. - `uv run pytest tests/` → **541 passed** - ruff, format, `mypy --strict`, `mkdocs build --strict` → clean - Deliberate deletions confirmed still absent (no resurrection of `agents/`, `skills/dvc`, `skills/pydantic-strict`) - **Wheel built from this branch: 430 files, 32 skills** — the packaging fix is genuinely carried across 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release branch for v0.3.0, merging
developintomain.1. A release blocker was found and fixed here. I installed the built wheel into a clean venv and ran the CLI outside any checkout — what a user actually does — and got:
The wheel packaged only
src/whet: 36 files, zeroSKILL.md. The skills were listed for the sdist but never the wheel, and the bundled dirs resolved viaPath(__file__).parents[3], which is the repo root in a checkout but points outsidesite-packagesonce installed. The currently published 0.2.1 almost certainly has this same defect. Fixed here; the wheel now carries 430 files (32 skills, 155 references, 125 template files).2. Version had drifted. PyPI carries 0.2.1 while both
mainanddevelopdeclared 0.1.0, and the repo has no git tags — 0.2.1 was published outside this tag-triggered workflow. Releasing from 0.1.0 would have built a package older than what is live.Version: 0.3.0
Breaking, so a minor bump under pre-1.0 semver:
agents/concept and--agents-only/--skills-onlyflags are removeddvcandcv-model-selectiondeleted;pydantic-strictrenamed topydanticwhet initnow installs skills instead of printing a hintWhat's in the release
Thirteen merged PRs (#6–#18) auditing all three pillars against Anthropic's Agent Skills guidance:
references/; every description rewritten as a trigger-first statement.agent.tomlwas never parsed. GSD owns agency, whet owns knowledge.Full detail in
CHANGELOG.md, added in this PR.Verification
uv run pytest tests/→ 541 passed (5 new packaging guards)mypy --strict,mkdocs build --strict→ cleanuv build→whet-0.3.0wheel + sdistwhet listshows 32 skills,whet doctorpasses, andwhet init cv-inference-servicescaffolds a project with 8 skills and 43 reference files installedAfter merge
Tagging
v0.3.0triggersrelease.yml, which publishes to PyPI and creates a GitHub Release. That step is irreversible — a PyPI version can never be reused — so I'll confirm before pushing the tag.🤖 Generated with Claude Code