# Code beside a recipe

**Declare by default.** Python is for what a declaration cannot compose: a **protocol** - the body of a GraphQL request, a form exchanged for a token, a signature. Everything after the answer stays declarative - which paths hold the data, which variant to prefer, how the cursor threads the next page - because a person can see and fix that in the editor without a programmer.

- **Handler** (`write_code(kind="handler")`): a `.py` beside the recipe, named by the recipe's `"handler"` field. One class deriving from `nd_crawler.SiteHandler`, overriding one or more hooks: `ask(step, engine)` - what to request instead of the queued address; `read(step, answer, engine)` - take over reading a body (return `True`), or `None` to let the nodes read it (`engine.declared()` runs them); `refused(view)` - how this site's refusals read (`HoldHost`, `RetryLater`, `GiveUp` from `nd_sdk.refusals`).
- **Page script** (`kind="page"`): a `.js` the recipe's `"inject"` names, run in a browser page.
- Prefer a node's `fetch` (headers, method, form) to code when the protocol is just a header or a POST.
- `write_code` says whether the file loads and which hooks it overrides. Say `why` - what the declaration could not express; it is how the format learns what it lacks.

Code runs with the person's rights. It must not read what the task does not need: no cookies into variables, no files outside the recipe's own.
