billy-lyc/neuropilot/qc-agent-skill

Claude Code and agent skill by billy-lyc/neuropilot

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Semi-automatic QC agent for structural MRI (T1w and T2w). Runs Raw Image QC → Brain Extraction QC → Registration QC → Segmentation QC (T1w only) → Surface QC (T1w only). For each step: auto-detects and localises problems in the image, shows annotated PNG, proposes fix, user says yes/no, agent applies fix and shows before/after. Use when the user wants to QC T1w or T2w images, check skull stripping, registration, FreeSurfer segmentation, or generate a QC report.

Install

npx vskill@latest install billy-lyc/neuropilot/qc-agent-skill

SKILL.md

Structural QC Agent (T1w / T2w)

Type menu at any time to return to the step selection menu.
## 🔒 OUTPUT TARGET + DISMISS (cross-step contract — ask FIRST, applies to all 5 steps)
Before step 1, the FIRST thing the skill MUST ask the user is where corrected/kept data goes
(steps/_shared/qc_target.py → $QC_OUT/qc_target.json):
- `overwrite` (default) — fixes are applied IN PLACE in the source dataset; dismissed subjects are left untouched.
- `new` — create a fresh output folder and COPY each kept+fixed subject into it; dismissed subjects are simply never copied.
- `custom <path>` — same as new at a user-given path.
DISMISS = the user drops a subject. Any step's review can dismiss → POST /dismiss →
appended to the ONE shared $QC_EXCLUDED ($QC_OUT/excluded_subjects.json, via qc_exclude.py).
Every later step's generator already filters this list (step1 dashboard, qc_html, step3 build_html1,
step4 07/08, step5 03/06) — a dismissed subject never reappears downstream.
- new/custom: a dismissed subject is NOT copied to the output. overwrite: it is left alone in source.
- After step 5, run python steps/_shared/qc_dismissed_report.py → $QC_OUT/dismissed_subjects.{md,html}
= a table of everything the user dropped. REPORT only — never auto-delete the user's data.
SIGN-OFF = every "Export decision" button (all 5 steps) is gated by a reviewer-signature modal
(steps/_shared/qc_sign_js.py → qcSign()): it requires Full name + Onyen/email + a confirm
checkbox before the export proceeds (identity remembered in localStorage, re-confirmed each export).
On confirm it POST /sign → appended to $QC_OUT/signoffs.json (audit ledger, never overwritten:
{by, onyen, step, at, summary}) so a supervisor can see WHO confirmed each batch. The server that
serves the dashboards (scripts/qc_server.py) holds both /dismiss and /sign; if a page reports
unknown endpoint on sign/dismiss, the served qc_server.py is stale — restart it.
bash
# QC_SKILL = this skill's own directory (the folder holding this SKILL.md).
# The bundled scripts under scripts/ and slurm/ self-locate; export QC_SKILL only to override.
QC_SKILL="${QC_SKILL:-/path/to/qc-agent-skill}"
PYTHON="${PYTHON:-$(command -v python3)}"
THRESHOLDS="${THRESHOLDS:-$QC_SKILL/thresholds/thresholds_structural.yaml}"
# DIVISION OF LABOR (do not blur this line):
# • DETECTION = this skill's own scripts (check_raw_image / collect_metrics_structural /
# detect_issues / annotate_qc) — we find and localise the problem.
# • FIXING = the FreeSurfer editing tools (bundled under $QC_SKILL/freeview) — we never
# hand-roll mask/wm edits here.
# • VIEWING = freeview (bundled web viewer under $QC_SKILL/freeview, or local freeview).
# ── ENVIRONMENT (self-contained — ANYONE who downloads this skill can run it) ──
# FIRST RUN, once, from the skill root:
# bash setup_env.sh # creates <skill>/.venv from requirements.txt (pip only,
# # no conda, no cluster paths — just needs python3 ≥ 3.9)
# source steps/config.sh # auto-detects <skill>/.venv → sets QC_PYTHON
# That covers the CORE end-to-end: every step's detection, all review dashboards, niivue 3D,
# dismiss, and sign-off. Machine-specific paths live ONLY in steps/config.sh (all overridable
# via env); the bundled FreeSurfer helper is $QC_SKILL/freeview (no external skill needed).
#
# OPTIONAL, only for the FIX / rerun stages (not needed to review or triage):
# • FreeSurfer (step2 watershed autofix, step5 recon-all, step4 SynthSeg) — set FREESURFER_HOME
# + QC_FS_LICENSE to your own install (external, licensed, not bundled).
# • an fMRIPrep image (step4 FAIL backup) — set QC_FMRIPREP_SIMG.
# SELF-CONTAINED: all skill-owned code/templates live under $QC_SKILL. Only genuinely
# external installs (FreeSurfer / FSL / ANTs) are resolved from your environment.
FS_SKILL=$QC_SKILL/freeview # bundled FreeSurfer editing tools + web viewer
FS_VIEWER=$FS_SKILL/freeview_skill/start_viewer.sh
# Step-2 fix candidate generator (watershed vertex-sweep A/B/C)
BRAINMASK_FIX=$QC_SKILL/brainmask_fix
# Interpreter: the skill's own venv (bash setup_env.sh), overridable via QC_PYTHON.
PY=${QC_PYTHON:-$QC_SKILL/.venv/bin/python3}
# FreeSurfer (mri_synthstrip / recon-all) — external + licensed, only for FIX stages.
# Resolved from your environment: export FREESURFER_HOME, or `module load freesurfer`.
FREESURFER_HOME=${FREESURFER_HOME:?export FREESURFER_HOME=/path/to/freesurfer (fix stages only)}
# ANTs skill — robust registration, brain extraction (bundled under $QC_SKILL)
ANTS_SKILL=$QC_SKILL/ants_skill
MNI_BRAIN=$ANTS_SKILL/templates/MNI152/MNI152_T1_1mm_brain.nii.gz
MNI_BRAIN_MASK=$ANTS_SKILL/templates/MNI152/MNI152_T1_1mm_brain_mask.nii.gz
OASIS_DIR=$ANTS_SKILL/templates/OASIS-30
# FSL tools (for fslreorient2std — works without a full FSL environment).
# Optional; only used if present. Set FSL_BIN, or leave it to $FSLDIR/bin on PATH.
FSL_BIN=${FSL_BIN:-${FSLDIR:+$FSLDIR/bin}}

