# Input and output schemas

> The two JSON Schemas of a workflow, the rules both must follow, alternatives for the input, and where to find the full references.

Source: https://qsolve.omlabs.co/docs/build/input-and-output-schemas
Updated: 2026-11-13

A workflow has two JSON Schema files. `schemas/input.json` describes what a user provides; Qsolve validates every run's input against it and builds the input form from it. `schemas/output.json` describes the answer `answer()` returns; Qsolve validates the answer against it and draws it from the schema's titles and units. Both use JSON Schema draft-07 with a few restrictions.

| Page | What it covers |
|---|---|
| This page | The shared rules, alternatives, and the check commands. |
| [Input schema reference](/docs/build/input-schema-reference) | Every input keyword and `x-ui` hint, and how the form is built. |
| [Output schema reference](/docs/build/output-schema-reference) | How the answer is validated and drawn, and every output hint. |

## Rules both schemas must follow

`qsolve lint` and the platform reject a schema that breaks these rules:

| Rule | Lint code |
|---|---|
| It is valid draft-07 (`"$schema": "http://json-schema.org/draft-07/schema#"`) | `E020` |
| It does not use `pattern` or `patternProperties` anywhere, because regular expressions can hang validation. Use `enum`, `minLength` or `maxLength` | `E021` |
| Every `$ref` is local, starting with `#`, for example `#/definitions/point` | `E021` |
| It does not use `"format": "regex"` | `E021` |
| It serialises to at most 256 KB | `E022` |
| Every example input in `inputs.examples` validates against the input schema | `E023` |
| It is a JSON object, and its path stays inside the repository | manifest load |

`E022` is measured on the schema's JSON text, in characters, and applies to both files. `E023` applies to the input schema only, and an input schema with no example is `E024` (see [The manifest](/docs/build/manifest#inputs-and-outputs)).

Declare bounds so the form and the validator catch mistakes early: `minItems`, `maxItems`, `minimum`, `maximum`, `maxLength`. Match them to your manifest's `envelope`: `max-cut` allows 24 nodes in the manifest and says `"maxItems": 24` in the schema.

Set `additionalProperties: false` at the top of the input schema so a misspelled field is an error rather than silently ignored. A failing input is refused with `Invalid input at <path>: <message>`, for example `Invalid input at nodes: [] is too short`. Checks a schema cannot express, such as "node names must be unique", belong in `__init__`, which raises `WorkflowError` with a message for the user.

The output schema is stricter in effect than it looks: an answer that does not match fails the run with `Workflow produced an invalid answer: <message>`. See the [output schema reference](/docs/build/output-schema-reference#validation).

## Presentation hints with `x-ui`

`x-ui` is an extra object you may add to a property. It only affects how the form and the answer are drawn; the validator ignores it, so a wrong hint never rejects an input or an answer. The input form reads many hints (`widget`, `labels_from`, `slider` and more); the answer view reads only `unit` and `format`. Both are documented in full in the two reference pages above. Give every property a `title`: without one, the form and the answer show the property name with underscores turned into spaces.

## Alternatives: one input, two descriptions

A top-level `anyOf` of `required` lists lets a user choose how to describe the problem. `portfolio-optimization` accepts either expected returns with a covariance matrix, or a history of returns:

```json
"anyOf": [
  {"title": "Expected returns and covariance", "required": ["expected_returns", "covariance"]},
  {"title": "Historical returns", "required": ["returns_history"]}
]
```

The form shows these as alternatives, titled by each entry's `title`. Details, including the `also` hint, are in the [input schema reference](/docs/build/input-schema-reference).

## Check your schemas

```bash
qsolve validate .     # loads both schemas and validates the example inputs
qsolve lint .         # applies the restrictions above
```
