WeatherOps is an AI-assisted weather decision system.
It is not intended to be a generic weather dashboard. The product goal is to help users answer a practical question:
Is this planned activity reasonable given the weather, and what should I do?
This repository was built through small implementation and hardening phases. The README describes the current product state for review.
WeatherOps follows a deliberately scoped product and engineering strategy:
Small UI, serious backend logic, meaningful AI integration.
The product keeps a compact three-screen user flow:
- New Plan
- Plan Result
- Saved Plans
The engineering depth comes from the backend:
- location validation
- real forecast data ingestion
- forecast normalization
- activity-specific risk rules
- deterministic recommendation logic
- grounded AI-generated explanations
- persisted system/data quality metadata
- deterministic better-time options for risky plans
- reproducible analysis trace metadata
- strict provider, normalizer, and activity-profile contracts
- deterministic scenario evaluation tooling
- immutable saved plan records
- exportable decision reports
- tests and validation behavior
A basic weather app tells users what the weather is.
WeatherOps aims to help users make a decision based on the weather.
Example use cases:
- Should I go hiking during this time window?
- Is this outdoor event weather-risky?
- Is this running plan reasonable given rain, wind, and temperature?
- What are the main weather risks I should prepare for?
The product is intentionally everyday and understandable, while the implementation is designed to show stronger backend and AI-system engineering than a typical CRUD/API weather app.
Status: MVP+ implementation and hardening complete; ready for review
The repository contains a FastAPI backend, deterministic backend core behavior, Open-Meteo-backed weather integration, SQLite-backed immutable plan and analysis persistence, grounded AI recommendation support, persisted Markdown/JSON decision exports, deterministic better-time options for eligible risky plans, scenario evaluation tooling, and a compact React/Vite frontend for the three-screen product flow. The deterministic risk engine remains the source of truth for the final recommendation, risk score, and alternative-window ranking.
The substantial-system hardening sequence is complete. Future work should keep the product scope stable unless a new bounded phase is explicitly approved.
Core planning documents:
docs/project_spec.md- product scope, user flow, system requirements, acceptance criteriadocs/architecture.md- implementation reference, module boundaries, data flow, and flexibility rulesAGENTS.md- instructions for Codex / AI coding agents working in this repositoryAI_native_builder_journal.md- visible evidence of the AI-native development workflow used to build this project
This project was built through an AI-native development workflow.
That means the project was not blindly generated by AI. It was built through a human-led workflow with Codex as an implementation partner and ChatGPT supporting planning, specification, and design review in selected phases.
The file AI_native_builder_journal.md is a
first-class project artifact. It explains how the project was built, how phase
boundaries were handled, what role Codex played, and how human review and
architectural control remained part of the process.
The README explains what WeatherOps does.
The AI-native builder journal explains how WeatherOps was built.
WeatherOps currently supports:
- creating a new weather plan from:
- location
- activity
- date/time window
- user preferences
- resolving and validating the location
- fetching real forecast data
- normalizing forecast data into a consistent internal format
- applying activity-specific risk profiles
- computing a deterministic risk score
- producing a final recommendation:
GOODCAUTIONAVOID
- generating a grounded AI explanation
- preserving compact trace metadata for reproducibility and debugging
- validating activity profiles before risk scoring
- suggesting up to three deterministic lower-risk time windows when a risky plan requests better-time options
- classifying provider warnings and forecast-window coverage where useful
- saving immutable plan and analysis records
- viewing saved plans
- duplicating a saved plan into a new plan form
- deleting saved plans
- exporting Markdown and JSON reports from saved analysis snapshots
- running deterministic scenario checks without live weather or live AI
- testing the backend workflow with mocked weather and AI providers
The preference toggles are preserved as part of the plan contract and saved
snapshot. Current deterministic scoring is driven by configured activity
profiles; suggest_better_time controls whether risky plans attempt
alternative-window generation.
Location input is text-based: city, town, ZIP/postal-style, or landmark queries supported by the location resolver and provider. Coordinate input is intentionally deferred until a later phase.
Plan times are submitted as local date/time values without timezone offsets. Forecast windows must overlap weather data available from the provider; windows outside the available forecast response are rejected instead of guessed.
New Plan
-> Analyze Plan
-> Plan Result
-> Export / Review
-> Saved Plans
The UI remains small and focused. It is intentionally not a large weather dashboard.
High-level backend flow:
User Input
-> Location Resolver
-> Weather Client
-> Forecast Normalizer
-> Risk Engine
-> AI Recommender
-> Persistence
-> Export Service
-> UI Result
The deterministic risk engine should remain the source of truth for the final recommendation.
The AI layer should explain and summarize the deterministic result. It should not invent weather facts or override the rule engine.
The project is implemented in small, reviewable phases. Earlier foundation phases established the backend core, weather integration, persistence, AI explanation, exports, compact UI, scenario coverage, data quality, and better-time options.
The substantial-system upgrade sequence uses S-phases:
- S1: Activity Profile Contract Hardening - validate profile schema, duplicate activities, required factors, and threshold consistency.
- S2: Analysis Trace and Reproducibility - persist compact trace metadata for analysis version, risk profile version, provider/normalizer version, AI mode, fallback reason, and deterministic decision steps.
- S3: Provider Coverage and Warning Propagation - distinguish hard failures for required scoring inputs from warnings for optional or quality-related provider issues.
- S4: API and Export Snapshot Contracts - keep API errors consistent and ensure Markdown/JSON exports represent saved analysis snapshots, including compact provenance where appropriate.
- S5: Scenario Evaluation Runner - run scenario fixtures as deterministic product regression checks and produce reviewer-friendly JSON/Markdown reports without live weather or live AI.
- S6: Saved Analysis Consistency Checks - protect immutable analysis records from malformed or internally inconsistent persisted snapshots.
Each phase should produce a reviewable increment and a short closeout note.
- Keep the UI compact.
- Put the serious engineering in the backend.
- Use deterministic rules before AI explanation.
- Treat saved plans as immutable analysis records.
- Keep hard delete for saved plans in the current product scope.
- Preserve compact traceability for analysis decisions without turning debug metadata into a new user-facing feature.
- Keep external APIs behind service boundaries.
- Standardize external API error responses while preserving meaningful status codes.
- Treat provider warnings and forecast coverage as deterministic data-quality inputs, not AI confidence.
- Default tests should not require live weather or AI API calls.
- Use AI as a development partner, but keep human ownership over product direction, architecture, and quality.
- Update documentation as the project evolves.
WeatherOps currently has a Python FastAPI backend with SQLite persistence and a
React/Vite frontend. The frontend uses a Vite dev proxy for /api requests, so
the backend should be running on http://127.0.0.1:8000 during local UI demos.
Install Python dependencies from the repository root:
python -m pip install -r requirements.txtRun the backend:
uvicorn app.main:app --app-dir backend --reloadHealth check:
http://127.0.0.1:8000/health
Install frontend dependencies from the committed lockfile:
cd frontend
npm ciRun the frontend:
npm run devThen open the Vite local URL, usually:
http://127.0.0.1:5173
Demo flow:
- Start the backend.
- Start the frontend.
- Create a plan from the New Plan screen.
- Review the saved Plan Result with recommendation, score, Better Time Options when generated, weather factors, triggered rules, Data Quality, AI explanation, export actions, and collapsed debug JSON.
- Open Saved Plans.
- View, duplicate, delete, and export saved analyses.
Persisted analyze-plan endpoint:
POST http://127.0.0.1:8000/api/analyze
This is the canonical backend flow. It accepts a plan, resolves the
location with Open-Meteo geocoding, fetches and normalizes the forecast, computes
the deterministic risk result, generates deterministic better-time options when
the plan is risky and suggest_better_time is true, adds a grounded AI
recommendation or deterministic fallback explanation, and saves an immutable
plan plus analysis run in SQLite.
Mock deterministic analysis endpoint:
POST http://127.0.0.1:8000/api/analyze/mock
This endpoint accepts a plan plus manually supplied normalized forecast data and returns the deterministic risk result. It does not call a real weather API, use AI, or save data.
Live weather analysis endpoint:
POST http://127.0.0.1:8000/api/analyze/weather
This endpoint accepts a plan, resolves the location with Open-Meteo geocoding, fetches an Open-Meteo forecast, normalizes the forecast into WeatherOps' internal shape, and returns the deterministic risk result. It does not use AI or save data.
Saved plan endpoints:
GET http://127.0.0.1:8000/api/plans
GET http://127.0.0.1:8000/api/plans/{plan_id}
POST http://127.0.0.1:8000/api/plans/{plan_id}/duplicate
DELETE http://127.0.0.1:8000/api/plans/{plan_id}
Saved plans are immutable. Duplicate returns the original plan input values for a new analysis; it does not create a new saved record. Delete performs a hard delete of the saved plan and associated analysis run for the current product scope.
Export endpoints:
GET http://127.0.0.1:8000/api/plans/{plan_id}/export?format=markdown
GET http://127.0.0.1:8000/api/plans/{plan_id}/export?format=json
Exports are generated on demand, written to tmp/exports by default, and
recorded in SQLite. JSON exports use a stable S4 envelope with export
metadata and a snapshot object containing the saved immutable analysis.
Markdown exports keep the same decision-report focus with compact data quality
and provenance. CSV export is intentionally deferred.
The current test suite is intentionally deterministic. It does not require live weather or AI API access.
From the repository root:
$env:PYTHONPATH = "backend"
python -m pytest backend/testsRun only the scenario regression pack:
$env:PYTHONPATH = "backend"
python -m pytest backend/tests/test_scenarios.pyRun the deterministic scenario evaluation reports:
$env:PYTHONPATH = "backend"
python -m app.scenario_runner --scenario-dir backend/tests/scenarios --output-dir tmp/scenario-reportsFrontend tests:
cd frontend
npm ci
npm testFrontend production build:
cd frontend
npm ci
npm run buildOptional manual live weather smoke:
uvicorn app.main:app --app-dir backend --reloadThen post a plan with a forecast window supported by Open-Meteo to:
http://127.0.0.1:8000/api/analyze/weather
The app includes a .env.example file for local configuration.
Expected variables may include:
AI_PROVIDER=fallback
OPENAI_MODEL=gpt-5-mini
OPENAI_API_KEY=
DATABASE_URL=sqlite:///weatherops.db
EXPORT_DIR=tmp/exports
DEBUG=false
AI_PROVIDER=fallback is the default and does not call a live AI API.
AI_PROVIDER=mock returns a deterministic mock AI-style response for tests and
demos. AI_PROVIDER=openai enables live OpenAI recommendation generation when
OPENAI_API_KEY is available. The app loads .env automatically for local
backend runs.
Local .env files, SQLite databases, generated exports, and temporary runtime
artifacts are intentionally excluded from Git. Do not commit live API keys or
generated local state.
DATABASE_URL currently supports SQLite URLs only. If unset, the backend uses
sqlite:///weatherops.db.
WeatherOps should not become:
- a generic weather clone
- a large frontend dashboard
- a map-heavy app
- a notification platform
- a mobile app
- an AI-only decision system with no deterministic grounding
The goal is a finished, product-like, backend-serious portfolio project.
The AI-native build process and phase documentation may later inform separate repository-evaluation or methodology work. WeatherOps itself should remain framed as the product: a weather decision system with compact UI, serious backend logic, and grounded AI explanation.
WeatherOps demonstrates:
- product thinking
- backend architecture
- API integration
- data normalization
- deterministic business logic
- reproducible analysis contracts
- grounded AI integration
- persistence design
- exports
- scenario-based regression checks
- testing discipline
- AI-native development workflow
The intended final framing is:
WeatherOps is an AI-assisted weather decision system that combines real forecast data, activity-specific risk rules, immutable saved analyses, and grounded AI explanations to help users make practical weather-informed decisions.