Core interaction loop (applies to every QC step)

Every step follows this exact pattern:

1. Run metrics + detect issues
2. Run annotate_qc.py → auto-localises problem → outputs annotated PNG
3. Assess severity (see 3-tier table below)
4. Send PNG to user with SendUserFile + describe "Issue: [what/where]" + proposed fix
5. AskUserQuestion → user approves fix
6. Apply fix → save fixed NIfTI/surface to OUTPUT_DIR (via fix_output_path)
7. Generate AFTER visualization:
- Mask/seg fixes → re-run annotate_qc.py (before/after comparison)
- Registration → run annotate_qc.py --mode overlay (T1 + yellow template)
AND plain T1 image side-by-side
8. Send BOTH before and after PNGs with SendUserFile in a single call
9. AskUserQuestion with options:
[A] Looks good — continue to next step
[R] Still not right — re-run with different parameters ← always include this
[S] Skip this step

CRITICAL: Never show a PNG as a file path or markdown link. Always use SendUserFile so the image renders inline. Every PNG must be sent immediately after it is generated — before showing any text description.

The re-run option ([R]) must always appear, even after a successful autofix. If user chooses re-run: ask which parameters to change, submit SLURM job, wait, re-QC from this step.

NEVER silently apply any fix. Always tell the user what was found and ask before touching anything.

Severity tiers — how to present and what to offer
TierWhenWhat to sayOptions to offer
MildIssue present but unlikely to affect downstream analysis"Small issue found: [X]. OK to fix directly."Fix / Skip
ModerateClear problem; rerunning the pipeline is the natural first fix"Issue found: [X]. A pipeline rerun is likely to fix this."Rerun / Manual fix / Skip
SevereComplete failure OR rerun almost certainly won't help"Severe issue: [X]. Rerun unlikely to help — attempting manual fix."Manual fix / Skip

How to judge "rerun won't help":

  • NCC < 0.45 AND NMI < 0.06 after ANTs re-registration → image itself has quality issues
  • Euler < −500 after checking skull strip quality → surface topology is too damaged
  • dseg > 50% labels missing → segmentation never ran or input was wrong
True UNSAFE (only 2 cases — flag and stop, do not attempt fix)
  • Raw image is empty or all-zero (data is gone)
  • Image is clearly not a brain (wrong scan acquired)

Everything else: attempt a fix.


Step 0 — Collect inputs

Follow this exact sequence: paths first → discover subjects → select subject → details.


Step 0a — Paths:

