CSFS — Community Streamflow Service
Live acquisition and harmonization of global streamflow observations.
CSFS connects to open streamflow data providers worldwide — national hydrological agencies, regional networks, research archives, and global model products — harmonizes their observations into one canonical station/observation schema (SI units per variable — discharge m³/s, stage m, water temperature °C — timestamps in UTC), and maintains a near-real-time DuckDB store with scheduled acquisition, health monitoring, a CLI, and a FastAPI read layer.
Documentation: https://darriey.github.io/CSFS/
Why CSFS?
Programmatic access to river discharge data is fragmented: the community
relies either on static archives (GRDC, Caravan, GSIM, EStreams, CAMELS)
that are frozen at publication time, or on single-agency clients (USGS
dataretrieval, hydrofunctions) that each cover one network. Getting
current discharge across, say, France, Brazil, and Japan means learning three
APIs, three formats, and three unit conventions. CSFS provides a single
interface for live, multi-provider acquisition — one connector per agency,
every observation normalized to a common schema, re-acquisition scheduled to
each provider's update cadence — and keeps its provider roster honest
mechanically, with CI-enforced integrity tests.
Provider roster (the honest numbers)
- 98 sources cataloged in
inventory/providers.yaml, labeled by readiness: 76 implemented, 8 research, 5 fallback, 5 manual, 1 degraded, 3 deprecated. - 84 connectors registered in code — the 76
implementedentries plus 8 still labeledresearch/degradedwhile their upstream data paths are validated. - 34 implemented providers are realtime/near-realtime; the rest are recent/archive sources, including roughly a dozen offline research archives (GRDC, Caravan, GSIM, EStreams, LamaH, CAMELS variants, ROBIN, ADHI, SIEREM).
These numbers are generated by scripts/gen_catalog.py and CI fails when
they drift from the inventory and registry.
These statuses are CI-enforced: tests/test_connector_integrity.py
fails the build if a connector ships without tests, lacks a scheduler tier,
or if the inventory claims implemented for a connector that does not exist.
See the full provider catalog.
Note: live-provider commands talk to real agency APIs and can hit transient upstream outages — a failed fetch is usually them, not you.
Install
pip install community-streamflow-service # core
pip install "community-streamflow-service[pandas]" # + DataFrame store queries
pip install "community-streamflow-service[api]" # + FastAPI read layer
Requires Python 3.11+.
Quick start (CLI)
csfs providers # list registered providers + tiers
csfs fetch -p usgs --lookback 168 -n 50 # fetch a week of USGS data
csfs status # what's in the local DuckDB
csfs health # per-connector freshness + run health
csfs serve # HTTP read layer (needs the api extra)
Quick start (Python)
import asyncio
import csfs
async def main() -> None:
async with csfs.open_store("csfs.duckdb", read_only=False) as store:
await csfs.run_acquisition(store, providers=["usgs"], lookback_hours=48, max_stations=20)
stations = await store.get_stations(provider="usgs", limit=5)
# pandas DataFrame indexed by timestamp (needs the [pandas] extra);
# get_observations() / get_observations_arrow() need no extra.
df = await store.get_observations_df(stations[0].id)
print(df["value"].describe())
asyncio.run(main())
Or pull one gauge's series straight from a provider, no database involved:
from datetime import UTC, datetime, timedelta
import csfs
end = datetime.now(UTC)
chunk = csfs.fetch_observations_sync("usgs", "usgs:01646500", start=end - timedelta(days=7), end=end)
The store is a plain DuckDB file — any SQL/pandas/Arrow tooling works on it
directly. The blessed, stable surface is what import csfs re-exports; see
the Python API guide.
SYMFLUENCE integration
CSFS doubles as a streamflow-observation plugin for SYMFLUENCE: install both packages and SYMFLUENCE auto-discovers the handler, so an experiment YAML needs only
ADDITIONAL_OBSERVATIONS: csfs
CSFS_STATION_ID: "usgs:01646500"
to calibrate against any CSFS-reachable gauge (live fetch, or offline from a
CSFS store via CSFS_DB_PATH). See the
SYMFLUENCE integration guide.
API keys
Most connectors need no credentials. Exceptions: norway_nve (free
NVE HydAPI key) and glofas
(Copernicus CDS token in ~/.cdsapirc).
Keep keys out of tracked config files.
Architecture
connectors/ Provider plugins (one per data source)
core/ Canonical data models, registry, health, exceptions
store/ Persistence layer (DuckDB default)
scheduler/ Acquisition runner, cron tiers, daemon
api/ FastAPI query layer
cli/ Command-line interface
inventory/ Global provider inventory (YAML)
Details — including the roster-integrity guard system and the hermetic test policy — in the architecture docs.
Contributing
The most valuable contribution is a new provider connector. See CONTRIBUTING.md for the walkthrough and the roster-integrity requirements your PR must satisfy.
Automated CI triage
When CI fails on main, a Claude Code agent (.github/workflows/ci-autotriage.yml) reads the
failure, posts a triage report as a commit comment, and classifies it:
| Classification | Action |
|---|---|
adapter_drift / data_drift — a data provider changed; fix confined to connectors//tests/ |
fix PR labeled automerge-on-green, auto-merged once CI passes |
contract_change — touches src/csfs/core/ |
PR labeled needs-human-review (a human merges) |
tooling_drift — build / CI / dependency / packaging |
PR labeled needs-human-review (a human merges) |
outage / real_bug / other |
report only, no code change |
Safety: the auto-merge workflow (autofix-automerge.yml) merges a PR only if its entire diff is
within connectors//tests/ — a misclassified change can never auto-merge, regardless of label.
Claude authenticates via the ANTHROPIC_API_KEY_OAUTH repo secret. Pause anytime with
gh workflow disable "CI Auto-Triage" -R DarriEy/CSFS.
Labels: claude-autofix (agent-opened) · automerge-on-green (drift fix, self-merges on green) ·
needs-human-review (needs a human).
Citing
See CITATION.cff.
License
GPL-3.0-or-later. See LICENSE.
Metadata
Release files for community-streamflow-service 0.4.0
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 |
|---|---|---|---|---|
| community_streamflow_service-0.4.0.tar.gz | 1.7 MB | Without provenance | Details for community_streamflow_service-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| community_streamflow_service-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for community_streamflow_service-0.4.0-py3-none-any.whl |
Total release size: 2.1 MB
Release files / community_streamflow_service-0.4.0.tar.gz
| Download URL | community_streamflow_service-0.4.0.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8821db5f03b2b7563828e3dc356481e00c47042f5d0f20196f63a6a578b57662
|
|
BLAKE2b-256 checksum How to use checksums |
4abfa3b1641de0d9669f760dd14f358cce5327d24435e53967a6b18ef8c2d0f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|
Release files / community_streamflow_service-0.4.0-py3-none-any.whl
| Download URL | community_streamflow_service-0.4.0-py3-none-any.whl |
|---|---|
| Size | 395.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d579fc560d6d7a4192e75726080bbae07142594584e47ffbd371c77b347c9d8
|
|
BLAKE2b-256 checksum How to use checksums |
442ed38f9322be8a914623cf80571a3615effb47e43302f8a91de352a976f51f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|
Security for community-streamflow-service 0.4.0
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.