medsci-skills 5.15.0 → 5.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/README.md +10 -5
  2. package/metadata/distribution_files.json +67 -12
  3. package/metadata/distribution_manifest.json +2 -1
  4. package/metadata/skills_catalog.json +13 -3
  5. package/package.json +1 -1
  6. package/skills/model-scaffold/SKILL.md +31 -15
  7. package/skills/model-scaffold/references/finetuning_guide.md +91 -0
  8. package/skills/model-scaffold/scripts/check_training_hygiene.py +38 -2
  9. package/skills/model-scaffold/scripts/scaffold.py +263 -1
  10. package/skills/model-scaffold/scripts/scaffold_challenge/problem.md +6 -0
  11. package/skills/model-scaffold/scripts/scaffold_challenge/verify.sh +20 -2
  12. package/skills/model-scaffold/skill.yml +4 -1
  13. package/skills/model-scaffold/tests/fixtures/finetune_no_provenance/train.py +24 -0
  14. package/skills/model-scaffold/tests/test_training_hygiene.sh +14 -1
  15. package/skills/radiomics-ml/SKILL.md +134 -0
  16. package/skills/radiomics-ml/references/radiomics_ml_guide.md +115 -0
  17. package/skills/radiomics-ml/scripts/check_radiomics_ml.py +229 -0
  18. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/expected/strong.txt +9 -0
  19. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/expected/weak.txt +14 -0
  20. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/fixture/pipeline_strong.json +13 -0
  21. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/fixture/pipeline_weak.json +13 -0
  22. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/problem.md +20 -0
  23. package/skills/radiomics-ml/scripts/check_radiomics_ml_challenge/verify.sh +37 -0
  24. package/skills/radiomics-ml/skill.yml +46 -0
  25. package/skills/radiomics-ml/tests/test_radiomics_ml.sh +88 -0
package/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  # MedSci Skills
4
4
 
5
- **53 skills that actually work.** Built by a physician-researcher, tested on real publications.
5
+ **54 skills that actually work.** Built by a physician-researcher, tested on real publications.
6
6
 
7
7
  *MedSci Skills is an end-to-end research tool for physician and medical-engineering researchers — design → scaffold → validate → publish — for the clinical manuscript and the medical-AI model behind it. Its moat is the compliance layer — 44 reporting guidelines and risk-of-bias tools, reference/citation verification, and deterministic integrity gates before peer review — now extended by a model-engineering lane that scaffolds reproducible, leakage-safe training repos and audits model validation. Clinical AI model research engineering is in scope; a general AI-scientist platform is not. It competes on clinical submission reliability, not skill count.*
