Skill Tracer
Skills › Scientific Agent Skills › bids › core_workflows.md

core_workflows.md

557 lines · skills/bids/references/core_workflows.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# BIDS Core Workflows
2
3The twelve workflow areas in full, with worked code and commands: directory structure,
4`dataset_description.json`, querying with PyBIDS, validation (PyPI wrapper, Deno, legacy
5Node, and `.bidsignore`), entities and file naming, DICOM-to-BIDS conversion with
6HeuDiConv and dcm2bids, metadata sidecars, events files, the participants file,
7derivatives, advanced PyBIDS usage, and running BIDS-Apps.
8

BIDS Core Workflows

The twelve workflow areas in full, with worked code and commands: directory structure, dataset_description.json, querying with PyBIDS, validation (PyPI wrapper, Deno, legacy Node, and .bidsignore), entities and file naming, DICOM-to-BIDS conversion with HeuDiConv and dcm2bids, metadata sidecars, events files, the participants file, derivatives, advanced PyBIDS usage, and running BIDS-Apps.

Raw lines 1 to 8
9## Core Workflows

Core Workflows

Raw lines 9 to 10
11### 1. BIDS Directory Structure
13Illustrative single-session layout (include only acquired modalities; not a complete ASL example):
15```
16my_dataset/
17 dataset_description.json # Required: name, BIDSVersion, etc.
18 participants.tsv # Recommended: subject-level phenotypic data
19 participants.json # Recommended: column descriptions
20 README # Recommended: dataset documentation
21 CHANGES # Recommended: version history
22 .bidsignore # Optional: patterns to exclude from validation
23 sub-01/
24 anat/
25 sub-01_T1w.nii.gz
26 sub-01_T1w.json # Sidecar metadata
27 func/
28 sub-01_task-rest_bold.nii.gz
29 sub-01_task-rest_bold.json
30 sub-01_task-rest_events.tsv # Event timing for task fMRI
31 sub-01_task-rest_events.json
32 dwi/
33 sub-01_dwi.nii.gz
34 sub-01_dwi.json
35 sub-01_dwi.bvec
36 sub-01_dwi.bval
37 fmap/
38 sub-01_phasediff.nii.gz
39 sub-01_phasediff.json
40 sub-01_magnitude1.nii.gz
41 perf/
42 sub-01_asl.nii.gz
43 sub-01_asl.json
44```
46**Key points:**
47- Required metadata must be available through matching JSON sidecars and inheritance; a separate JSON file beside every NIfTI is not mandatory
48- File names encode entities: `sub-<label>[_ses-<label>][_task-<label>][_acq-<label>][_run-<index>]_<suffix>.<extension>`
49- Entity order in filenames is fixed by the specification
50- `dataset_description.json` is required at the root; additional files depend on dataset type and modality
51- For multiple sessions use `sub-01/ses-pre/anat/sub-01_ses-pre_T1w.nii.gz`; do not mix session and sessionless acquisitions for one subject

1. BIDS Directory Structure

Illustrative single-session layout (include only acquired modalities; not a complete ASL example):

my_dataset/
  dataset_description.json      # Required: name, BIDSVersion, etc.
  participants.tsv              # Recommended: subject-level phenotypic data
  participants.json             # Recommended: column descriptions
  README                        # Recommended: dataset documentation
  CHANGES                       # Recommended: version history
  .bidsignore                   # Optional: patterns to exclude from validation
  sub-01/
    anat/
      sub-01_T1w.nii.gz
      sub-01_T1w.json           # Sidecar metadata
    func/
      sub-01_task-rest_bold.nii.gz
      sub-01_task-rest_bold.json
      sub-01_task-rest_events.tsv     # Event timing for task fMRI
      sub-01_task-rest_events.json
    dwi/
      sub-01_dwi.nii.gz
      sub-01_dwi.json
      sub-01_dwi.bvec
      sub-01_dwi.bval
    fmap/
      sub-01_phasediff.nii.gz
      sub-01_phasediff.json
      sub-01_magnitude1.nii.gz
    perf/
      sub-01_asl.nii.gz
      sub-01_asl.json

Key points:

  • Required metadata must be available through matching JSON sidecars and inheritance; a separate JSON file beside every NIfTI is not mandatory
  • File names encode entities: sub-<label>[_ses-<label>][_task-<label>][_acq-<label>][_run-<index>]_<suffix>.<extension>
  • Entity order in filenames is fixed by the specification
  • dataset_description.json is required at the root; additional files depend on dataset type and modality
  • For multiple sessions use sub-01/ses-pre/anat/sub-01_ses-pre_T1w.nii.gz; do not mix session and sessionless acquisitions for one subject
Raw lines 11 to 52
53### 2. Creating dataset_description.json
55```python
56import json
58dataset_description = {
59 "Name": "My Neuroimaging Study",
60 "BIDSVersion": "1.11.2",
61 "DatasetType": "raw",
62 "License": "CC0",
63 "Authors": ["First Author", "Second Author"],
64 "GeneratedBy": [
65 {
66 "Name": "HeuDiConv",
67 "Version": "1.5.1",
68 "CodeURL": "https://github.com/nipy/heudiconv"
69 }
70 ]
73with open("dataset_description.json", "w") as f:
74 json.dump(dataset_description, f, indent=4)
75```
77Illustrative provenance: replace author, pipeline, and version values with actual records.
78For **derivatives**, set `"DatasetType": "derivative"` and add `"GeneratedBy"` listing the pipeline:
80```python
81deriv_description = {
82 "Name": "fMRIPrep - fMRI PREProcessing",
83 "BIDSVersion": "1.11.2",
84 "DatasetType": "derivative",
85 "GeneratedBy": [
86 {
87 "Name": "fMRIPrep",
88 "Version": "24.1.0",
89 "CodeURL": "https://github.com/nipreps/fmriprep"
90 }
91 ]
93```

