Skip to content

Requesting reference data

Everything the IDC builds, from a MetaPhlAn database to a genome and its Bowtie2 index, is produced by a Galaxy data manager and requested the same way: a pull request that adds one YAML file describing which data manager to run and with which parameters. The file is linted on the PR and built after the merge, and a maintainer then publishes the result to the idc.galaxyproject.org CVMFS repository, where any Galaxy server that mounts it can use it.

This page covers writing that file, checking it locally, and following it through the pipeline afterwards. When in doubt, the request files already under data-managers/ show what works. If you use a coding agent, the repository has skills for the same steps.

Before you start: does it already exist?

Don't request data that is already served. You can check with the data table API of test.galaxyproject.org, which shows the IDC's data along with the other galaxyproject.org reference data:

curl -s https://test.galaxyproject.org/api/tool_data/metaphlan_database_versioned
{"name": "metaphlan_database_versioned",
 "columns": ["value", "name", "dbkey", "path", "db_version"],
 "fields": [["mpa_vOct22_CHOCOPhlAnSGB_202212-03042023", "MetaPhlAn clade-specific marker genes (mpa_vOct22_CHOCOPhlAnSGB_202212)", "mpa_vOct22_CHOCOPhlAnSGB_202212", "...", "SGB"],
            ...]}

