This repository is a template for implementing a BrkRaw dataset hook (rules/specs/transforms + Python hook entry points).
- Copy this template into a new repository, then update
pyproject.tomlmetadata (name, entry point, dependencies) before publishing to PyPI. - Implement the dataset-specific hook in
src/brkraw_hook_template/hook.py. BrkRaw expects aHOOKdict that exposesget_dataobjandget_affine(and optionallyconvertfor a richer workflow). - Declare hook assets in
src/brkraw_hook_template/brkraw_hook.yaml, which references package-local directories likesrc/brkraw_hook_template/docs/,src/brkraw_hook_template/rules/,src/brkraw_hook_template/specs/, andsrc/brkraw_hook_template/transforms/. - Use
src/brkraw_hook_template/docs/as a writing template: define scope, document the rule/spec/transform flow, and record conversion notes and limitations. - Keep
build-backendonsetuptools/wheel. BrkRaw still has fragile file-fetch paths when hooks rely on hatch-based installers. - Optional maintainer tooling:
.vscode/tasks.jsoncontains release task placeholders,.github/workflows/contains CI/publish placeholders, andtests/contains a minimal hook install test.
- BrkRaw loads datasets via
from brkraw import load(seebrkraw/src/brkraw/__init__.py). The loader exposesget_scan(scan_id); hook code should operate on BrkRawScanobjects. get_dataobj(scan, reco_id, **kwargs)andget_affine(scan, reco_id, space=..., **kwargs)are called during conversion to resolve the raw data and spatial orientation.- If conversion requires custom NIfTI assembly or multi-stage processing, implement
convert(scan, dataobj, affine, **kwargs)and expose it viaHOOK. This function receives the outputs ofget_dataobjandget_affineand should return a NIfTI image object (or anything supporting.to_filename()). - Always accept
**kwargs.brkraw convert(seebrkraw/src/brkraw/cli/commands/convert.py) forwards--hook-arg name:key=valueintohook_args_by_name={...}and ultimately into your hook functions (e.g.,--hook-arg template:offset=5). - Keep responsibilities separated:
rules/*.yamlfor detection/routing,specs/*.yamlfor metadata mapping,transforms/*.pyfor sanitisation helpers. Document shared transforms insrc/brkraw_hook_template/docs/(seesrc/brkraw_hook_template/docs/rule_spec_transform.md).
If your hook exposes get_affine, do not "simplify" the API. Prefer a thin wrapper that forwards BrkRaw's full get_affine() signature so downstream users can request the correct coordinate space and apply subject overrides consistently.
In particular, get_affine should accept and forward:
space("raw" | "scanner" | "subject_ras")override_subject_type,override_subject_pose(valid only forspace="subject_ras")decimals- extra kwargs (for post-transforms like
flip_x/flip_y/flip_z,rad_x/rad_y/rad_zif supported)
Recommended practice:
- Do not invent a new affine resolver inside the hook.
- Instead, follow the reference implementation in the main BrkRaw repo:
BrkRaw/brkraw -> src/brkraw/apps/loader/helper.py:get_affine - The goal is to ensure the hook output is aligned the same way as online reconstruction (2dseq).
If you need a concrete validation pattern, see the example notebooks in brkraw-sordino/notebooks (they demonstrate how to sanity-check alignment against online recon outputs).
As AI-assisted development workflows continue to emerge, some contributors may choose to use AI agents when implementing or extending BrkRaw hooks. This section provides practical guidance on how to do so without breaking BrkRaw's extension model or hook contract.
When prompting an AI agent, be explicit about the boundaries it must respect. In particular:
-
In your prompt, point the agent to the base hook repository (
git@github.com:BrkRaw/brkraw-hook.git) and to at least one real, working hook (for examplebrkraw-mrsorbrkraw-sordino). -
Call out the non-negotiables: BrkRaw loads scans via
load(), hook code must operate onScanobjects, and the hook must exposeHOOK = {'get_dataobj': ..., 'get_affine': ...}(andconvertonly if required).from brkraw import load loader = load("/path/to/source") scan = loader.get_scan(scan_id) # metadata resolution is usually handled via spec, not directly in the hook metadata = scan.get_metadata(reco_id=1) dataobj = scan.get_dataobj(reco_id=1) affine = scan.get_affine(reco_id=1)
-
Make it clear that all hook options must be wired through
--hook-arg(kwargs), not by inventing new CLI flags. -
If the workflow requires more than
get_dataobjandget_affine, explicitly ask the agent to implement a realconvert()method, not a placeholder.
A concrete example prompt that works well is:
"Use
git@github.com:BrkRaw/brkraw-hook.gitas the base hook. Mimicbrkraw-mrs: implementHOOK = {'get_dataobj': ..., 'get_affine': ..., 'convert': ...}inhook.py, operate onScanobjects frombrkraw.load(...).get_scan(scan_id), and use hook args (from--hook-arg) to enable optional preprocessing. Provide rule/spec/transform files that match the detection logic, and include a completeconvert()implementation that returns a nibabel image."
- Rules should be the first line of defense: keep them focused on scan identifiers, modality flags, or Bruker sequence/method markers, then route to the right spec/hook.
info_specdrives the BrkRaw info parser (what appears inbrkraw info), whilemetadata_specfeedsget_metadataand sidecar generation. Both should map raw headers to BrkRaw metadata keys and call intotransforms/helpers for sanitisation (trim strings, convert units, inject constants).- Document transforms that are shared between specs so future hooks can reuse them; check
src/brkraw_hook_template/docs/rule_spec_transform.mdfor a general flow chart and template snippets. - Tests should exercise the hook integration path (install the hook, ensure rules/specs/transforms register) rather than only unit-testing isolated helpers.
If your hook exposes get_affine, do not "simplify" the API. Prefer a thin wrapper that forwards BrkRaw's full get_affine() signature so downstream users can request the correct coordinate space and apply subject overrides consistently.
In particular, get_affine should accept and forward:
space("raw" | "scanner" | "subject_ras")override_subject_type,override_subject_pose(valid only forspace="subject_ras")decimals- extra kwargs (for post-transforms like
flip_x/flip_y/flip_z,rad_x/rad_y/rad_zif supported)
Recommended practice:
- Do not invent a new affine resolver inside the hook.
- Instead, follow the reference implementation in the main BrkRaw repo:
BrkRaw/brkraw -> src/brkraw/apps/loader/helper.py:get_affine - The goal is to ensure the hook output is aligned the same way as online reconstruction (2dseq).
If you need a concrete validation pattern, see the example notebooks in brkraw-sordino/notebooks (they demonstrate how to sanity-check alignment against online recon outputs).