# Authoring User-Defined Tools Create a Galaxy tool from a containerized command without waiting for an administrator to install it. Define its inputs and outputs here, then run it like any other tool. ## Getting Started (quick-start)= ### Quick start Paste this definition into the editor. It accepts a text dataset and writes a copy without lines beginning with `#`. ```yaml class: GalaxyUserTool id: remove_comments name: Remove Comment Lines version: 0.1.0 description: from a text file container: quay.io/biocontainers/grep:3.4--hf43ccf4_4 shell_command: grep -v '^#' '$(inputs.input_file.path)' > output.txt || test "$?" = 1 inputs: - name: input_file type: data format: - txt outputs: - name: output_file type: data format_source: input_file from_work_dir: output.txt ``` ## Reference (tool-format)= ### Tool definition A user-defined tool is a YAML document. `class: GalaxyUserTool` selects the user-defined tool format. [`container` #](#containers-reference) selects a **container image** containing the program and everything it needs to run. [`shell_command` #](#expressions) supplies the **command line** Galaxy runs inside that image, with inputs referenced as `$(inputs.input_name)` for scalar values and `$(inputs.input_name.path)` for files. | Field | Details | Required | | --- | --- | --- | | [`class` #](#tool-format) | Selects the user-defined tool format. Must be `GalaxyUserTool`. | Yes | | `id` | Stable lowercase identifier. Must start with a letter and may contain letters, digits, `_`, and `-`. | No | | `name` | Name displayed in the tool menu. | Yes | | `version` | Version of this wrapper. Change it when behavior or the container changes. | Yes | | `description` | Short text displayed after the tool name. | No | | [`container` #](#containers-reference) | Fully qualified image supplying the program, interpreters, libraries, and utilities the tool needs. | Yes | | [`shell_command` #](#expressions) | Command line Galaxy evaluates and runs in the selected image, with inputs referenced through expressions. | Yes | | [`configfiles` #](#configfiles) | Scripts and configuration files required by the software you are wrapping. | No | | [`inputs` #](#parameters) | Input parameters shown on the tool form. | No | | [`outputs` #](#outputs) | Datasets and collections Galaxy claims after the command finishes. | No | | [`requirements` #](#resource-requirements) | JavaScript helpers and compute-resource requests. | No | | [`help` #](#help-content) | Longer help text shown below the tool form. | No | | [`tests` #](#testing) | Tool test declarations. | No | | [`citations` #](#citations-metadata), [`license` #](#citations-metadata), [`edam_operations` #](#citations-metadata), [`edam_topics` #](#citations-metadata), [`xrefs` #](#citations-metadata) | Publication and ontology metadata. | No | | [`profile` #](#tool-format) | Galaxy tool profile controlling versioned tool behavior. | No | Compared with an equivalent [Galaxy XML tool](../dev/schema.md), three things differ: - `class: GalaxyUserTool` is required. - A top-level [`container` #](#containers-reference) is required. XML tools may instead resolve dependencies through Conda. - The command lives under [`shell_command` #](#expressions) and is templated with sandboxed JavaScript expressions rather than Cheetah, so it has no access to the Galaxy database or filesystem. Every output must say where its bytes come from: a `data` output needs `from_work_dir` or [`discover_datasets` #](#discover-datasets), and a collection output needs [`discover_datasets` #](#discover-datasets). An output that declares neither is rejected, because nothing would ever be claimed from the working directory. (configfiles)= ### Config files Use [`configfiles` #](#configfiles) for scripts and configuration files required by the software you are wrapping. Galaxy writes each file into the job working directory before it runs [`shell_command` #](#expressions). File content supports the same sandboxed ECMAScript expressions as the command. | Field | Details | Default | Required | | --- | --- | --- | --- | | `filename` | Name of the file in the job working directory. | — | No | | `content` | File contents, including any input expressions. | — | Yes | | `name` | Internal name for the config file. | — | No | | `eval_engine` | Template engine; user-defined tools use `ecmascript`. | `ecmascript` | No | ```yaml configfiles: - filename: message.txt content: | Selected motif: $(inputs.motif) shell_command: cat message.txt ``` (parameters)= ### Input parameters User-defined tools support the input types listed below. Unknown and unsupported fields are rejected. | Parameter type | Details | | --- | --- | | [`boolean` #](#parameter-boolean) | A true-or-false input. | | [`color` #](#parameter-color) | A color-picker input. | | [`conditional` #](#parameter-conditional) | A control input that selects which nested inputs are displayed and supplied to the command. | | [`data` #](#parameter-data) | One dataset, or a list of datasets when `multiple` is true. | | [`data_collection` #](#parameter-data_collection) | A dataset collection input. | | [`float` #](#parameter-float) | A numeric input with optional bounds and validators. | | [`integer` #](#parameter-integer) | A whole-number input with optional bounds and validators. | | [`repeat` #](#parameter-repeat) | A group the user may add multiple times, with `parameters` defining one repeated entry. | | [`section` #](#parameter-section) | Related inputs that users can expand or collapse to reduce form complexity. | | [`select` #](#parameter-select) | A choice from a fixed list of options. | | [`text` #](#parameter-text) | A single-line or multiline text input. | Each type below has its own field table and example. For `data` inputs, `format` lists accepted Galaxy datatype extensions. See the **Datatypes page** in your Galaxy instance for the extensions available there. Types that exist in the XML tool vocabulary but are rejected here: `hidden`, `drill_down`, `data_column`, `genomebuild`, `group_tag`, `baseurl`, `rules`, `directory`. XML-only fields such as `truevalue`, `falsevalue`, `argument`, `is_dynamic` and `parameter_type` are likewise rejected on any parameter. (validators)= #### Validators Validators reject parameter values before a job starts. Each parameter type's field table lists the validators it supports. | Validator type | Details | | --- | --- | | [`empty_field` #](#validator-empty_field) | Require a value that is neither an empty string nor null. | | [`in_range` #](#validator-in_range) | Require a numeric value to fall within optional lower and upper bounds. | | [`length` #](#validator-length) | Require the number of characters in a text value to fall within optional bounds. | | [`no_options` #](#validator-no_options) | Require a select parameter to have at least one available option. | | [`regex` #](#validator-regex) | Require a regular expression to match from the start of the value. | (outputs)= ### Outputs Each output declares a `type` and a `name`. Dataset outputs identify the produced file with `from_work_dir`; collection outputs use [`discover_datasets` #](#discover-datasets). | Output type | Details | | --- | --- | | [`collection` #](#output-collection) | A user-defined tool collection populated only by matching produced filenames. | | [`data` #](#output-data) | A user-defined tool dataset discovered only from files inside the job working directory. | Each type below has a field table and example. (help-content)= ### Tool help Tool help is rendered below the input form. Declare its format and content together. | Field | Details | Required | | --- | --- | --- | | `format` | One of `markdown`, `restructuredtext`, or `plain_text`. | Yes | | `content` | Help shown to the user. | Yes | ```yaml help: format: markdown content: | Finds lines containing the selected motif. ``` (citations-metadata)= ### Citations and metadata Use [`citations` #](#citations-metadata) for publications describing the wrapped tool, [`license` #](#citations-metadata) for the wrapper license, EDAM identifiers for topics and operations, and [`xrefs` #](#citations-metadata) for identifiers in other registries. ```yaml citations: - type: doi content: 10.1093/bioinformatics/bts611 license: MIT edam_topics: - topic_0102 edam_operations: - operation_0308 xrefs: - type: bio.tools value: example_tool ``` (expressions)= ### Expression syntax [`shell_command` #](#expressions) is not handed to the shell unchanged. Galaxy first evaluates it with a sandboxed ECMAScript 5.1 engine, using the same parameter-reference syntax CWL uses, and only the evaluated result is written into the job script. | Form | Details | Example | | --- | --- | --- | | `$( ... )` | Parameter reference or single expression. | `$(inputs.num_lines)`, `$(inputs.query.path)` | | `${ ... }` | Function body that must return a value. | `${ return inputs.num_lines * 2 }` | Substituted values are inserted literally; Galaxy does **not** shell-quote them. Quote any substitution that can contain spaces yourself, as `'$(inputs.query.path)'`. Reusable helper functions can be declared with a `javascript` requirement, and are then available to every expression in the tool: ```yaml requirements: - type: javascript expression_lib: - | function basename(path) { return path.split('/').pop(); } ``` (resource-requirements)= ### Resource requirements Declare compute needs with a `resource` entry under [`requirements` #](#resource-requirements): ```yaml requirements: - type: resource cores_min: 32 ram_min: 8192 cuda_device_count_min: 1 cuda_device_count_max: 1 gpu_memory_min: 40960 ``` | Field | Details | Required | | --- | --- | --- | | `type` | Selects a resource requirement. Must be `resource`. | Yes | | `cores_min`, `cores_max` | Minimum and maximum reserved CPU cores. Fractional values are allowed. | No | | `ram_min`, `ram_max` | Minimum and maximum reserved RAM in MiB. | No | | `tmpdir_min`, `tmpdir_max` | Minimum and maximum temporary-directory space in MiB. | No | | `cuda_version_min` | Minimum required CUDA runtime version. | No | | `cuda_compute_capability` | Minimum required CUDA compute capability. | No | | `gpu_memory_min` | Minimum required GPU memory in MiB. | No | | `cuda_device_count_min`, `cuda_device_count_max` | Minimum and maximum number of GPUs to reserve. | No | | `shm_size` | Requested `/dev/shm` size in bytes. | No | | `timelimit` | Maximum runtime in seconds. Galaxy terminates the job if it is exceeded. | No | Pass `$GALAXY_SLOTS` to threaded programs; Galaxy sets it to the number of CPU cores allocated to the job. Use numbers or numeric strings. Other strings are reserved for runtime expressions, which are not supported yet: a non-numeric value such as `2g` fails the create-time lint check (`ResourceRequirementExpression`), so the tool cannot be saved until it is corrected. (api)= ### API endpoints This editor is a client of a small API, so tools can also be created and managed programmatically, which is useful when registering many tools or many versions of one tool. All of these endpoints require the `Custom Tool Execution` role and operate only on the calling user's own tools. | Endpoint | Purpose | | --- | --- | | `POST /api/unprivileged_tools` | Create a tool; returns its `uuid`. | | `GET /api/unprivileged_tools` | List the calling user's tools. | | `GET /api/unprivileged_tools/{uuid}` | Show one tool and its representation. | | `DELETE /api/unprivileged_tools/{uuid}` | Deactivate a tool. | | `POST /api/unprivileged_tools/build?history_id=...` | Render the tool form without saving the tool. | | `POST /api/unprivileged_tools/runtime_model` | Return an OpenAPI model of the tool's inputs. | The create payload wraps the YAML document, converted to JSON, in a `representation` key. Keeping it in a file avoids complex shell quoting for [`shell_command` #](#expressions): ```json { "representation": { "class": "GalaxyUserTool", "id": "my-cool-tool", "name": "My Cool Tool", "version": "0.1.0", "container": "quay.io/biocontainers/python:3.13", "shell_command": "head -n '$(inputs.n_lines)' '$(inputs.data_input.path)' > out.txt", "inputs": [ {"type": "integer", "name": "n_lines"}, {"type": "data", "name": "data_input"} ], "outputs": [ {"type": "data", "name": "out", "from_work_dir": "out.txt"} ] } } ``` ```console $ curl -X POST "$GALAXY_URL/api/unprivileged_tools" \ -H "x-api-key: $GALAXY_API_KEY" \ -H 'Content-Type: application/json' \ -d @tool.json ``` Run the resulting tool by passing its `uuid` to the normal tool execution endpoint: `POST /api/tools` with `tool_uuid` instead of `tool_id`. Your server publishes the request and response details at `/api/docs` under the `dynamic_tools` tag. ## Detailed reference (parameter-types-reference)= ### Input parameter types Field tables and examples for every input type supported by user-defined tools. (parameter-boolean)= #### boolean parameter A true-or-false input. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Presents a true-or-false choice and supplies the selected Boolean value to expressions. | — | Yes | | `value` | Initial choice shown when the user first opens the tool form. | `false` | No | Add this `boolean` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Include a header line name: include_header type: boolean value: true ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | include_header="$(inputs.include_header)" ``` (parameter-color)= #### color parameter A color-picker input. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Presents a color picker and supplies the selected hexadecimal color string. | — | Yes | | `value` | Color initially selected in the picker, written in hexadecimal notation. | `null` | No | Add this `color` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Plot color name: plot_color type: color value: '#3366cc' ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | plot_color="$(inputs.plot_color)" ``` (parameter-conditional)= #### conditional parameter A control input that selects which nested inputs are displayed and supplied to the command. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Shows one set of nested inputs at a time according to a Boolean or select control. | — | Yes | | `test_parameter` | Boolean or select input whose submitted value chooses the active `whens` branch. | — | Yes | | `whens` | Maps each control value to the nested parameters shown and supplied for that branch. | — | Yes | Add this `conditional` parameter under [`inputs` #](#parameters): ```yaml inputs: - name: search_options test_parameter: label: Search mode name: mode options: - label: Fast selected: true value: fast - label: Sensitive selected: false value: sensitive type: select type: conditional whens: - discriminator: fast parameters: [] - discriminator: sensitive parameters: - name: iterations type: integer value: 3 ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | mode="$(inputs.search_options.mode)" iterations="$(inputs.search_options.iterations)" ``` (parameter-data)= #### data parameter One dataset, or a list of datasets when `multiple` is true. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Lets the user select history datasets and exposes their paths and metadata to expressions. | — | Yes | | `format` | Limits selectable datasets to these Galaxy datatype extensions. | `["data"]` | No | | `multiple` | Set true to accept several datasets (a list) for this input instead of one. | `false` | No | Add this `data` parameter under [`inputs` #](#parameters): ```yaml inputs: - format: - txt - tabular label: Input file name: input_file type: data ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | input_file='$(inputs.input_file.path)' ``` (parameter-data_collection)= #### data_collection parameter A dataset collection input. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Lets the user select a history collection and exposes its elements to expressions. | — | Yes | | `collection_type` | Limits selectable collections to this structure, such as `list` or `paired`. | `null` | No | | `format` | Requires every selectable collection element to use one of these datatype extensions. | `["data"]` | No | Add this `data_collection` parameter under [`inputs` #](#parameters): ```yaml inputs: - collection_type: paired format: - fastqsanger label: Paired reads name: reads type: data_collection ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | forward='$(inputs.reads.elements.forward.path)' reverse='$(inputs.reads.elements.reverse.path)' ``` (parameter-float)= #### float parameter A numeric input with optional bounds and validators. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Accepts a number, including decimal values, and supplies it to expressions. | — | Yes | | `value` | Number prefilled when the user first opens the tool form. | `null` | No | | `min` | Rejects submitted values smaller than this inclusive lower bound. | `null` | No | | `max` | Rejects submitted values larger than this inclusive upper bound. | `null` | No | | [`validators` #](#validators) | Additional validation rules; supports `in_range`. | `[]` | No | Add this `float` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Score threshold max: 1.0 min: 0.0 name: threshold type: float value: 0.5 ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | threshold="$(inputs.threshold)" ``` (parameter-integer)= #### integer parameter A whole-number input with optional bounds and validators. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Accepts a whole number and supplies it as a numeric value to expressions. | — | Yes | | `value` | Number prefilled when the user first opens the tool form. | `null` | No | | `min` | Rejects submitted values smaller than this inclusive lower bound. | `null` | No | | `max` | Rejects submitted values larger than this inclusive upper bound. | `null` | No | | [`validators` #](#validators) | Additional validation rules; supports `in_range`. | `[]` | No | Add this `integer` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Number of lines max: 1000 min: 1 name: num_lines type: integer value: 10 ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | num_lines="$(inputs.num_lines)" ``` (parameter-repeat)= #### repeat parameter A group the user may add multiple times, with `parameters` defining one repeated entry. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Lets the user add multiple entries that all contain the same nested inputs. | — | Yes | | `parameters` | Nested inputs that make up one entry in the repeated group. | `[]` | No | | `min` | Keeps at least this many entries in the group and creates them when the form opens. | `null` | No | | `max` | Prevents the user from adding more than this many entries. | `null` | No | Add this `repeat` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Additional files max: 3 min: 0 name: extra_files parameters: - format: - txt name: input_file type: data type: repeat ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | files='$(inputs.extra_files.map((item) => item.input_file.path).join(" "))' ``` (parameter-section)= #### section parameter Related inputs that users can expand or collapse to reduce form complexity. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Places related inputs in a collapsible group to simplify the tool form. | — | Yes | | `parameters` | Nested inputs displayed together inside the section. | `[]` | No | Add this `section` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Advanced options name: advanced parameters: - max: 1.0 min: 0.0 name: threshold type: float value: 0.5 type: section ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | threshold="$(inputs.advanced.threshold)" ``` (parameter-select)= #### select parameter A choice from a fixed list of options. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Lets the user choose from the declared `options` and supplies the selected value. | — | Yes | | `options` | Choices presented on the tool form, each with a display label and value. | — | Yes | | `multiple` | Set true to let the user select and supply several option values instead of one. | `false` | No | | [`validators` #](#validators) | Additional validation rules; supports `no_options`. | `[]` | No | Add this `select` parameter under [`inputs` #](#parameters): ```yaml inputs: - label: Search mode name: mode options: - label: Fast selected: true value: fast - label: Sensitive selected: false value: sensitive type: select ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | mode="$(inputs.mode)" ``` (parameter-text)= #### text parameter A single-line or multiline text input. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to read this input from [`shell_command` #](#expressions) and other expressions. | — | Yes | | `label` | Label shown for the input on the tool form. | `null` | No | | [`help` #](#help-content) | Additional guidance shown on the tool form to help users choose a value. | `null` | No | | `optional` | Set true when the command can run without the user supplying this input. | `false` | No | | `type` | Accepts user-entered text and supplies the resulting string to expressions. | — | Yes | | `value` | Text prefilled when the user first opens the tool form. | `null` | No | | `area` | Set true to use a multiline editor instead of a single-line text box. | `false` | No | | [`validators` #](#validators) | Additional validation rules; supports `length`, `regex`, and `empty_field`. | `[]` | No | Add this `text` parameter under [`inputs` #](#parameters): ```yaml inputs: - area: false label: Sequence motif name: motif type: text value: ACGT ``` Use the parameter in [`shell_command` #](#expressions) like this: ```yaml shell_command: | motif="$(inputs.motif)" ``` (validator-types-reference)= ### Validator types Field tables and examples for every validator supported by user-defined tool inputs. (validator-empty_field)= #### empty_field validator Require a value that is neither an empty string nor null. | Field | Details | Default | Required | | --- | --- | --- | --- | | `type` | Fails validation when the submitted value is an empty string or null. | `"empty_field"` | No | | `message` | Error message shown when validation fails; `%s` is replaced with the rejected value. | `null` | No | | `implicit` | Set internally when Galaxy added the validator automatically; tool authors normally leave this false. | `false` | No | | `negate` | Require the value to be empty or null instead. | `false` | No | Use this validator on a compatible input: ```yaml inputs: - label: Sample name name: sample_name type: text validators: - type: empty_field ``` (validator-in_range)= #### in_range validator Require a numeric value to fall within optional lower and upper bounds. | Field | Details | Default | Required | | --- | --- | --- | --- | | `type` | Enforces the numeric boundaries configured by `min` and `max`. | `"in_range"` | No | | `message` | Error message shown when validation fails; `%s` is replaced with the rejected value. | `null` | No | | `implicit` | Set internally when Galaxy added the validator automatically; tool authors normally leave this false. | `false` | No | | `min` | Rejects smaller values; omit to leave the range without a lower bound. | `null` | No | | `max` | Rejects larger values; omit to leave the range without an upper bound. | `null` | No | | `exclude_min` | Whether a value equal to `min` is rejected. | `false` | No | | `exclude_max` | Whether a value equal to `max` is rejected. | `false` | No | | `negate` | Reject values inside the configured range instead of values outside it. | `false` | No | Use this validator on a compatible input: ```yaml inputs: - label: Score threshold name: threshold type: float validators: - max: 1 min: 0 type: in_range value: 0.5 ``` (validator-length)= #### length validator Require the number of characters in a text value to fall within optional bounds. | Field | Details | Default | Required | | --- | --- | --- | --- | | `type` | Enforces character-count boundaries on a submitted text value. | `"length"` | No | | `message` | Error message shown when validation fails; `%s` is replaced with the rejected value. | `null` | No | | `implicit` | Set internally when Galaxy added the validator automatically; tool authors normally leave this false. | `false` | No | | `min` | Rejects text with fewer characters; omit to leave the length without a lower bound. | `null` | No | | `max` | Rejects text with more characters; omit to leave the length without an upper bound. | `null` | No | | `negate` | Reject values whose length is inside the configured range instead of outside it. | `false` | No | Use this validator on a compatible input: ```yaml inputs: - label: Sample name name: sample_name type: text validators: - max: 20 min: 1 type: length ``` (validator-no_options)= #### no_options validator Require a select parameter to have at least one available option. | Field | Details | Default | Required | | --- | --- | --- | --- | | `type` | Fails validation when a select input has no choices available. | `"no_options"` | No | | `message` | Error message shown when validation fails; `%s` is replaced with the rejected value. | `null` | No | | `implicit` | Set internally when Galaxy added the validator automatically; tool authors normally leave this false. | `false` | No | | `negate` | Require the select parameter to have no available options instead. | `false` | No | Use this validator on a compatible input: ```yaml inputs: - label: Reference database name: database options: - label: Human value: human type: select validators: - type: no_options ``` (validator-regex)= #### regex validator Require a regular expression to match from the start of the value. End the expression with `$` to require a full-value match. Each option of a select parameter is checked separately. | Field | Details | Default | Required | | --- | --- | --- | --- | | `type` | Applies the regular expression in `expression` to each submitted text value. | `"regex"` | No | | `message` | Error message shown when validation fails; `%s` is replaced with the rejected value. | `null` | No | | `implicit` | Set internally when Galaxy added the validator automatically; tool authors normally leave this false. | `false` | No | | `negate` | Reject matching values instead of values that do not match. | `false` | No | | `expression` | Regular expression matched from the start of the value. Add `$` at the end to require a complete-value match. | — | Yes | Use this validator on a compatible input: ```yaml inputs: - label: DNA motif name: motif type: text validators: - expression: ^[ACGT]+$ type: regex ``` (output-types-reference)= ### Output types Field tables and examples for dataset and dataset collection outputs. (output-collection)= #### collection output A user-defined tool collection populated only by matching produced filenames. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to connect this output in workflows and address it in tool tests. | `null` | No | | `label` | Name shown for the produced dataset or collection in the history. | `null` | No | | `hidden` | Hide the output in the history. The dataset is still created and usable by other tools and workflows. | `null` | No | | `type` | Creates one history dataset collection populated from files produced by the command. | — | Yes | | `format_source` | Input whose datatype supplies the default format for collection elements. | `null` | No | | `metadata_source` | Dataset input whose metadata supplies defaults for collection elements. | `null` | No | | `format` | Default datatype extension assigned to collection elements. | `null` | No | | [`collection_type` #](#output-collection-collection-type) | Fixed structure Galaxy creates for this output, such as `list`, `paired`, or a nested type such as `list:paired`. | `null` | No | | [`collection_type_source` #](#output-collection-collection-type-source) | Declared data-collection input whose runtime structure determines this output's collection type. | `null` | No | | [`structured_like` #](#output-collection-structured-like) | Declared input whose element count, identifiers, and nesting this output mirrors. Use this when each produced element corresponds to an input element. | `null` | No | | [`discover_datasets` #](#discover-datasets) | Filename pattern used to discover and populate collection elements. | `null` | No | Add this `collection` output under [`outputs` #](#outputs): ```yaml outputs: - collection_type: list discover_datasets: - format: txt pattern: (?P.+)\.txt label: Results name: results type: collection ``` (output-collection-collection-type)= ##### collection_type `collection_type` can be used to declare a fixed output structure. A `list` contains an ordered set of discovered elements; `paired` requires `forward` and `reverse` identifiers. ```yaml inputs: [] shell_command: mkdir reports && printf 'sample\tvalue\nA\t1\n' > reports/A.tsv && printf 'sample\tvalue\nB\t2\n' > reports/B.tsv outputs: - collection_type: list discover_datasets: - directory: reports format: tabular pattern: (?P.+)\.tsv name: reports type: collection ``` (output-collection-collection-type-source)= ##### collection_type_source `collection_type_source` can be used when the output has the same runtime collection type as a declared data-collection input, including when that input accepts more than one structure. ```yaml inputs: - collection_type: paired format: - fastqsanger name: reads type: data_collection shell_command: mkdir copied && cp '$(inputs.reads.elements.forward.path)' copied/forward.fastq && cp '$(inputs.reads.elements.reverse.path)' copied/reverse.fastq outputs: - collection_type_source: reads discover_datasets: - directory: copied format: fastqsanger pattern: (?Pforward|reverse)\.fastq name: copied_reads type: collection ``` (output-collection-structured-like)= ##### structured_like `structured_like` can be used when each produced element corresponds to an element of a declared input. Galaxy mirrors that input's element identifiers and nesting in the output. ```yaml inputs: - collection_type: paired format: - fastqsanger name: reads type: data_collection shell_command: mkdir trimmed && head -n 400 '$(inputs.reads.elements.forward.path)' > trimmed/forward.fastq && head -n 400 '$(inputs.reads.elements.reverse.path)' > trimmed/reverse.fastq outputs: - collection_type: paired discover_datasets: - directory: trimmed format: fastqsanger pattern: (?Pforward|reverse)\.fastq name: trimmed_reads structured_like: reads type: collection ``` (output-data)= #### data output A user-defined tool dataset discovered only from files inside the job working directory. | Field | Details | Default | Required | | --- | --- | --- | --- | | `name` | Identifier used to connect this output in workflows and address it in tool tests. | `null` | No | | `label` | Name shown for the produced dataset or collection in the history. | `null` | No | | `hidden` | Hide the output in the history. The dataset is still created and usable by other tools and workflows. | `null` | No | | `type` | Creates one history dataset from a file produced by the command. | — | Yes | | [`format` #](#output-data-format) | Galaxy datatype extension assigned when the command always produces a fixed representation. Use `format_source` instead when the datatype depends on an input. | `null` | No | | [`format_source` #](#output-data-format-source) | Data or collection input whose datatype extension this output inherits. Use this when the command preserves the input representation, such as filtering reads without changing their format. | `null` | No | | [`metadata_source` #](#output-data-metadata-source) | Data input whose datatype-specific metadata this output copies as defaults. Use this when the command preserves metadata Galaxy cannot infer from the output, such as interval column assignments. | `null` | No | | [`discover_datasets` #](#discover-datasets) | Filename pattern used to discover additional datasets produced by the command. | `null` | No | | [`from_work_dir` #](#output-data-from-work-dir) | Relative path, inside the job working directory, that the command writes for this output. Galaxy claims that file after the command finishes. | `null` | No | | [`precreate_directory` #](#output-data-precreate-directory) | Set true when `from_work_dir` names a produced directory for a composite datatype. Galaxy copies the directory contents into the output dataset's extra-files area. | `false` | No | Add this `data` output under [`outputs` #](#outputs): ```yaml outputs: - format: txt from_work_dir: result.txt label: Result name: result type: data ``` (output-data-format)= ##### format `format` can be used to assign a fixed Galaxy datatype when every run writes the same representation. The value is a datatype extension, not a filename suffix. ```yaml inputs: [] shell_command: printf 'gene\tscore\nBRCA1\t0.95\n' > scores.tsv outputs: - format: tabular from_work_dir: scores.tsv name: scores type: data ``` (output-data-format-source)= ##### format_source `format_source` can be used to assign an output the selected input dataset's datatype when the command preserves its representation. ```yaml inputs: - format: - fastq - fastqsanger name: reads type: data shell_command: head -n 400 '$(inputs.reads.path)' > first.fastq outputs: - format_source: reads from_work_dir: first.fastq name: first_reads type: data ``` (output-data-metadata-source)= ##### metadata_source `metadata_source` can be used to copy datatype-specific metadata from an input when the command preserves information Galaxy cannot infer from the produced file, such as interval column assignments. ```yaml inputs: - format: - interval name: intervals type: data shell_command: awk '$3 > $2' '$(inputs.intervals.path)' > filtered.interval outputs: - format: interval from_work_dir: filtered.interval metadata_source: intervals name: filtered_intervals type: data ``` (output-data-from-work-dir)= ##### from_work_dir `from_work_dir` can be used to claim a file written by the command. The relative path must match the command's destination and remain inside the job working directory. ```yaml inputs: - label: Message name: message type: text shell_command: printf '%s\n' '$(inputs.message)' > message.txt outputs: - format: txt from_work_dir: message.txt name: message_file type: data ``` (output-data-precreate-directory)= ##### precreate_directory `precreate_directory` can be used with a directory-backed composite datatype. The command creates the directory named by `from_work_dir`; Galaxy then copies its contents into the output dataset's extra-files area. ```yaml inputs: - format: - fasta name: reference type: data shell_command: mkdir index && bwa-mem2 index -p index/reference '$(inputs.reference.path)' outputs: - format: bwa_mem2_index from_work_dir: index name: index precreate_directory: true type: data ``` (discover-datasets)= ### Discover datasets Use [`discover_datasets` #](#discover-datasets) when a command creates a variable set of files. User-defined tools discover them by matching filenames produced in the job working directory. Pattern discovery matches a regular expression against filenames. Named groups such as `name`, `designation`, `ext`, and `dbkey` set the corresponding dataset metadata. Use `directory` to search below the job working directory, and set `recurse: true` to include nested directories. With recursion, `match_relative_path: true` applies the pattern to each path relative to `directory` instead of only the filename. The `format` field sets the Galaxy datatype extension when the pattern does not provide `ext`. See the **Datatypes page** in your Galaxy instance for the extensions it supports. Set `visible: true` to show discovered datasets individually in the history. For a `data` output, `assign_primary_output: true` assigns the first match to the declared primary output. Results default to lexical filename order. Choose `sort_key` from `filename`, `name`, `designation`, or `dbkey`; choose `sort_comp` as `lexical` or `numeric`; and set `sort_reverse: true` for descending order. ```yaml inputs: [] shell_command: | mkdir reports printf 'sample\tvalue\nA\t1\n' > reports/A.tsv printf 'sample\tvalue\nB\t2\n' > reports/B.tsv outputs: - name: reports type: collection collection_type: list discover_datasets: - pattern: "(?P.+)\\.tsv" directory: reports format: tabular visible: true sort_key: name ``` ## Common questions (expressions-shell)= ### Why do some shell constructs fail? The expression evaluator interprets `$(` and `${` as expression delimiters, so shell constructs using them are not passed to the shell: | Written in [`shell_command` #](#expressions) | Result | | --- | --- | | `$(date +%s)` | Evaluated as JavaScript; the job fails with an expression evaluation error. | | `${HOME}`, `${f%.txt}`, `${VAR:-default}` | Evaluated as JavaScript; normally a syntax error. | | `$(( 1 + 2 ))` | Evaluated as JavaScript and replaced by `3`, changing the command's meaning without an error. | | `$GALAXY_SLOTS`, `$HOME`, `$1` | Passed through untouched. A `$` not followed by `(` or `{` is ignored. | An unbraced shell variable is therefore the safe form, and `$GALAXY_SLOTS` in particular works as it does in XML tools. To emit a literal `$(` or `${`, escape the dollar with a backslash: `\$(date +%s)` reaches the shell as `$(date +%s)`. Backslash handling has one more consequence worth knowing. Escape processing only runs when the command contains `$(` or `${` somewhere; a command with no expression at all is passed through byte for byte. In a command that *does* contain an expression, `\\` collapses to a single `\` everywhere in that command, so a literal backslash pair has to be written as `\\\\`. Lone backslashes such as `\;`, `\.` and `\t` are left alone. (expressions-pattern)= ### How should I structure a command? Keep [`shell_command` #](#expressions) to a short invocation. When a command needs a script, put it in [`configfiles` #](#configfiles); each file's `content` is evaluated with the same expression syntax as [`shell_command` #](#expressions). Within a shell script, evaluate each input once into a variable and use plain, unbraced shell variables below. CPU allocation is not a tool input: declare it with a [resource requirement](#resource-requirements) and pass the allocated `$GALAXY_SLOTS` value to the program. ```yaml requirements: - type: resource cores_min: 4 configfiles: - filename: run.sh content: | set -eu query='$(inputs.query.path)' db='$(inputs.database.path)' foldseek easy-search "$query" "$db" result.m8 tmp --threads "$GALAXY_SLOTS" shell_command: sh run.sh ``` User-defined tool commands run under `set -e`, so the first failing command ends the job. (containers)= ### Why is a command missing from the container? [`container` #](#containers-reference) is required, and the image it names is the only environment the command gets. Every binary, interpreter and library referenced by [`shell_command` #](#expressions), including utilities used to sort, reformat or rename outputs, has to already exist in that image. A single-tool BioContainer is built to be small. Many do ship a Python interpreter, since they are conda environments, but a given image may not, and may equally lack utilities like `jq` or `bc`. Check before relying on one: ```console $ docker run --rm quay.io/biocontainers/foldseek:10.941cd33 sh -c 'command -v python3 awk sort' ``` If a command needs several packages, use a multi-package (mulled) image or an image you build and publish yourself, rather than assuming a single-tool image also carries the others. (containers-reference)= ### How should I write the container image reference? Use a fully qualified `registry/repository:tag` reference: ```yaml container: quay.io/biocontainers/foldseek:10.941cd33 ``` A bare `foldseek:10.941cd33` is not resolved by Galaxy against BioContainers. The identifier is passed to the container runtime as written, and the runtime applies its own default registry, which for Docker is `docker.io/library`, where the image almost certainly does not exist. The failure surfaces at job runtime as an image pull error, not at tool creation. Do **not** prefix the value with `docker://`. Galaxy stores a [`container` #](#containers-reference) string as a Docker container description and adds the `docker://` prefix itself when the destination executes through Singularity or Apptainer; writing the prefix yourself produces a doubled `docker://docker://...` identifier. Author user-defined tools with the top-level [`container` #](#containers-reference) field. Which container runtime executes that image, and whether images are converted and cached ahead of time, depends on the server. (validation)= ### What does Galaxy check for me? Galaxy checks a user-defined tool at several points before it ever runs: - **Schema validation.** Unknown keys are rejected anywhere in the document, including inside inputs, outputs, requirements, config files and citations, so a misspelled or XML-only field fails immediately rather than being ignored. - **Cross-field validation.** Every `$(inputs.input_name)` referenced from [`shell_command` #](#expressions) or a config file must correspond to a declared input, and every output must declare where its bytes come from. - **Linting.** Creating or editing a tool runs Galaxy's tool linters and refuses the tool if any of them reports a problem. This includes a check that the container reference has a recognizable shape. Linters that call external services are skipped so that authoring does not depend on third-party availability. Two endpoints check a draft without saving it: `POST /api/unprivileged_tools/build` renders the tool form, which is the quickest way to confirm the input interface is what you intended, and `POST /api/unprivileged_tools/runtime_model` returns an OpenAPI model of the tool's inputs. None of this checks that the tool produces *correct results*. A tool that validates, lints and runs to completion can still be wrong: a misquoted path, a flag that silently changes meaning between tool versions, or a container whose tool version differs from the one the command was written against. (testing)= ### Can Galaxy run the declared tests? A user-defined tool may declare a [`tests` #](#testing) block, using the same test syntax as other YAML-format Galaxy tools: ```yaml tests: - inputs: input1: class: File path: simple_line.txt outputs: output1: simple_line.txt ``` Galaxy stores and returns these tests, but does not currently run them for a tool held in the database. There is no in-application "run this tool's tests" action, and a database-stored tool has no tool directory, so file-based test inputs such as the `simple_line.txt` above cannot be resolved. Declared tests become executable once the tool is exported to disk and loaded like a regular tool, at which point the usual tool-test tooling applies. Until in-platform testing exists, validate correctness by running the tool on inputs whose answer you already know, and comparing the outputs against a run of the same command outside Galaxy. This is worth doing once per registered version, since a version bump usually means a new container image as well.