Website: English · Deutsch — command reference, guides and API docs
Follow Germany's Bundesrat — the chamber of the sixteen Länder — from your
terminal. bundesrat is a command-line tool over the Bundesrat's public data
feeds (the data behind the official Bundesrat app): the current plenary sitting's
agenda and its Drucksachen, the members, and committee dates — as clean JSON you
can pipe straight into jq.
--state / --party.--compact for scripting, -o <file>
to write to disk.Want to use this as a TypeScript library, or curious how it parses the XML feeds with zero dependencies? See DEVELOPING.md.
npm i -g @maschinenlesbar.org/bundesrat-cli
This installs the bundesrat command. Requires Node.js 20+. No API key.
Check it works:
bundesrat session | jq '.title'
# The current plenary sitting: title + agenda items with their Drucksachen
bundesrat session | jq '{title, tops: [.tops[] | {toptitle, topdrucksache, topheader}]}'
# Every member from Bavaria
bundesrat members --state Bayern | jq -r '.[] | "\(.firstname) \(.name) — \(.party)"'
# All Green members across the Länder
bundesrat members --party grüne | jq length
# Committee appointments with their dates
bundesrat appointments | jq -r '.[] | "\(.startdate // "")\t\(.title)"'
| Command | What it shows |
|---|---|
session |
Current plenary sitting: title, date and agenda items (TOPs) with their Drucksachen |
members |
Members of the Bundesrat (--state <Land>, --party <text>) |
appointments |
Committee appointments and dates (Termine) |
New to terms like TOP, Drucksache or Land? The Glossary decodes every one.
Why only three commands? The Bundesrat feeds also carry news/press items, the BundesratKOMPAKT editorial summaries, the Stimmverteilung graphic, and the Präsidium / next-sitting HTML pages. Those return copyright-protected editorial text and images, not open data, so this CLI doesn't expose them (and strips the editorial fields — HTML
detail, biographies, images — from the three it keeps). See DATA_LICENSE.md.
members filters| Option | Meaning |
|---|---|
--state <Land> |
Only members of that federal state — case-insensitive, exact Land match (e.g. Bayern, Baden-Württemberg) |
--party <text> |
Only members whose party contains this text — case-insensitive substring (e.g. grüne, CDU) |
Filtering happens client-side (the feed returns everyone), so both filters compose
and an unmatched filter yields [] rather than the full list.
Every command prints JSON to stdout; diagnostics go to stderr, so piping into
jq stays clean.
# How many agenda items in the current sitting?
bundesrat session | jq '.tops | length'
# Drucksachen on the agenda
bundesrat session | jq -r '.tops[].topdrucksache | select(.)'
# Members grouped by party (mitglied marks the 69 members; the rest are deputies and plenipotentiaries)
bundesrat members | jq -r '[.[] | select(.mitglied == "true")] | group_by(.party)[] | "\(.[0].party // "no party given"): \(length)"'
Use --compact for single-line JSON and -o <file> to write to a file — both are
global options that work before or after the command.
Exit codes make the CLI easy to use in scripts:
| Code | Meaning |
|---|---|
0 |
Success (also --help / --version) |
2 |
Bad usage / invalid argument (nothing was sent) |
4 |
Not found (404 from the server) |
6 |
Network / transport failure (DNS, connection, timeout, size cap) |
1 |
Any other error — including a non-XML response (the feed returned the website's HTML shell) |
command not found: bundesrat — the global npm bin directory isn't on your
PATH. Run npm bin -g to find it and add it, or run via
npx @maschinenlesbar.org/bundesrat-cli ….1 / "received an HTML page" — the feed returned the website's HTML
shell instead of XML (it may have moved). The CLI already adds the required
?view=renderXml render parameter; if this persists, the upstream feed changed.6 / read ECONNRESET — the server dropped the connection. This
happens now and then; --max-retries retries only 429/503 responses, not
network errors, so run the command again.tops between sittings — outside an active sitting the agenda feed can
be sparse: tops may be [] and session's title/header may be absent
(both are optional), so guard for them in scripts.detail/abstract bodies, biographies and images
are stripped on purpose (see DATA_LICENSE.md).Given before or after the command, e.g. bundesrat --compact session:
| Option | Description |
|---|---|
-V, --version |
Print the version number |
-h, --help |
Show help for the program or a command |
--compact |
Print JSON on a single line instead of pretty-printed |
-o, --output <file> |
Write output to this file instead of stdout |
--base-url <url> |
API base URL (default https://www.bundesrat.de) |
--timeout <ms> |
Time limit per request, reading the whole response included (default 30000; 0 = none; at most 2147483647) |
--user-agent <ua> |
User-Agent header value |
--max-retries <n> |
Retries for transient 429/503 responses (0..10, default 2) |
--max-response-bytes <n> |
Cap response body size in bytes (0 = unlimited; default 100 MiB) |
This CLI is a client — it accesses data it does not own or redistribute. The upstream data is © the Bundesrat and licensed separately from this tool's code. See DATA_LICENSE.md.
Bundesrat — website content is copyright-protected (personal use only; commercial use / redistribution need permission), so cite "Quelle: Bundesrat" and don't republish editorial text or images without asking. The Drucksachen and Plenarprotokolle are amtliche Werke (§ 5 Abs. 2 UrhG) — free to reuse unaltered and with a source citation.
Dual-licensed — use it under either:
See LICENSING.md for details, and CONTRIBUTING.md for the contribution policy (this project does not accept external code contributions). Commercial enquiries: sebs@2xs.org.