Skip to content

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:

Nesting values under 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:

Read info from a session
--8 < --"test_docs_core_concepts.py:read_info"

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:

Reload to get full info payload
session = session.reload()
print(session.info)

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:

Merge keys into existing info
--8 < --"test_docs_core_concepts.py:update_info"

This also works with nested structures:

Merge a nested info structure
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:

Safely merge into a nested key
--8 < --"test_docs_core_concepts.py:safe_merge_info"

Replacing all info

replace_info() overwrites the entire info dict. Any keys not included in the new dict are lost:

Replace all info on an acquisition
--8 < --"test_docs_core_concepts.py:replace_info"

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:

Remove info keys
--8 < --"test_docs_core_concepts.py:delete_info"

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

Read info from a file entry
--8 < --"test_docs_core_concepts.py:read_file_info"

Writing file info via the parent container

Write 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:

Write file info directly on a FileEntry
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

Read tags from a session
--8 < --"test_docs_core_concepts.py:read_tags"

Adding and removing tags

Add, remove, and rename tags
--8 < --"test_docs_core_concepts.py:add_remove_tags"

Filtering with tags

Tags are indexed and can be used in finder filter expressions. See Core Concepts: Finders for full filter syntax.

Filter containers by tag
--8 < --"test_docs_core_concepts.py:filter_by_tag"

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

Read notes from a session
--8 < --"test_docs_core_concepts.py:read_notes"

Adding a note

Add a note to a session
--8 < --"test_docs_core_concepts.py:add_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:

Delete a note by ID
--8 < --"test_docs_core_concepts.py:delete_note"

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

Read file 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:

Replace file classification
--8 < --"test_docs_core_concepts.py:replace_file_classification"

Adding to classification

update_file_classification() merges values into specific aspects without clearing others:

Add values to file classification
--8 < --"test_docs_core_concepts.py:update_file_classification"

Removing classification values

delete_file_classification() removes specific values from specific aspects:

Remove values from file classification
--8 < --"test_docs_core_concepts.py:delete_file_classification"

On a file object directly:

Modify classification on a file object
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 info for 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 tags for 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 notes for 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.