# YAML Format & Validate

> Convert between JSON and YAML 1.2, with warnings for YAML 1.1 pitfalls like yes/no and 0755.

Category: Text & Data · Page: https://util.caruana.me/tools/yaml/

## API, MCP and A2A

### Convert JSON to YAML (`json_to_yaml`)

`GET|POST https://util.caruana.me/api/convert/json-to-yaml` · MCP tool `json_to_yaml` · A2A skill `json_to_yaml` · [reference](https://util.caruana.me/reference/json_to_yaml/)

Parses `input` strictly as JSON and writes it as a YAML 1.2 document (block style, no `---` marker, no line folding). Key order is kept unless `sort_keys` is set; integers keep every digit; `1.0` stays `1.0`. Strings that a YAML 1.1 parser would read as something else (`yes`, `no`, `on`, `off`, `y`, `n`, `0755`, `1:20`, `2024-01-01`, `<<`, …) or that YAML 1.2 would read as a number, boolean or null are double-quoted, so the output means the same under both versions. Multi-line strings use literal block scalars (`|`). Duplicate keys keep the last value, with a warning.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string (≤ 100000 chars) | yes | The JSON text, as a string field or a raw `text/plain` POST body. |
| `indent` | integer (2–8) | no | Spaces per YAML indentation level. |
| `sort_keys` | boolean | no | Sort object keys recursively, by UTF-16 code units (the order RFC 8785 uses). Array order never changes. |

Privacy: The server receives the JSON text, processes it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing.

### Convert YAML to JSON (`yaml_to_json`)

`GET|POST https://util.caruana.me/api/convert/yaml-to-json` · MCP tool `yaml_to_json` · A2A skill `yaml_to_json` · [reference](https://util.caruana.me/reference/yaml_to_json/)

Parses `input` as YAML 1.2 with the core schema, whatever any `%YAML` directive says, so `yes`/`no`/`on`/`off` are strings, `0755` is the decimal 755, and dates stay strings; each such value gets a warning because YAML 1.1 parsers read them differently. Duplicate keys are an error. Aliases are expanded, with at most 1,000 expansions and 200,000 output values (billion-laughs protection); recursive aliases are an error. `<<` merge keys are applied unless `merge_keys` is false. `.inf`/`.nan` and complex (collection) keys are errors; non-string scalar keys become strings with a warning. Tags outside the core schema (`!!binary`, `!!timestamp`, `!Ref`, …) follow `custom_tags`. Errors give line, column and code.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string (≤ 30000 chars) | yes | The YAML text, as a string field or a raw `text/plain` POST body. |
| `documents` | first \| all | no | `first` converts the first document (with a warning if there are more; no documents gives `null`). `all` returns a JSON array with one element per document. |
| `indent` | 2 \| 4 \| tab \| none | no | JSON output indentation: `2` or `4` spaces, `tab`, or `none` for minified output (no whitespace at all). |
| `sort_keys` | boolean | no | Sort object keys recursively, by UTF-16 code units (the order RFC 8785 uses). Array order never changes. |
| `merge_keys` | boolean | no | Apply `<<` merge keys (YAML 1.1 feature, common in Compose and CI files). `false` keeps `<<` as an ordinary key. |
| `custom_tags` | error \| drop \| wrap | no | Values with a tag outside the core schema: `error` rejects them; `drop` keeps the value and discards the tag; `wrap` produces `{"<tag>": value}`, e.g. `{"!Ref": "MyBucket"}`. |

Privacy: The server receives the YAML text, processes it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing.

### Lint and format YAML (`yaml_format`)

`GET|POST https://util.caruana.me/api/yaml/format` · MCP tool `yaml_format` · A2A skill `yaml_format` · [reference](https://util.caruana.me/reference/yaml_format/)

Parses `input` as YAML 1.2 (core schema) and reports every finding with its rule, severity, line, column and offset. Rules follow yamllint's default set and names: `syntax`, `key-duplicates`, `anchors`, `braces`, `brackets`, `colons`, `commas`, `comments`, `comments-indentation`, `document-start`, `empty-lines`, `empty-values`, `hyphens`, `indentation`, `line-length`, `new-line-at-end-of-file`, `new-lines`, `octal-values`, `quoted-strings`, `trailing-spaces`, `truthy`, `byte-order-mark`. Errors (`syntax`, `key-duplicates`, an alias without an anchor) make the document invalid; everything else is a warning or info. An invalid document is still a 200 response, with `valid: false`, the findings, and `formatted` and `value` set to null. When the YAML is valid, `formatted` is the document re-written with the chosen indentation, one space after colons and hyphens, no padding inside `{}`/`[]`, at most one blank line in a row, LF line breaks and a final newline. Comments, anchors, tags, key order, block scalars and the text of numbers are kept; quotes are removed only where the plain form means the same string in YAML 1.2 and 1.1 (`"yes"`, `"0755"`, `"null"` stay quoted). The formatted text is re-parsed and compared with the input before it is returned, so it always has the same value. `value` is the data as JSON: the first document's value, or an array of all documents when there are several (merge keys applied, at most 1,000 alias expansions).

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string (≤ 15000 chars) | yes | The YAML text, as a string field or a raw `text/plain` POST body. |
| `indent` | 2 \| 4 | no | Spaces per indentation level, for the `indentation` rule and the formatted output. |
| `indent_sequences` | consistent \| indented \| flush | no | How a sequence under a mapping key is indented: `indented` (`key:` then `  - item`), `flush` (`- item` at the key’s column), or `consistent` (either, as long as the whole file does the same; the first one decides). yamllint’s `indent-sequences`. |
| `max_line_length` | integer (0–1000) | no | Longest allowed line, in characters, for the `line-length` rule; `0` turns the rule off. The default is 120 (yamllint’s is 80, which most Kubernetes and CI files exceed). |
| `document_start` | ignore \| require \| forbid | no | `require`: every document starts with `---`. `forbid`: the first document has no `---`. `ignore`: either. Applies to the findings and the formatted output. |
| `quote_style` | any \| single \| double | no | `single` or `double`: quoted values should use that quote character (`quoted-strings` rule), and the formatter converts them. `any`: no check, and the formatter removes quotes that are not needed. |

Privacy: The server receives the YAML text and the options, processes them in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing.


## User guide

The YAML studio checks, formats and converts YAML in one place. Paste or type a document into **Input**: it is checked as you type. Choose what to look at from the **View** menu; the badge in the status line names the current view, and the **Problems** button next to it counts the findings.

| View          | What it shows                                                                                                                                       |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Input**     | Your YAML, editable, with line numbers.                                                                                                             |
| **Formatted** | The document re-written to a consistent style, with your comments kept. **Use as input** copies it back into Input. Empty when the YAML is invalid. |
| **Tree**      | The data as a collapsible tree. Each entry shows its type (mapping, sequence, string, integer, float, boolean, null) and its path.                  |
| **JSON**      | The same data converted to JSON (see _YAML → JSON_ below).                                                                                          |
| **Problems**  | Every finding, in document order, with its rule, severity, line and column. Click one to jump to that spot in Input.                                |

**Menus.** The studio works like a desktop window. Its menu bar has **File** (open, load the sample, download, clear), **Edit** (format, copy), **View** (switch views, show the options inline, full screen), **Settings** (**Options…** opens the options in an overlay) and **Help** (jumps to these sections, and lists the keyboard shortcuts). The **full-screen** icon sits at the right of the same row: two arrows pointing out make the studio fill the window, and arrows pointing in (or **Esc**) bring it back.

**Edit → Format** (or **Ctrl+Enter**) shows the formatted document on the **Formatted** view; your **Input** is never changed unless you press **Use as input** there. The **JSON** view always shows the converted data, updating as you type. The **Formatted** and **JSON** views each have their own **Copy** and **Download** buttons. The **File** menu has **Open file…** (a `.yaml` or `.yml` file), **Load sample** (a short file with a few findings), **Download input** and **Clear input**.

**Settings → Options….** These settings change the findings and the formatted output together:

- **Indent**: 2 or 4 spaces per level.
- **Sequences**: whether lists under a key are indented. _Indented_ puts `- item` one level in under `key:`. _Flush_ puts `- item` in the key's column. _Consistent_ (the default) accepts either, as long as the whole file does the same; the first list decides.
- **Max line length**: 120 by default, or off. yamllint's default is 80, which most Kubernetes manifests and CI files exceed, so the default here is 120.
- **Document start**: _Ignore_ (default), _Require_ `---` before every document, or _Forbid_ it on the first document.
- **Quote style**: _Any_ (default), _Single_ or _Double_.

**Reading the findings.** An **error** means the YAML is unusable: it does not parse, a mapping has the same key twice, or an alias refers to an anchor that does not exist. Formatted, Tree and JSON stay empty until errors are fixed. A **warning** is a style or portability problem, and **info** is a note. The rules and their IDs match [yamllint](https://yamllint.readthedocs.io/), so a finding here is one yamllint would report with the same settings. The exception is that some yamllint errors are warnings here (see the rules table).

**Why YAML 1.1 matters.** YAML has two versions in wide use. YAML 1.2 (2009) is what this page and the eemeli/yaml library follow. YAML 1.1 is still what PyYAML, Ruby's Psych, SnakeYAML and Go's yaml.v2 implement, so Ansible, many CI systems and older Kubernetes tooling read your file as 1.1. The same plain text means different things:

| You write                             | YAML 1.2 (this page)      | YAML 1.1 parsers               |
| ------------------------------------- | ------------------------- | ------------------------------ |
| `country: no`                         | the string `"no"`         | `false` (the "Norway problem") |
| `enabled: yes`, `on`, `off`, `y`, `n` | strings                   | booleans                       |
| `mode: 0755`                          | the integer 755           | octal 0755 = 493               |
| `mode: 0o755`                         | octal 0o755 = 493         | the string `"0o755"`           |
| `time: 1:20`                          | the string `"1:20"`       | 80 (base 60)                   |
| `size: 1_000`                         | the string `"1_000"`      | 1000                           |
| `date: 2024-01-01`                    | the string `"2024-01-01"` | a date                         |

The `truthy` and `octal-values` rules flag the first rows. YAML → JSON warns about every value in the left column whose meaning differs, and JSON → YAML double-quotes any string that either version would read as something else.

**Converting.**

- **YAML → JSON** takes the first document, or all of them (_All documents_ gives a JSON array). **Merge keys** (`<<: *defaults`, common in Docker Compose and CI files) are applied by default; turn them off to keep `<<` as an ordinary key. **Custom tags** such as CloudFormation's `!Ref` and `!GetAtt`, or YAML 1.1's `!!binary`, have no JSON equivalent, so by default they are an error. _Drop tags_ keeps the value and discards the tag; _Wrap tags_ keeps both, as `{"!Ref": "MyBucket"}`.
- **JSON → YAML** is the reverse conversion. On this site it is the **As YAML** view of the [JSON studio](/tools/json/). The result is block-style YAML 1.2 that means the same under YAML 1.1.

## Specification

**Library.** [eemeli/yaml](https://eemeli.org/yaml/) 2.9, configured for YAML 1.2 with the core schema, strict mode, and unique keys. The linter reads the library's concrete syntax tree, which holds every token with its position. It never matches regular expressions against raw lines, so a `#` inside a string or a blank line inside a block scalar is never mistaken for a comment or a style problem.

**YAML 1.2 is pinned.** A `%YAML 1.1` directive does not switch rules; YAML → JSON warns about it. Plain scalars resolve as in the 1.2 core schema:

| Type    | Forms                                                                                       |
| ------- | ------------------------------------------------------------------------------------------- |
| null    | `null`, `Null`, `NULL`, `~`, or nothing                                                     |
| boolean | `true`, `True`, `TRUE`, `false`, `False`, `FALSE`                                           |
| integer | decimal (`-17`, `0755` is 755), octal `0o17`, hexadecimal `0x1F`                            |
| float   | `1.5`, `.5`, `1e3`, `-1.5E-3`; `.inf`, `-.inf`, `.nan` (rejected by YAML → JSON, see below) |
| string  | everything else, including `yes`, `no`, `on`, `off`, `1_000`, `0b101`, `1:20` and dates     |

### Lint rules

Rule IDs and default behaviour follow yamllint's default configuration. yamllint reports most style rules at error level; here they are warnings, because they do not change what the document means, and an error is kept for YAML that cannot be used. Positions are 1-based lines and columns counted in Unicode code points, plus a 0-based UTF-16 offset; most findings also give an end position.

| ID                        | Level   | What it checks                                                                                                                                                                                                                                                                                       | Format fixes it                                                                       | yamllint                                                                    |
| ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `syntax`                  | error   | The text parses. The message is the library's, at the exact position (unclosed quotes and brackets, bad indentation, tabs used for indentation, a nested mapping on one line, and so on); at most 50 are listed. A core tag that does not fit its value, such as `!!int abc`, is a warning.          | no                                                                                    | syntax errors                                                               |
| `key-duplicates`          | error   | No key appears twice in one mapping. `<<` merge keys may repeat.                                                                                                                                                                                                                                     | no                                                                                    | `key-duplicates`                                                            |
| `anchors`                 | error   | Every alias `*name` has an anchor `&name` before it in the same document (error). An anchor declared again is a warning, and an anchor that no alias uses is info.                                                                                                                                   | no                                                                                    | `anchors` (with `forbid-duplicated-anchors` and `forbid-unused-anchors` on) |
| `braces`                  | warning | No spaces just inside `{}`: `{a: 1}`, and `{}` when empty.                                                                                                                                                                                                                                           | yes                                                                                   | `braces`                                                                    |
| `brackets`                | warning | No spaces just inside `[]`: `[1, 2]`, and `[]` when empty.                                                                                                                                                                                                                                           | yes                                                                                   | `brackets`                                                                  |
| `colons`                  | warning | No space before `:` and one space after it. `*alias : value` is allowed, because the space is required there.                                                                                                                                                                                        | yes                                                                                   | `colons`                                                                    |
| `commas`                  | warning | No space before `,` and exactly one after it, unless the line ends.                                                                                                                                                                                                                                  | yes                                                                                   | `commas`                                                                    |
| `comments`                | warning | A comment starts with `# ` (shebangs `#!` on line 1, `###` banners and a bare `#` are fine), and an inline comment is at least 2 spaces after the content.                                                                                                                                           | spacing before the `#` only                                                           | `comments`                                                                  |
| `comments-indentation`    | warning | A comment on its own line is indented like the next line of content, or like the previous one when it closes a block.                                                                                                                                                                                | yes, except a comment just before the closing bracket of a multi-line flow collection | `comments-indentation`                                                      |
| `document-start`          | warning | Off unless chosen. _Require_: every document starts with `---`. _Forbid_: the first document has no `---`. Later `---` markers separate documents, a document with `%` directives needs its marker, and so does an empty first document.                                                             | yes                                                                                   | `document-start`                                                            |
| `empty-lines`             | warning | At most 2 blank lines in a row, none at the start of the file and none at the end. Lines inside block or multi-line scalars are content and are not counted.                                                                                                                                         | yes (Format keeps at most 1)                                                          | `empty-lines`                                                               |
| `empty-values`            | info    | `key:` with nothing after it, in block or flow mappings. The value is null, which is often a mistake; write `null` or `~` to say so.                                                                                                                                                                 | no                                                                                    | `empty-values` (off by default in yamllint)                                 |
| `hyphens`                 | warning | Exactly one space after the `-` of a list item.                                                                                                                                                                                                                                                      | yes                                                                                   | `hyphens`                                                                   |
| `indentation`             | warning | The root starts in column 1. Each nested block is indented by the chosen width relative to its parent's content. Lists under a key follow the Sequences option. A mapping that starts on the same line as its `- ` is measured from its first key. Block scalar contents are not checked.            | yes                                                                                   | `indentation` (`check-multi-line-strings: false`)                           |
| `line-length`             | warning | No line is longer than the limit (120 by default; off on request). A line whose content is a single word, such as a long URL after `- ` or `# `, is allowed.                                                                                                                                         | no                                                                                    | `line-length` (`allow-non-breakable-words`)                                 |
| `new-line-at-end-of-file` | warning | The text ends with a line break.                                                                                                                                                                                                                                                                     | yes                                                                                   | `new-line-at-end-of-file`                                                   |
| `new-lines`               | warning | Line breaks are LF. CRLF, CR, or a mix, are reported once, at the first one.                                                                                                                                                                                                                         | yes                                                                                   | `new-lines` (`type: unix`)                                                  |
| `octal-values`            | warning | No plain `0755` (decimal 755 in 1.2, octal 493 in 1.1) or `0o755` (octal in 1.2, a string in 1.1). Quoted or tagged values are fine.                                                                                                                                                                 | no                                                                                    | `octal-values` (off by default in yamllint)                                 |
| `quoted-strings`          | warning | Off unless chosen. _Single_: values in double quotes that could use single quotes. _Double_: values in single quotes. Keys are not checked.                                                                                                                                                          | yes                                                                                   | `quoted-strings` (`quote-type`)                                             |
| `trailing-spaces`         | warning | No spaces or tabs at the end of a line.                                                                                                                                                                                                                                                              | yes, except inside block scalars, where they are part of the value                    | `trailing-spaces`                                                           |
| `truthy`                  | warning | Booleans are `true` or `false`. `yes`, `no`, `on`, `off` in any case are flagged because YAML 1.1 reads them as booleans, and `True`, `FALSE` and other casings because they are not portable. Keys are checked too, so GitHub Actions' `on:` is reported. Quoted or `!!str`-tagged values are fine. | no                                                                                    | `truthy`                                                                    |
| `byte-order-mark`         | warning | No U+FEFF at the start.                                                                                                                                                                                                                                                                              | yes                                                                                   | none                                                                        |

Formatting cannot fix the `no` rules without changing what the file means, or what a YAML 1.1 reader sees. For example, quoting `yes` keeps the YAML 1.2 meaning, but tools that read YAML 1.1 lose the boolean they expected.

### Formatting

The formatter uses the yaml library's document model, which keeps comments, anchors, aliases, tags, key order, directives and document markers.

- **Layout.** The chosen indentation, the Sequences option, one space after `:` and `-`, no padding inside `{}` and `[]`, `, ` between flow items, at most one blank line in a row, no blank lines at the start or end, LF line breaks, no byte-order mark, and a final newline. Inline comments get two spaces before the `#`. Lines are never wrapped.
- **Scalars.** Numbers keep their spelling (`0x1F`, `1e3`, `1.50`, `+12` and big integers stay as written), and so do `~`, `True` and other null and boolean forms. Plain multi-line scalars and folded (`>`) scalars are joined onto one line, which leaves their value unchanged. Literal (`|`) scalars keep their lines, chomping and indentation indicators.
- **Quotes.** With quote style _Any_, quotes are removed only from strings that are plainly words: they start with a letter, `_` or `/`, contain only letters, digits, `_ . / @ + -`, parentheses and single spaces, and mean the same string in YAML 1.2 and 1.1. So `"yes"`, `"on"`, `"0755"`, `"1.0"`, `"null"`, `"true"`, `"~"`, `"2024-01-01"`, `"1:20"`, `"<<"` and `""` stay quoted. With _Single_ or _Double_, quoted values switch to that quote character when the content allows (a value containing `'` or a backslash escape stays double-quoted).
- **Comments.** Every comment is kept, next to the node it describes, and own-line comments are re-indented with their content. A few move to the library's canonical place. A comment after `key:` whose value is on the next line moves above the value. A comment on the line after a short value can become that value's inline comment. A comment at the end of the file gets a blank line before it. A comment between documents goes just before the next `---`.
- **Safety check.** The formatted text is parsed again and compared with the original, node by node: values, tags, anchors and alias names. If anything differs, the original text is returned unchanged. One case where this happens is a root block scalar with an indentation indicator, which the library would re-indent incorrectly.
- **Only comments.** A file with comments but no documents is tidied line by line.

### Value

The Tree and JSON tabs (and `value` in the API) show the data of the first document. When there are several documents, they show an array with one element per document. Merge keys are applied, aliases are expanded, integers beyond 2^53 − 1 lose precision, and `.inf` and `.nan` become null. If the aliases would expand past 1,000 copies (a "billion laughs" document), or refer to a collection that contains them, the value is not shown and an `anchors` warning says why; the YAML is still valid and is still formatted.

### YAML → JSON

**Warnings** (at most 100, then a count) cover plain scalars that YAML 1.1 parsers read differently: the 1.1 booleans (`y`, `n`, `yes`, `no`, `on`, `off` in lower, title and upper case), integers with a leading zero (with the octal value 1.1 would give), base-60 numbers, timestamps, and binary or `_`-separated numbers. Also: non-string keys converted to strings, two keys that become the same string, extra documents, and integers beyond 2^53 − 1.

**Errors** stop the conversion and give the line, column, an excerpt, and a code. Parse errors use the library's codes, for example `BAD_INDENT`, `TAB_AS_INDENT`, `MISSING_CHAR`, `DUPLICATE_KEY`, `UNEXPECTED_TOKEN`, `BLOCK_AS_IMPLICIT_KEY`. Conversion errors:

| Code                  | Cause                                                                                                 |
| --------------------- | ----------------------------------------------------------------------------------------------------- |
| `DUPLICATE_KEY`       | The same key twice in one mapping (YAML requires unique keys; JSON's "last one wins" is not applied). |
| `NON_FINITE_NUMBER`   | `.inf`, `-.inf` or `.nan`: JSON numbers must be finite.                                               |
| `COMPLEX_KEY`         | A mapping or sequence used as a key (`? [a, b]`).                                                     |
| `CUSTOM_TAG`          | A tag outside the core schema, with custom tags set to error.                                         |
| `RECURSIVE_ALIAS`     | An alias inside the collection it refers to (`&a [*a]`).                                              |
| `BAD_ALIAS`           | An alias with no matching anchor.                                                                     |
| `BAD_MERGE`           | A `<<` value that is not a mapping or a list of mappings.                                             |
| `RESOURCE_EXHAUSTION` | Over 1,000 alias expansions, or over 200,000 values in the output.                                    |

**Anchors and aliases.** Every alias is expanded into a copy, because JSON has no references. To stop "billion laughs" documents (a few lines of nested aliases that expand to gigabytes), conversion stops after 1,000 alias expansions or 200,000 output values, whichever comes first.

**Merge keys.** A plain (unquoted) `<<` key whose value is an alias or mapping, or a sequence of them, merges those mappings into the current one. Keys written explicitly in the mapping win, wherever they appear; among several merged mappings, earlier ones win. Merged keys are inserted where the `<<` appears. A quoted `"<<"` is always an ordinary key.

**Tags.** The core tags `!!str`, `!!int`, `!!float`, `!!bool`, `!!null`, `!!map`, `!!seq` and the non-specific `!` are applied (`!!str 123` is the string `"123"`). Every other tag, including the YAML 1.1 types `!!binary`, `!!timestamp`, `!!set`, `!!omap` and `!!pairs`, follows the custom-tags option. With _wrap_, the key is the tag as written in short form (`!!binary`, `!Ref`).

**Keys.** JSON keys are strings. A null, boolean or number key becomes its text (`1` → `"1"`, `true` → `"true"`, `~` → `"null"`), with a warning; if two keys end up equal, the later one wins, with a warning.

**Numbers and order.** Integers are converted exactly, however many digits they have. Floats are written in the shortest form that round-trips (`1.5e3` → `1500`). Key order is preserved as written. Comments are discarded (JSON has none).

### JSON → YAML

- The input is parsed with the same strict JSON parser as the JSON tool, so errors give line, column and offset, and duplicate keys keep the last value with a warning.
- Output is block style, indented 2 to 8 spaces per level (2 by default), with sequences indented under their key, no `---` marker, no line folding, and a final newline. Empty objects and arrays are written `{}` and `[]`.
- Key order is kept unless **Sort keys** is on (UTF-16 code unit order, as in the JSON tool).
- Strings are plain when that is unambiguous under both YAML 1.1 and 1.2, double-quoted otherwise. Multi-line strings use literal block scalars (`|`, or `|-` when there is no final newline).
- Integers keep every digit. A number with a fraction or exponent stays a float: `1.0` → `1.0`, `1e5` → `100000.0`, `2.50` → `2.5`, `1e-7` → `1e-7`.

### API

- `POST /api/yaml/format` lints and formats in one call. It takes `input` (at most 15,000 characters; linting and formatting parse the YAML twice, so use the page for larger files), `indent` (`2` or `4`), `indent_sequences` (`consistent`, `indented` or `flush`), `max_line_length` (`0` turns the rule off; default 120), `document_start` (`ignore`, `require` or `forbid`) and `quote_style` (`any`, `single` or `double`). The response has `valid`, `summary` (counts by severity), `diagnostics`, `documents`, `formatted` and `value`. Invalid YAML is a 200 response with `valid: false` and `formatted` and `value` set to null, not an HTTP error.
- `POST /api/convert/yaml-to-json` takes `input` (at most 30,000 characters), `documents` (`first` or `all`), `indent`, `sort_keys`, `merge_keys` and `custom_tags`. The response has `json` (exact text) and `value` (the same data as a JSON value; integers beyond 2^53 − 1 lose precision there, as in any JSON parser).
- `POST /api/convert/json-to-yaml` takes `input` (at most 100,000 characters), `indent` (2–8) and `sort_keys`.