2. Creating dataset_description.json

import json

dataset_description = {
    "Name": "My Neuroimaging Study",
    "BIDSVersion": "1.11.2",
    "DatasetType": "raw",
    "License": "CC0",
    "Authors": ["First Author", "Second Author"],
    "GeneratedBy": [
        {
            "Name": "HeuDiConv",
            "Version": "1.5.1",
            "CodeURL": "https://github.com/nipy/heudiconv"
        }
    ]
}

with open("dataset_description.json", "w") as f:
    json.dump(dataset_description, f, indent=4)

Illustrative provenance: replace author, pipeline, and version values with actual records. For derivatives, set "DatasetType": "derivative" and add "GeneratedBy" listing the pipeline:

deriv_description = {
    "Name": "fMRIPrep - fMRI PREProcessing",
    "BIDSVersion": "1.11.2",
    "DatasetType": "derivative",
    "GeneratedBy": [
        {
            "Name": "fMRIPrep",
            "Version": "24.1.0",
            "CodeURL": "https://github.com/nipreps/fmriprep"
        }
    ]
}
Raw lines 53 to 94
95### 3. Querying BIDS Datasets with PyBIDS
97```python
98from bids import BIDSLayout
100# Index BIDS-compatible names; this is not full dataset validation
101layout = BIDSLayout("/path/to/bids_dataset")
103# Basic queries
104subjects = layout.get_subjects() # ['01', '02', '03', ...]
105sessions = layout.get_sessions() # ['pre', 'post'] or []
106tasks = layout.get_tasks() # ['rest', 'nback']
107runs = layout.get_runs() # [1, 2] or []
109# Find specific files
110bold_files = layout.get(
111 suffix="bold",
112 extension=".nii.gz",
113 return_type="filename"
116# Filter by subject, task, session
117nback_sub01 = layout.get(
118 subject="01",
119 task="nback",
120 suffix="bold",
121 extension=".nii.gz",
122 return_type="filename"
125# Get metadata from JSON sidecars (automatic inheritance)
126metadata = layout.get_metadata(bold_files[0]) # first check that a match exists
127tr = metadata["RepetitionTime"]
129# Get entity definitions in this layout
130entities = layout.get_entities()
132# Inspect a matching file and its entity values
133bids_file = layout.get(subject="01", suffix="T1w", extension=".nii.gz")[0]
134print(bids_file.path)
135print(bids_file.get_entities())
136```
138**Key points:**
139- `BIDSLayout` indexes the entire dataset on initialization; for large datasets use `database_path` to cache the index
140- Metadata inheritance: a JSON sidecar at a higher level (e.g., root or subject) is inherited by matching files below unless overridden; minimize overrides and resolve ambiguous same-level matches
141- Use `return_type="filename"` for paths, `return_type="object"` (default) for `BIDSFile` objects

3. Querying BIDS Datasets with PyBIDS

from bids import BIDSLayout

# Index BIDS-compatible names; this is not full dataset validation
layout = BIDSLayout("/path/to/bids_dataset")

# Basic queries
subjects = layout.get_subjects()          # ['01', '02', '03', ...]
sessions = layout.get_sessions()          # ['pre', 'post'] or []
tasks = layout.get_tasks()                # ['rest', 'nback']
runs = layout.get_runs()                  # [1, 2] or []

# Find specific files
bold_files = layout.get(
    suffix="bold",
    extension=".nii.gz",
    return_type="filename"
)

# Filter by subject, task, session
nback_sub01 = layout.get(
    subject="01",
    task="nback",
    suffix="bold",
    extension=".nii.gz",
    return_type="filename"
)

# Get metadata from JSON sidecars (automatic inheritance)
metadata = layout.get_metadata(bold_files[0])  # first check that a match exists
tr = metadata["RepetitionTime"]

# Get entity definitions in this layout
entities = layout.get_entities()

# Inspect a matching file and its entity values
bids_file = layout.get(subject="01", suffix="T1w", extension=".nii.gz")[0]
print(bids_file.path)
print(bids_file.get_entities())

Key points:

  • BIDSLayout indexes the entire dataset on initialization; for large datasets use database_path to cache the index
  • Metadata inheritance: a JSON sidecar at a higher level (e.g., root or subject) is inherited by matching files below unless overridden; minimize overrides and resolve ambiguous same-level matches
  • Use return_type="filename" for paths, return_type="object" (default) for BIDSFile objects
