{
  "openapi": "3.1.1",
  "info": {
    "title": "Greenplot API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://greenplot.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "greenplot-sowing-calendar",
                "greenplot-succession-planner",
                "greenplot-companion-check",
                "greenplot-weather-tasks",
                "hearth-frost-dates"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/greenplot-sowing-calendar/calculate": {
      "post": {
        "operationId": "calculateGreenplotSowingCalendar",
        "summary": "Sowing, planting, harvest and pruning dates for 122 garden plants from your frost dates.",
        "description": "Turns your last spring and first autumn frost into a garden calendar for up to 60 of 122 vegetables, herbs, fruit and flowers: sow indoors, plant out, sow outside with repeat sowings, autumn planting, the harvest or flowering window, and the yearly pruning of fruit and perennials, with a calendar file.\n\nMethodology:\n- Annual vegetables, herbs and flowers go through Hearth’s sowing calendar unchanged (Greenplot passes its bigger plant table): weeks to sow indoors, to plant out and to sow outside are counted from your last spring frost; bulbs and garlic are planted around the first autumn frost; repeat sowings every 2–4 weeks stop when a sowing would no longer ripen before frost.\n- Perennials — fruit trees and bushes, perennial herbs and flowers, asparagus, rhubarb, horseradish — get their yearly windows in weeks from the last spring frost: planting (bare-root or pot), the harvest or flowering window, and pruning or cutting back with its kind (winter pruning of apples and pears, summer pruning of plums and cherries to avoid silver leaf, raspberry canes after fruiting …).\n- Each plant was compiled from its RHS “Grow your own” or growing-guide page (linked in the plant library); weeks are rules of thumb for temperate gardens and shift with your frost dates.\n- Calendar file: one all-day event per window start and per sowing, named after the task.\n\nTimings are rules of thumb. Soil temperature, variety and the weather of the year matter more than any calendar; perennials crop only after their first years.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "greenplot_sowing_calendar",
        "x-owner-app": "greenplot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GreenplotSowingCalendarInput"
              },
              "examples": {
                "example1": {
                  "summary": "Berlin: vegetables, fruit and flowers",
                  "value": {
                    "plants": [
                      "tomato",
                      "lettuce",
                      "strawberry",
                      "apple",
                      "sweet-pea",
                      "garlic"
                    ],
                    "lastFrost": "04-08",
                    "firstFrost": "11-02",
                    "year": 2027
                  }
                },
                "example2": {
                  "summary": "Short season: Munich, cautious dates",
                  "value": {
                    "plants": [
                      "potato",
                      "kale",
                      "raspberry",
                      "blackcurrant",
                      "cosmos",
                      "tulip"
                    ],
                    "lastFrost": "05-06",
                    "firstFrost": "10-06",
                    "year": 2027
                  }
                },
                "example3": {
                  "summary": "Herb garden",
                  "value": {
                    "plants": [
                      "basil",
                      "parsley",
                      "rosemary",
                      "thyme",
                      "mint",
                      "chervil"
                    ],
                    "lastFrost": "04-15",
                    "firstFrost": "10-25",
                    "year": 2027
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GreenplotSowingCalendarResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/greenplot-succession-planner/calculate": {
      "post": {
        "operationId": "calculateGreenplotSuccessionPlanner",
        "summary": "Space repeat sowings of lettuce, radish, beans and more so you harvest all season.",
        "description": "Plans repeat sowings of one vegetable, herb or flower from your frost dates: a sowing every few weeks, each with its harvest window and number of plants, until the last sowing that still ripens before the autumn frost — with gaps in the harvest pointed out and a timeline chart.\n\nMethodology:\n- The first sowing is the start of the plant’s outdoor sowing (or planting-out) window, counted in weeks from your last spring frost — the same window as the garden calendar — or the date you give.\n- Sowings repeat every n weeks (the plant’s usual interval when you leave 0, or three weeks). The last sowing is the last one that still ripens before the end of the season: the first autumn frost minus 14 days for tender plants, the frost itself for half-hardy ones and two weeks after it for hardy ones, minus the days to harvest.\n- Each sowing is picked for the interval (at least two weeks), so harvests follow on; a gap is reported where one harvest ends before the next begins. Plants per sowing = squares × plants per 30 cm square (square-foot spacing from the plant table).\n- Sowings after the end of the usual sowing window are marked: many crops still ripen then, but bolting (lettuce, spinach, coriander in hot weather) and slow autumn growth are more likely.\n\nDays to harvest vary with variety and weather; in midsummer choose bolt-resistant varieties and shade young sowings.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "greenplot_succession_planner",
        "x-owner-app": "greenplot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GreenplotSuccessionPlannerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Lettuce every three weeks, two squares each",
                  "value": {
                    "plant": "lettuce",
                    "lastFrost": "04-08",
                    "firstFrost": "11-02",
                    "year": 2027,
                    "intervalWeeks": 0,
                    "squares": 2
                  }
                },
                "example2": {
                  "summary": "Radishes every two weeks",
                  "value": {
                    "plant": "radish",
                    "lastFrost": "04-20",
                    "firstFrost": "10-20",
                    "year": 2027,
                    "intervalWeeks": 2,
                    "squares": 1
                  }
                },
                "example3": {
                  "summary": "Bush beans from mid-May, every four weeks",
                  "value": {
                    "plant": "bush-bean",
                    "lastFrost": "05-06",
                    "firstFrost": "10-06",
                    "year": 2027,
                    "intervalWeeks": 4,
                    "squares": 4,
                    "start": "2027-05-15"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GreenplotSuccessionPlannerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/greenplot-companion-check/calculate": {
      "post": {
        "operationId": "calculateGreenplotCompanionCheck",
        "summary": "Check which of your plants go well together, which to keep apart, and why.",
        "description": "Checks every pair in a list of up to 40 vegetables, herbs, fruit and flowers for companions and antagonists. Each pair says why — a plain reason such as shared blight or shade, or gardening tradition with weak evidence — and same-family neighbours that share soil pests are listed too.\n\nMethodology:\n- The pair table is our own compilation: Hearth’s twelve traditional pairs plus about sixty more for Greenplot’s library of vegetables, herbs, fruit and flowers. Every pair is either good (grow together) or bad (keep apart).\n- Each pair carries its reason and an evidence label. “Practical” means a plain mechanism: the same disease (late blight on potatoes and tomatoes, verticillium wilt on potatoes and raspberries), shade or competition, a quick crop that is cleared before its neighbour needs the space, pollinators, support for climbers. “Tradition” means gardening lore with weak or no trial evidence; it is shown, never promised.\n- Every pair inside your list is looked up once. The score adds 1 per practical good pair and 0.5 per traditional one, and subtracts the same for bad pairs; the verdict is “conflicts” when any practical bad pair is present.\n- Same-family neighbours are listed for the families that share soil pests and diseases (potato family, cabbage family, onion family, carrot family, legumes, cucurbits): they are fine together in one season but should move on together in the rotation.\n\nCompanion planting is mostly tradition. Spacing, light, water and rotation matter far more than neighbours.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "greenplot_companion_check",
        "x-owner-app": "greenplot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GreenplotCompanionCheckInput"
              },
              "examples": {
                "example1": {
                  "summary": "Tomato bed with potatoes nearby",
                  "value": {
                    "plants": [
                      "tomato",
                      "basil",
                      "potato",
                      "carrot",
                      "onion",
                      "bush-bean"
                    ]
                  }
                },
                "example2": {
                  "summary": "Three sisters with sunflowers",
                  "value": {
                    "plants": [
                      "sweetcorn",
                      "pole-bean",
                      "squash",
                      "sunflower",
                      "nasturtium"
                    ]
                  }
                },
                "example3": {
                  "summary": "Herb spiral",
                  "value": {
                    "plants": [
                      "rosemary",
                      "sage",
                      "thyme",
                      "lavender",
                      "mint",
                      "parsley",
                      "chives"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GreenplotCompanionCheckResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/greenplot-weather-tasks/calculate": {
      "post": {
        "operationId": "calculateGreenplotWeatherTasks",
        "summary": "Frost warnings, watering you can skip after rain, and litres per bed from the MET Norway forecast.",
        "description": "Reads the MET Norway forecast for your garden and turns it into garden tasks for the coming days: frost and cold-night warnings for tender plants in the ground, days when rain makes watering unnecessary, hot days, and how many litres each bed needs from FAO-56 crop water use — with the best days to water.\n\nMethodology:\n- Fetches the MET Norway Locationforecast 2.0 for the place (rounded to 0.01°) through Hearth’s cached client, which honours MET’s Expires and If-Modified-Since rules, and groups the hours into complete local days (at least 20 forecast hours).\n- Frost: a day with a minimum of 1 °C or lower while a tender or half-hardy plant is in the ground (planted or sown before that day) → protect it with fleece or bring pots in; ground frost often comes at 1–3 °C air temperature. Cold night: a minimum of 4 °C or lower while tender plants (tomatoes, beans, courgettes …) are out. Hot day: a maximum of 30 °C or more.\n- Skip watering: a day with 5 mm of rain or more, or the day after one; established beds need no extra water then.\n- Litres per bed: Hearth’s FAO-56 watering need — Penman–Monteith reference evapotranspiration from the forecast, times the crop coefficient of each plant and its growth stage, minus the rain that reaches the roots (80 % of daily rain over 2 mm) — with one soaking per about 12 mm of need, placed on evenly spread days that are not skip days.\n\nForecasts change; frost in hollows and on clear, still nights can come earlier than forecast for the area. Containers and greenhouses need more water.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "greenplot_weather_tasks",
        "x-owner-app": "greenplot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GreenplotWeatherTasksInput"
              },
              "examples": {
                "example1": {
                  "summary": "Berlin: tomatoes, basil and strawberries",
                  "value": {
                    "place": "52.47, 13.40",
                    "timeZone": "Europe/Berlin",
                    "days": 7,
                    "plantings": [
                      {
                        "bed": "Raised bed 1",
                        "plant": "tomato",
                        "areaM2": 0.72
                      },
                      {
                        "bed": "Raised bed 1",
                        "plant": "basil",
                        "areaM2": 0.18
                      },
                      {
                        "bed": "Raised bed 2",
                        "plant": "strawberry",
                        "areaM2": 1.08
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Oslo allotment with young courgettes",
                  "value": {
                    "place": "59.91, 10.75",
                    "timeZone": "Europe/Oslo",
                    "days": 5,
                    "plantings": [
                      {
                        "bed": "Plot",
                        "plant": "zucchini",
                        "areaM2": 2
                      },
                      {
                        "bed": "Plot",
                        "plant": "potato",
                        "areaM2": 6
                      },
                      {
                        "bed": "Fruit",
                        "plant": "blackcurrant",
                        "areaM2": 3
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GreenplotWeatherTasksResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/hearth-frost-dates/calculate": {
      "post": {
        "operationId": "calculateHearthFrostDates",
        "summary": "Last spring and first autumn frost at your place, with the chance of a later or earlier frost.",
        "description": "Finds the nearest weather station with frost statistics for 1991–2020 — Deutscher Wetterdienst for Germany, NOAA for the United States — and gives the last spring frost and the first autumn frost at three risk levels, a hard frost and the length of the frost-free season.\n\nMethodology:\n- Germany: the nearest of 265 Deutscher Wetterdienst stations (within 40 km) with daily minimum temperatures for at least 25 of the years 1991–2020, from a bundled table built by scripts/data/hearth-dwd-frost.py. Frost = a daily minimum at 2 m of 0 °C or lower; hard frost = −2.2 °C or lower (NOAA’s 32 °F and 28 °F).\n- Per year, the last spring frost is the last such day from January to July and the first autumn frost the first one from August to December; a year counts when March–June (or September–December) miss at most five days. The 10 / 50 / 90 % dates are percentiles over the years (linear interpolation): after the 10 % spring date a frost came in only one year in ten.\n- United States: the nearest NOAA NCEI station with 1991–2020 freeze-date probabilities (annual/seasonal normals ANN-TMIN-PRBLST/PRBFST at 32 °F and 28 °F, same 10 / 50 / 90 % meaning) found with the NCEI search service in a box of ±0.4° (then ±1.2°) around the place; answers are cached for 30 days.\n- Frost-free days per level = days between the last spring and the first autumn frost of that level. The station’s own median frost-free season is shown as well.\n\nFrost dates describe 1991–2020 at a weather station; hollows, slopes and city gardens can differ by weeks. Watch the forecast before planting out tender plants.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "hearth_frost_dates",
        "x-owner-app": "hearth",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HearthFrostDatesInput"
              },
              "examples": {
                "example1": {
                  "summary": "Berlin",
                  "value": {
                    "place": "52.47, 13.40"
                  }
                },
                "example2": {
                  "summary": "Munich",
                  "value": {
                    "place": "48.14, 11.58"
                  }
                },
                "example3": {
                  "summary": "Hamburg",
                  "value": {
                    "place": "53.55, 9.99"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HearthFrostDatesResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "GreenplotSowingCalendarInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "plants": {
            "title": "Plants",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "tomato",
                "pepper",
                "eggplant",
                "potato",
                "cucumber",
                "zucchini",
                "squash",
                "melon",
                "sweetcorn",
                "bush-bean",
                "pole-bean",
                "pea",
                "broad-bean",
                "lettuce",
                "spinach",
                "chard",
                "beet",
                "carrot",
                "parsnip",
                "radish",
                "turnip",
                "onion",
                "spring-onion",
                "garlic",
                "leek",
                "cabbage",
                "broccoli",
                "cauliflower",
                "kale",
                "brussels-sprouts",
                "kohlrabi",
                "pak-choi",
                "rocket",
                "celery",
                "fennel",
                "parsley",
                "basil",
                "dill",
                "coriander",
                "chives",
                "asparagus",
                "rhubarb",
                "artichoke",
                "jerusalem-artichoke",
                "sweet-potato",
                "okra",
                "celeriac",
                "swede",
                "endive",
                "chicory",
                "mizuna",
                "corn-salad",
                "shallot",
                "chilli",
                "mangetout",
                "chinese-cabbage",
                "horseradish",
                "cress",
                "mustard-greens",
                "soybean",
                "tomatillo",
                "watermelon",
                "rosemary",
                "thyme",
                "sage",
                "oregano",
                "mint",
                "lavender",
                "tarragon",
                "lemon-balm",
                "lovage",
                "sorrel",
                "bay",
                "marjoram",
                "chamomile",
                "borage",
                "chervil",
                "summer-savory",
                "strawberry",
                "raspberry",
                "autumn-raspberry",
                "blackberry",
                "blueberry",
                "gooseberry",
                "redcurrant",
                "blackcurrant",
                "apple",
                "pear",
                "plum",
                "cherry",
                "peach",
                "apricot",
                "quince",
                "fig",
                "grape",
                "kiwi",
                "physalis",
                "sunflower",
                "french-marigold",
                "calendula",
                "nasturtium",
                "sweet-pea",
                "cosmos",
                "zinnia",
                "cornflower",
                "poppy",
                "nigella",
                "phacelia",
                "crimson-clover",
                "dahlia",
                "tulip",
                "daffodil",
                "snapdragon",
                "alyssum",
                "larkspur",
                "gladiolus",
                "echinacea",
                "rudbeckia",
                "lupin",
                "hollyhock",
                "verbena",
                "sweet-william"
              ]
            },
            "default": [
              "tomato",
              "lettuce",
              "strawberry",
              "apple",
              "sweet-pea",
              "garlic"
            ]
          },
          "lastFrost": {
            "title": "Last spring frost (MM-DD)",
            "description": "Month and day, for example 04-20. Hearth’s Frost Dates Finder gives it for Germany and the United States.",
            "type": "string",
            "maxLength": 5,
            "default": "04-20"
          },
          "firstFrost": {
            "title": "First autumn frost (MM-DD)",
            "type": "string",
            "maxLength": 5,
            "default": "10-20"
          },
          "year": {
            "title": "Season (year of the spring frost)",
            "type": "integer",
            "minimum": 2000,
            "maximum": 2100,
            "default": 2027
          }
        },
        "required": [
          "lastFrost",
          "firstFrost"
        ]
      },
      "GreenplotSowingCalendarResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "year",
              "lastFrost",
              "firstFrost",
              "frostFreeDays",
              "crops",
              "events",
              "tooLong",
              "ics"
            ],
            "properties": {
              "year": {
                "type": "integer"
              },
              "lastFrost": {
                "type": "string"
              },
              "firstFrost": {
                "type": "string"
              },
              "frostFreeDays": {
                "type": "integer"
              },
              "crops": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "crop",
                    "name",
                    "category",
                    "frost",
                    "daysToHarvest",
                    "tasks",
                    "sowings",
                    "lastSowing",
                    "fits",
                    "perennial",
                    "firstYears",
                    "pruneKind"
                  ],
                  "properties": {
                    "crop": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "frost": {
                      "type": "string"
                    },
                    "daysToHarvest": {
                      "type": "integer"
                    },
                    "tasks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "task",
                          "from",
                          "to"
                        ],
                        "properties": {
                          "task": {
                            "enum": [
                              "indoor",
                              "out",
                              "direct",
                              "autumn",
                              "harvest",
                              "prune"
                            ]
                          },
                          "from": {
                            "type": "string"
                          },
                          "to": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "sowings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "lastSowing": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "fits": {
                      "type": "boolean"
                    },
                    "perennial": {
                      "type": "boolean"
                    },
                    "firstYears": {
                      "type": "integer"
                    },
                    "pruneKind": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "crop",
                    "task",
                    "until"
                  ],
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "crop": {
                      "type": "string"
                    },
                    "task": {
                      "type": "string"
                    },
                    "until": {
                      "type": "string"
                    }
                  }
                }
              },
              "tooLong": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "ics": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "GreenplotSuccessionPlannerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "plant": {
            "title": "Plant",
            "type": "string",
            "enum": [
              "tomato",
              "pepper",
              "eggplant",
              "potato",
              "cucumber",
              "zucchini",
              "squash",
              "melon",
              "sweetcorn",
              "bush-bean",
              "pole-bean",
              "pea",
              "broad-bean",
              "lettuce",
              "spinach",
              "chard",
              "beet",
              "carrot",
              "parsnip",
              "radish",
              "turnip",
              "onion",
              "spring-onion",
              "garlic",
              "leek",
              "cabbage",
              "broccoli",
              "cauliflower",
              "kale",
              "brussels-sprouts",
              "kohlrabi",
              "pak-choi",
              "rocket",
              "celery",
              "fennel",
              "parsley",
              "basil",
              "dill",
              "coriander",
              "chives",
              "jerusalem-artichoke",
              "sweet-potato",
              "okra",
              "celeriac",
              "swede",
              "endive",
              "chicory",
              "mizuna",
              "corn-salad",
              "shallot",
              "chilli",
              "mangetout",
              "chinese-cabbage",
              "cress",
              "mustard-greens",
              "soybean",
              "tomatillo",
              "watermelon",
              "marjoram",
              "chamomile",
              "borage",
              "chervil",
              "summer-savory",
              "physalis",
              "sunflower",
              "french-marigold",
              "calendula",
              "nasturtium",
              "sweet-pea",
              "cosmos",
              "zinnia",
              "cornflower",
              "poppy",
              "nigella",
              "phacelia",
              "crimson-clover",
              "dahlia",
              "tulip",
              "daffodil",
              "snapdragon",
              "alyssum",
              "larkspur",
              "gladiolus"
            ],
            "default": "lettuce"
          },
          "lastFrost": {
            "title": "Last spring frost (MM-DD)",
            "description": "Month and day, for example 04-20. Hearth’s Frost Dates Finder gives it for Germany and the United States.",
            "type": "string",
            "maxLength": 5,
            "default": "04-20"
          },
          "firstFrost": {
            "title": "First autumn frost (MM-DD)",
            "type": "string",
            "maxLength": 5,
            "default": "10-20"
          },
          "year": {
            "title": "Season (year of the spring frost)",
            "type": "integer",
            "minimum": 2000,
            "maximum": 2100,
            "default": 2027
          },
          "intervalWeeks": {
            "title": "Weeks between sowings (0 = the plant’s usual interval)",
            "type": "integer",
            "minimum": 0,
            "maximum": 12,
            "default": 0
          },
          "squares": {
            "title": "30 cm squares per sowing",
            "type": "integer",
            "minimum": 1,
            "maximum": 64,
            "default": 2
          },
          "start": {
            "title": "First sowing (optional)",
            "description": "Empty = start of the sowing window.",
            "type": "string",
            "format": "date"
          }
        },
        "required": [
          "lastFrost",
          "firstFrost"
        ]
      },
      "GreenplotSuccessionPlannerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "year",
              "lastFrost",
              "firstFrost",
              "name",
              "plant",
              "intervalWeeks",
              "squares",
              "plantsPerSowing",
              "daysToHarvest",
              "windowFrom",
              "windowTo",
              "lastSowing",
              "seasonEnd",
              "sowings",
              "totalPlants",
              "gaps",
              "harvestFrom",
              "harvestTo",
              "outsideWindow"
            ],
            "properties": {
              "year": {
                "type": "integer"
              },
              "lastFrost": {
                "type": "string"
              },
              "firstFrost": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "plant": {
                "type": "string"
              },
              "intervalWeeks": {
                "type": "integer"
              },
              "squares": {
                "type": "integer"
              },
              "plantsPerSowing": {
                "type": "integer"
              },
              "daysToHarvest": {
                "type": "integer"
              },
              "windowFrom": {
                "type": "string"
              },
              "windowTo": {
                "type": "string"
              },
              "lastSowing": {
                "type": "string"
              },
              "seasonEnd": {
                "type": "string"
              },
              "sowings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "n",
                    "sow",
                    "indoor",
                    "harvestFrom",
                    "harvestTo",
                    "plants",
                    "inWindow"
                  ],
                  "properties": {
                    "n": {
                      "type": "integer"
                    },
                    "sow": {
                      "type": "string"
                    },
                    "indoor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "harvestFrom": {
                      "type": "string"
                    },
                    "harvestTo": {
                      "type": "string"
                    },
                    "plants": {
                      "type": "integer"
                    },
                    "inWindow": {
                      "type": "boolean"
                    }
                  }
                }
              },
              "totalPlants": {
                "type": "integer"
              },
              "gaps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "after",
                    "days"
                  ],
                  "properties": {
                    "after": {
                      "type": "integer"
                    },
                    "days": {
                      "type": "integer"
                    }
                  }
                }
              },
              "harvestFrom": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "harvestTo": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "outsideWindow": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "GreenplotCompanionCheckInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "plants": {
            "title": "Plants",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "tomato",
                "pepper",
                "eggplant",
                "potato",
                "cucumber",
                "zucchini",
                "squash",
                "melon",
                "sweetcorn",
                "bush-bean",
                "pole-bean",
                "pea",
                "broad-bean",
                "lettuce",
                "spinach",
                "chard",
                "beet",
                "carrot",
                "parsnip",
                "radish",
                "turnip",
                "onion",
                "spring-onion",
                "garlic",
                "leek",
                "cabbage",
                "broccoli",
                "cauliflower",
                "kale",
                "brussels-sprouts",
                "kohlrabi",
                "pak-choi",
                "rocket",
                "celery",
                "fennel",
                "parsley",
                "basil",
                "dill",
                "coriander",
                "chives",
                "asparagus",
                "rhubarb",
                "artichoke",
                "jerusalem-artichoke",
                "sweet-potato",
                "okra",
                "celeriac",
                "swede",
                "endive",
                "chicory",
                "mizuna",
                "corn-salad",
                "shallot",
                "chilli",
                "mangetout",
                "chinese-cabbage",
                "horseradish",
                "cress",
                "mustard-greens",
                "soybean",
                "tomatillo",
                "watermelon",
                "rosemary",
                "thyme",
                "sage",
                "oregano",
                "mint",
                "lavender",
                "tarragon",
                "lemon-balm",
                "lovage",
                "sorrel",
                "bay",
                "marjoram",
                "chamomile",
                "borage",
                "chervil",
                "summer-savory",
                "strawberry",
                "raspberry",
                "autumn-raspberry",
                "blackberry",
                "blueberry",
                "gooseberry",
                "redcurrant",
                "blackcurrant",
                "apple",
                "pear",
                "plum",
                "cherry",
                "peach",
                "apricot",
                "quince",
                "fig",
                "grape",
                "kiwi",
                "physalis",
                "sunflower",
                "french-marigold",
                "calendula",
                "nasturtium",
                "sweet-pea",
                "cosmos",
                "zinnia",
                "cornflower",
                "poppy",
                "nigella",
                "phacelia",
                "crimson-clover",
                "dahlia",
                "tulip",
                "daffodil",
                "snapdragon",
                "alyssum",
                "larkspur",
                "gladiolus",
                "echinacea",
                "rudbeckia",
                "lupin",
                "hollyhock",
                "verbena",
                "sweet-william"
              ]
            },
            "default": [
              "tomato",
              "basil",
              "potato",
              "carrot",
              "onion",
              "bush-bean"
            ]
          }
        },
        "required": []
      },
      "GreenplotCompanionCheckResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "plants",
              "good",
              "bad",
              "sameFamily",
              "neutralPairs",
              "score",
              "verdict",
              "perPlant"
            ],
            "properties": {
              "plants": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "good": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "a",
                    "b",
                    "kind",
                    "evidence",
                    "note"
                  ],
                  "properties": {
                    "a": {
                      "type": "string"
                    },
                    "b": {
                      "type": "string"
                    },
                    "kind": {
                      "enum": [
                        "good",
                        "bad"
                      ]
                    },
                    "evidence": {
                      "enum": [
                        "practical",
                        "tradition"
                      ]
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "bad": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "a",
                    "b",
                    "kind",
                    "evidence",
                    "note"
                  ],
                  "properties": {
                    "a": {
                      "type": "string"
                    },
                    "b": {
                      "type": "string"
                    },
                    "kind": {
                      "enum": [
                        "good",
                        "bad"
                      ]
                    },
                    "evidence": {
                      "enum": [
                        "practical",
                        "tradition"
                      ]
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "sameFamily": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "family",
                    "plants"
                  ],
                  "properties": {
                    "family": {
                      "type": "string"
                    },
                    "plants": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "neutralPairs": {
                "type": "integer"
              },
              "score": {
                "type": "number"
              },
              "verdict": {
                "enum": [
                  "conflicts",
                  "tradition-conflicts",
                  "good",
                  "neutral"
                ]
              },
              "perPlant": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "plant",
                    "family",
                    "group",
                    "goodOutside"
                  ],
                  "properties": {
                    "plant": {
                      "type": "string"
                    },
                    "family": {
                      "type": "string"
                    },
                    "group": {
                      "type": "string"
                    },
                    "goodOutside": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "GreenplotWeatherTasksInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "place": {
            "title": "Place (latitude, longitude)",
            "description": "Decimal degrees such as “52.47, 13.40”. Rounded to 0.01° (about 1 km).",
            "type": "string",
            "maxLength": 80,
            "default": "52.47, 13.40"
          },
          "timeZone": {
            "title": "Time zone of the place",
            "type": "string",
            "maxLength": 40,
            "default": "Europe/Berlin"
          },
          "days": {
            "title": "Days ahead",
            "type": "integer",
            "minimum": 1,
            "maximum": 9,
            "default": 7
          },
          "plantings": {
            "title": "Plantings",
            "type": "array",
            "minItems": 1,
            "maxItems": 120,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bed": {
                  "title": "Bed",
                  "type": "string",
                  "maxLength": 40
                },
                "plant": {
                  "title": "Plant",
                  "type": "string",
                  "enum": [
                    "tomato",
                    "pepper",
                    "eggplant",
                    "potato",
                    "cucumber",
                    "zucchini",
                    "squash",
                    "melon",
                    "sweetcorn",
                    "bush-bean",
                    "pole-bean",
                    "pea",
                    "broad-bean",
                    "lettuce",
                    "spinach",
                    "chard",
                    "beet",
                    "carrot",
                    "parsnip",
                    "radish",
                    "turnip",
                    "onion",
                    "spring-onion",
                    "garlic",
                    "leek",
                    "cabbage",
                    "broccoli",
                    "cauliflower",
                    "kale",
                    "brussels-sprouts",
                    "kohlrabi",
                    "pak-choi",
                    "rocket",
                    "celery",
                    "fennel",
                    "parsley",
                    "basil",
                    "dill",
                    "coriander",
                    "chives",
                    "asparagus",
                    "rhubarb",
                    "artichoke",
                    "jerusalem-artichoke",
                    "sweet-potato",
                    "okra",
                    "celeriac",
                    "swede",
                    "endive",
                    "chicory",
                    "mizuna",
                    "corn-salad",
                    "shallot",
                    "chilli",
                    "mangetout",
                    "chinese-cabbage",
                    "horseradish",
                    "cress",
                    "mustard-greens",
                    "soybean",
                    "tomatillo",
                    "watermelon",
                    "rosemary",
                    "thyme",
                    "sage",
                    "oregano",
                    "mint",
                    "lavender",
                    "tarragon",
                    "lemon-balm",
                    "lovage",
                    "sorrel",
                    "bay",
                    "marjoram",
                    "chamomile",
                    "borage",
                    "chervil",
                    "summer-savory",
                    "strawberry",
                    "raspberry",
                    "autumn-raspberry",
                    "blackberry",
                    "blueberry",
                    "gooseberry",
                    "redcurrant",
                    "blackcurrant",
                    "apple",
                    "pear",
                    "plum",
                    "cherry",
                    "peach",
                    "apricot",
                    "quince",
                    "fig",
                    "grape",
                    "kiwi",
                    "physalis",
                    "sunflower",
                    "french-marigold",
                    "calendula",
                    "nasturtium",
                    "sweet-pea",
                    "cosmos",
                    "zinnia",
                    "cornflower",
                    "poppy",
                    "nigella",
                    "phacelia",
                    "crimson-clover",
                    "dahlia",
                    "tulip",
                    "daffodil",
                    "snapdragon",
                    "alyssum",
                    "larkspur",
                    "gladiolus",
                    "echinacea",
                    "rudbeckia",
                    "lupin",
                    "hollyhock",
                    "verbena",
                    "sweet-william"
                  ],
                  "default": "tomato"
                },
                "areaM2": {
                  "title": "Area (m²)",
                  "type": "number",
                  "minimum": 0.01,
                  "maximum": 500,
                  "default": 1
                },
                "planted": {
                  "title": "Planted or sown on (optional)",
                  "type": "string",
                  "format": "date"
                }
              },
              "required": [
                "bed"
              ]
            },
            "default": [
              {
                "bed": "Raised bed 1",
                "plant": "tomato",
                "areaM2": 0.72
              },
              {
                "bed": "Raised bed 1",
                "plant": "basil",
                "areaM2": 0.18
              },
              {
                "bed": "Raised bed 2",
                "plant": "strawberry",
                "areaM2": 1.08
              }
            ]
          }
        },
        "required": [
          "place"
        ]
      },
      "GreenplotWeatherTasksResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "place",
              "timeZone",
              "forecastUpdated",
              "days",
              "plantings",
              "beds",
              "totalLitres",
              "et0Total",
              "rainTotal",
              "warnings",
              "skipWatering",
              "attribution"
            ],
            "properties": {
              "place": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "lat",
                  "lon"
                ],
                "properties": {
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  }
                }
              },
              "timeZone": {
                "type": "string"
              },
              "forecastUpdated": {
                "type": "string"
              },
              "days": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "et0",
                    "rain",
                    "effectiveRain",
                    "tmax",
                    "tmin",
                    "cloud",
                    "wind"
                  ],
                  "properties": {
                    "et0": {
                      "type": "number"
                    },
                    "rain": {
                      "type": "number"
                    },
                    "effectiveRain": {
                      "type": "number"
                    },
                    "tmax": {
                      "type": "number"
                    },
                    "tmin": {
                      "type": "number"
                    },
                    "cloud": {
                      "type": "number"
                    },
                    "wind": {
                      "type": "number"
                    },
                    "date": {
                      "type": "string"
                    }
                  }
                }
              },
              "plantings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "bed",
                    "crop",
                    "areaM2",
                    "planted",
                    "stage",
                    "etcMm",
                    "rainMm",
                    "needMm",
                    "litres"
                  ],
                  "properties": {
                    "bed": {
                      "type": "string"
                    },
                    "crop": {
                      "type": "string"
                    },
                    "areaM2": {
                      "type": "number"
                    },
                    "planted": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "stage": {
                      "type": "string"
                    },
                    "etcMm": {
                      "type": "number"
                    },
                    "rainMm": {
                      "type": "number"
                    },
                    "needMm": {
                      "type": "number"
                    },
                    "litres": {
                      "type": "number"
                    }
                  }
                }
              },
              "beds": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "bed",
                    "areaM2",
                    "litres",
                    "needMm",
                    "waterings",
                    "litresPerWatering",
                    "when"
                  ],
                  "properties": {
                    "bed": {
                      "type": "string"
                    },
                    "areaM2": {
                      "type": "number"
                    },
                    "litres": {
                      "type": "number"
                    },
                    "needMm": {
                      "type": "number"
                    },
                    "waterings": {
                      "type": "integer"
                    },
                    "litresPerWatering": {
                      "type": "number"
                    },
                    "when": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "totalLitres": {
                "type": "number"
              },
              "et0Total": {
                "type": "number"
              },
              "rainTotal": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "code",
                    "date",
                    "plants",
                    "beds"
                  ],
                  "properties": {
                    "code": {
                      "enum": [
                        "frost",
                        "cold",
                        "heat"
                      ]
                    },
                    "date": {
                      "type": "string"
                    },
                    "tmin": {
                      "type": "number"
                    },
                    "tmax": {
                      "type": "number"
                    },
                    "plants": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "beds": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "skipWatering": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "rain",
                    "rainBefore"
                  ],
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "rain": {
                      "type": "number"
                    },
                    "rainBefore": {
                      "type": "number"
                    }
                  }
                }
              },
              "attribution": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "HearthFrostDatesInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "place": {
            "title": "Place (latitude, longitude)",
            "description": "Decimal degrees such as “52.47, 13.40”. Rounded to 0.01° (about 1 km).",
            "type": "string",
            "maxLength": 80,
            "default": "52.47, 13.40"
          }
        },
        "required": [
          "place"
        ]
      },
      "HearthFrostDatesResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "place",
              "station",
              "frost",
              "levels",
              "attribution"
            ],
            "properties": {
              "place": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "lat",
                  "lon"
                ],
                "properties": {
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  }
                }
              },
              "station": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "source",
                  "id",
                  "name",
                  "lat",
                  "lon",
                  "elevation",
                  "distanceKm",
                  "years"
                ],
                "properties": {
                  "source": {
                    "enum": [
                      "dwd",
                      "noaa"
                    ]
                  },
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  },
                  "elevation": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "distanceKm": {
                    "type": "number"
                  },
                  "years": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  }
                }
              },
              "frost": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "spring",
                  "autumn",
                  "hardSpring",
                  "hardAutumn",
                  "frostFreeDays"
                ],
                "properties": {
                  "spring": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "p10",
                      "p50",
                      "p90"
                    ],
                    "properties": {
                      "p10": {
                        "type": "string"
                      },
                      "p50": {
                        "type": "string"
                      },
                      "p90": {
                        "type": "string"
                      }
                    }
                  },
                  "autumn": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "p10",
                      "p50",
                      "p90"
                    ],
                    "properties": {
                      "p10": {
                        "type": "string"
                      },
                      "p50": {
                        "type": "string"
                      },
                      "p90": {
                        "type": "string"
                      }
                    }
                  },
                  "hardSpring": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "additionalProperties": false,
                    "required": [
                      "p10",
                      "p50",
                      "p90"
                    ],
                    "properties": {
                      "p10": {
                        "type": "string"
                      },
                      "p50": {
                        "type": "string"
                      },
                      "p90": {
                        "type": "string"
                      }
                    }
                  },
                  "hardAutumn": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "additionalProperties": false,
                    "required": [
                      "p10",
                      "p50",
                      "p90"
                    ],
                    "properties": {
                      "p10": {
                        "type": "string"
                      },
                      "p50": {
                        "type": "string"
                      },
                      "p90": {
                        "type": "string"
                      }
                    }
                  },
                  "frostFreeDays": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  }
                }
              },
              "levels": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "level",
                    "lastSpring",
                    "firstAutumn",
                    "frostFreeDays"
                  ],
                  "properties": {
                    "level": {
                      "type": "integer"
                    },
                    "lastSpring": {
                      "type": "string"
                    },
                    "firstAutumn": {
                      "type": "string"
                    },
                    "frostFreeDays": {
                      "type": "integer"
                    }
                  }
                }
              },
              "attribution": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}