Ask:

  1. "What is your BIDS root directory? (raw input data, e.g. /path/to/bids)"
  2. "What is your derivatives root directory? (pipeline outputs — fMRIPrep, FreeSurfer, etc.)"
bash
[[ -d "$BIDS_DIR" ]] || echo "WARNING: BIDS_DIR not found: $BIDS_DIR"
[[ -d "$DERIV" ]] || echo "WARNING: DERIV not found: $DERIV"

Step 0b — Discover subjects (agent runs automatically):

bash
ls "$BIDS_DIR" | grep '^sub-'
ls "$DERIV/fmriprep" 2>/dev/null | grep '^sub-'

List discovered subjects, then ask user to select.

Step 0c — Session, modality, QC output directory:

Auto-detect sessions:

bash
ls "$BIDS_DIR/$SUBJECT" 2>/dev/null | grep '^ses-'
ls "$DERIV/fmriprep/$SUBJECT" 2>/dev/null | grep '^ses-'

Ask: session / modality (T1w or T2w) / output directory.

bash
SESSION=ses-01 # empty string if None
MODALITY=T1w
QC_OUT="${QC_OUT:-$QC_SKILL/output/$SUBJECT}" # override with QC_OUT=/your/output/dir
mkdir -p $QC_OUT/{screenshots/{before,after},metrics,reports,fixed}

Fixed files always go to `$QC_OUT/fixed/`.

python
def fix_output_path(original_path, qc_out, overwrite=False):
from pathlib import Path
if overwrite:
return Path(original_path)
return Path(qc_out) / "fixed" / Path(original_path).name

After all inputs confirmed:

bash
echo "QC_OUT: $QC_OUT"
echo "SUBJECT: $SUBJECT SESSION: ${SESSION:-none} MODALITY: $MODALITY"
echo "BIDS_DIR: $BIDS_DIR"
echo "DERIV: $DERIV"

═══ T1w PIPELINE ═══

Step 1 — Raw Image QC

(Corresponds to IBIS Phase A/B: "Did we get usable data?" + "Which series to use?")


⭐ LOCKED — canonical Step-1 cohort review pipeline (use this exact format for every new dataset)

This is the fixed, agreed solution. Reuse the same scripts, the same call order, and the same HTML logic on any new cohort. Do NOT substitute other generators.

Scripts (do not swap):

  • detection (per subject) → check_raw_image.py → writes one *_step1.json per subject (holds the

grade: PASS/WARN/FAIL, slightly stricter than MRIQC) + a 3-view screenshot.

  • cohort review HTML → `generate_interactive_dashboard.py` (this is THE generator). It renders

whatever grade is in the *_step1.json and produces the dashboard_v5-style page: MRIQC comparison panel, per-card screenshot, an inline niivue viewer under each screenshot, per-card decision buttons, exportDecisions() + copyJson(), and the POST `/save` auto-save to the cluster. No motion-score-distribution bar.

  • Decision buttons (LOCKED): exactly three — `PASS` / `DISMISS` / `FLAG`, keyboard `1` / `2` / `3`.

There is NO "APPLY FIX" button (removed — Step 1 is raw-image triage, not a fix stage). Do not re-add it or renumber the keys.

  • 🧊 Per-card inline niivue viewer (LOCKED — same machinery as Step-2 review): each card embeds a

real niivue <canvas> UNDER its screenshot (same width) showing THAT subject's raw T1 (*_step1.json → data["path"], grayscale — no mask in Step 1), scroll=slice / drag=pan / scroll=zoom. niivue is imported in-page from the jsDelivr ESM CDN (@niivue/niivue@0.67.0/+esm); volumes are served same-origin by qc_server.py's POST /stage_all (symlinks under <served-dir>/_nv_vols/). Canvas MUST be position:absolute;inset:0 inside a fixed-height .nv-canvas-wrap (else it grows forever); toggleCard()→window.__nvEnsure(idx) inits a viewer only when its card opens. This REPLACES the old freeview-window "View 3D" button (no iframe, no port 9081 — tunnel only the dashboard port 8802).

  • serve + JSON auto-save + same-origin volumes → qc_server.py (GET no-cache + POST /save + POST /stage_all).

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
54
Repository forks
5
7-day trend score
20

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/billy-lyc/neuropilot/qc-agent-skill/badge)](https://verified-skill.com/skills/billy-lyc/neuropilot/qc-agent-skill)

Something wrong with this skill or its page? Tell us.