plan_passage
Read-onlyIdempotent
Plan an A→B passage. Compare departure windows by default; pin a single departure only when the user gives an explicit time.
## Tool routing: read this first
Before calling, classify the user's question:
1. **Pure weather lookup at a point** ("y aura-t-il du vent à Cassis
samedi à 14h ?", "quelles vagues dimanche au cap Sicié ?"): call
``get_marine_forecast`` and answer in text. Do NOT call
``plan_passage``: there's no route to plan.
2. **Trajet question with a flexible date** ("Marseille → Porquerolles
ce week-end", "demain ou après-demain", "dans les prochains jours"):
call ``plan_passage`` in **compare-windows mode**, passing
``latest_departure`` (e.g. earliest+48h) and ``sweep_interval_hours``
(3 or 6 typically) so the user sees several departure scenarios
side-by-side. Then pick 2-3 good ones and let the user choose.
This is the **default** for trajet planning: same API cost as a
single passage thanks to cache prewarm, much more value.
3. **Trajet with a precise hour pinned by the user** ("je pars demain
à 8h", "départ Saturday 9am"): call ``plan_passage`` in single
mode (no ``latest_departure``). Used for the final "show me the
detailed plan for THIS departure" view, often after step 2.
4. **Two ways to go** ("nord ou sud du Fromveur pour Ouessant ?",
"par l'intérieur ou l'extérieur des Glénan ?", "Ré ou Aix
demain ?"): one ``plan_passage`` call, the first route in
``waypoints`` and the others in ``alternatives`` (two at most),
each with a short ``label`` saying how it goes ("Par le nord du
Fromveur"). Every route is computed for the same departures, so
the widget compares them cell by cell. Do not make one call per
route.
5. **When to be at a pass** ("à quelle heure au Raz de Sein ?",
"quand renverse le courant au Fromveur ?"): ``get_tidal_stream``
at the pass, with the course you will steer, and ``plan_passage``
comparing departures, both in the same turn; then pick the
departure that brings you there in the favourable window.
6. **Methodology question** ("comment c'est calculé ?",
"quelle efficacité par défaut ?"): call ``read_me``.
Rule of thumb: if the user does NOT give an exact hour, prefer
compare-windows. The widget renders one of the windows by default
and the chat lets the user pick another.
## Waypoints must stay in the water
This server runs a coarse land check before anything else: a leg
that runs a couple of kilometres over land, or a waypoint inland, gets
the call refused before any forecast request, with the leg and the
place named. Redraw it and call again; never show the user a route
over land. The shoreline is coarse (about 1 km, the coast widened by
2 km so harbours stay at sea, and any water a fine current atlas
resolves counts as sea): a spit narrower than about 4 km, or a
leg that shaves a headland, passes the check and is timed as drawn,
too short, too fast, and scored on conditions the boat would never
meet.
So the route is still yours to draw. Between every consecutive pair of
waypoints the straight line must stay at sea. Add intermediate
waypoints to round anything the direct line would cut: headlands,
peninsulas, islands, shoals.
- Toulon to Saint-Tropez: the direct line crosses the Massif des
Maures. Pass south of the presqu'île de Giens, then round cap Bénat
and cap Camarat before turning north into the gulf.
- Brest to Douarnenez: the direct line crosses the presqu'île de
Crozon. Exit the goulet, round the cap de la Chèvre, then head east
into the bay.
Keep about 1 NM of clearance off headlands, more with onshore wind or
swell, and do not shave the inside of islands. Extra waypoints are
close to free: the cap is 50, and sampling cost follows
``segment_length_nm`` and total distance, not the waypoint count. When
in doubt, add the waypoint.
A waypoint that lands ashore has a second effect. Open-Meteo returns
no sea state over land, so those samples carry a null wave height and
the complexity score silently falls back to wind only, dropping the
axis that would have flagged a rough passage.
Name the capes you routed around in your reply ("passage au large du
cap Bénat"), so the user can correct a leg you drew wrong.
## Returned payload
Every time comes back in the UTC offset of ``departure``: send the
user's own (``+02:00`` for France in summer) and read the times as
their clock.
Single mode:
- ``passage``: per-segment timing report (distance_nm, duration_h,
model used, segments[] with TWS/TWA/boat_speed/Hs, warnings).
- ``complexity``: 1-5 difficulty score with wind/sea breakdown and a
human-readable rationale.
- ``openwind_url``: deep-link to ohmywind.fr/plan that renders the
same passage in the standalone web app.
- ``waypoints``: the route as you sent it, which the widget draws on
a map.
- ``route_label`` and ``alternatives[]``, only when you passed
alternatives: each alternative has its ``label``, ``waypoints``,
``passage``, ``complexity`` and ``openwind_url``.
- ``disclaimer``: usage warning to relay (see below).
Compare-windows mode (``latest_departure`` set):
- ``mode``: ``"multi_window"``.
- ``sweep``: ``earliest`` / ``latest`` / ``interval_hours`` /
``window_count``.
- ``windows[]``: each entry has ``departure``, its ``weekday``,
``arrival``, ``duration_h``, ``distance_nm``, ``complexity`` (level
+ label + rationale), ``conditions_summary`` (tws_min/max,
predominant sail angle, hs_min/max), ``warnings`` (the difficulty
first), ``openwind_url``.
- ``meta_warnings``: notes about the whole sweep or the route ("3
fenêtres ignorées …", a long route sampled more sparsely).
- ``waypoints``: the route as you sent it, once for all windows.
- ``route_label`` and ``alternatives[]``, only when you passed
alternatives: each alternative has its ``label``, ``waypoints``
and its own ``windows[]``, same departures.
- ``disclaimer``: usage warning to relay (see below).
## ALWAYS relay the disclaimer
This tool returns an ETA and a difficulty score the user may act on to
decide whether to put to sea. Carry the ``disclaimer`` field into your
reply, once, in the user's language, phrased naturally rather than
quoted verbatim. Put it after the numbers, not before: it qualifies
them, it does not replace them. Do not drop it because the plan looks
easy, and do not repeat it on every follow-up turn about the same
passage.
## How it renders
On hosts that support MCP Apps (Claude, Claude Desktop, ChatGPT, VS
Code Copilot, Goose, Postman, MCPJam), the response is automatically
accompanied by an interactive widget served via the
``ui://openwind/plan-passage`` resource declared on this tool's
``_meta``. In compare-windows mode it lists the departures; the one
the user selects (the earliest at first) drives a map of the route
you drew, coloured by its wind, and its per-leg detail. In single
mode it shows the figures, the map and the per-leg detail. The user
sees your waypoints on that map, one more reason to keep every leg at
sea.
On hosts without MCP Apps support (Cursor, Le Chat, terminal), present
a short text summary of the result (route, ETA, complexity, warnings)
and offer ``openwind_url`` as the link to adjust the route or the
departure on the site.
## Offer the openwind_url(s) in your text reply
Even when the widget renders inline, the link is useful spelled out:
it opens this very plan in the web app, where the user can drag the
route, move the departure or change the boat, and share or bookmark
it.
- **Single mode**: end your reply with a Markdown link built from the
``openwind_url`` field, e.g. ``[Modifier le tracé ou le départ →](<openwind_url>)``.
Always use that value verbatim, never a URL you compose yourself: it
points at the environment this server is configured for, which is not
always the production site.
- **Compare-windows mode**: list 2-4 of the most relevant windows
and give each its own link, e.g.
``- Sam 2 mai 09h · 11h12 · ⚡2/5 · [voir →](url)``.
The widget lets the user inspect any window, but it does not
rank them: your picks and their links still belong in the reply.
Phrase the link with intent, as what the user can do there
("modifier le tracé ou le départ", "ajuster ce départ dans l'app"),
not just a bare URL: the user should know what clicking does.
## Args
waypoints: list of ``{"lat": ..., "lon": ...}`` dicts, 2 to 50.
Used exactly as drawn. Read "Waypoints must stay in the
water" above before building it.
departure: ISO-8601 datetime, timezone-aware.
archetype: the boat. Pick it yourself from what the user sails,
among these (``list_boat_archetypes`` returns the same list):
- ``cruiser_20ft``: 20 ft (6 m) monohull, slow (Beneteau First 210, Catalina 22, Jeanneau Tonic 23)
- ``cruiser_25ft``: 25 ft (8 m) monohull, slow (Beneteau First 25, Catalina 25, Jeanneau Sun Odyssey 24)
- ``cruiser_30ft``: 30 ft (9 m) monohull, slow (Sun Odyssey 32, Bavaria 31, Beneteau Oceanis 31)
- ``cruiser_40ft``: 40 ft (12 m) monohull, average (Sun Odyssey 410, Bavaria 41 Cruiser, Hanse 418)
- ``cruiser_50ft``: 50 ft (15 m) monohull, fast (Sun Odyssey 519, Bavaria C50, Hanse 508)
- ``catamaran_40ft``: 40 ft (12 m) catamaran, fast-reach (Lagoon 40, Bali 4.1, Fountaine Pajot Lucia 40)
- ``racer_cruiser``: 40 ft (12 m) monohull, very-fast (J/122, Pogo 12.50, Solaris 40)
- ``voile_aviron_16ft``: 16 ft (5 m) monohull, slow (Vivier Ilur, Vivier Aven, Vivier Aber)
``voile_aviron_16ft`` is an open sail-and-oar dinghy only; a small cabin cruiser is ``cruiser_20ft``.
efficiency: multiplier on polar speed. ``0.85`` racing, ``0.75``
cruising (default), ``0.65`` loaded family cruising, ``0.55``
heavy seas / fouled hull.
segment_length_nm: target sub-segment length. Default 10 nm
balances precision vs Open-Meteo budget; drop to 5 for tight
coastal work, raise to 20 for long offshore legs.
model: wind model. Default ``"auto"`` tries AROME (≤48 h) →
ICON-EU (≤5 d) → ECMWF IFS 0.25° (≤10 d) → GFS (≤16 d).
Pass ``arome``, ``icon_eu``, ``ecmwf`` or ``gfs`` to bypass.
max_hs_m: optional max significant wave height (meters) over the
route: pass it if you have a sea-state estimate from
``get_marine_forecast`` and want it factored into the score.
Defaults to wind-only scoring.
motor_threshold_kn: optional sail-speed floor (knots) under which
the simulator switches to engine power. Must be paired with
``motor_speed_kn`` (either alone is ignored). Typical value
2 kn: sailors fire up the engine rather than crawl in light
wind. Leave unset for 100% sail. Range (0, 10].
motor_speed_kn: optional speed under engine (knots) applied to
segments where the sail estimate falls under
``motor_threshold_kn``. Typical 5-6 kn for a cruising boat.
Range (0, 12].
min_upwind_twa_deg: optional minimum sailable TWA (degrees)
overriding the archetype's own value (42-50 deg depending on
the boat). Pass it when you know the boat points better or
worse than the archetype suggests. Range [25, 70].
route_label: optional short name for the main route, shown in
the widget when you pass alternatives ("Par le nord").
alternatives: optional other routes for the same trip, at most
two: ``[{"label": "Par le sud", "waypoints": [...]}, ...]``.
Same departures, same boat, same rules for the waypoints
(stay at sea). Each route costs its own forecast requests:
pass them only when the user weighs two ways to go.
inland_waterway: true only when the user sails up a river or a
canal the coarse shoreline counts as land (the Seine to
Rouen, the Loire to Nantes): it turns the land check off for
this call. Never set it to get past a refusal at sea; redraw
the route instead.
## Compare-windows mode (latest_departure set)
When ``latest_departure`` is provided, the tool switches into a
window-comparison call: it walks departure times from ``departure``
up to ``latest_departure`` every ``sweep_interval_hours`` (default
1 h). Returns ``{"mode": "multi_window", "sweep": {...}, "windows":
[...]}`` instead of the single-passage payload. Each window contains
``departure``, ``arrival``, ``duration_h``, ``distance_nm``,
``complexity``, ``conditions_summary``, ``warnings``, and its own
``openwind_url``.
``target_eta``: optional ISO-8601 datetime. When set, only windows that
arrive within ±2 h of the target are returned. If none match, all
windows are returned with a ``meta_warnings`` note.
## Failure modes
Raises ``ForecastHorizonError`` if the chosen model's horizon doesn't
cover the passage and ``model != "auto"``. The error message names the
failing model and suggests longer-range alternatives.Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | auto | |
| max_hs_m | No | ||
| archetype | Yes | ||
| departure | Yes | ||
| waypoints | Yes | ||
| efficiency | No | ||
| target_eta | No | ||
| route_label | No | ||
| alternatives | No | ||
| motor_speed_kn | No | ||
| inland_waterway | No | ||
| latest_departure | No | ||
| segment_length_nm | No | ||
| min_upwind_twa_deg | No | ||
| motor_threshold_kn | No | ||
| sweep_interval_hours | No |
Output Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||