guru
Windguru CLI + MCP + Python library for kiters and agents — free named spots, WINDGURU DEFAULT top models, gear advice. No HTML scraping. No PRO.
Free only — named spots + WINDGURU DEFAULT Tune top-3. No PRO lat/lon click-forecast.
Humans: paste this repo URL into Cursor, Claude, Codex, or ChatGPT and ask “set this up and tell me where I can kite.” The agent instructions below are written for that.
For AI agents (mandatory protocol)
If the user pasted https://github.com/berendgort/guru (or this README), you must follow this section exactly. Do not invent a Windguru scrape, browser walkthrough, or multi-question onboarding.
Goal
Onboard the rider on the first message, then answer kite questions with gear advice using the windguru package (guru CLI and/or guru-mcp tools). Speak like a kite bro (instruct → data.voice): SEND IT / SOFT CALL / SIT IT OUT — honest, never hype a long haul. Not a JSON dump.
Bootstrap (do this first)
- Prefer PyPI, and upgrade every session before briefing:
pipx upgrade windguru || pipx install 'windguru[mcp]' # or: pip install -U 'windguru[mcp]' (activate venv first)
- Run
guru doctor --json— checknetwork.reachableandupgrade.update_available. - Immediately check the profile. If
first_pass/ready=false/range_ready=false, your first reply to the human must be the intake prompt (include level). Do not run weekend/best yet. - One path for every app: run
guru … --jsonon a host that reaches Windguru. Ifnetwork.reachableis false, followon_unreachable: never ask the human to install/run guru or paste bash — intake in-chat only if needed, then one sentence to continue in a local agent (Cursor / local Claude Code). No wire/tunnel unless shellguruis unavailable and a local MCP host needs it.
Optional MCP (only if the host already uses MCP):
{
"mcpServers": {
"guru": {
"command": "guru-mcp"
}
}
}
Operating loop (every kite question)
| Step | CLI | MCP |
|---|---|---|
| 0. Recipe / profile | guru instruct --json or guru profile --json |
instruct / get_profile |
| 1. First pass if needed | see below | see below |
| 2. “Where can I kite?” | guru weekend --json |
weekend_spots — narrate data.schedule (whole horizon) |
| 3. Named / numeric spot | guru best <id> --advise --json |
best_forecast with advise=true |
| 4. Ambiguous name | use candidates → ask user or pass id / --pick |
same via resolve_spot |
First pass (mandatory on the first kite message when ready=false or range_ready=false / first_pass=true):
- Your first message to the human must show exactly
data.intake.prompt_to_user(or the template below). Collect sport, weight, level (required — changes GO wind and sizing), quiver, wetsuits, home range — one message. - Wait for one reply (key=value paste). Do not ask sport, then weight, then kites separately. Do not skip intake.
- Run:
guru setup --intake '<their paste>' --json
or MCPsetup_profilewith the same fields (includinglevel). - Only then continue with weekend / best.
Template to show if you cannot read prompt_to_user yet:
sport=kitefoil weight=78 level=intermediate kites=7,9,12 wetsuits=3/2,4/3 session=3 home=41.39,2.17 drive_km=200 range=Trabucador → Leucate
How to talk to the human
After tools return, narrate for a rider:
- Verdict: GO / MARGINAL / NO-GO
- Week plan from
schedule(Tue / Wed / Thu…) — do not wait for “what about Thursday?” - Best spot + rough drive distance
- Window in local-friendly terms if you can, else UTC
- Wind + gusts; model_agree; size for gusts
- Kite size from quiver; wetsuit for session hours
- Short checklist: watch beach 5 min, side-shore preference, don’t long-drive for marginal
Do not dump raw model tables unless they ask.
Hard rules
- Use preset WINDGURU_DEFAULT only (
guru best/best_forecast). Do not default to raw GFS. - Never scrape windguru.cz HTML, Tune UI, or MapLibre.
- Never require PRO or invent lat/lon click-forecasts.
- On
error_type: ambiguous, pick fromcandidates— never silent first-match. - Respect
retryableon errors; don’t hammer rate limits. - Profile lives at
~/.config/guru/profile.json(override withGURU_CONFIG_DIR).
MCP tool map
| Tool | Use for |
|---|---|
instruct |
Load this recipe into context |
get_profile / setup_profile |
Onboarding |
weekend_spots |
“Where can I kite?” |
search_spots / resolve_spot / near_spots |
Find spot ids |
best_forecast (advise=true) |
Single spot + gear |
get_forecast / list_models |
Escape hatches only |
More: docs/mcp.md · skill copy: skills/guru/SKILL.md
Install
pipx install windguru # CLI: guru … ← canonical path for every app
pipx install 'windguru[mcp]' # + optional STDIO/HTTP adapters
guru doctor --json
Or with pip: pip install windguru / pip install 'windguru[mcp]'.
PyPI: windguru
Every app: guru … --json on a host that reaches Windguru. Optional guru-mcp is the same library for STDIO hosts. Cloud sandboxes that block Windguru are unsupported — move to a local agent; do not tunnel by default.
CLI
| Command | Role |
|---|---|
guru setup |
Rider + home range (sport / weight / level / quiver / drive_km) |
guru profile |
Show profile + missing fields |
guru weekend |
Where can I kite? ~4-day schedule + top-3 model agree |
guru instruct |
Teach agents the workflow |
guru spots <q> |
Name search (resolve id) |
guru near --lat --lon |
Free map markers near a point |
guru best <spot> |
Spot call + gear advice (default; --no-advise for raw) |
guru forecast <spot> -m gfs |
Single model escape hatch |
guru models / schema / doctor / wire |
Discoverability + network probe + optional MCP adapters |
Ambiguous names fail with error_type: ambiguous + candidates (pass numeric id or --pick).
Library
from guru import get_best_forecast, search_spots
from guru.rider.advice import advise_forecast, drive_km_from_home
from guru.rider.profile_store import load_profile
spots = search_spots("castelldefels")
best = get_best_forecast(201, top=3, hours=24)
profile = load_profile()
advice = advise_forecast(
best.forecasts[0], profile, drive_km=drive_km_from_home(profile, best.spot)
)
print(advice.verdict, advice.summary)
Develop
git clone https://github.com/berendgort/guru.git
cd guru
pipx install -e ".[dev,mcp]"
# or: python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev,mcp]"
pytest -q
ruff check .
| Layer | Path | Role |
|---|---|---|
| Core | guru/core/ |
Shared envelope, errors, instruct recipe |
| CLI | guru/cli/ |
Typer + Rich + --json (thin over core) |
| MCP | guru/mcp/ |
FastMCP over core (no CLI imports) |
| Rider | guru/rider/ |
Profile store + kite/wetsuit advice |
| Search | guru/search/ |
HTTP (curl_cffi), blend_math, near, forecast |
| Models | guru/models/ |
Pydantic + aliases only |
| Wire | docs/WIRE.md |
Captured iapi.php |
| MCP | docs/mcp.md |
guru-mcp setup + tools |
Read AGENTS.md before extending. Capture Network → fixtures → tests.
Engineering standards (kept in-repo):
docs/code_quality.md— Korotkevich / Tourist bardocs/data_engineering_standards.md— Gray / Stonebraker bar
Disclaimer
Unofficial. Not affiliated with Windguru. Personal / research use; respect ToS and rate limits.
License
MIT
Metadata
Release files for windguru 0.3.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| windguru-0.3.11.tar.gz | 393.1 kB | Without provenance | Details for windguru-0.3.11.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| windguru-0.3.11-py3-none-any.whl | Python 3 | none | any | Details for windguru-0.3.11-py3-none-any.whl |
Total release size: 453.5 kB
Release files / windguru-0.3.11.tar.gz
| Download URL | windguru-0.3.11.tar.gz |
|---|---|
| Size | 393.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48519081b3b5d49d2a5027e561c47e6b3e25e460ce717b4280ca8c3b16be1d19
|
|
BLAKE2b-256 checksum How to use checksums |
18744f2b8df686894922edaefac7c7e7f62972c71b34fc02bd22df5352f1ddf8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / windguru-0.3.11-py3-none-any.whl
| Download URL | windguru-0.3.11-py3-none-any.whl |
|---|---|
| Size | 60.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6ee47fce0aa577eddd298959a2a9bd5a8d2df7bbd4f4e1259c5a55d0bac1729e
|
|
BLAKE2b-256 checksum How to use checksums |
d2972c264a45c76312c37ffb9f5d9c8a4857923094b9acdf51997db701ffb00f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for windguru 0.3.11
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.