# The recipe format, briefly

Read a shipped recipe of the same shape with `get_recipe` - they are the real reference. This page is the map.

```json
{
  "id": "example",
  "version": 1,
  "domains": ["example.com", "*.example.com"],
  "check": ["https://example.com/gallery/123"],
  "nodes": [
    {
      "id": "gallery",
      "name": "a gallery page",
      "when": {"path": "/gallery/{gallery}"},
      "actions": [
        {"do": "extract", "name": "project_name", "kind": "css", "expr": "h1", "first_only": true},
        {"do": "download", "kind": "css", "expr": "a.full", "attr": "href",
         "page": "https://example.com/photo/{item.id}", "expect": "image/"}
      ],
      "paging": {}
    }
  ]
}
```

- **`domains`** - which hosts it claims, and which it may ask. A wildcard covers subdomains.
- **`check`** - addresses that prove it works, **one per kind of page it takes**. A node with no check address is a node nobody ever ran.
- **A node** is a place you stand; `actions` is what you do there, **in order**. `extract` fills the bag; everything below reads it.
- **`when`**: `path` (a pattern, `{name}` becomes a variable), `pattern` (a regex, named groups become variables), `payload` (what the `follow` that queued the step wrote), `contains` (text in the body), `unless`. **The first node that matches takes the address**; order matters.
- **Values** carry a `kind`: `css` / `xpath` (with `attr`), `json` (a path like `items[].url`), `between` (`before`, `after`), `pattern` (`group`), `value` (a template `{var}`), `fallback` and `union` (with `of`), `map`, `pick`, `call`. `first_only: true` takes one. Test a value with `query` before it goes into the recipe.
- **Actions**: `extract`, `download`, `follow` (queue a step; `nodes` names who takes it, or `loop_level: true` comes back to this level), `scope` (narrow to a region and run actions inside each).
- **A `follow` with neither `nodes` nor `loop_level` is refused** by the reader.
- **An action's `when` and `unless` are a template read as true or false, not an object**: `"when": "{param.all_sizes}"` for a boolean parameter, `"when": "{found}"` for a value extracted above (empty is false). A node's `when` is the object form; on an action the reader refuses it. There is no comparison: give the choice its own boolean parameter.
- **Parameters**: `try_step` and `run_recipe` take `params` - the values a project would carry, by id; the rest keep their defaults. Check both settings of a parameter before saving.
- **Nodes conditioned on `payload` stand above nodes conditioned on the address**: a step a node queued for itself would otherwise be taken back by the address node.
- **Reduce an address to the entity with a regex, not a full path**: `/gallery/(?P<gallery>rg\d+)` catches the id and ignores what follows.
- **Keep ids of different entities apart**; an id of one sort in a query of another gives `null` without an error.
- `fetch` on a node replaces the step's request (headers, a POST body) when the site needs one. Prefer it to code.

`put_draft` answers with the reader's words when something is wrong - they name the field.
