Local-first, open-source surf condition forecasting powered by LightGBM and free marine APIs.
SurfCast AI downloads free weather, wave and tide data, trains a machine-learning model on your machine, and predicts surf quality for any beach you configure — all without a paid API key or cloud service.
SurfCast AI is an experimental hobby project. Surf-quality predictions are based on synthetic physics-derived labels, not verified surf reports. Never rely on this tool for safety decisions in the ocean. Always check official forecasts, know your limits, and surf with others.
- Free data only — Open-Meteo (weather + marine), NOAA CO-OPS (US tides), harmonic model (global tides)
- Aggressive local caching — minimal network requests; continues working offline with cached data
- LightGBM baseline — fast, interpretable gradient-boosting regressor
- Walk-forward backtesting — chronological splits only, no data leakage
- Feature explanations — top positive and negative factors per prediction
- Polished TUI — seven-screen Textual application (Home, Forecast, Benchmark, Data Sync, Beaches, Model, Settings)
- CLI — sync, train, predict, benchmark, list/add beaches
- Local-first — all data stored in DuckDB under
~/.local/share/surfcast/ - XDG-compliant paths for config, data and cache
# 1. Clone
git clone https://github.com/danh2011/surfcast.git
cd surfcast
# 2. Install
pip install -e .
---
## Quick Start
```bash
# 1. Copy and customise the example configuration
cp config.example.toml ~/.config/surfcast/config.toml
$EDITOR ~/.config/surfcast/config.toml
# 2. Download data (90 days by default)
surfcast sync-data
# 3. Train the model
surfcast train
# 4. Predict surf quality
surfcast predict "Pipeline, Oahu" --date 2024-06-15 --hour 8
# 5. Launch the interactive TUI
surfcast tuiConfig lives at ~/.config/surfcast/config.toml (created automatically on first run).
[general]
cache_ttl_hours = 6 # how long to trust cached HTTP responses
history_days = 90 # how many days of history to download
log_level = "INFO"
[model]
num_leaves = 63
learning_rate = 0.05
n_estimators = 500
min_child_samples = 20
[[beaches]]
name = "Pipeline, Oahu"
lat = 21.6647
lon = -158.0492
orientation = 350 # degrees the beach faces (0=N, 90=E …)
exposure = 5 # 1 (sheltered) – 5 (open ocean)
country = "US"
timezone = "Pacific/Honolulu"
# noaa_station = "1612340" # optional: NOAA station ID for US tidesOrientation tip: set this to the compass direction waves come from to reach the beach. A west-facing beach that receives westerly swells would be 270.
| Source | Data | Key |
|---|---|---|
| Open-Meteo Archive | Historical weather | None |
| Open-Meteo Forecast | 7-day weather forecast | None |
| Open-Meteo Marine | Wave height, period, swell | None |
| NOAA CO-OPS | US tide predictions | None |
| Harmonic model (built-in) | Global tide approximation | None |
All data is cached to disk under ~/.cache/surfcast/http/.
# Sync all beaches (uses config history_days)
surfcast sync-data
# Sync a specific beach for 60 days
surfcast sync-data --beach "Bells Beach, Victoria" --days 60
# Train on all beaches
surfcast train
# Train on one beach, custom window
surfcast train --beach "Fistral Beach, Newquay" --days 45
# Predict surf quality
surfcast predict "Pipeline, Oahu"
surfcast predict "Bells Beach, Victoria" --date 2024-12-01 --hour 6
# Backtest over 60 days
surfcast benchmark "Pipeline, Oahu" --days 60
# Manage beaches
surfcast list-beaches
surfcast add-beach
# Launch TUI
surfcast tui
# Show version
surfcast --versionLaunch with surfcast tui. Navigate using the sidebar or keyboard shortcuts 1–7.
| Key | Screen |
|---|---|
1 |
🏠 Home – dashboard and status |
2 |
🏄 Forecast – pick beach / time, run prediction |
3 |
📊 Benchmark – configure and run backtests |
4 |
🔄 Data Sync – download data, view cache status |
5 |
🏖️ Beaches – browse and add beaches |
6 |
🤖 Model – training info and feature importances |
7 |
⚙️ Settings – config values and paths |
q |
Quit |
SurfCast uses walk-forward (expanding-window) backtesting — the training window grows forward in time, and each test fold evaluates only on future data the model has never seen. This prevents data leakage.
Train ─────────────────────────▶ Test ────
Fold 1 ▶ Fold 2
Fold 2 ▶ Fold 3
Fold 3 ▶ Fold 4
Reported metrics:
| Metric | Description |
|---|---|
| MAE | Mean Absolute Error (score units, 0–10) |
| RMSE | Root Mean Squared Error |
| Band Accuracy | % predictions in the correct quality band (Flat / Poor / Fair / Good / Epic) |
All benchmark runs are saved to the local DuckDB database.
surfcast/
├── config.example.toml # Copy to ~/.config/surfcast/config.toml
├── pyproject.toml
├── README.md
├── src/surfcast/
│ ├── __init__.py
│ ├── cli.py # Click CLI entry point
│ ├── config.py # TOML config loader
│ ├── database.py # DuckDB schema & CRUD
│ ├── data/
│ │ ├── fetcher.py # Orchestrates data downloads
│ │ └── sources/
│ │ ├── open_meteo.py # Weather + marine API client
│ │ └── tides.py # NOAA + harmonic tide model
│ ├── features/
│ │ └── engineer.py # Feature engineering + synthetic labels
│ ├── models/
│ │ ├── base.py # Abstract model interface
│ │ └── lgbm_model.py # LightGBM implementation
│ ├── benchmarking/
│ │ └── backtester.py # Walk-forward backtester
│ ├── tui/
│ │ ├── app.py # Textual app + navigation
│ │ └── screens/
│ │ ├── home.py
│ │ ├── forecast.py
│ │ ├── benchmark.py
│ │ ├── data_sync.py
│ │ ├── beaches.py
│ │ ├── model_status.py
│ │ └── settings.py
│ └── utils/
│ ├── paths.py # XDG path helpers
│ └── logging_setup.py # Structured logging
└── tests/
├── test_config.py
├── test_database.py
├── test_features.py
├── test_model.py
├── test_tides.py
└── test_backtester.py
# Install dev extras
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=surfcast --cov-report=term-missing
# Lint
ruff check src/ tests/
# Type-check
mypy src/surfcast/The test suite covers:
- Config loading and defaults
- DuckDB schema, upserts and JOIN queries
- Feature engineering (all columns present, no NaNs, cyclical bounds)
- Physics-based surf scorer (range, flat/good conditions)
- LightGBM train / predict / save / load round-trip
- Harmonic tide model (count, timezone, oscillation, range)
- Walk-forward backtester (result structure, metric sanity on synthetic data)
32 passed in 5.5 s
- Real surf-report labels (Surfline open data, Magic Seaweed)
- SHAP values for richer per-prediction explanations
- Multi-model registry (XGBoost, MLP, ensemble)
- Swell-window alerts (notify when score exceeds threshold)
- Web dashboard option (FastAPI + HTMX)
- Docker / Nix packaging
- CI/CD with GitHub Actions
MIT — see LICENSE.
- Open-Meteo for the free weather and marine API
- NOAA CO-OPS for free US tide data
- Textual for the TUI framework
- LightGBM for the gradient-boosting library