Spaces:
Sleeping
Sleeping
|
Download AGENTS.md from lucashudsn/wavereader: direct link, hf CLI and curl.
- Browser
- Download file 6.92 kB
-
https://huggingface.co/spaces/lucashudsn/wavereader/resolve/main/AGENTS.md
- Command line
-
hf download hf://spaces/lucashudsn/wavereader/AGENTS.md
-
curl -L -o AGENTS.md https://huggingface.co/spaces/lucashudsn/wavereader/resolve/main/AGENTS.md
6.92 kB
| # AGENTS.md | |
| Guidance for AI coding agents working in this repo. The active surface is | |
| `app.py` + `ui/` + `wavereader/` + `data/` (the v2 rebuild). `legacy/` | |
| holds the frozen v1 front end (`main.py` + `app/`) β don't extend it; it | |
| survives only as the fallback layer in `ui/_compat.py`. | |
| ## What is live now | |
| - `app.py` β v2 entrypoint: `build()` + `gr.api` tools + | |
| `demo.launch(css=APP_CSS, mcp_server=True)`. Run `uv run python app.py`. | |
| - `ui/` β the single-page front end (no tabs): `app.py` (layout + wiring, | |
| β€3 `gr.State`; Bells Beach auto-selected on load so there are no empty | |
| states), `panels/{lens,story,intel,agent}.py` (map-lens column | forecast | |
| story | intel rail | full-width agent bar), `charts/{strip,score,seafloor,climate,map,_style}.py`, | |
| `contracts.py` (`SELECT_KEYS`/`FETCH_KEYS`/`AGENT_KEYS` + `fill()` β | |
| handlers return via `fill(KEYS, β¦)` so output ordering can't drift), | |
| `_compat.py` (backend access: v2 core β `legacy.app.*` β stubs; also | |
| wetsuit hints, engine chips, surf cams), `theme.py` (`APP_CSS`, IBM Plex | |
| Mono lo-fi identity β don't restyle without asking). | |
| - `wavereader/` β pure core, typed + tested, no Gradio imports: | |
| `breaks.py` (catalogue, memoized `load_breaks`), `openmeteo.py` | |
| (versioned/atomic disk cache, seaward grid-snap), `scoring.py` (deterministic | |
| 0β10 engine β the LLM never owns numbers), `seafloor.py` (GEBCO world model), | |
| `climate.py` (ERA5 5-yr profiles + audit; `break_climate` reads the | |
| profile embedded on each break record, per-slug file fallback), `tools.py` | |
| (the typed tool functions shared by agent + MCP), `agent.py` | |
| (smolagents `ToolCallingAgent`, | |
| native tool calls, budget: 6 steps / 2 score_week / 700 tokens), | |
| `narrate.py` + `llm.py` (one InferenceClient factory: | |
| Nemotron 3 Ultra via deepinfra, `WR_*` env overrides). | |
| - `scripts/warm_caches.py` β pre-fill forecast + seafloor caches (demo hot | |
| start). `scripts/build_climate.py` β climatology builder (re-embeds built | |
| profiles into the catalogue after each run, backup first). | |
| - `scripts/check_coords.py` + `scripts/check_coast.py` β break-coordinate | |
| maintenance: `check_coords` validates/fixes state/region/duplicate | |
| placement against OSM; `check_coast` audits GEBCO elevation at every | |
| break point and (`--fix`) snaps non-coastal ones to the nearest 0 m | |
| shoreline crossing (both write a timestamped backup first). | |
| - `data/` β `australia-surf-breaks-enriched.json` (238 breaks; each record | |
| embeds its ERA5 profile under `climate` β 236 of 238, the two duplicate | |
| Gnaraloo rows have no profile), | |
| `surf-break-schema.json` (contract), `climate/*.json` (per-slug ERA5 | |
| profiles β `build_climate.py` output and `break_climate`'s fallback; | |
| also `index.json` manifest), `surf-cams.json` (camera links keyed | |
| `"name | state | region"`), `surf-break-example-bells.json` (prompt worked | |
| example). | |
| ## Deploying to HF Spaces | |
| - The Space `lucashudsn/wavereader` (public) *is* this repo β remote | |
| `space`. Every push to `main` auto-deploys via | |
| `.github/workflows/deploy-space.yml` (needs the GitHub repo secret | |
| `HF_TOKEN`) β merging to main ships it; no manual step. For any other | |
| branch, ship manually with `scripts/deploy_space.sh [ref]` (builds a | |
| throwaway commit that prepends `space-config.yaml` to `README.md` and | |
| force-pushes it to `space:main` β Spaces need YAML frontmatter, GitHub | |
| doesn't have to see it; the ref defaults to your current branch), then | |
| `git push origin <branch>` to keep GitHub in sync. The Space builds | |
| from the pushed commit; watch *Logs β Build* on the Space page or poll | |
| `HfApi().get_space_runtime("lucashudsn/wavereader")` until `RUNNING`. | |
| - `space-config.yaml` is the Space config. Keep | |
| `sdk_version` in lockstep with the gradio pin in `requirements.txt` | |
| (regenerate that file only via `uv export --no-hashes | |
| --format requirements-txt --no-dev -o requirements.txt` β other | |
| invocations can leave stray progress lines that break pip), and | |
| `python_version` in lockstep with `pyproject.toml`'s `requires-python`. | |
| If you change Space settings via the web UI, HF rewrites the Space's | |
| `README.md` β mirror anything you care about back into the yaml. | |
| - `HF_TOKEN` is a Space secret (set once via *Settings β Variables and | |
| secrets* or `HfApi().add_space_secret`); `WR_*` overrides can be added | |
| the same way. `.cache/` is ephemeral on the Space and rebuilds lazily β | |
| no persistent storage, no warm step. | |
| ## Conventions that matter | |
| - One spot drives everything: `selected` (gr.State) is the single source of | |
| truth β picking a spot re-aims the map, badges, forecast strip, world | |
| model and climatology together. Keep it that way. | |
| - Staged spin-ups: `ui/panels/story.py::fetch_forecast` is a **generator** | |
| that yields stage 1 (charts, ~ms) then stage 2 (seafloor world model from | |
| a parallel thread). Status lines name the engine + latency. Keep that | |
| pattern for anything slow. | |
| - Charts: theme through `ui/charts/_style.py::style_fig`; weekend shading | |
| via `add_weekend_shading`. The week strip lives in `charts/strip.py` | |
| (score/swell/wind rows); window slicing (weekend/mornings/arvos) re-charts | |
| from state via `filter_hours` β no refetch. Seafloor display is bicubically | |
| smoothed (scipy) and its wave animation is period-driven β smoothing and | |
| animation are display-only; stats stay on the raw grid. | |
| - MCP surface = exactly `score_week` / `rank_region_week` / `explain_score` | |
| (`gr.api` in `app.py`). All event listeners are registered with | |
| `api_name=False` β keep it that way. | |
| - The LLM never owns numbers. Scores/forecasts/analysis stay deterministic; | |
| the model narrates and cites tools. | |
| ## Data contracts | |
| - Required break fields: `name`, `state`, `region`, `location`, | |
| `skillLevel`, `breakType`, `peakType`, `idealSwell`, `idealWind`, | |
| `idealTide`. Optional: `description`, `id`, `bestSeason`, `hazards`, | |
| `crowdFactor`. Never invent enum values β check | |
| `data/surf-break-schema.json` first. | |
| - Canonical `state`/`region` always come from the input list, never the | |
| model. `location.country` is `"Australia"`. | |
| - New prompts must load schema + example from `data/` (don't paste copies). | |
| ## Rules for edits | |
| 1. Everything is tracked in this repo (no nested git β don't re-init one). | |
| 2. Never commit `.env`, `.venv/`, `__pycache__/`, `.DS_Store`, `.cache/` | |
| (all ignored). | |
| 3. Never read `.env` or print secrets/tokens. Use `.env.example` for var | |
| names; check presence with `printenv HF_TOKEN | wc -c` or | |
| `[ -n "$HF_TOKEN" ]` style checks that never echo the value. | |
| 4. Keep prompt files in `data/`; keep `app.py` free of embedded schema text. | |
| 5. Test cheaply: `uv run pytest -q` (offline fixtures) + | |
| `uv run python -c "import app"` for import health. Live LLM calls cost | |
| inference β dry-run the agent via the injected fake model | |
| (`tests/test_agent_dryrun.py`) before any live turn. | |