Inspiration

Politicians say a lot of things in the Dáil. But who actually checks whether what they said last Tuesday contradicts what they said last year? Ireland has KildareStreet.com, a public archive of every word spoken in parliament. The thing is, there was no useful analysis of this information, and it lacked any user friendly UI. We built PolicyPulse to change that: an AI-powered accountability tool that reads the parliamentary record so voters don't have to.

What it does

PolicyPulse analyses the Dáil speeches of 26 TDs across Ireland's six major parties and surfaces contradictions, moments where a politician took one position in parliament, then took an incompatible position later.

  • Contradiction Leaderboard: Every TD receives a "follow through" score from 0 to 100. The leaderboard ranks all 26 with severity labels

  • Party & TD Detail: Drill into any party to see their TDs ranked by consistency, or into any individual TD to see their full contradiction profile: paired quotes with dates, severity ratings, and a plain-English explanation of what changed.

  • Find Your Match: Enter your Eircode and adjust sliders across eight policy issues that matter to you, from housing, healthcare, climate, agriculture, cost of living, infrastructure, public services, to border/unity. PolicyPulse scores each party against your priorities, weighted by your region's real concerns, and shows their average contradiction record alongside the match.

  • Recent Wins: A curated feed of real policy victories, so the picture isn't only about what went wrong, but also highlights what we're doing right.

  • Every Claim Has Receipts: Contradictions are not opinions. Each one surfaces the exact quotes, exact dates, and severity level so users can judge the context for themselves.

How we built it

Data pipeline (Bun + TypeScript): Four scripts run in sequence. fetch-roster.ts scrapes KildareStreet to identify the five longest-serving TDs per party (26 total across Fianna Fáil, Fine Gael, Sinn Féin, Green, Labour, and the Social Democrats). fetch-speeches.ts pulls up to 100 Dáil speeches per TD using concurrent requests with rate limiting. score.ts sends the full speech corpus to Claude Haiku 4.5 with a strict system prompt: "identify contradictions only from the provided speeches; do not use prior knowledge", and validates the structured JSON output, retrying with a simplified fallback prompt on malformed responses. build-index.ts merges roster and scores into a single all-scores.json consumed by the frontend.

A separate fetch-wins.ts script queries the Brave Search API for recent news coverage of each party, then passes the results through Claude to extract only genuine, verifiable policy wins, bills passed, funding secured, measurable outcomes, filtering out vague PR claims.

Frontend (React 19 + TypeScript): Six distinct views: home, party, politician, leaderboard, match, and wins, all managed through state in App.tsx. No external UI library. All styling is custom CSS with a deliberate design language: bold 3px borders, offset drop shadows, warm beige palette, and party-specific accent colours. Custom SVG visualisations include a political compass for each party's ideological position and an animated podium illustration on the landing page.

Regional personalisation: The match feature parses Irish Eircodes to detect the user's region and pre-fills issue weights based on local demographics. Dublin inner-city defaults to housing and cost of living. Border counties default to agriculture and border/unity issues. Users can then override any slider to reflect their own priorities.

Challenges we ran into

  • KildareStreet blocks fetch(): Bun's native HTTP client gets connection-reset by KildareStreet's servers. We routed all API calls through curl via Bun.spawn

  • Narrow speech windows: Our initial approach for fetching "older" speeches picked a single calculated page deep in the results, which landed on one narrow week of debates. Claude saw near-identical timestamps and flagged only mild intra-session inconsistencies instead of career-spanning contradictions. Diversifying the page spread improved coverage, but robust time-range sampling remains an open problem.

  • Context vs. contradiction: A politician updating their position after new evidence isn't the same as contradicting themselves. We tuned Claude's prompt to look for genuinely incompatible positions, not just evolution of thought, and to assign severity levels (low, medium, high) so users can weigh the difference themselves.

  • Structured AI output at scale: Claude occasionally returns malformed JSON when processing dozens of speeches. We validate every response against a strict schema and retry once with a simplified fallback prompt before marking a TD as an error case rather than shipping bad data.

Accomplishments that we're proud of

  • Non-partisan by design. The exact same pipeline, prompt, and scoring methodology runs for every TD regardless of party. No editorial hand on the scale.

  • Real data, real quotes. Every contradiction card shows two direct quotes with dates from the Dáil record. Users see the evidence and can judge the context, we're not asking anyone to trust an AI's opinion.

  • Regional intelligence. The Eircode-based match feature reflects geographic differences in Irish political priorities. A voter in Donegal sees different default issue weights than a voter in Dún Laoghaire, because their concerns are different.

What we learned

  • Citations are the product. In political tech, the score is just the hook. What earns trust is showing the exact quotes, the exact dates, and letting the user decide. We designed every screen around this principle.

  • Small models punch above their weight for structured tasks. Claude Haiku 4.5 was fast, affordable, and precise at contradiction detection when given a well-constrained prompt and strict output schema. Bigger models weren't necessary.

  • Irish political data is more accessible than people think. KildareStreet.com is a remarkable public resource with decades of Dáil transcripts. The gap was never data availability, it was always there for us to use, no one had thought of it before.

What's next for PolicyPulse

  • Say vs. Vote: Cross-reference what TDs say in the Dáil with how they actually vote, using the Oireachtas /votes API for key legislation like the Housing for All plan and the Climate Action Act.

  • Deeper speech coverage: Sample speeches from multiple time-spread pages across each TD's career so Claude can surface contradictions that span years, not just sessions.

  • Live monitoring: Automate the pipeline to re-run as new Dáil debates are published, with push alerts when a TD says something that contradicts their prior record.

Built With

Share this project:

Updates