Skip to content

lefranz/parl

Repository files navigation

parl — Swiss Parliament watcher

A small toolkit to monitor the Swiss Parliament (Curia Vista parliamentary items) through its undocumented OData API. It tracks a curated watchlist of items, detects changes (Federal Council responses, status changes, votes), and discovers new items matching your keywords — notifying you when something moves.

Two independent scripts:

  • parl_sync.py — re-fetches every item in your watchlist, records changes to a per-item changelog, and notifies on editorially relevant changes.
  • parl_discover.py — searches for new items matching your keywords since the last run, and notifies with a ready-to-paste YAML snippet.

The most reusable piece is probably docs/swiss-parliament-odata.md: field-level notes on the OData endpoint (collections, filters, /Date(ms)/ timestamps, the apostrophe-escaping gotcha, the mandatory User-Agent, language filtering to avoid multilingual duplicates) — the kind of thing that is otherwise nowhere to be found.

Status: working version, early and opinionated. The default keywords target financial-crime topics; change them to fit yours.

Install

python3 -m venv venv
venv/bin/pip install -r requirements.txt
cp watchlist.example.yaml watchlist.yaml   # then edit it

Dependencies: swissparlpy (OData client for the Swiss Parliament) and ruamel.yaml (comment-preserving YAML).

Usage

# Sync the watchlist against the API
./sync.sh                      # via the cron-ready runner (logs to logs/)
./parl_sync.py --dry-run       # show diffs without writing or notifying
./parl_sync.py --item 26.3313  # a single item
./parl_sync.py --no-notify     # sync + write, but no notifications

# Discover new items matching the keywords
./discover.sh                       # normal run (updates state/)
./parl_discover.py --dry-run        # show hits without writing state or notifying
./parl_discover.py --since 2026-01-01

The runners (sync.sh, discover.sh) create a venv-aware wrapper with dated logs and 30-day rotation — handy for cron:

0 7 * * *   /path/to/parl/sync.sh        # daily sync
0 8 * * 1   /path/to/parl/discover.sh    # weekly discovery (Monday 8am)

Configuration

Both scripts read two environment variables:

Variable Default Purpose
PARL_WATCHLIST ./watchlist.yaml Path to your watchlist file
PARL_NOTIFY_CMD (unset) Command used to dispatch notifications. The message is appended as the final argument. If unset, notifications are printed to stdout.

Example — wire notifications to any CLI notifier:

export PARL_NOTIFY_CMD="/path/to/notify.sh --channel parl --message"
./parl_sync.py

With PARL_NOTIFY_CMD unset, messages just print to stdout, so the tool is usable out of the box and easy to pipe.

The watch keywords live at the top of parl_discover.py (KEYWORDS_TITLE, KEYWORDS_DEEP). They are queried against the French-language API, so they are in French.

The watchlist

watchlist.yaml is the source of truth for the items you track. See watchlist.example.yaml for the full field glossary. In short, each entry holds:

  • stable fields you fill in by hand (odata_id, type, titre, auteur, themes, note, ...)
  • synced fields refreshed from OData (statut, cf_proposition, cf_date, modified_odata)
  • a changes[] changelog that parl_sync.py appends to automatically

Your live watchlist.yaml is git-ignored — only the example is committed — so your editorial notes never end up in the repo.

Tests

venv/bin/python -m unittest tests.test_odata_escape

Covers OData string escaping (the délit d'initiédélit d''initié fix) and filter construction.

Documentation

  • docs/swiss-parliament-odata.md — field-level reference for the undocumented Curia Vista OData endpoint (the source the scripts use today).
  • docs/lobbywatch-api.md — the Lobbywatch dataIF API, an optional source for the declared interests of item authors. Not wired in yet; includes an integration plan.
  • docs/openparldata.md — evaluation of the OpenParlData API (federal + cantonal + municipal). Not adopted yet (two blockers documented); worth re-evaluating as it matures.
  • docs/voting-integration.md — design note for adding roll-call vote tracking via the OData Voting collection.

Data source & attribution

Data comes from the Swiss Parliament's Curia Vista service via its OData API. Per the Parliament's terms of use, any reproduction must:

  • attribute "Services du Parlement de l'Assemblée fédérale, Berne";
  • keep the data content unchanged and show the download date;
  • not be presented as an official publication.

This is an independent project, not affiliated with or endorsed by the Swiss Parliament. The OData endpoint is undocumented and may change without notice.

License

MIT.

About

Monitor the Swiss Parliament (Curia Vista parliamentary items) via its undocumented OData API: track a watchlist, detect changes, discover new items.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors