Skip to main content

pytest linter codecov GitHub last commit

cli-surf is a real-time ocean data and surf forecasting tool for the command line.

  • Live wave height, swell direction, period, UV index, wind, and more
  • Real-time tide level with direction indicator and next tide extreme (via NOAA)
  • Sea surface temperature
  • Forecasts up to 7 days out
  • Use as a CLI tool (surf) or query via HTTP API / browser
  • Optional GPT-powered surf reports (includes tide and sea temp context)
  • Supports metric and imperial units, custom colors, and JSON output

Inspired by wttr.in · Documentation · Discord

cli-surf gif


Table of Contents


💻 Usage

There are several ways to use cli-surf: install it as a CLI tool via pipx, hit the public API, or run the server locally and access it via API/browser.

Installing via pipx (pypi)

brew install pipx
pipx install cli-surf
surf --help
surf --location scripps_pier --forecast 4

Hitting the public API

curl https://api.clisurf.com

Running the server locally and using via API

Start the server locally (see Setup below), then query it from your browser or CLI:

$ curl localhost:8000

Location:  San Diego

      .-``'.
    .`   .`
_.-'     '._

UV index:  6.4
Wave Height:  3.9
Wave Direction:  238.0
Wave Period:  9.8
Sea Surface Temp: 64.8
Tide: 3.2 ft ↑ | Next High: 5.1 ft @ 14:30 UTC

API Examples

Arguments are separated by commas.

curl localhost:8000
curl localhost:8000?location=new_york,hide_height,hide_wave,show_large_wave
curl localhost:8000?fc=3,hdate,loc=trestles,c=light_blue
curl localhost:8000?show_past_uv,show_height_history,show_direction_history,show_period_history
curl localhost:8000?loc=malibu,gpt,color=yellow
curl localhost:8000?loc=nazare,json

For the full argument reference, see below or run:

curl localhost:8000/help

API Arguments

Display

Argument Shorthand Description
location loc Location for the forecast. Ex: loc=new_york_city or loc=nyc
hide_wave hw Hide the default wave art
show_large_wave slw Show the large wave art
color c Color of wave art. Ex: color=light_blue
hide_location hl Hide location name
hide_date hdate Hide date in forecast
metric m Use metric units (default: imperial)
decimal dec Specify decimal places in output
json j Output data as JSON. Must be the only argument

Surf Conditions

Argument Shorthand Description
hide_height hh Hide wave height
hide_direction hdir Hide swell direction
hide_period hp Hide swell period
hide_uv huv Hide UV index
hide_tide ht Hide tide level and next extreme (shown by default, requires US coastal location)
show_air_temp sat Show air temperature
show_wind_speed sws Show wind speed
show_wind_direction swd Show wind direction
show_rain_sum srs Show rain sum
show_precipitation_prob spp Show max precipitation chance
show_cloud_cover scc Show hourly cloud cover
show_visibility sv Show hourly visibility

Historical Data

Argument Shorthand Description
show_past_uv spuv Show past UV index
hide_past_uv — Hide past UV index
show_height_history shh Show past wave height
hide_height_history — Hide past wave height
show_direction_history sdh Show past wave direction
hide_direction_history — Hide past wave direction
show_period_history sph Show past wave period
hide_period_history — Hide past wave period

GPT

Argument Shorthand Description
gpt g Activate GPT surf report. Customize via GPT_PROMPT in .env. Default: off

🛠️ Setup

How to Start Locally with Poetry

  1. Install Poetry.

  2. Clone the repository.

    git clone https://github.com/ryansurf/cli-surf.git
    cd cli-surf
    
  3. Install dependencies and activate the virtual environment.

    make install
    
  4. Start the server.

    poetry run python src/server.py
    
    # Or via Makefile
    make run
    

How to Start with Docker

  1. Install Docker and Docker Compose.

  2. Clone the repository.

    git clone https://github.com/ryansurf/cli-surf.git
    cd cli-surf
    
  3. Start the container.

    docker compose up -d
    
    # Or via Makefile
    make run_docker
    

Variables

When running locally with Poetry, create a .env file from the example:

cp .env.example .env

When starting with Docker, the .env file is created automatically from .env.example during the image build.

General

Variable Description
PORT Port to run the application on. Default: 8000
IP_ADDRESS IP address the server runs on. Default: localhost

Email (optional — see Email Server)

Variable Description
SMTP_SERVER Email server. Default: smtp.gmail.com
SMTP_PORT Email server port. Default: 587
EMAIL Address to send the report from
EMAIL_PW Sending email's password
EMAIL_RECEIVER Address to receive the report
COMMAND Command shown in the email. Default: localhost:8000
SUBJECT Email subject line. Default: Surf Report

GPT (optional — see GPT Surf Report)

Variable Description
GPT_PROMPT Prompt sent to the model along with surf data. Ex: With this data, recommend what size board I should ride.
API_KEY OpenAI API key. Create one here
GPT_MODEL OpenAI model to use. Default: gpt-3.5-turbo (recommended: gpt-4o). See all models here

Database (optional — see MongoDB)

Variable Description
DB_URI MongoDB connection URI

Email Server

Optional — sends a surf report to a specified email on a schedule.

You'll need an email account with SMTP access. Gmail works; follow Method #1 here, then update the email variables in .env.