8
8
 
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
10
  [![Release](https://img.shields.io/github/v/release/Aperivue/medsci-skills?style=flat-square&color=blue)](https://github.com/Aperivue/medsci-skills/releases/latest)
11
11
  [![CI](https://img.shields.io/github/actions/workflow/status/Aperivue/medsci-skills/validate.yml?branch=main&style=flat-square&label=CI)](https://github.com/Aperivue/medsci-skills/actions/workflows/validate.yml)
12
- ![Skills](https://img.shields.io/badge/Skills-53-brightgreen?style=flat-square)
12
+ ![Skills](https://img.shields.io/badge/Skills-54-brightgreen?style=flat-square)
13
13
  [![npm](https://img.shields.io/npm/v/medsci-skills?style=flat-square&label=npm&color=cb3837)](https://www.npmjs.com/package/medsci-skills)
14
14
  [![Watch the 2-min intro](https://img.shields.io/badge/▶_Watch-2--min_intro-FF0000?style=flat-square&logo=youtube&logoColor=white)](https://youtu.be/MclQ_RIofpE)
15
15
  [![good first issues](https://img.shields.io/github/issues/Aperivue/medsci-skills/good%20first%20issue?style=flat-square&label=good%20first%20issues&color=7057ff)](https://github.com/Aperivue/medsci-skills/contribute)
@@ -285,6 +285,8 @@ The E2E pipeline (`orchestrate --e2e`) produces everything up to `qc/`. The `sub
285
285
 
286
286
  ## What's New
287
287
 
288
+ **v5.16** — model-engineering produce-side depth, clinical fine-tuning focus (Items 3–4 of the [produce-side depth roadmap](docs/roadmap_model_engineering_depth.md)). A new **`radiomics-ml`** skill + `check_radiomics_ml` gate for the most common solo-doable clinical-ML workflow — radiomics / tabular features → any classical learner (LASSO / SVM / random forest / XGBoost / …) → a clinical outcome, no GPU — with a learner-agnostic nested-CV / calibration / stability gate; plus a **`model-scaffold` fine-tuning mode** (`--task finetune` + `--from-pretrained`) that adapts a pretrained backbone on collected clinical data with a frozen→unfrozen schedule, discriminative learning rates, and a pretrained-weight provenance record (`PRETRAINED.md` + a `PRETRAINED_PROVENANCE_MISSING` verdict on the existing `check_training_hygiene`, plus a MedSAM-adaptation + train-only diffusion-augmentation guide). Additive and backward-compatible; **54 skills / 44 guidelines / 49 integrity detectors / 22 domain-probe modules**. (See the [CHANGELOG](CHANGELOG.md) for v5.0–v5.15.)
289
+
288
290
  **v5.15** — model-engineering produce-side depth. Two new skills that *produce* what the review lane previously only audited: **`preprocess-imaging`** (DICOM/NIfTI data prep + a `check_preprocessing_leakage` gate that extends the split-leakage moat upstream to the data stage) and **`explainability`** (Grad-CAM / saliency held to the reviewer bar — Adebayo sanity checks, quantitative localisation vs ground truth, attribution-not-validation framing, via `check_explainability_report`). Plus a by-stage skill index, multi-host README/About (Claude Code · Codex · Cursor · Copilot), copy-paste citation ergonomics, and a real-project precision fix. Additive and backward-compatible; **53 skills / 44 guidelines / 48 integrity detectors / 22 domain-probe modules**. (See the [CHANGELOG](CHANGELOG.md) for v5.0–v5.14.)
289
291
 
290
292
  **v4.10** — reviewer-coverage expansion reverse-engineered from high-IF, CC-BY papers (learn-only under the `reverse_engineer/` license firewall), plus a clinician-friendly update path. Additive and backward-compatible; 45 skills / **44 guidelines** / 36 detectors / **15 domain-probe modules** (was 12):
@@ -402,6 +404,8 @@ MedSci Skills is **opinionated and narrow on purpose**: a single physician-resea
402
404
 
403
405
  📖 **Per-skill reference:** [`docs/skills/`](docs/skills/) — one page per skill (what it does, when it activates, its Quality Card — purpose, safety boundaries, known limitations, validation, evidence — and bundled resources), generated from each `SKILL.md` + `skill.yml`. See [`docs/skills/AUDIT.md`](docs/skills/AUDIT.md) for how the skills are validated.
404
406
 
407
+ 🧠 **ML / DL method coverage:** [`docs/method_coverage_map.md`](docs/method_coverage_map.md) — which machine-learning and deep-learning method families (CNN / transformer / segmentation / detection / foundation / diffusion / SSL for imaging; the full classical family — penalised regression, SVM, k-NN, trees, boosting [XGBoost / LightGBM / CatBoost], MLP, ensembles, clustering — for radiomics/tabular; LLM/MLLM) map to which skills for selection, production, validation, interpretation, and reporting.
408
+
405
409
  ```
406
410
  ┌─────────────────────────────────┐
407
411
  │ orchestrate: single entry point │
@@ -451,14 +455,14 @@ ma-scout -> search-lit -> fulltext-retrieval -> design-study ──> write-proto
451
455
 
452
456
  ### By research stage
453
457
 
454
- All 53 skills, grouped by where they fit in the clinical-manuscript and medical-AI lifecycle. Full descriptions are in the table below; one page per skill lives in the [per-skill reference](docs/skills/).
458
+ All 54 skills, grouped by where they fit in the clinical-manuscript and medical-AI lifecycle. Full descriptions are in the table below; one page per skill lives in the [per-skill reference](docs/skills/).
455
459
 
456
460
  | Stage | Skills |
457
461
  |-------|--------|
458
462
  | 🔭 **Discover & scope** | `ma-scout` · `find-cohort-gap` · `search-lit` · `fulltext-retrieval` · `lit-sync` · `author-strategy` |
459
463
  | 📐 **Design & plan** | `design-study` · `calc-sample-size` · `define-variables` · `write-protocol` · `fill-protocol` · `design-ai-benchmarking` |
460
464
  | 🧹 **Data & analysis** | `deidentify` · `clean-data` · `generate-codebook` · `version-dataset` · `analyze-stats` · `batch-cohort` · `cross-national` · `replicate-study` |
461
- | 🤖 **Medical-AI model engineering** | `preprocess-imaging` · `architecture-zoo` · `model-scaffold` · `model-validation` · `model-evaluation` · `explainability` · `model-card` · `mllm-eval` |
465
+ | 🤖 **Medical-AI model engineering** | `preprocess-imaging` · `architecture-zoo` · `model-scaffold` · `model-validation` · `model-evaluation` · `explainability` · `radiomics-ml` · `model-card` · `mllm-eval` |
462
466
  | ✍️ **Write & visualize** | `write-paper` · `make-figures` · `review-paper` · `present-paper` · `humanize` · `polish-language` · `academic-aio` |
463
467
  | ✅ **Comply & verify** | `check-reporting` · `self-review` · `verify-refs` · `manage-refs` |
464
468
  | 📤 **Submit & respond** | `find-journal` · `add-journal` · `sync-submission` · `revise` · `peer-review` · `fill-icmje-coi` |
@@ -481,11 +485,12 @@ All 53 skills, grouped by where they fit in the clinical-manuscript and medical-
481
485
  | **design-ai-benchmarking** | Design and validity review for benchmarking AI system(s) against a human-expert panel: evaluation-question and arm definition, decoupled multi-dimensional rubrics with anchors, planted calibration probes (positive-control / known-bad / instability / mechanism-contradiction), reviewer-panel construction with per-reviewer randomization, inter-rater reliability targets with separate control-item reliability, LLM-as-judge vs human-as-judge adjudication, construct-independence guards, and a structured JSON rating-export schema. Locks the rubric before data collection. |
482
486
  | **model-validation** | Design or audit the clinical-validation study for an engineer-built medical-imaging model (segmentation / classification / detection): patient-level split disjointness and the data-leakage taxonomy, tuning-on-test, internal vs genuine external validation, comparator design, single-run vs multi-seed variance, task-correct metric selection (Metrics Reloaded), test-set sizing, and CLAIM 2024 / TRIPOD+AI / STARD-AI reporting fit. Ships a deterministic split-leakage gate that proves patient disjointness by set arithmetic on the emitted split table. Integrates with MONAI / nnU-Net — does not replace them. |
483
487
  | **preprocess-imaging** | Design or audit the data-preparation stage of a medical-imaging model — DICOM/NIfTI intake, resampling, intensity normalization, and the augmentation plan — so the pipeline is leakage-safe before `model-scaffold` builds the training repo. Emits a declarative preprocessing manifest and a deterministic data-stage leakage gate (`check_preprocessing_leakage`) that catches what the split table cannot see: a dataset-level normaliser fit on non-train data (`NORMALIZATION_LEAKAGE`), a data-fitted transform run before the split (`PREPROCESS_BEFORE_SPLIT`), and a patient's slices crossing splits (`PATIENT_CROSS_SPLIT`). Integrates MONAI / TorchIO transforms; never reimplements them or touches real patient data. |
484
- | **model-scaffold** | Generate a reproducible, runnable PyTorch training repo for a medical-imaging task — segmentation (U-Net), classification, detection, image-to-image synthesis, or self-supervised pretraining — the missing middle link between choosing an architecture and validating a trained model. Emits a patient-level seed-locked split as an auditable artifact, a task-appropriate model, train/evaluate scripts that seed every RNG and infer under eval mode, a config, requirements, a reproducibility record, and a Methods stub with VERIFY placeholders (no fabricated numbers). Reproducibility holds by construction; ships a `check_training_hygiene` AST gate + a network-free build→validate challenge. Emits a minimal runnable default model for a forward-pass smoke test, and integrates with MONAI / nnU-Net / TorchIO / timm / torchvision for production-grade models. |
488
+ | **model-scaffold** | Generate a reproducible, runnable PyTorch training repo for a medical-imaging task — segmentation (U-Net), classification, detection, image-to-image synthesis, self-supervised pretraining, or fine-tuning a pretrained backbone (transfer learning) — the missing middle link between choosing an architecture and validating a trained model. Emits a patient-level seed-locked split as an auditable artifact, a task-appropriate model, train/evaluate scripts that seed every RNG and infer under eval mode, a config, requirements, a reproducibility record, and a Methods stub with VERIFY placeholders (no fabricated numbers). Fine-tuning mode (`--task finetune`) adds a frozen→unfrozen schedule, discriminative learning rates, and a pretrained-weight provenance record (`PRETRAINED.md`), with a MedSAM-adaptation + train-only diffusion-augmentation guide. Reproducibility holds by construction; ships a `check_training_hygiene` AST gate (RNG seeding, eval-mode inference, train-split-only loaders, pretrained-provenance) + a network-free build→validate challenge. Integrates with MONAI / nnU-Net / TorchIO / timm / torchvision for production-grade models. |
485
489
  | **architecture-zoo** | "Which architecture for which research question" decision tool: maps task (classification / segmentation / detection / transfer), modality, data scale, and class imbalance to a paper-grounded architecture shortlist. Curates the foundational curriculum (ResNet / DenseNet / EfficientNet / ViT / Swin; U-Net / 3-D U-Net / Attention & Residual U-Net / nnU-Net / Mask R-CNN; SAM/MedSAM / TotalSegmentator / BiomedCLIP / DINO / MAE / SimCLR) — each with core idea, when-to-use, medical-imaging use, reference implementation, validation setup, and the matching model-scaffold template. Advisory; teaches archetypes, not a live SOTA leaderboard. |
486
490
  | **model-card** | Generate the documentation an engineer-built medical-imaging model must carry — a Model Card (Mitchell et al. 2019), a Datasheet for its dataset (Gebru et al. 2021), and a METRIC-informed data-quality pass — filled from user-supplied facts (never fabricated), then verify every required section is present and non-empty with a deterministic completeness gate (`check_model_card_complete`). Model Card / Datasheet are documentation standards vendored as templates, not counted reporting checklists. |
487
491
  | **model-evaluation** | Compute and report task-correct held-out metrics for a trained medical-imaging model — segmentation (Dice + a boundary metric HD95/NSD, per structure), classification (AUROC + AUPRC + sensitivity/specificity with bootstrap CIs at the deployment prevalence), or detection (FROC/mAP with a stated IoU criterion) — plus calibration and subgroup slices. Emits a per-case table for analyze-stats and gates the metric choice against Metrics Reloaded / CLAIM 2024 (`check_metric_reporting`). Numbers come only from executed code. |
488
492
  | **explainability** | Produce or audit the interpretability/explainability analysis of a medical-imaging model — Grad-CAM / Grad-CAM++ / attention-rollout / saliency / integrated-gradients — so it clears the rigor bar: mandatory Adebayo sanity checks (model- and data-randomisation), a quantitative localisation metric against ground truth (IoU / pointing game / Dice) instead of eyeballed examples, a cohort-level result, and attribution framing rather than "proof the model is correct". Emits an explainability-report manifest + a deterministic gate (`check_explainability_report`): `SALIENCY_AS_VALIDATION`, `NO_SANITY_CHECK`, `NO_LOCALIZATION_METRIC` (Major); `INSUFFICIENT_SANITY`, `CHERRY_PICKED_EXAMPLES`, `MISSING_METHOD` (Minor). Integrates captum / pytorch-grad-cam; never reimplements them or touches real patient data. |
493
+ | **radiomics-ml** | Produce or audit a radiomics / tabular clinical-ML study — features → random forest / XGBoost / regularised logistic → clinical outcome — the most common solo-doable clinical-ML workflow (no GPU, no engineer). Emits a pipeline manifest + a deterministic rigor gate (`check_radiomics_ml`): `NO_NESTED_CV`, `HIGH_DIM_LOW_EVENTS`, `SELECTION_OUTSIDE_CV` (Major); `NO_FEATURE_STABILITY`, `NO_CALIBRATION`, `NO_EXTERNAL_VALIDATION` (Minor). pyradiomics/IBSI settings, nested CV with in-fold selection, ICC stability, SHAP, calibration + decision curve, CLEAR/TRIPOD+AI/PROBAST-AI reporting. Integrates scikit-learn / xgboost / pyradiomics; never reimplements them. |
489
494
  | **mllm-eval** | Model-agnostic evaluation harness (closed API or open weights) for an LLM/MLLM on a clinical task — radiology report generation, VQA, clinical text extraction — covering the adjudicated reference standard, clinical-efficacy metrics (RadGraph-F1 / CheXbert-F1 beyond BLEU/ROUGE), faithfulness/hallucination, pretraining-contamination, prompt sensitivity, and a reader study; gates the plan with `check_mllm_eval_completeness` and routes the reviewer audit to the MLLM probe. |
490
495
  | **intake-project** | Classifies new research projects, summarizes current state, identifies missing inputs, and recommends next steps. |
491
496
  | **grant-builder** | Structures grant proposals: significance, innovation, approach, milestones, and consortium roles. |
@@ -2868,8 +2868,13 @@
2868
2868
  },
2869
2869
  {
2870
2870
  "path": "skills/model-scaffold/SKILL.md",
2871
- "size": 7686,
2872
- "sha256": "cede2020d3ceee0e1599cbcfb412230ab9c04b08032c8bbaff620e4129ec6785"
2871
+ "size": 9237,
2872
+ "sha256": "d7e736178cb60d2d13cef9174474297bd54bc6d4d1f3862023d802ff0c034a95"
2873
+ },
2874
+ {
2875
+ "path": "skills/model-scaffold/references/finetuning_guide.md",
2876
+ "size": 6208,
2877
+ "sha256": "b7817d53eeeb506b573beaae1889fa863dd81286d474ab99b46b38ad046b32e7"
2873
2878
  },
2874
2879
  {
2875
2880
  "path": "skills/model-scaffold/references/training_guide.md",
@@ -2878,13 +2883,13 @@
2878
2883
  },
2879
2884
  {
2880
2885
  "path": "skills/model-scaffold/scripts/check_training_hygiene.py",
2881
- "size": 11752,
2882
- "sha256": "66970049c85e46a0080b5f19eb3b5ac9dfd656a674b6f1698825e968eedd4814"
2886
+ "size": 14095,
2887
+ "sha256": "57542a54dac607e89e7f13e5025bd2ce6b32e629064a18cbb0f0c15fdfc6181c"
2883
2888
  },
2884
2889
  {
2885
2890
  "path": "skills/model-scaffold/scripts/scaffold.py",
2886
- "size": 40470,
2887
- "sha256": "33569806ecd230aebb9d35c77a27b8480d23329b00f633d7fee9531a7bcec974"
2891
+ "size": 51482,
2892
+ "sha256": "150abbc4864a92913b202893962c29cda8ec6ce1918f35558aa5b02514b6a0cb"
2888
2893
  },
2889
2894
  {
2890
2895
  "path": "skills/model-scaffold/scripts/scaffold_challenge/expected/split_assignment.csv",
@@ -2898,18 +2903,18 @@
2898
2903
  },
2899
2904
  {
2900
2905
  "path": "skills/model-scaffold/scripts/scaffold_challenge/problem.md",
2901
- "size": 2678,
2902
- "sha256": "369e98da65cbd16c67f5ff3f17d99b707d713bbf3239409f9921190c85f8f08a"
2906
+ "size": 3226,
2907
+ "sha256": "950af6c956f73b491b2bee102d884765aaeb783b5842eb428ac2ad81b49f67e8"
2903
2908
  },
2904
2909
  {
2905
2910
  "path": "skills/model-scaffold/scripts/scaffold_challenge/verify.sh",
2906
- "size": 5136,
2907
- "sha256": "040acee712943e8392b70b40b790438bec056a3a4e7a282f76455d2a2b791447"
2911
+ "size": 6396,
2912
+ "sha256": "77d81387647abf00de4b03f91a7c7bf9bef38d9679b148762c906eaccfee9f73"
2908
2913
  },
2909
2914
  {
2910
2915
  "path": "skills/model-scaffold/skill.yml",
2911
- "size": 3195,
2912
- "sha256": "06c4ed02872bfc38abd1c753c02a640a2bfaa1141fbfdd9f8b9ccbe18a148d82"
2916
+ "size": 3772,
2917
+ "sha256": "aaae59edb50c50b01be2aaca3c94b63ce76af067ff25750248517c5ce91ccf41"
2913
2918
  },
2914
2919
  {
2915
2920
  "path": "skills/model-validation/SKILL.md",
@@ -3411,6 +3416,56 @@
3411
3416
  "size": 1372,
3412
3417
  "sha256": "81caa10775246f2db3f5e08948292f63076d44ffc039d8eec764f1d46aab275f"
3413
3418
  },
3419
+ {
3420
+ "path": "skills/radiomics-ml/SKILL.md",
3421
+ "size": 8273,
3422
+ "sha256": "cc65bfd50db2b6e9b6681e1c9649b306490cd5dd74192bfdf5316362b71f141b"
3423
+ },
3424
+ {
3425
+ "path": "skills/radiomics-ml/references/radiomics_ml_guide.md",
3426
+ "size": 6707,
3427
+ "sha256": "29bf2b2b847c488ddb33e50cd21ea0e2cd4937a1a62ab2655f31227a0e42215a"
3428
+ },
3429
+ {
3430
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml.py",
3431
+ "size": 10179,
3432
+ "sha256": "b1cfbd9991aa8871d5aabc528c9aa22eecf8e46cb5983872bca2359229223840"
3433
+ },
3434
+ {
3435
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/expected/strong.txt",
3436
+ "size": 369,
3437
+ "sha256": "c73c776e6558d9a78dacd3c63ae1cc3dee183d9e1a2f27d99b1e0db70f44997e"
3438
+ },
3439
+ {
3440
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/expected/weak.txt",
3441
+ "size": 1408,
3442
+ "sha256": "3bb90f31587e94f3f2b267874a9ac58cce5adf3436254bc206092e0acfb86cd7"
3443
+ },
3444
+ {
3445
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/fixture/pipeline_strong.json",
3446
+ "size": 322,
3447
+ "sha256": "83d128fe0b728ef52a1fd98ef5b5bd478c3e48455cdb07d8040f9d130df81cee"
3448
+ },
3449
+ {
3450
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/fixture/pipeline_weak.json",
3451
+ "size": 313,
3452
+ "sha256": "2fa1a3f98f952faf2e6e1faf1bdbf4675a44dc88679dcfaf18a4f32eb47ba9e7"
3453
+ },
3454
+ {
3455
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/problem.md",
3456
+ "size": 894,
3457
+ "sha256": "9a6abad4e12f9b4e9290eb305fb9ad04127fa1cde03961a38ac4ccb5431a2100"
3458
+ },
3459
+ {
3460
+ "path": "skills/radiomics-ml/scripts/check_radiomics_ml_challenge/verify.sh",
3461
+ "size": 1988,
3462
+ "sha256": "b9e55aaf9b29f3e810b837fc373c7a212dc5f778a49bac11854bdb50ed84a184"
3463
+ },
3464
+ {
3465
+ "path": "skills/radiomics-ml/skill.yml",
3466
+ "size": 3790,
3467
+ "sha256": "9b99b87add656873d3f7277ce12490ffea36d919e9538bc4f4fbe1ebbfedc18e"
3468
+ },
3414
3469
  {
3415
3470
  "path": "skills/render-pdf-doc/SKILL.md",
3416
3471
  "size": 7490,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema_version": 1,
3
- "version": "5.15.0",
3
+ "version": "5.16.0",
4
4
  "owned_skills": [
5
5
  "academic-aio",
6
6
  "add-journal",
@@ -43,6 +43,7 @@
43
43
  "preprocess-imaging",
44
44
  "present-paper",
45
45
  "publish-skill",
46
+ "radiomics-ml",
46
47
  "render-pdf-doc",
47
48
  "replicate-study",
48
49
  "review-paper",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "_comment": "AUTO-GENERATED by scripts/gen_skills_catalog_json.py from each skills/<slug>/SKILL.md + skill.yml. Machine-readable skill catalog (single source of truth) consumed by external surfaces such as the aperivue.com storefront to gate skill-list completeness. Do not hand-edit; CI gate: python3 scripts/gen_skills_catalog_json.py --check.",
3
- "skill_count": 53,
3
+ "skill_count": 54,
4
4
  "categories": [
5
5
  {
6
6
  "key": "literature_references",
@@ -38,7 +38,8 @@
38
38
  "model-evaluation",
39
39
  "model-scaffold",
40
40
  "model-validation",
41
- "preprocess-imaging"
41
+ "preprocess-imaging",
42
+ "radiomics-ml"
42
43
  ]
43
44
  },
44
45
  {
@@ -415,7 +416,7 @@
415
416
  "layer": "B",
416
417
  "owner_domain": "model_development",
417
418
  "maturity": "official",
418
- "description": "Generate a reproducible, runnable PyTorch training repo for a medical-imaging task — segmentation, classification, detection, image-to-image synthesis, or self-supervised pretraining the missing mid…"
419
+ "description": "Generate a reproducible, runnable PyTorch training repo for a medical-imaging task — segmentation, classification, detection, image-to-image synthesis, self-supervised pretraining, or fine-tuning a pr…"
419
420
  },
420
421
  {
421
422
  "slug": "model-validation",
@@ -480,6 +481,15 @@
480
481
  "maturity": "official",
481
482
  "description": "Convert a personal agent skill into a distributable, open-source-ready skill."
482
483
  },
484
+ {
485
+ "slug": "radiomics-ml",
486
+ "category": "model_engineering",
487
+ "category_label": "Model Engineering & Validation",
488
+ "layer": "D",
489
+ "owner_domain": "model_validation",
490
+ "maturity": "official",
491
+ "description": "Produce or audit a radiomics / tabular clinical-ML study — imaging or clinical features → any classical learner (penalised logistic [LASSO / ridge / elastic-net], SVM, k-NN, naive Bayes, LDA/QDA, deci…"
492
+ },
483
493
  {
484
494
  "slug": "render-pdf-doc",
485
495
  "category": "presentation_tooling",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medsci-skills",
3
- "version": "5.15.0",
3
+ "version": "5.16.0",
4
4
  "description": "MedSci Skills — a medical/scientific research skill suite for AI coding agents (Claude Code, Codex, Cursor, Copilot). The npm package is a terminal-friendly installer shortcut; the canonical distribution remains the GitHub repository and the Claude Code plugin marketplace.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://github.com/Aperivue/medsci-skills#readme",
@@ -2,14 +2,16 @@
2
2
  name: model-scaffold
3
3
  description: >
4
4
  Generate a reproducible, runnable PyTorch training repo for a medical-imaging task — segmentation,
5
- classification, detection, image-to-image synthesis, or self-supervised pretraining the missing
6
- middle link between choosing an architecture and validating a trained model. Emits a patient-level
7
- seed-locked split as an auditable artifact, a task-appropriate model, train and evaluate scripts that
8
- seed every RNG and infer under eval mode, a config, requirements, a reproducibility record, and a
9
- Methods stub with VERIFY placeholders (no fabricated numbers). The reproducibility guarantees hold by
10
- construction, so the build is leakage-safe before any training runs. Integrates with MONAI, nnU-Net,
11
- TorchIO, timm, and torchvision it does not reimplement them.
12
- triggers: model scaffold, scaffold a model, training repo, PyTorch repo, build a model, train a model, segmentation, classification, detection, image synthesis, self-supervised, SimCLR, Pix2Pix, Faster R-CNN, U-Net, UNet, nnU-Net, MONAI, timm, torchvision, dataloader, train.py, patient-level split, reproducible training, seed everything, generate training code, medical imaging model
5
+ classification, detection, image-to-image synthesis, self-supervised pretraining, or fine-tuning a
6
+ pretrained backbone (transfer learning) — the missing middle link between choosing an architecture and
7
+ validating a trained model. Emits a patient-level seed-locked split as an auditable artifact, a
8
+ task-appropriate model, train and evaluate scripts that seed every RNG and infer under eval mode, a
9
+ config, requirements, a reproducibility record, and a Methods stub with VERIFY placeholders (no
10
+ fabricated numbers). Fine-tuning mode adds a frozen-then-unfrozen schedule, discriminative learning
11
+ rates, and a pretrained-weight provenance record. The reproducibility guarantees hold by construction,
12
+ so the build is leakage-safe before any training runs. Integrates with MONAI, nnU-Net, TorchIO, timm,
13
+ and torchvision — it does not reimplement them.
14
+ triggers: model scaffold, scaffold a model, training repo, PyTorch repo, build a model, train a model, fine-tune, finetune, transfer learning, pretrained backbone, MedSAM, SAM adaptation, segmentation, classification, detection, image synthesis, self-supervised, SimCLR, Pix2Pix, Faster R-CNN, U-Net, UNet, nnU-Net, MONAI, timm, torchvision, dataloader, train.py, patient-level split, reproducible training, seed everything, generate training code, medical imaging model
13
15
  tools: Read, Write, Edit, Bash, Grep, Glob
14
16
  model: inherit
15
17
  ---
@@ -20,7 +22,8 @@ model: inherit
20
22
 
21
23
  This skill stamps out a **runnable PyTorch training repo** for a medical-imaging task — `--task`
22
24
  **segmentation** (U-Net), **classification** (CNN / `timm` backbone), **detection** (torchvision Faster
23
- R-CNN / FPN), **synthesis** (Pix2Pix generator + PatchGAN), or **ssl** (SimCLR encoder)
25
+ R-CNN / FPN), **synthesis** (Pix2Pix generator + PatchGAN), **ssl** (SimCLR encoder), or **finetune**
26
+ (transfer-learning a pretrained backbone with a frozen→unfrozen schedule + a provenance record) —
24
27
  with the reproducibility guarantees **baked in by construction** — so the build is leakage-safe and
25
28
  reproducible before a single epoch runs. It is the imaging analogue of how `/analyze-stats` generates
26
29
  runnable statistical code: the generator produces the repo, you run the training on your GPU / Colab,
@@ -34,6 +37,9 @@ in the generated `requirements.txt`); it does not reimplement them.
34
37
  ## When to use
35
38
  - You have a data manifest (one row per image, with a patient/subject ID) and want a reproducible,
36
39
  leakage-safe starting repo for a segmentation model.
40
+ - You want to **fine-tune a pretrained backbone** (transfer learning — the common clinician workflow:
41
+ a `timm` / MONAI / MedSAM checkpoint adapted to your collected clinical data) with the freeze schedule,
42
+ discriminative learning rates, and pretrained-weight provenance recorded (`--task finetune`).
37
43
 
38
44
  ## When NOT to use
39
45
  - Auditing an already-trained model's validation design → `/model-validation`.
@@ -54,8 +60,14 @@ patient level off this column.
54
60
  python3 ${CLAUDE_SKILL_DIR}/scripts/scaffold.py \
55
61
  --manifest <manifest.csv> --task segmentation --out model_repo --seed 42 \
56
62
  --in-channels 1 --out-channels 1
57
- # --task = segmentation | classification | detection | synthesis | ssl
58
- # (out-channels = num classes for classification, target channels for synthesis)
63
+ # --task = segmentation | classification | detection | synthesis | ssl | finetune
64
+ # (out-channels = num classes for classification/finetune, target channels for synthesis)
65
+ # fine-tuning a pretrained backbone (transfer learning) on collected clinical data:
66
+ python3 ${CLAUDE_SKILL_DIR}/scripts/scaffold.py \
67
+ --manifest <manifest.csv> --task finetune --out model_repo --seed 42 \
68
+ --out-channels <num_classes> --from-pretrained timm:resnet50.a1_in1k
69
+ # emits PRETRAINED.md (provenance) + a frozen→unfrozen train.py with discriminative LRs;
70
+ # record the exact pretrained source so the fine-tune is reproducible.
59
71
  ```
60
72
  This writes `model_repo/` with `config.yaml`, `model.py` (the task's model — U-Net / CNN / Faster R-CNN
61
73
  / Pix2Pix / SimCLR encoder), `dataset.py` (reads the frozen split), `losses.py` (task-appropriate),
@@ -79,9 +91,11 @@ patient-disjointness proof, and (optionally, locally with torch installed)
79
91
  ### Phase 4 — Plug in your data and train
80
92
  Implement `dataset.py`'s `_load_image` / `_load_label` for your modality (DICOM / NIfTI / TIFF via
81
93
  nibabel / pydicom / tifffile / TorchIO / MONAI transforms). For production, swap `model.py` for MONAI
82
- `UNet` / `SegResNet` or an nnU-Net plan (see `${CLAUDE_SKILL_DIR}/references/training_guide.md`). Run
83
- `python train.py` (best model selected on the **val** split), then `python evaluate.py` (predictions on
84
- the **test** split, touched once).
94
+ `UNet` / `SegResNet` or an nnU-Net plan (see `${CLAUDE_SKILL_DIR}/references/training_guide.md`). For a
95
+ fine-tuning repo (`--task finetune`), fill `PRETRAINED.md` and set the freeze schedule / discriminative
96
+ learning rates (see `${CLAUDE_SKILL_DIR}/references/finetuning_guide.md`, which also covers MedSAM/SAM
97
+ adaptation and train-only diffusion augmentation). Run `python train.py` (best model selected on the
98
+ **val** split), then `python evaluate.py` (predictions on the **test** split, touched once).
85
99
 
86
100
  ### Phase 5 — Validate, evaluate, publish
87
101
  Hand off to `/model-validation` (validation-tier + comparator + metric-selection audit),
@@ -110,7 +124,9 @@ runnability.
110
124
  ## Deterministic gates
111
125
  - `scripts/scaffold.py` — the generator (stdlib + numpy; deterministic given manifest + seed).
112
126
  - `scripts/check_training_hygiene.py` — AST linter: all RNGs seeded, cuDNN deterministic,
113
- `eval()` + `no_grad()` inference, no training on a non-train split.
127
+ `eval()` + `no_grad()` inference, no training on a non-train split, and (fine-tuning) a
128
+ recorded pretrained-weight provenance when pretrained weights are loaded
129
+ (`PRETRAINED_PROVENANCE_MISSING`).
114
130
  - `scripts/scaffold_challenge/verify.sh` — the build → validate chain, network-free (torch tier
115
131
  self-skips).
116
132
 
@@ -0,0 +1,91 @@
1
+ # Fine-tuning guide (model-scaffold — `--task finetune`)
2
+
3
+ Load-on-demand notes for the target workflow of a clinician-researcher: **fine-tune an
4
+ existing pretrained model on collected clinical data**, rather than train from scratch or
5
+ design a new architecture. `scaffold.py --task finetune` emits a leakage-safe transfer-learning
6
+ repo (frozen→unfrozen schedule, discriminative learning rates, a `PRETRAINED.md` provenance
7
+ record); this guide covers the decisions it deliberately leaves to you.
8
+
9
+ ## When to fine-tune (vs train from scratch)
10
+ Fine-tuning a pretrained backbone is the right default whenever the labelled clinical set is
11
+ small (hundreds–low-thousands of patients) — the regime almost every solo clinical study is
12
+ in. From-scratch training needs far more data to beat a fine-tuned ImageNet/medical backbone.
13
+ Pick the backbone in `/architecture-zoo`; adapt it here.
14
+
15
+ ## The provenance record is load-bearing — `PRETRAINED.md`
16
+ A fine-tune is only reproducible if the **exact** pretrained weights are recorded. `--task
17
+ finetune` emits `PRETRAINED.md` with `[VERIFY]` fields; fill them before publishing:
18
+ - **Source** — the exact model + weights tag (`timm:resnet50.a1_in1k`, `MedSAM`, a URL/DOI),
19
+ set via `--from-pretrained`.
20
+ - **Pretraining data** — the dataset the backbone was pretrained on. **Confirm it does not
21
+ overlap this study's test set.** A backbone pretrained on (or including) your evaluation
22
+ images is *pretraining-set contamination*: leakage that no train/val/test split table can
23
+ see, because it entered through the weights, not the split. This is the fine-tuning analogue
24
+ of benchmark contamination in LLM evaluation (`/mllm-eval`).
25
+ - **License**, **checkpoint hash** (sha256), **access date** — for auditability.
26
+
27
+ `check_training_hygiene.py` fires `PRETRAINED_PROVENANCE_MISSING` (Minor) when a training
28
+ script loads pretrained weights (`pretrained=True` / `from_pretrained`) but the repo carries
29
+ no `PRETRAINED.md` and no `pretrained:` block in `config.yaml`. The scaffold passes by
30
+ construction; a hand-rolled repo (a copied Kaggle notebook that does
31
+ `timm.create_model(..., pretrained=True)` and records nothing) fails.
32
+
33
+ ## The frozen→unfrozen schedule
34
+ The emitted `train.py` implements the standard two-phase transfer schedule:
35
+ 1. **Freeze the backbone, warm up the fresh head** for a few epochs (`FREEZE_EPOCHS`). The
36
+ randomly-initialised head would otherwise back-propagate large gradients that damage the
37
+ pretrained features.
38
+ 2. **Unfreeze with discriminative learning rates** — a small learning rate for the pretrained
39
+ backbone (`BACKBONE_LR`, e.g. 1e-5) and a larger one for the head (`HEAD_LR`, e.g. 1e-3).
40
+ The backbone should *adapt*, not be overwritten.
41
+
42
+ Tune the two rates and `FREEZE_EPOCHS` per task. For very small datasets, keep more of the
43
+ backbone frozen (train only the last block + head) and lean on regularisation (weight decay,
44
+ dropout, strong but physiology-preserving augmentation, early stopping on the **val** split).
45
+
46
+ ## BatchNorm and small clinical batches
47
+ Fine-tuning with small batches destabilises BatchNorm running statistics. Options: keep the
48
+ backbone's BN layers in `eval()` (frozen running stats) while the backbone is frozen; switch
49
+ to GroupNorm; or use a larger effective batch (gradient accumulation). Record the choice in
50
+ Methods — it materially affects reproducibility.
51
+
52
+ ## MedSAM / SAM adaptation
53
+ Promptable foundation segmenters (SAM, **MedSAM**) are adapted, not retrained. The common,
54
+ solo-doable path is **adapter / decoder fine-tuning**: freeze the heavy image encoder and
55
+ fine-tune only the mask decoder (and optionally a lightweight adapter or the prompt encoder)
56
+ on your labelled masks. Integrate the upstream implementation
57
+ ([MedSAM](https://github.com/bowang-lab/MedSAM),
58
+ [SAM](https://github.com/facebookresearch/segment-anything)) — do not reimplement it. Keep the
59
+ scaffold's split-reading contract (`splits/split_assignment.csv`) so the patient-level split
60
+ is preserved, and record the SAM/MedSAM checkpoint in `PRETRAINED.md`. Prompt design (points /
61
+ boxes / automatic) is part of the method — report it, and report whether prompts used any
62
+ ground-truth information at test time (a leakage trap unique to promptable models).
63
+
64
+ ## Diffusion augmentation — train split only
65
+ A diffusion model can synthesise extra training images (an off-the-shelf augmentation, **not**
66
+ a novel method here). Two hard rules keep it leakage-safe:
67
+ 1. **Any generative model used for augmentation must be trained on the TRAIN split only.** If
68
+ the diffusion (or GAN) model saw val/test images, its samples leak that distribution into
69
+ training — the generative analogue of fitting a normaliser on full data
70
+ (`/preprocess-imaging` `NORMALIZATION_LEAKAGE`).
71
+ 2. **Synthetic images augment TRAIN only, never val/test.** Evaluating on — or augmenting —
72
+ the held-out split with synthetic data invalidates the metric. `check_preprocessing_leakage`
73
+ flags `AUGMENTATION_ON_EVAL`; declare synthetic augmentation in the preprocessing manifest
74
+ as `applies_to: ["train"]`.
75
+ Report the synthetic:real ratio and show the result holds without synthetic data (a sensitivity
76
+ analysis) — reviewers discount models propped up by synthetic training data.
77
+
78
+ ## Reporting
79
+ Fill `methods_stub.md` and `PRETRAINED.md`, then hand off to `/write-paper` +
80
+ `/check-reporting`. Fine-tuning specifics reviewers expect: the pretrained source + its
81
+ pretraining data (contamination check), the freeze/unfreeze schedule and learning rates,
82
+ and — for SAM/MedSAM — the prompt protocol. Report held-out metrics as **mean ± SD over ≥ 3
83
+ seeds** (`/model-evaluation` → `/analyze-stats`); fine-tuning is seed-sensitive on small data.
84
+
85
+ ## Hand-offs
86
+ - Backbone / architecture choice (incl. SAM/MedSAM, diffusion) → `/architecture-zoo`.
87
+ - Data-stage leakage (normalisation fit, augmentation-on-eval, slice crossing) →
88
+ `/preprocess-imaging` (`check_preprocessing_leakage`).
89
+ - Split / validation-design audit → `/model-validation` (`check_split_leakage.py`).
90
+ - Held-out metrics + CIs → `/model-evaluation` → `/analyze-stats`.
91
+ - Provenance/model documentation → `/model-card` (Model Card + Datasheet).
@@ -27,6 +27,14 @@ CHECKS (verdicts):
27
27
  5. EVAL_SHUFFLE (Minor) an evaluation DataLoader uses shuffle=True
28
28
  (reorders the test set; harmless for metrics but
29
29
  a smell, and breaks index-aligned outputs).
30
+ 6. PRETRAINED_PROVENANCE_MISSING (Minor) the training script loads PRETRAINED weights
31
+ (a `pretrained=True` kwarg or a `from_pretrained`
32
+ call — fine-tuning / transfer learning) but the repo
33
+ records no pretrained-weight provenance (no non-empty
34
+ PRETRAINED.md and no `pretrained:` block in
35
+ config.yaml). A fine-tune whose starting checkpoint is
36
+ unrecorded is not reproducible. Fires only in --repo
37
+ mode (the provenance record is a repo-level artifact).
30
38
 
31
39
  INPUTS
32
40
  --repo a scaffolded repo directory; train.py and evaluate.py are auto-found.
@@ -84,6 +92,7 @@ def _scan(src: str):
84
92
  "cudnn_determ": False, # cudnn.deterministic = True
85
93
  "dataset_split": {}, # var name -> split literal it was built with
86
94
  "loaders": [], # (first_arg_name, shuffle_bool)
95
+ "loads_pretrained": False, # a pretrained=True kwarg or a from_pretrained call
87
96
  }
88
97
  # dataset var <- Ctor(..., split="X")
89
98
  for node in ast.walk(tree):
@@ -120,6 +129,9 @@ def _scan(src: str):
120
129
  name = first.id if isinstance(first, ast.Name) else None
121
130
  sh = _kw(node, "shuffle")
122
131
  facts["loaders"].append((name, _is_true(sh)))
132
+ # pretrained-weight load: `...(pretrained=True)` or a `...from_pretrained(...)` call
133
+ if _is_true(_kw(node, "pretrained")) or tail == "from_pretrained":
134
+ facts["loads_pretrained"] = True
123
135
  # cudnn.deterministic = True (assignment to an Attribute target)
124
136
  if isinstance(node, ast.Assign):
125
137
  for tgt in node.targets:
@@ -129,7 +141,21 @@ def _scan(src: str):
129
141
  return facts
130
142
 
131
143
 
132
- def analyze(train: str | None, eval_: str | None) -> dict:
144
+ def _has_pretrained_provenance(repo: Path) -> bool:
145
+ """True if the repo records pretrained-weight provenance: a non-empty PRETRAINED.md, or
146
+ a `pretrained:` block in config.yaml."""
147
+ pm = repo / "PRETRAINED.md"
148
+ if pm.is_file() and pm.read_text(encoding="utf-8").strip():
149
+ return True
150
+ cfg = repo / "config.yaml"
151
+ if cfg.is_file():
152
+ for line in cfg.read_text(encoding="utf-8").splitlines():
153
+ if line.strip().startswith("pretrained:"):
154
+ return True
155
+ return False
156
+
157
+
158
+ def analyze(train: str | None, eval_: str | None, repo: str | None = None) -> dict:
133
159
  claims = []
134
160
  tfacts = _scan(Path(train).read_text(encoding="utf-8")) if train else None
135
161
  efacts = _scan(Path(eval_).read_text(encoding="utf-8")) if eval_ else None
@@ -160,6 +186,16 @@ def analyze(train: str | None, eval_: str | None) -> dict:
160
186
  f"'{name}' constructed with split=\"{sp}\" — training on the {sp} split",
161
187
  "where": Path(train).name,
162
188
  })
189
+ # fine-tuning: pretrained weights loaded but no provenance recorded (repo mode only)
190
+ if tfacts["loads_pretrained"] and repo and not _has_pretrained_provenance(Path(repo)):
191
+ claims.append({
192
+ "verdict": "PRETRAINED_PROVENANCE_MISSING", "severity": "Minor",
193
+ "detail": "the training script loads pretrained weights (fine-tuning) but the "
194
+ "repo records no pretrained-weight provenance (a non-empty PRETRAINED.md "
195
+ "or a 'pretrained:' block in config.yaml). Record the exact "
196
+ "source / checkpoint / license / hash so the fine-tune is reproducible.",
197
+ "where": Path(train).name,
198
+ })
163
199
 
164
200
  if efacts is not None:
165
201
  if not (efacts["has_eval"] and efacts["has_no_grad"]):
@@ -229,7 +265,7 @@ def main() -> int:
229
265
  args = ap.parse_args()
230
266
 
231
267
  train, eval_ = _resolve(args.repo, args.train, args.eval_)
232
- result = analyze(train, eval_)
268
+ result = analyze(train, eval_, repo=args.repo)
233
269
 
234
270
  if not args.quiet:
235
271
  print("=" * 41)