Raw lines 95 to 142
143### 4. Validating BIDS Datasets
145#### Using bids-validator via PyPI (recommended)
147The `bids-validator-deno` PyPI package bundles the Deno-based validator as a standalone CLI:
149```bash
150# Install
151uv pip install bids-validator-deno
152# Use an activated virtual environment so the wrapper can locate its Deno runtime.
154# Validate a dataset
155bids-validator-deno /path/to/bids_dataset
157# Save a full machine-readable report, including NIfTI header checks
158bids-validator-deno /path/to/bids_dataset --format json --max-rows -1 --outfile validation.json
159# Pin the schema when reproducing a review
160bids-validator-deno /path/to/bids_dataset --schema file:///absolute/path/to/bids_schema.json
161```
163#### Using bids-validator via Deno directly
165If Deno is already available, you can install or run the validator without PyPI:
167```bash
168# Install globally via Deno
169deno install -ERWN -g -n bids-validator jsr:@bids/validator
171# Or run without installing
172deno run -ERWN jsr:@bids/validator /path/to/bids_dataset
173```
175#### Legacy Node.js validator
177The older Node.js-based validator (`npm install -g bids-validator`) is deprecated in favor of the Deno-based version. Use the current schema validator for new work. The PyPI wrapper command is `bids-validator-deno`; the Deno installation above deliberately names its executable `bids-validator`.
179Validator 3.0.2 defaults to checking 1000 TSV rows; pass `--max-rows -1` for all rows.
180Use `--format json` (`--json` is a deprecated alias in 3.0.2). A local schema must be
181a `file:///...` URI, not a bare filesystem path.
182`--ignoreNiftiHeaders` skips header-dependent checks and cannot establish full compliance.
183The legacy `--ignoreSubjectConsistency` flag is absent. Inspect JSON issue codes and, only
184for justified exceptions, pass `--config` with scoped issue objects (see the
185[CLI documentation](https://bids-validator.readthedocs.io/en/latest/user_guide/command-line.html)).
187#### Using .bidsignore
189Create `.bidsignore` at the dataset root to exclude files from validation (gitignore syntax):
191```
192# Exclude sourcedata and extra files
193sourcedata/
194extra_data/
195*.log
196**/.DS_Store
197```

4. Validating BIDS Datasets

Using bids-validator via PyPI (recommended)

The bids-validator-deno PyPI package bundles the Deno-based validator as a standalone CLI:

# Install
uv pip install bids-validator-deno
# Use an activated virtual environment so the wrapper can locate its Deno runtime.

# Validate a dataset
bids-validator-deno /path/to/bids_dataset

# Save a full machine-readable report, including NIfTI header checks
bids-validator-deno /path/to/bids_dataset --format json --max-rows -1 --outfile validation.json
# Pin the schema when reproducing a review
bids-validator-deno /path/to/bids_dataset --schema file:///absolute/path/to/bids_schema.json

Using bids-validator via Deno directly

If Deno is already available, you can install or run the validator without PyPI:

# Install globally via Deno
deno install -ERWN -g -n bids-validator jsr:@bids/validator

# Or run without installing
deno run -ERWN jsr:@bids/validator /path/to/bids_dataset

Legacy Node.js validator

The older Node.js-based validator (npm install -g bids-validator) is deprecated in favor of the Deno-based version. Use the current schema validator for new work. The PyPI wrapper command is bids-validator-deno; the Deno installation above deliberately names its executable bids-validator.

Validator 3.0.2 defaults to checking 1000 TSV rows; pass --max-rows -1 for all rows. Use --format json (--json is a deprecated alias in 3.0.2). A local schema must be a file:///... URI, not a bare filesystem path. --ignoreNiftiHeaders skips header-dependent checks and cannot establish full compliance. The legacy --ignoreSubjectConsistency flag is absent. Inspect JSON issue codes and, only for justified exceptions, pass --config with scoped issue objects (see the CLI documentation).

Using .bidsignore

Create .bidsignore at the dataset root to exclude files from validation (gitignore syntax):

# Exclude sourcedata and extra files
sourcedata/
extra_data/
*.log
**/.DS_Store
Raw lines 143 to 198
199### 5. BIDS Entities and File Naming
201The authoritative, machine-readable source of truth for entities, their ordering, allowed suffixes, and all filename rules is the **BIDS Schema** — a structured YAML/JSON representation of the specification. A JSON export is shipped with this skill at `references/bids_schema.json`. The schema is defined in the [bids-specification `src/schema/`](https://github.com/bids-standard/bids-specification/tree/master/src/schema) directory and published at https://bids-specification.readthedocs.io/en/stable/schema.json. BEP-specific schema previews are available at https://github.com/bids-standard/bids-schema/tree/main/BEPs.
203Run `scripts/update_schema.py` to refresh the schema and BEPs list from upstream (no dependencies beyond stdlib).
205The tables below are a convenient summary; when in doubt, consult the schema.
207BIDS filenames are built from ordered key-value entity pairs:
209| Entity | Key | Example | Required for |
210|--------|-----|---------|--------------|
211| Subject | `sub-` | `sub-01` | Subject data; not dataset-level files |
212| Session | `ses-` | `ses-pre` | Multi-session studies |
213| Task | `task-` | `task-rest` | func (bold, cbv, phase), eeg, meg |
214| Acquisition | `acq-` | `acq-highres` | Distinguishing acquisition parameters |
215| Contrast enhancing agent | `ce-` | `ce-gadolinium` | Contrast-enhanced images |
216| Reconstruction | `rec-` | `rec-magnitude` | Reconstruction variants |
217| Direction | `dir-` | `dir-AP` | Fieldmaps, DWI, phase-encoding |
218| Run | `run-` | `run-01` | Multiple identical acquisitions |
219| Echo | `echo-` | `echo-1` | Multi-echo sequences |
220| Part | `part-` | `part-mag` | Magnitude/phase splits |
221| Space | `space-` | `space-MNI152NLin2009cAsym` | Derivatives in template space |
222| Description | `desc-` | `desc-preproc` | Derivatives only |
224**Entity ordering in filenames** is fixed by the spec (defined in `rules.entities` in `bids_schema.json`). See `references/bids_specification.md` for the complete numbered ordering table. A common subset:
225`sub-<label>[_ses-<label>][_task-<label>][_acq-<label>][_ce-<label>][_rec-<label>][_dir-<label>][_run-<index>][_echo-<index>][_part-<label>][_space-<label>][_desc-<label>]_<suffix>.<extension>`
227**Common suffixes by datatype:**
229| Datatype | Suffixes |
230|----------|----------|
231| anat | `T1w`, `T2w`, `FLAIR`, `T2starw`, `T1map`, `T2map`, `defacemask` |
232| func | `bold`, `cbv`, `sbref`, `events`, `physio`, `stim` |
233| dwi | `dwi`, `sbref` |
234| fmap | `phasediff`, `phase1`, `phase2`, `magnitude1`, `magnitude2`, `fieldmap`, `epi` |
235| perf | `asl`, `m0scan`, `aslcontext` |
236| eeg | `eeg`, `channels`, `electrodes`, `events` |
237| meg | `meg`, `channels`, `coordsystem`, `events` |
238| ieeg | `ieeg`, `channels`, `electrodes`, `coordsystem`, `events` |
239| pet | `pet`, `blood` |

5. BIDS Entities and File Naming

The authoritative, machine-readable source of truth for entities, their ordering, allowed suffixes, and all filename rules is the BIDS Schema — a structured YAML/JSON representation of the specification. A JSON export is shipped with this skill at references/bids_schema.json. The schema is defined in the [bids-specification src/schema/](https://github.com/bids-standard/bids-specification/tree/master/src/schema) directory and published at https://bids-specification.readthedocs.io/en/stable/schema.json. BEP-specific schema previews are available at https://github.com/bids-standard/bids-schema/tree/main/BEPs.

Run scripts/update_schema.py to refresh the schema and BEPs list from upstream (no dependencies beyond stdlib).

The tables below are a convenient summary; when in doubt, consult the schema.

BIDS filenames are built from ordered key-value entity pairs:

EntityKeyExampleRequired for
Subjectsub-sub-01Subject data; not dataset-level files
Sessionses-ses-preMulti-session studies
Tasktask-task-restfunc (bold, cbv, phase), eeg, meg
Acquisitionacq-acq-highresDistinguishing acquisition parameters
Contrast enhancing agentce-ce-gadoliniumContrast-enhanced images
Reconstructionrec-rec-magnitudeReconstruction variants
Directiondir-dir-APFieldmaps, DWI, phase-encoding
Runrun-run-01Multiple identical acquisitions
Echoecho-echo-1Multi-echo sequences
Partpart-part-magMagnitude/phase splits
Spacespace-space-MNI152NLin2009cAsymDerivatives in template space
Descriptiondesc-desc-preprocDerivatives only

Entity ordering in filenames is fixed by the spec (defined in rules.entities in bids_schema.json). See references/bids_specification.md for the complete numbered ordering table. A common subset: sub-<label>[_ses-<label>][_task-<label>][_acq-<label>][_ce-<label>][_rec-<label>][_dir-<label>][_run-<index>][_echo-<index>][_part-<label>][_space-<label>][_desc-<label>]_<suffix>.<extension>

Common suffixes by datatype:

DatatypeSuffixes
anatT1w, T2w, FLAIR, T2starw, T1map, T2map, defacemask
funcbold, cbv, sbref, events, physio, stim
dwidwi, sbref
fmapphasediff, phase1, phase2, magnitude1, magnitude2, fieldmap, epi
perfasl, m0scan, aslcontext
eegeeg, channels, electrodes, events
megmeg, channels, coordsystem, events
ieegieeg, channels, electrodes, coordsystem, events
petpet, blood
Raw lines 199 to 240
Runs code scripts/update_schema.py :203
241### 6. DICOM to BIDS Conversion
243#### HeuDiConv
245HeuDiConv supports Python heuristic-based DICOM-to-BIDS conversion. It supports three usage modes — from fully automatic to fully custom — and handles duplicates, provenance tracking, and sourcedata archiving out of the box.
247**Mode 1: ReproIn (turnkey, recommended for new studies)**
249If scanner protocol names follow the [ReproIn naming convention](https://github.com/repronim/reproin), conversion is fully automatic — no heuristic file to write:
251```bash
252# Turnkey conversion: HeuDiConv maps ReproIn protocol names to BIDS automatically
253heudiconv --files dicom/001 -o /path/to/bids -f reproin --bids --minmeta
254```
256ReproIn protocol names encode BIDS entities directly:
257- `anat-T1w` → `sub-XX/anat/sub-XX_T1w.nii.gz`
258- `func-bold_task-rest` → `sub-XX/func/sub-XX_task-rest_bold.nii.gz`
259- `dwi_dir-AP` → `sub-XX/dwi/sub-XX_dir-AP_dwi.nii.gz`
260- `fmap_dir-PA` → `sub-XX/fmap/sub-XX_dir-PA_epi.nii.gz`
262Session can be set once on the localizer (e.g., `anat-scout_ses-pre`) and ReproIn propagates it to all sequences in that Program. Subject ID is extracted from DICOM metadata. Encode runs explicitly and inspect duplicate/cancelled-run handling; not every repeated series becomes a valid numbered run.
264**Mode 2: Custom heuristic mapping into ReproIn (for existing data)**
266If you already have data with non-ReproIn protocol names, you can write a thin heuristic that maps your names into ReproIn conventions, gaining all ReproIn benefits (automatic entity handling, duplicate management, etc.). See https://github.com/repronim/reproin/issues/18 for a HOWTO.
268**Mode 3: Custom heuristic (full flexibility)**
270For complex mappings, write a Python heuristic file:
272```bash
273# Step 1: Reconnaissance — discover DICOM series
274heudiconv --files dicom/219/itbs/*/*.dcm -o Nifti/ -f convertall -s 219 -c none
276# This creates .heudiconv/219/info/dicominfo.tsv — inspect it to understand
277# what was acquired and map series to BIDS names.
279# Step 2: Write a heuristic file (see references/conversion_tools.md)
281# Step 3: Convert
282heudiconv --files dicom/219/itbs/*/*.dcm -s 219 -ss itbs \
283 -f Nifti/code/heuristic.py -c dcm2niix --bids --minmeta -o Nifti/
284```
286See `references/conversion_tools.md` for complete heuristic file examples.
288**Key points:**
289- HeuDiConv wraps `dcm2niix` for the actual DICOM-to-NIfTI conversion
290- **`--minmeta`**: omit additional scaninfo metadata; it does not remove the BIDS acquisition fields produced by dcm2niix
291- **Duplicate handling**: use `{item:03d}` in templates for auto-numbering when the same protocol is run multiple times; review collisions explicitly instead of relying on overwriting
292- **`.heudiconv/` directory**: created alongside output, stores provenance (heuristic used, dicominfo.tsv, conversion records). Keep it with your data for reproducibility
293- **`sourcedata/`**: DICOM archival depends on heuristic output types (ReproIn requests `dicom`; the custom example requests only `nii.gz`). Preserve source data separately when not archiving
294- **`is_motion_corrected` filter**: use in heuristics to exclude scanner-generated MOCO series (e.g., `if not s.is_motion_corrected`)
295- Both `--files` (explicit paths) and `-d` (template with `{subject}`, `{session}` placeholders) are supported for specifying DICOM input
297#### dcm2bids (Configuration-file-based)
299```bash
300# Step 1: Generate helper output to inspect series
301dcm2bids_helper -d /path/to/dicom
303# Step 2: Create config file (dcm2bids_config.json)
304# Step 3: Convert
305dcm2bids -d /path/to/dicom -p 01 -c dcm2bids_config.json -o /path/to/bids_output
306```
308See `references/conversion_tools.md` for detailed configuration examples.

6. DICOM to BIDS Conversion

HeuDiConv

HeuDiConv supports Python heuristic-based DICOM-to-BIDS conversion. It supports three usage modes — from fully automatic to fully custom — and handles duplicates, provenance tracking, and sourcedata archiving out of the box.

Mode 1: ReproIn (turnkey, recommended for new studies)

If scanner protocol names follow the ReproIn naming convention, conversion is fully automatic — no heuristic file to write:

# Turnkey conversion: HeuDiConv maps ReproIn protocol names to BIDS automatically
heudiconv --files dicom/001 -o /path/to/bids -f reproin --bids --minmeta

ReproIn protocol names encode BIDS entities directly:

  • anat-T1w → sub-XX/anat/sub-XX_T1w.nii.gz
  • func-bold_task-rest → sub-XX/func/sub-XX_task-rest_bold.nii.gz
  • dwi_dir-AP → sub-XX/dwi/sub-XX_dir-AP_dwi.nii.gz
  • fmap_dir-PA → sub-XX/fmap/sub-XX_dir-PA_epi.nii.gz

Session can be set once on the localizer (e.g., anat-scout_ses-pre) and ReproIn propagates it to all sequences in that Program. Subject ID is extracted from DICOM metadata. Encode runs explicitly and inspect duplicate/cancelled-run handling; not every repeated series becomes a valid numbered run.

Mode 2: Custom heuristic mapping into ReproIn (for existing data)

If you already have data with non-ReproIn protocol names, you can write a thin heuristic that maps your names into ReproIn conventions, gaining all ReproIn benefits (automatic entity handling, duplicate management, etc.). See https://github.com/repronim/reproin/issues/18 for a HOWTO.

Mode 3: Custom heuristic (full flexibility)

For complex mappings, write a Python heuristic file:

# Step 1: Reconnaissance — discover DICOM series
heudiconv --files dicom/219/itbs/*/*.dcm -o Nifti/ -f convertall -s 219 -c none

# This creates .heudiconv/219/info/dicominfo.tsv — inspect it to understand
# what was acquired and map series to BIDS names.

# Step 2: Write a heuristic file (see references/conversion_tools.md)

# Step 3: Convert
heudiconv --files dicom/219/itbs/*/*.dcm -s 219 -ss itbs \
  -f Nifti/code/heuristic.py -c dcm2niix --bids --minmeta -o Nifti/

See references/conversion_tools.md for complete heuristic file examples.

Key points:

  • HeuDiConv wraps dcm2niix for the actual DICOM-to-NIfTI conversion
  • **--minmeta**: omit additional scaninfo metadata; it does not remove the BIDS acquisition fields produced by dcm2niix
  • Duplicate handling: use {item:03d} in templates for auto-numbering when the same protocol is run multiple times; review collisions explicitly instead of relying on overwriting
  • **.heudiconv/ directory**: created alongside output, stores provenance (heuristic used, dicominfo.tsv, conversion records). Keep it with your data for reproducibility
  • **sourcedata/**: DICOM archival depends on heuristic output types (ReproIn requests dicom; the custom example requests only nii.gz). Preserve source data separately when not archiving
  • **is_motion_corrected filter**: use in heuristics to exclude scanner-generated MOCO series (e.g., if not s.is_motion_corrected)
  • Both --files (explicit paths) and -d (template with {subject}, {session} placeholders) are supported for specifying DICOM input

dcm2bids (Configuration-file-based)

# Step 1: Generate helper output to inspect series
dcm2bids_helper -d /path/to/dicom

# Step 2: Create config file (dcm2bids_config.json)
# Step 3: Convert
dcm2bids -d /path/to/dicom -p 01 -c dcm2bids_config.json -o /path/to/bids_output

See references/conversion_tools.md for detailed configuration examples.

Raw lines 241 to 309
310### 7. Metadata Sidecars
312Required acquisition metadata must be available through applicable JSON sidecars. Metadata fields follow the inheritance principle: a sidecar at a higher directory level applies to all matching files below.
314**Inheritance example:**
315```
316my_dataset/
317 task-rest_bold.json # Applies to ALL rest BOLD files
318 sub-01/
319 func/
320 sub-01_task-rest_bold.json # Overrides/extends for sub-01 only
321```
323**Illustrative metadata only; use measured values and match the image dimensions:**
325For **func (BOLD)**:
326```json
328 "RepetitionTime": 2.0,
329 "TaskName": "rest",
330 "PhaseEncodingDirection": "j-",
331 "TotalReadoutTime": 0.05,
332 "SliceTiming": [0, 0.5, 1.0, 1.5],
333 "EchoTime": 0.03
335```
337For **anat**:
338```json
340 "MagneticFieldStrength": 3,
341 "Manufacturer": "Siemens",
342 "ManufacturersModelName": "Prisma",
343 "RepetitionTime": 2.3,
344 "EchoTime": 0.00293,
345 "FlipAngle": 8
347```
349For **DWI**:
350```json
352 "PhaseEncodingDirection": "j-",
353 "TotalReadoutTime": 0.05,
354 "EchoTime": 0.089,
355 "RepetitionTime": 3.4,
356 "MultipartID": "dwi_1"
358```
360**Key points:**
361- `dcm2niix` auto-generates most sidecar fields from DICOM headers
362- `TaskName` and either `RepetitionTime` or `VolumeTiming` are required for BOLD; timing alternatives have additional constraints
363- `SliceTiming` is essential for slice-timing correction in fMRI preprocessing
364- `PhaseEncodingDirection` and `TotalReadoutTime` (or `EffectiveEchoSpacing`) are needed for distortion correction
365- See `references/metadata_fields.md` for comprehensive field reference

7. Metadata Sidecars

Required acquisition metadata must be available through applicable JSON sidecars. Metadata fields follow the inheritance principle: a sidecar at a higher directory level applies to all matching files below.

Inheritance example:

my_dataset/
  task-rest_bold.json           # Applies to ALL rest BOLD files
  sub-01/
    func/
      sub-01_task-rest_bold.json  # Overrides/extends for sub-01 only

Illustrative metadata only; use measured values and match the image dimensions:

For func (BOLD):

{
    "RepetitionTime": 2.0,
    "TaskName": "rest",
    "PhaseEncodingDirection": "j-",
    "TotalReadoutTime": 0.05,
    "SliceTiming": [0, 0.5, 1.0, 1.5],
    "EchoTime": 0.03
}

For anat:

{
    "MagneticFieldStrength": 3,
    "Manufacturer": "Siemens",
    "ManufacturersModelName": "Prisma",
    "RepetitionTime": 2.3,
    "EchoTime": 0.00293,
    "FlipAngle": 8
}

For DWI:

{
    "PhaseEncodingDirection": "j-",
    "TotalReadoutTime": 0.05,
    "EchoTime": 0.089,
    "RepetitionTime": 3.4,
    "MultipartID": "dwi_1"
}

Key points:

  • dcm2niix auto-generates most sidecar fields from DICOM headers
  • TaskName and either RepetitionTime or VolumeTiming are required for BOLD; timing alternatives have additional constraints
  • SliceTiming is essential for slice-timing correction in fMRI preprocessing
  • PhaseEncodingDirection and TotalReadoutTime (or EffectiveEchoSpacing) are needed for distortion correction
  • See references/metadata_fields.md for comprehensive field reference
Raw lines 310 to 366
367### 8. Events Files for Task fMRI
369Represent recorded task events with `_events.tsv`; not every task has recorded events (for example resting state):
371```
372onset duration trial_type response_time
3730.0 0.5 face 0.435
3742.5 0.5 house 0.367
3755.0 0.5 face 0.512
3767.5 0.5 scrambled 0.298
377```
379**Required columns:**
380- `onset` - onset time in seconds relative to the first stored data point (negative values are allowed)
381- `duration` - duration in seconds (use `0` for instantaneous events and `n/a` only if unavailable)
383**Optional columns:**
384- `trial_type` - categorical label for condition
385- `response_time` - RT in seconds
386- Custom columns as needed (with descriptions in corresponding `.json` sidecar)

8. Events Files for Task fMRI

Represent recorded task events with _events.tsv; not every task has recorded events (for example resting state):

onset	duration	trial_type	response_time
0.0	0.5	face	0.435
2.5	0.5	house	0.367
5.0	0.5	face	0.512
7.5	0.5	scrambled	0.298

Required columns:

  • onset - onset time in seconds relative to the first stored data point (negative values are allowed)
  • duration - duration in seconds (use 0 for instantaneous events and n/a only if unavailable)

Optional columns:

  • trial_type - categorical label for condition
  • response_time - RT in seconds
  • Custom columns as needed (with descriptions in corresponding .json sidecar)
Raw lines 367 to 387
388### 9. Participants File
390```
391participant_id age sex group handedness
392sub-01 25 M control right
393sub-02 30 F patient left
394sub-03 28 M control right
395```
397The `participants.json` sidecar describes columns:
399```json
401 "age": {
402 "Description": "Age of the participant at time of scanning",
403 "Units": "year"
404 },
405 "sex": {
406 "Description": "Biological sex",
407 "Levels": {
408 "M": "male",
409 "F": "female"
410 }
411 },
412 "group": {
413 "Description": "Experimental group",
414 "Levels": {
415 "control": "Healthy control",
416 "patient": "Patient group"
417 }
418 },
419 "handedness": {
420 "Description": "Dominant hand",
421 "Levels": {
422 "right": "Right-handed",
423 "left": "Left-handed",
424 "ambidextrous": "Ambidextrous"
425 }
426 }
428```

9. Participants File

participant_id	age	sex	group	handedness
sub-01	25	M	control	right
sub-02	30	F	patient	left
sub-03	28	M	control	right

The participants.json sidecar describes columns:

{
    "age": {
        "Description": "Age of the participant at time of scanning",
        "Units": "year"
    },
    "sex": {
        "Description": "Biological sex",
        "Levels": {
            "M": "male",
            "F": "female"
        }
    },
    "group": {
        "Description": "Experimental group",
        "Levels": {
            "control": "Healthy control",
            "patient": "Patient group"
        }
    },
    "handedness": {
        "Description": "Dominant hand",
        "Levels": {
            "right": "Right-handed",
            "left": "Left-handed",
            "ambidextrous": "Ambidextrous"
        }
    }
}
Raw lines 388 to 429
430### 10. BIDS Derivatives
432Processed outputs go under a `derivatives/` directory:
434```
435my_dataset/
436 derivatives/
437 fmriprep-24.1.0/
438 dataset_description.json # DatasetType: "derivative"
439 sub-01/
440 anat/
441 sub-01_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz
442 sub-01_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz
443 func/
444 sub-01_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz
445 sub-01_task-rest_desc-confounds_timeseries.tsv
446 mriqc-24.0.0/
447 dataset_description.json
448 sub-01/
449 anat/
450 sub-01_T1w.html
451 func/
452 sub-01_task-rest_bold.html
453 group_T1w.tsv
454 group_bold.tsv
455```
457**Derivative conventions:**
458- `space-<label>` - template/reference space (e.g., `MNI152NLin2009cAsym`, `T1w`)
459- `desc-<label>` - description of processing (e.g., `preproc`, `brain`, `smoothed`)
460- `res-<label>` - resolution label; document its meaning in `Resolution` metadata (the label need not be a voxel size)
461- Each pipeline gets its own directory under `derivatives/`
462- Must have its own `dataset_description.json` with `GeneratedBy`

10. BIDS Derivatives

Processed outputs go under a derivatives/ directory:

my_dataset/
  derivatives/
    fmriprep-24.1.0/
      dataset_description.json      # DatasetType: "derivative"
      sub-01/
        anat/
          sub-01_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz
          sub-01_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz
        func/
          sub-01_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz
          sub-01_task-rest_desc-confounds_timeseries.tsv
    mriqc-24.0.0/
      dataset_description.json
      sub-01/
        anat/
          sub-01_T1w.html
        func/
          sub-01_task-rest_bold.html
      group_T1w.tsv
      group_bold.tsv

Derivative conventions:

  • space-<label> - template/reference space (e.g., MNI152NLin2009cAsym, T1w)
  • desc-<label> - description of processing (e.g., preproc, brain, smoothed)
  • res-<label> - resolution label; document its meaning in Resolution metadata (the label need not be a voxel size)
  • Each pipeline gets its own directory under derivatives/
  • Must have its own dataset_description.json with GeneratedBy
Raw lines 430 to 463
464### 11. PyBIDS: Advanced Usage
466```python
467from bids import BIDSLayout
468from bids.layout import BIDSLayoutIndexer
470# Cache the layout index for faster repeated access
471layout = BIDSLayout("/path/to/dataset", database_path="/path/to/pybids-cache")
473# Existing cache directories are reused; set reset_database=True after file changes.
475# Include derivatives
476layout = BIDSLayout(
477 "/path/to/dataset",
478 derivatives=["/path/to/dataset/derivatives/fmriprep-24.1.0"]
481# Get derivative files
482preproc = layout.get(
483 subject="01",
484 task="rest",
485 desc="preproc",
486 suffix="bold",
487 space="MNI152NLin2009cAsym",
488 extension=".nii.gz",
489 return_type="filename"
492# Get confound regressors
493confounds = layout.get(
494 subject="01",
495 task="rest",
496 desc="confounds",
497 suffix="timeseries",
498 extension=".tsv",
499 return_type="filename"
502# Build BIDS path from entities
503from bids import BIDSLayout
504layout = BIDSLayout("/path/to/dataset")
505path = layout.build_path(
506 {
507 "subject": "01",
508 "session": "pre",
509 "task": "rest",
510 "suffix": "bold",
511 "extension": ".nii.gz",
512 "datatype": "func"
513 },
514 validate=True
517# Get all files for a subject as a DataFrame
518import pandas as pd
519files_df = layout.to_df()
520sub01_df = files_df[files_df["subject"] == "01"]
521```

11. PyBIDS: Advanced Usage

from bids import BIDSLayout
from bids.layout import BIDSLayoutIndexer

# Cache the layout index for faster repeated access
layout = BIDSLayout("/path/to/dataset", database_path="/path/to/pybids-cache")

# Existing cache directories are reused; set reset_database=True after file changes.

# Include derivatives
layout = BIDSLayout(
    "/path/to/dataset",
    derivatives=["/path/to/dataset/derivatives/fmriprep-24.1.0"]
)

# Get derivative files
preproc = layout.get(
    subject="01",
    task="rest",
    desc="preproc",
    suffix="bold",
    space="MNI152NLin2009cAsym",
    extension=".nii.gz",
    return_type="filename"
)

# Get confound regressors
confounds = layout.get(
    subject="01",
    task="rest",
    desc="confounds",
    suffix="timeseries",
    extension=".tsv",
    return_type="filename"
)

# Build BIDS path from entities
from bids import BIDSLayout
layout = BIDSLayout("/path/to/dataset")
path = layout.build_path(
    {
        "subject": "01",
        "session": "pre",
        "task": "rest",
        "suffix": "bold",
        "extension": ".nii.gz",
        "datatype": "func"
    },
    validate=True
)

# Get all files for a subject as a DataFrame
import pandas as pd
files_df = layout.to_df()
sub01_df = files_df[files_df["subject"] == "01"]
Raw lines 464 to 522
523### 12. BIDS-Apps
525BIDS-Apps are containerized analysis pipelines that accept BIDS datasets as input:
527Illustrative container invocation; replace the image tag, paths, license and resources
528with the selected app release's requirements. Images are not executed by this skill's tests.
530```bash
531docker run --rm \
532 -v /path/to/bids:/data:ro -v /path/to/output:/out \
533 -v /path/to/license.txt:/license.txt:ro \
534 nipreps/fmriprep:<pinned-version> /data /out participant \
535 --participant-label 01 --fs-license-file /license.txt
536```
538Consult the current [fMRIPrep](https://fmriprep.org/en/stable/usage.html),
539[MRIQC](https://mriqc.readthedocs.io/en/stable/running.html), and
540[QSIPrep](https://qsiprep.readthedocs.io/en/latest/) CLI documentation.
541Check each app's supported analysis levels and participant flag spelling.
543**BIDS-App interface convention:**
544```
545bids-app input_dataset output_dir {participant|group} [options]
546```
548- `participant` level: runs per-subject
549- `group` level: runs across all subjects (aggregation/group stats)

12. BIDS-Apps

BIDS-Apps are containerized analysis pipelines that accept BIDS datasets as input:

Illustrative container invocation; replace the image tag, paths, license and resources with the selected app release's requirements. Images are not executed by this skill's tests.

docker run --rm \
  -v /path/to/bids:/data:ro -v /path/to/output:/out \
  -v /path/to/license.txt:/license.txt:ro \
  nipreps/fmriprep:<pinned-version> /data /out participant \
  --participant-label 01 --fs-license-file /license.txt

Consult the current fMRIPrep, MRIQC, and QSIPrep CLI documentation. Check each app's supported analysis levels and participant flag spelling.

BIDS-App interface convention:

bids-app input_dataset output_dir {participant|group} [options]
  • participant level: runs per-subject
  • group level: runs across all subjects (aggregation/group stats)
Raw lines 523 to 550
551## Review scope
553Reviewed against BIDS 1.11.2, PyBIDS 0.22.0, validator wrapper 3.0.2, HeuDiConv
5541.5.1 and dcm2bids 3.3.1 on 2026-09-30. Local synthetic tests cover PyBIDS
555queries/inheritance/cache/derivatives and the conversion mapping APIs. Commands
556requiring scanner DICOMs, containers or a GUI are illustrative; no real acquisition
557conversion or BIDS-App processing was performed.

Review scope

Reviewed against BIDS 1.11.2, PyBIDS 0.22.0, validator wrapper 3.0.2, HeuDiConv 1.5.1 and dcm2bids 3.3.1 on 2026-09-30. Local synthetic tests cover PyBIDS queries/inheritance/cache/derivatives and the conversion mapping APIs. Commands requiring scanner DICOMs, containers or a GUI are illustrative; no real acquisition conversion or BIDS-App processing was performed.

Raw lines 551 to 557