This file provides instructions for AI coding agents and human maintainers working on ASLPrep, a BIDS App for preprocessing Arterial Spin Labeling (ASL) MRI data.
The following conventions apply equally to qsiprep, qsirecon, xcp_d, and aslprep. All four are PennLINC BIDS Apps built on the NiPreps stack.
- These projects belong to the NiPreps ecosystem and follow its community guidelines.
- Core dependencies include nipype (workflow engine), niworkflows (reusable workflow components), nireports (visual reports), pybids (BIDS dataset querying), and nibabel (neuroimaging I/O).
- All four apps are containerized via Docker and distributed on Docker Hub under the
pennlinc/namespace. - Contributions follow the NiPreps contributing guidelines.
Every PennLINC BIDS App follows this execution flow:
CLI (parser.py / run.py)
-> config singleton (config.py, serialized as ToML)
-> workflow graph construction (workflows/*.py)
-> Nipype interfaces (interfaces/*.py)
-> BIDS-compliant derivative outputs
- CLI (
<pkg>/cli/):parser.pydefines argparse arguments;run.pyis the entry point;workflow.pybuilds the execution graph;version.pyhandles--version. - Config (
<pkg>/config.py): A singleton module with class-based sections (environment,execution,workflow,nipype,seeds). Config is serialized to ToML and passed across processes via the filesystem. Access settings asconfig.section.setting. - Workflows (
<pkg>/workflows/): Built usingnipype.pipeline.engine(pe.Workflow,pe.Node,pe.MapNode). UseLiterateWorkflowfromniworkflows.engine.workflowsfor auto-documentation. Every workflow factory function must be namedinit_<descriptive_name>_wf. - Interfaces (
<pkg>/interfaces/): Custom Nipype interfaces wrapping external tools or Python logic. Follow standard Nipype patterns: define_InputSpec/_OutputSpecwithBaseInterfaceInputSpec/TraitedSpec, implement_run_interface(). - Utilities (
<pkg>/utils/): Shared helper functions. BIDS-specific helpers live inutils/bids.py. - Reports (
<pkg>/reports/): HTML report generation using nireports. - Data (
<pkg>/data/): Static package data (config files, templates, atlases). Accessed viaimportlib.resourcesor theacrespackage. - Tests (
<pkg>/tests/): Pytest-based. Unit tests run without external data. Integration tests are gated behind pytest markers and are skipped by default.
- Every workflow factory function must be named
init_<name>_wfand return aWorkflowobject. - Use
LiterateWorkflow(fromniworkflows.engine.workflows) to enable automatic workflow graph documentation. - Define
inputnodeandoutputnodeasniu.IdentityInterfacenodes to declare the workflow's external API. - Connect nodes using
workflow.connect([(source, dest, [('out_field', 'in_field')])])syntax. - Add
# fmt:skipafter multi-lineworkflow.connect()calls to prevent ruff from reformatting them. - Include a docstring with
Workflow Graphand.. workflow::Sphinx directive for auto-generated documentation. - Use
configmodule values (not function parameters) for global settings inside workflow builders.
- Input/output specs use Nipype traits (
File,traits.Bool,traits.Int, etc.). mandatory = Truefor required inputs; providedesc=for all traits.- Implement
_run_interface(self, runtime)-- neverrun(). - Return
runtimefrom_run_interface. - Set outputs via
self._results['field'] = value.
from <pkg> import config
# Read a setting
work_dir = config.execution.work_dir
# Serialize to disk
config.to_filename(path)
# Load from disk (in a subprocess)
config.load(path)The config module is the single source of truth for runtime parameters. Never pass global settings as function arguments when they are available via config.
- Unit tests: Files named
test_*.pyin<pkg>/tests/. Must not require external neuroimaging data or network access. - Integration tests: Decorated with
@pytest.mark.<marker_name>. Excluded by default viaaddoptsinpyproject.toml. Require Docker or pre-downloaded test datasets. - Fixtures: Defined in
conftest.py. Common fixtures includedata_dir,working_dir,output_dir, anddatasets. - Coverage: Configured in
pyproject.tomlunder[tool.coverage.run]and[tool.coverage.report].
- Built with Sphinx using
sphinx_rtd_theme. - Source files in
docs/. - Workflow graphs are auto-rendered via
.. workflow::directives that callinit_*_wffunctions. - API docs generated via
sphinxcontrib-apidoc. - Bibliography managed with
sphinxcontrib-bibtexandboilerplate.bib.
- Each app has a base image with runtime dependencies and a main Dockerfile that installs the Python environment and the app itself.
- ASLPrep, fMRIPrep, and XCP-D have migrated to Pixi-based multi-stage Docker builds:
Dockerfile.baseowns non-Python/non-conda runtime dependencies, whileDockerfileuses pixi to createbuild,test, and production targets frompixi.lock. qsiprep and qsirecon still use micromamba +pip install. - Base image naming: ASLPrep and XCP-D use date-based tags (
pennlinc/<pkg>-base:<YYYYMMDD>); qsiprep and qsirecon usepennlinc/<pkg>_build:<version>. - Entrypoint is the CLI binary in the pixi environment (e.g.,
/app/.pixi/envs/<env>/bin/<pkg>). - Labels follow the
org.label-schemaconvention.
- Versions are derived from git tags via
hatch-vcs(VCS-based versioning). - GitHub Releases use auto-generated changelogs configured in
.github/release.yml. - Release categories: Breaking Changes, New Features, Deprecations, Bug Fixes, Other.
- Docker images are built and pushed via CI on tagged releases.
- Formatter:
ruff format(target: all four repos). - Linter:
ruff checkwith an extended rule set (F, E, W, I, UP, YTT, S, BLE, B, A, C4, DTZ, T10, EXE, FA, ISC, ICN, PT, Q). - Import sorting: Handled by ruff's
Irule (isort-compatible). - Pre-commit: Uses
ruff-pre-commithooks for both linting and formatting. - Black is disabled:
[tool.black] exclude = ".*"in repos that have migrated to ruff.
- All outputs must conform to the BIDS Derivatives specification.
- Use
pybids.BIDSLayoutfor querying input datasets. - Use
DerivativesDataSink(from the project's interfaces or niworkflows) for writing BIDS-compliant output files. - Entity names, suffixes, and extensions must match the BIDS specification.
ASLPrep is a BIDS App for preprocessing Arterial Spin Labeling (ASL) perfusion MRI data. It handles:
- Anatomical preprocessing (via smriprep/fmriprep infrastructure)
- ASL reference image estimation
- Head motion correction for ASL time series
- Susceptibility distortion correction (via sdcflows)
- Cerebral blood flow (CBF) computation for single-PLD and multi-PLD acquisitions
- Support for PCASL and PASL labeling schemes
- Confound estimation
- Parcellation-based CBF summarization
- QC metric aggregation (
aslprep-combineqcCLI tool)
| Item | Value |
|---|---|
| Package name | aslprep |
| Default branch | main |
| Entry point | aslprep.cli.run:main |
| Python requirement | >=3.10 |
| Build backend | hatchling + hatch-vcs + nipreps-versions |
| Linter | ruff ~= 0.15.0 |
| Pre-commit | Yes (ruff v0.15.0) |
| Tox | Yes |
| Docker base | pennlinc/aslprep-base:<YYYYMMDD> |
| Dockerfile | Multi-stage pixi build |
aslprep/workflows/asl/: ASL-specific workflows organized by processing stage:fit.py: Model fittingbase.py: Main ASL workflow orchestrationcbf.py: Cerebral blood flow computationconfounds.py: Confound estimationhmc.py: Head motion correctionreference.py: Reference image estimationapply.py: Transform applicationresampling.py: Resampling to standard spacesoutputs.py: BIDS derivative output writingplotting.py: QC visualization
aslprep/workflows/base.py: Top-level workflow (subject iteration)aslprep/workflows/segmentation.py: Brain segmentationaslprep/interfaces/cbf.py: CBF computation interfacesaslprep/interfaces/parcellation.py: Atlas parcellation interfacesaslprep/utils/cbf.py: CBF calculation utilitiesaslprep/utils/asl.py: ASL-specific helper functions
ASLPrep has the deepest dependency chain of the four repos:
fmriprep ~= 25.2.2: Reuses fMRIPrep's anatomical and fieldmap workflowssdcflows >= 2.15.0: Susceptibility distortion correctionsmriprep >= 0.19.2: Structural MRI preprocessingniworkflows >= 1.14.4: Shared workflow componentsnitransforms >= 25.0.1: Spatial transforms
When updating these dependencies, check for breaking API changes across the stack.
ASLPrep imports __version__ directly from _version.py.
ASLPrep names its test dependencies tests (plural) in pyproject.toml, consistent with the other three repos.
ASLPrep's tox config references python scripts/fetch_templates.py as a commands_pre step before tests. This script downloads the required TemplateFlow templates and is also used by the Docker build's templates stage.
ASLPrep now follows the same CI trigger-condition pattern as XCP-D:
-
GitHub lockfile workflow (
.github/workflows/pixi-lock.yml):- Trigger: every
pull_request_targetevent. - Always runs checkout + "latest commit touched dependency files?" check.
- Lockfile update steps run only when latest commit touched
pyproject.tomlorpixi.lock. - Lockfile push-back is restricted to same-repo PR branches; fork PRs do not push.
- Trigger: every
-
CircleCI image workflow (
.circleci/config.yml):- Image rebuild trigger uses cache marker restoration keyed by
Dockerfile+pixi.lockchecksums (build-v3-...). - Editing
Dockerfileorpixi.lockinvalidates cache marker and triggers production/test image rebuild. - Base image rebuild remains controlled by
BASE_IMAGEmanifest existence;Dockerfile.baseedits alone do not force rebuild when tag exists. - Branch/tag filters are workflow-level (not file-path filters):
image_prepon all branches/tags, deploy only onmainand tags.
- Image rebuild trigger uses cache marker restoration keyed by
ASLPrep has 4 suppressed ruff rules:
UP031: Old-style string formatting (to be fixed incrementally)S311: Random not for crypto (intentional)ISC001: Implicit string concatenation (conflicts with formatter)S603: Subprocess with shell=True (trusted commands only)
When working on ASL workflows, know these domain terms:
- PLD (Post-Labeling Delay): Time between labeling and image acquisition
- CBF (Cerebral Blood Flow): The primary output metric
- PCASL (Pseudo-Continuous ASL): A labeling technique
- PASL (Pulsed ASL): Another labeling technique
- Single-PLD vs Multi-PLD: Whether one or multiple delay times are used
- Label-control pairs: ASL acquires alternating labeled and control images
This roadmap covers harmonization work across all four PennLINC BIDS Apps (qsiprep, qsirecon, xcp_d, aslprep) to reduce maintenance burden.
- Migrate qsirecon from flake8+black+isort to ruff -- copy the
[tool.ruff]config from xcp_d'spyproject.tomland remove[tool.black],[tool.isort],[tool.flake8]sections. - Add
.pre-commit-config.yamlto qsirecon -- identical to the config used by qsiprep, xcp_d, and aslprep. - Add
tox.inito qsirecon -- copy from qsiprep or xcp_d (they are identical). - Add
.github/dependabot.ymlto qsirecon. - Reformat qsirecon codebase -- run
ruff formatto switch from double quotes to single quotes.
- Rename qsiprep default branch from
mastertomainand update.github/workflows/lint.yml. Rename aslprep test extras from-- Done.testtotests- Converge on version management -- recommend the simpler
_version.pydirect-import pattern (used by qsiprep/qsirecon). ASLPrep has completed this migration; only xcp_d still uses__about__.py. - Pin the same ruff version in all four repos' dev dependencies and
.pre-commit-config.yaml. - Harmonize ruff ignore lists -- adopt xcp_d's minimal set (
S105,S311,S603) as the target; fix suppressed rules in qsiprep and aslprep incrementally.
- Extract a reusable GitHub Actions workflow for lint + codespell + build checks, hosted in a shared repo (e.g.,
PennLINC/.github). - Standardize Dockerfile patterns -- ASLPrep, fMRIPrep, and XCP-D have adopted pixi-based multi-stage Docker builds. Migrate qsiprep and qsirecon to the same pattern.
- Create a shared
pennlinc-stylepackage or cookiecutter template providingpyproject.tomllint/test config,.pre-commit-config.yaml,tox.ini, and CI workflows. - Evaluate
nipreps-versionscalver -- theraw-options = { version_scheme = "nipreps-calver" }line is commented out in all four repos. Decide whether to adopt it.