If one of the rows has a field equal to your version (for MetaPhlAn that's dbkey, for mOTUs version), or a value that is your version followed by -<date>, the data is already there. If it's served by another repository and you think it belongs in the IDC, open an issue; moving data is a maintainer decision. A 404 means nobody has requested data from that data manager yet.

Search the open PRs as well (gh pr list --repo galaxyproject/idc --search "<table>") and the catalog of existing requests.

1. Find the data manager

schemas/data_managers.yml lists the data managers you can request from, with their full tool GUIDs, so you can usually copy tool_id from there:

grep -n metaphlan schemas/data_managers.yml

tool_id has to be a production Tool Shed GUID that ends in the tool version:

toolshed.g2.bx.psu.edu/repos/<owner>/<repo>/<tool id>/<tool version>

<tool id> and <tool version> are the id= and version= attributes of the <tool> tag in the data manager's XML, which often differ from the repository name. The lint rejects GUIDs without a version and GUIDs from the Test Tool Shed. Note that the tool version isn't the database version: mOTUs' motus_db_fetcher/3.1.0+galaxy2 can also fetch mOTUs 3.0.1.

The data tables a data manager writes are the <data_table name="..."> entries in its repository's data_manager_conf.xml. The Tool Shed API tells you where the repository's source lives:

curl -s 'https://toolshed.g2.bx.psu.edu/api/repositories?name=data_manager_motus&owner=bgruening'

If the data manager you need isn't listed, see Adding a new data manager.

2. Name the file

A request lives at data-managers/<data_table>/<version>.yaml.

The directory is the data manager's primary data table, the one tools pick the data from, and it has to be one of the request's data_tables. The file name is the version identity and has to be unique within the table.

Use the name the data manager itself gives the data, such as MetaPhlAn's index name (mpa_vJan21_CHOCOPhlAnSGB_202103) or the mOTUs release (3.1.0). The pipeline recognises published data by finding the file name, a params value or a depends_on version in the data table row, either as a whole field or as the start of value followed by -. To see whether that works for your request, run the existence check against a server that already has the same data, e.g. python scripts/check_data_exists.py --reference-galaxy https://usegalaxy.eu <file>.

A matching name doesn't prove it's the same data. If the data is already served from outside the IDC (for example a genome on data.galaxyproject.org), pin its files with sha256: the build then counts the served entry as this request only if its files have those checksums, and fails if they don't. Compute the checksums from the data your recipe produces; a maintainer can check them against the served copy.

Data without a version of its own, like whatever BLAST nr is on the day it's downloaded, gets a date: nr_2026-09-21, with a description saying what the date means. Such a data manager is typically requested with params: {}; the date in the file name is what tells one build from the next. A database built from another one names its source, as in marker_db_motus_3.1.0 for SameStr built from mOTUs 3.1.0.

The name ends up in history names, paths and shell commands, so stick to letters, digits, ., _ and -.

3. Fill in the parameters

params holds the data manager's own tool parameters, keyed by the name= of its <param> tags and nested the way the tool form nests them, so a <conditional name="db_source"> containing db_type becomes db_source: {db_type: motus}.

The lint checks params against the parameter schema the Tool Shed publishes for that exact tool version, and its error messages list the names or values the tool does accept. To look at the schema yourself:

python scripts/tool_schemas.py toolshed.g2.bx.psu.edu/repos/bgruening/data_manager_motus/motus_db_fetcher/3.1.0+galaxy2

The output includes the options of every select, the defaults and the help text, and leaves out hidden parameters, which a request can't set.

If you start the file with

# yaml-language-server: $schema=https://raw.githubusercontent.com/galaxyproject/idc/main/schemas/request.schema.json

VS Code (with the Red Hat YAML extension) and JetBrains IDEs complete and check params as you type.

Matching another server's identifier

The value column of a data table is what workflows and tool runs refer to. If another Galaxy, usegalaxy.eu say, already has the same data, the IDC should write the same value, or a workflow built there won't find its data here:

curl -s https://usegalaxy.eu/api/tool_data/motus_db_versioned

Some data managers let you set value directly. The mOTUs one has a db_value parameter, and the mOTUs request uses it to write usegalaxy.eu's identifier:

params:
  version: "3.1.0"
  db_value: "db_from_2026-04-27T094930Z"

Nothing in the pipeline treats db_value specially; it's an ordinary tool parameter. If a data manager has no such parameter and would write a different value, mention it in the PR. The IUC guide on stable data table identifiers describes what new data managers should write.

Even when no other server has the data, inspect the pinned tool's wrapper to determine the value it will write, including what an empty identifier parameter means. The schema checks parameter names and types, not the output row's identity. For a chain, depends_on selects the upstream input but does not set the downstream identifier. Genome variants can share a dbkey while having different sequence identifiers; see Indexes.

4. Databases built from other databases

Some data managers take another database as input: SameStr builds its marker database from a MetaPhlAn or an mOTUs database, and a Bowtie2 index is built from a genome in all_fasta. Such a request names what it's built from with depends_on, mapping the upstream table to the upstream request's file name:

depends_on:
  motus_db_versioned: "3.1.0"

A request file for the upstream has to exist, and if the upstream version is new too, both files go in the same PR. If the upstream is already served, the build uses it; otherwise it's built first, in the same workflow.

depends_on also decides which input of the downstream tool the upstream goes into. CHAIN_WIRING in scripts/generate_build.py maps each pair of downstream and upstream table to the tool's conditional and input, which is why SameStr requests have params: {} even though the tool has a db_source conditional. A pair that isn't in CHAIN_WIRING yet needs an entry added in the same PR, and the lint says so.

5. Write the file

field required
tool_id yes version-pinned production Tool Shed GUID of the data manager
data_tables yes the tables the data manager writes, including the directory name
params no the tool's parameters for this build
depends_on no {upstream_table: upstream_version} for a database built from another
sha256 no {file name: sha256} of the entry's files, required in practice when the data is already served from outside the IDC
description no what the data is, for reviewers and the catalog
doi no DOI of the publication or dataset

Any other field is an error. Here is the mOTUs request, data-managers/motus_db_versioned/3.1.0.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/galaxyproject/idc/main/schemas/request.schema.json
# mOTUs database v3.1.0 (fetched from Zenodo record 7778108).
# Standalone build: the data manager downloads the DB by version.
tool_id: toolshed.g2.bx.psu.edu/repos/bgruening/data_manager_motus/motus_db_fetcher/3.1.0+galaxy2
data_tables:
  - motus_db_versioned
params:
  version: "3.1.0"   # the tool's "Database Version" select param
  # "Database identifier override": the exact `value` the tool writes to the data
  # table. Set to usegalaxy.eu's existing identifier so workflows built there
  # resolve here unchanged (left empty, the tool would stamp today's date).
  db_value: "db_from_2026-04-27T094930Z"
description: mOTUs profiler database, version 3.1.0

and the SameStr database built from it, data-managers/samestr_db/marker_db_motus_3.1.0.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/galaxyproject/idc/main/schemas/request.schema.json
# SameStr marker database built from the mOTUs 3.1.0 database.
# Chained build: samestr's "motus_db" input is backed by the motus_db_versioned
# data table, so the build workflow first runs the mOTUs data manager (bundle
# mode) and feeds its output into this step.
tool_id: toolshed.g2.bx.psu.edu/repos/iuc/data_manager_samestr/samestr_db/1.2025.111+galaxy4
data_tables:
  - samestr_db
depends_on:
  # Which mOTUs version this SameStr DB is built against. A request file must
  # exist at data-managers/motus_db_versioned/<version>.yaml.
  motus_db_versioned: "3.1.0"
# Empty on purpose: the tool's db_source conditional is not steered from here.
# depends_on names the upstream table, and CHAIN_WIRING in generate_build.py maps
# (samestr_db, motus_db_versioned) -> db_source: {db_type: motus} plus the input
# that receives the bundle, so the non-default branch is selected by the
# dependency itself. params is for a build's own tool parameters - see
# data-managers/motus_db_versioned/3.1.0.yaml for an example that uses it.
params: {}
description: SameStr marker database derived from mOTUs 3.1.0

Quote version numbers ("3.1.0") so YAML keeps them as strings. For genomes and their indexes, see Genomes.

6. Check it locally

CI runs these on the PR, but running them first saves a round trip. In a virtualenv, from a checkout of this repository:

pip install "pydantic>=2" pyyaml jsonschema gxformat2 pytest

python scripts/request_models.py <files>
python scripts/generate_schema.py --check
python scripts/generate_build.py <files> --outdir build
python scripts/check_data_exists.py <files>
python -m pytest tests/ -q

request_models.py validates the request itself, including params against the tool's schema. Without arguments it lints every request; --no-fetch keeps it from asking the Tool Shed and --no-tool-schemas skips the params check.

generate_schema.py --check reports the editor schema as stale when your request uses a tool_id it doesn't know. Run python scripts/generate_schema.py and commit the updated schemas/request.schema.json with the request.

Schema fixtures for a tool's first request

Every tool GUID used by a request also needs an offline test fixture under tests/fixtures/tool_schemas/, even if it already appears in the editor schema. The tests deliberately do not fetch missing schemas from the Tool Shed. Save its fixture with:

python scripts/tool_schemas.py --save-fixture <tool_id>

The command accepts either the full GUID from a request's tool_id or a compact owner~repo~tool~version ID. Both must include the version. These commands save the same fixture:

python scripts/tool_schemas.py --save-fixture toolshed.g2.bx.psu.edu/repos/devteam/data_manager_sam_fasta_index_builder/sam_fasta_index_builder/1.21+galaxy0
python scripts/tool_schemas.py --save-fixture devteam~data_manager_sam_fasta_index_builder~sam_fasta_index_builder~1.21+galaxy0

The compact form uses the production Tool Shed. Request YAML files still require the full GUID.

The script saves the raw Tool Shed response and derives the filename <owner>~<repo>~<tool>~<version>.json from that GUID, not from its upstream dependency. For the SAM FASTA index builder it is devteam~data_manager_sam_fasta_index_builder~sam_fasta_index_builder~1.21+galaxy0.json. Commit the fixture with the request and run python -m pytest tests/ -q. Without --save-fixture, both forms print the filtered contributor schema.

Generated workflows and existence checks

generate_build.py writes build/<table>/<version>/workflow.gxwf.yml and job.yml, the workflow and inputs the build will run after the merge, and validates the workflow with gxformat2.

check_data_exists.py prints No requested reference data already exists on ... if the data isn't served yet. It exits 1 if it is, or if the server didn't answer (cannot tell whether this already exists), in which case try again later.

CI additionally runs generate_schema.py --check --refresh and generate_build.py --all.

7. Open the pull request

Open one PR per request, or one for a new upstream together with what's built from it. The description should say what the data is and where it comes from, why it's needed, that you checked it isn't served yet, which server's identifier it matches if you pinned value, and how large the download and how long the build are if you know. Reviewers plan publishes around builds that take hours.

After the merge

flowchart LR
  pr(["PR"]) --> lint["Lint"]
  lint --> merge["Review + merge"]
  merge --> build["Build"]
  build --> publish["Publish to CVMFS<br/>(maintainer)"]
  publish --> done(["Available on<br/>Galaxy servers"])

Merging starts the build, which takes minutes for small databases and hours for large ones. When it's done, a maintainer checks the result and publishes it to CVMFS; see Publishing to CVMFS. Galaxy servers that use the IDC see new data within about an hour of the publish, once the CVMFS replicas have updated and the server has reloaded its data tables. How it works describes each stage in detail.

Checking on a request

None of this needs a Galaxy API key.

stage how to check
lint the PR's checks, or gh pr checks <number> --repo galaxyproject/idc
build started the Build reference-data bundles run for the merge (gh run list --repo galaxyproject/idc --workflow build.yml). Its "Select requests to build" step lists what it built and what it skipped.
build finished follow the Galaxy invocation link posted on the PR or in the Actions run summary; it shows current job status and outputs
published curl -s https://test.galaxyproject.org/api/tool_data/<table> shows the row, or python scripts/check_data_exists.py --expect-exists <file> prints ok: <table>/<version> is present

The build makes its workflow and history accessible by link and posts the invocation to the merged request PR. A green Actions run confirms submission, not completion of the Galaxy jobs. For a manual rebuild, set the workflow's optional pull_request input to the original request PR number; otherwise links go to a merged PR associated with the selected commit, if any. Links are always written to the Actions summary after sharing succeeds.

Adding a new data manager

A data manager that isn't in schemas/data_managers.yml has to be installed first, by adding it to usegalaxy-tools' test.galaxyproject.org/data_managers.yml. The lint here works before that's merged, but the build doesn't.

In this repository, its data tables go in config/tool_data_table_conf.xml, reading from /cvmfs/idc.galaxyproject.org/config/<table>.loc, with the columns of the data manager's tool_data_table_conf.xml.sample and allow_duplicate_entries="False". If it's built from another database, it needs a CHAIN_WIRING entry naming the conditional to set (if any) and the input that receives the upstream bundle. The table, the wiring and the first request can share a PR. Regenerate the editor schema with python scripts/generate_schema.py and commit it too.

Lint errors

tool_id must be a production Tool Shed GUID starting with 'toolshed.g2.bx.psu.edu/repos/'

The GUID is from the Test Tool Shed or misspelled.

tool_id must be a version-pinned GUID host/repos/owner/repo/tool/version

The tool version is missing from the end, e.g. /3.1.0+galaxy2.

params: Additional properties are not allowed ('version' was unexpected); this tool's parameters here are ['index']

The tool has no parameter of that name at that level. The message lists the ones it has; nested parameters go inside their section or conditional.

params: index: 'mpa_vJan25_CHOCOPhlAnSGB_2025' is not one of [...]

A select only accepts the options the tool offers, and the message lists them. If the version you need isn't among them, the data manager has to be updated first, or you have an older tool version pinned.

cannot check params - no parameter schema for tool_id ...

The Tool Shed has no schema for that GUID, usually because the tool id or version is wrong. python scripts/tool_schemas.py <GUID> shows the same error.

If the error ends with no fixture for ... in the unit tests, the offline fixture is missing instead. Follow Schema fixtures for a tool's first request; regenerating the editor schema alone does not fix it.

Extra inputs are not permitted

A field that isn't in the table under Write the file. There is no version field; the version is the file name.

directory name 'motus_db' is not in data_tables ['motus_db_versioned']

The directory has to be named after the primary data table.

depends_on ... but no request file exists at data-managers/<table>/<version>.yaml

Add the upstream request, or correct the version to an existing request's file name.

No chain wiring defined for downstream ...

The pair needs a CHAIN_WIRING entry; see Adding a new data manager.

error: schemas/request.schema.json is stale

Run python scripts/generate_schema.py and commit the result. If CI reports this but the local --check passes, the Tool Shed has changed a schema already in use, and python scripts/generate_schema.py --refresh picks that up.

Other questions

The lint warns that my data already exists. It's already served from some source. If the existing entry is wrong or should move into the IDC, say so on the PR; replacing an entry is done by hand by a maintainer. For a request that pins sha256, the lint can't read the served files (that needs an admin key), so it says it can't tell; the build checks them.

The build fails with "has the same name but different files". An entry with the request's name is served, but its files don't have the pinned checksums. Use a different name, or ask a maintainer which one is right.

The PR is merged but nothing was built. The build run's "Select requests to build" step says which requests it skipped and why. A maintainer can re-run the build for a single request once a failure is fixed.

It's published, but my Galaxy doesn't show it. Give it up to an hour, then reload the table on that Galaxy or restart it. The server also has to load the IDC's tool_data_table_conf.xml; see Using IDC data in Galaxy.

Can I request a new version of something the IDC already has? Yes, a new version is a new file. Requesting the same file name again does nothing.

Using an agent

Coding agents working in the repository can follow two skills, described in AGENTS.md. request-reference-data goes from "I need database X, version Y" to a linted request and a drafted PR, and check-reference-data-request finds out how far a request has got. Both use the scripts described on this page and neither needs an API key.