Note: The FastAPI server must be running to send emails.

# Send email locally (Poetry)
make send_email

# Send email via Docker
make send_email_docker

MongoDB

Optional — stores all request output in a MongoDB database.

See the MongoDB get started guide for setup, then set DB_URI in your .env.

Frontend

Note: The frontend is no longer maintained

cli-surf_website gif

Although this application was made with the CLI in mind, a frontend exists.

Streamlit Frontend

streamlit run src/dev_streamlit.py
# Available at http://localhost:8502

HTML/JS/CSS Frontend (legacy, no longer actively developed)

Available at http://localhost:8000/home or <ip_of_host>:<port>/home.

You may need to set IP_ADDRESS in .env to match the host's IP.


🧠 GPT Surf Report

cli-surf can generate personalized surf reports using OpenAI's GPT models.

Setup

  1. Get an OpenAI API key at platform.openai.com. Make sure a payment method is added.

  2. Update .env:

    API_KEY=your_openai_api_key_here
    GPT_MODEL=gpt-3.5-turbo   # gpt-4o recommended for better results
    GPT_PROMPT=With this data, recommend what size board I should ride and nearby surf spots that may be better with the given conditions.
    
  3. Use the gpt argument:

    curl localhost:8000?location=Malibu,gpt
    

Customizing the prompt

Change GPT_PROMPT in .env to get different types of reports:

GPT_PROMPT="Analyze the surf conditions and suggest the best time of day to surf."
GPT_PROMPT="What are some good places to eat around this surf spot?"

Notes

  • A payment method is required — OpenAI will reject requests from free accounts.
  • GPT responses consume tokens based on prompt and response size.
  • Response time may be slower than standard output, especially during OpenAI outages.
  • gpt-4o gives better results than gpt-3.5-turbo but costs more.

🔧 Tech Stack

Layer Technology
Language Python 3.10+
Web framework FastAPI + Uvicorn
CLI Click
Weather data Open-Meteo API
Optional AI OpenAI GPT API
Optional database MongoDB (pymongo)
Optional frontend Streamlit
Packaging Poetry, pipx
Containerization Docker / Docker Compose
Cloud AWS (Lambda, ECR, API Gateway), CloudFlare (DNS resolver), GoDaddy (register domain name)

📐 Architecture

Architecture

📈 Contributing

Thank you for considering contributing to cli-surf!

See CONTRIBUTING.md to get started.

Questions? Comments?


✨ Contributors

All Contributors

Ryan Frederich
Ryan Frederich

💻 📖 ⚠️ 🤔 💬
𝕂'
𝕂'

💻 📖 ⚠️ 🤔 💬
Corey L.
Corey L.

💻
Shaiful Azhar
Shaiful Azhar

💻
Hummus-Ful
Hummus-Ful

🚇
Rajiv-Rago
Rajiv-Rago

💻
Ulises-Sanch3z
Ulises-Sanch3z

💻
Andrew Koller
Andrew Koller

💻
Michael McGrain
Michael McGrain

💻
SeanAverS
SeanAverS

💻
Rabel Mervin
Rabel Mervin

💻
Vaibhav Chouhan
Vaibhav Chouhan

💻
Nandani Thakur
Nandani Thakur

💻
Brandon
Brandon

🚇
ChristianToro
ChristianToro

💻 🐛
Myles B.
Myles B.

💻
Balaji Ganapathy
Balaji Ganapathy

🐛
chengjackjelly
chengjackjelly

🚇
Varun Singh
Varun Singh

📖 🐛
macnult
macnult

💻
AITMAR-TAFE
AITMAR-TAFE

💻
Latif Fetahaj
Latif Fetahaj

💻 ⚠️
Kim
Kim

⚠️ 💻
Devon Hebenton
Devon Hebenton

💻
AristosKass
AristosKass

⚠️
Raza Khan
Raza Khan

💻

License

License

Metadata

Release files for cli-surf 2.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cli-surf 2.5.1
File Size Uploaded Provenance Actions
cli_surf-2.5.1.tar.gz 32.6 kB With provenance Details for cli_surf-2.5.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cli-surf 2.5.1
File Interpreter ABI Platform Actions
cli_surf-2.5.1-py3-none-any.whl Python 3 none any Details for cli_surf-2.5.1-py3-none-any.whl

Total release size: 64.4 kB

Release files / cli_surf-2.5.1.tar.gz

Download URL cli_surf-2.5.1.tar.gz
Size 32.6 kB
Tags Source
SHA-256 checksum
How to use checksums
3668e7c13e2edb740db196fba4bd069f8f612295a21f0594946519ddfdace82a
BLAKE2b-256 checksum
How to use checksums
033e542ca6feffb15a9a5ed0347e475ece954259c62ffc49fde3d6e4d6424b6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Release files / cli_surf-2.5.1-py3-none-any.whl

Download URL cli_surf-2.5.1-py3-none-any.whl
Size 31.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aaa1b2e3ac866e242e80cb2d5b0dd0a4f056d0cf0f8b8b8a6140965e8c9bda17
BLAKE2b-256 checksum
How to use checksums
b7247d9077fcc61e6d6142fae174dd54db761bef0fd0e3e40e12914155bde3f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Security for cli-surf 2.5.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cli_surf-2.5.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page