Metadata: Info, Tags, and Notes
Flywheel containers support three distinct types of metadata: info, tags, and notes. Each serves a different purpose and has a different structure.
| Type | Structure | Purpose | Supported on |
|---|---|---|---|
info | Arbitrary JSON dict (nested allowed) | Store structured key-value data for programmatic use | Project, Subject, Session, Acquisition, Analysis, File |
tags | List of strings | Label containers for filtering and search | Group, Project, Subject, Session, Acquisition, Analysis, File |
notes | List of timestamped text entries | Record freeform human-readable observations | Project, Subject, Session, Acquisition, Analysis |
All three types are accessed through methods on the container object. You must retrieve a live container from the SDK (not a search result stub) before calling write methods.
Tip
Avoid storing values directly at the top level of info. For example, storing MaxMotion, MaxHeartRate, and MaxRespiration as separate top-level keys (info.MaxMotion, info.MaxHeartRate) results in a flat, hard-to-read structure. Instead, nest related values under a descriptive parent key:
acquisition.update_info(
{
"Measurements": {
"MaxMotion": 0.42,
"MaxHeartRate": 72,
"MaxRespiration": 18,
}
}
)
This keeps the top level of info clean and makes the data easier to interpret.
Info
info is a free-form JSON dictionary attached to a container or file. Use it to store structured metadata that scripts or gears need to read back programmatically — for example, BIDS sidecar fields, pipeline parameters, or derived values.
Info supports arbitrary nesting. Keys that contain $ or . are sanitized by the SDK (replaced with - and _ respectively), so avoid those characters in key names.
Reading info
Access the current info via the .info attribute on the container object:
If the container was fetched via a finder or search, it may not include the full info payload. Call reload() to ensure you have the latest data:
Adding and merging keys
Warning
update_info() only merges at the top level. For a given top-level key, the entire value is replaced — not merged recursively. If you pass {"header": {"nifti": {"dim": [3, 64, 64, 32]}}}, the entire header key is replaced with the new value, removing any existing fields inside header that were not included. Use replace_info() when you want to explicitly overwrite, and read the current value before calling update_info() on nested structures if you need to preserve existing nested keys.
update_info() merges the provided dict into the existing info. It does not remove keys that are not in the new dict:
This also works with nested structures:
acquisition.update_info({"header": {"nifti": {"dim": [3, 64, 64, 32]}}})
To avoid overwriting an unrelated nested key when merging into a nested structure, read the current value first:
Replacing all info
replace_info() overwrites the entire info dict. Any keys not included in the new dict are lost:
Use replace_info() when you want a clean slate, and update_info() when you want to add or update individual keys.
Removing keys
delete_info() removes one or more keys. Pass key names as positional arguments:
Container info method summary
| Method | Effect |
|---|---|
container.info | Read the current info dict |
container.update_info({"key": "value"}) | Merge keys into existing info |
container.replace_info({"key": "value"}) | Overwrite entire info dict |
container.delete_info("key") | Remove one or more keys |
File Info
Files also carry info. You can access and modify file info through the parent container using the filename, or directly on the file object if you have it.
Reading file info
Writing file info via the parent container
--8 < --"test_docs_core_concepts.py:write_file_info_via_container"
Writing file info directly on the file object
If you have a FileEntry object (from acquisition.files), it exposes the same methods without needing the filename:
file_entry = acquisition.files[0]
file_entry.update_info({"EchoTime": 0.03})
file_entry.replace_info({"EchoTime": 0.03})
file_entry.delete_info("EchoTime")
File info method summary
| Called on | Method | Effect |
|---|---|---|
| Container | container.replace_file_info(filename, {...}) | Overwrite entire file info |
| Container | container.update_file_info(filename, {...}) | Merge keys into file info |
| Container | container.delete_file_info(filename, "key") | Remove keys from file info |
| File object | file.replace_info({...}) | Overwrite entire file info |
| File object | file.update_info({...}) | Merge keys into file info |
| File object | file.delete_info("key") | Remove keys from file info |
Tags
Tags are short string labels attached to containers. Use them to flag status, mark subsets for processing, or enable filtering in finder queries.
Available tags in a Flywheel instance are managed at the Group level. Adding a tag that does not exist in the group will create it.
Reading tags
Adding and removing tags
Filtering with tags
Tags are indexed and can be used in finder filter expressions. See Core Concepts: Finders for full filter syntax.
Tag method summary
| Method | Effect |
|---|---|
container.add_tag("label") | Add a tag |
container.delete_tag("label") | Remove a tag |
container.rename_tag("old", "new") | Rename a tag in place |
Files also support tags through file.add_tag(), file.delete_tag(), and file.rename_tag().
Notes
Notes are timestamped, user-attributed free-text entries. Each note records who wrote it and when. Use notes to document decisions, flag issues for human review, or maintain an audit trail on a container.
Notes are stored as a list under container.notes. Each note object has an .id, a .text, a .created timestamp, and a .user field identifying the author.
Reading notes
Adding a note
Deleting a note
You need the note's .id to delete it. Retrieve the notes list and select the one you want to remove:
There is no update_note() method in the SDK. To edit a note, delete it and add a new one.
Note method summary
| Method | Effect |
|---|---|
container.add_note("text") | Add a timestamped note |
container.delete_note(note_id) | Remove a note by ID |
File Classification
Files also carry a classification field that organizes them into modality-specific dimensions called aspects. For the MR modality, the standard aspects include Intent, Measurement, and Features. The Custom aspect is always available regardless of modality.
Classification is separate from info — it is used by Flywheel to organize files and drive gear rule matching.
Classifications set on files should adhere to the classification schema. To learn how to view or modify your site's classification schema, see Admin Concepts: Modality and Classification Schema.
For more about data classification on Flywheel, including the default classification schema, consult the Flywheel product documentation.
Warning
An invalid classification set on a file by the SDK cannot be modified from the UI and may cause validation errors at various stages of your workflow including gear runs, file moves, and copying operations.
Ensure that classifications being set by the SDK are valid according to your site's classification schema. Replace or remove invalid classification values with the SDK, or ask a site administrator to update your site's classification schema to align with your project's data classification needs.
Reading classification
file_entry = acquisition.files[0]
print(file_entry.classification)
# {'Intent': ['Structural'], 'Measurement': ['T1'], 'Custom': []}
Replacing classification
replace_file_classification() overwrites the entire classification and optionally sets the modality:
Adding to classification
update_file_classification() merges values into specific aspects without clearing others:
Removing classification values
delete_file_classification() removes specific values from specific aspects:
--8 < --"test_docs_core_concepts.py:delete_file_classification"
On a file object directly:
file_entry.replace_classification({"Intent": ["Functional"]}, modality="MR")
file_entry.update_classification({"Custom": ["processed"]})
file_entry.delete_classification({"Custom": ["processed"]})
Which Metadata Type to Use
-
Use
infofor free-form information storage, structured but schema-less metadata data that isn't a first-class Flywheel field but needs to live with the container, stay queryable, and travel alongside it through copies, exports, and jobs. Examples: Header information, gear output. -
Use
tagsfor flat list of short string labels attached to a container (or file). Tags are a set of identifier-like strings optimized for filtering and membership checks. Examples: status/workflow flags, cohort / study-arm membership, finder filters. -
Use
notesfor timestamped, user-attributed free-text entries attached to a container. Notes are prose written by humans for humans: a built-in comment thread on the container. Examples: Decision log, reviewer handoff, contextual narrative that does't fit a field.
Related
- Core Concepts: Containers — container types and their parent-child relationships
- Core Concepts: Finders — filter syntax for querying containers by tag and info fields
- Admin Concepts: Modality and Classification Schema - create, read, update, and delete modalities and classification schemas
- Data Classification product documentation - more information on Flywheel classification metadata