Politicians as software running on hardware (donors and networks). PoliDex maps every politician into a 20-dimensional policy space, scores your alignment against them in real time, and exposes the influence networks behind every vote — no party affiliation required.
- The Problem
- Technical Architecture
- Key Features
- How to Run
- Tech Stack
- Project Structure
- AI & Frameworks
- What We Learned
Voter engagement is backsliding — especially among young people. Voter turnout in the 2024 presidential election dropped to 65.3%, a 1.5 percentage point decline from 2020 (U.S. Census Bureau). Young adults under 30 made up 30% of all nonvoters in 2024, up from 25% in 2020, and less than half of eligible 18–24 year olds cast a ballot at all (Pew Research Center, USAFacts). Turnout declined across all racial and ethnic groups; Hispanic voters saw the steepest drop at 3.1 percentage points, reaching a turnout rate of just 50.6%.
Sources: U.S. Census Bureau (2024 Current Population Survey), Pew Research Center (2024 Election Analysis), USAFacts.
Americans have no reliable, unbiased source for political information. A late-2025 Gallup poll found only 28% of Americans have a "great deal" or "fair amount" of trust in mass media — an all-time low, down from 68% in 1972. For adults under 65, that number falls to 28% or lower across every age group. Trust is now so fractured along political lines that a truly neutral source is more valuable than ever.
Source: Gallup (Media Confidence Trend, 2025).
51% of Americans view made-up news as a "very big problem" (Pew Research Center). Nearly one-third of adults regularly encounter fake news online, and almost one-quarter admit to having shared it — knowingly or not. When social media news consumers were surveyed about their top complaint, "inaccuracy" ranked first.
Source: Pew Research Center (Global Public Concern about Made-Up News; Social Media News Consumer Reports).
PoliDex responds to all three by replacing editorial opinion with verifiable math: publicly available voting records, campaign finance data, and legislative history — scored, ranked, and surfaced in seconds.
At the core of PoliDex is a weighted cosine similarity function we derived from scratch to capture policy alignment across 20 independent dimensions:
Where:
-
$v_{\text{input}}$ = the user's 20-dimensional policy vector (generated by the onboarding quiz) -
$v_{\text{poli}}$ = a politician's 20-dimensional policy vector (LLM-tagged from legislative records) -
$w_i$ = per-dimension weight, either uniform (stated alignment mode) or adherence-weighted (follow-through mode)
This formula is original to our team. Standard cosine similarity treats all dimensions equally. Our key insight is that weighting each dimension independently lets the system redefine "closeness" based on a politician's consistency — not just their stated position — without any changes to the core calculation.
Every politician is represented as a coordinate in a 20-dimensional space spanning planks like Fiscal Policy, Civil Liberties, Energy, Healthcare, Foreign Policy, and more (defined in shared/taxonomy.json). Each plank is scored on a 1–5 scale. Two vectors are produced per politician:
- Theoretical Vector — LLM-tagged from stated positions via OpenStates
- Legislative Vector — derived from actual voting history via Legiscan and Congress.gov
The Adherence Toggle is the system's most original mechanic. It measures Δ(Theoretical Vector, Legislative Vector) and produces per-dimension consistency weights computed as
- Toggle OFF (default): uniform weights → "who says they agree with you"
- Toggle ON: adherence weights → "who actually follows through"
The dot representing a politician animates from their stated position to their actual legislative position as the toggle turns on.
The politician library is indexed in a k-d tree spatial index (LibraryIndexer.java) backed by MongoDB. At query time, the inference pipeline runs full-library scoring, neighborhood lookups, or catalog queries depending on request type. The k-d tree enables sublinear nearest-neighbor search across the full 20D space.
The Java chassis orchestrates all system state and HTTP traffic. Stateless math (cosine similarity, weight calculation, constraint discovery) lives in isolated Python workers. Communication flows via stdin/stdout JSON pipes through PythonRunner.java, keeping both runtimes cleanly separated with a strict data contract defined in InferencePayload.java.
- Take a 20-question quiz mapping your positions across all 20 policy planks (1–5 scale)
- Get a ranked list of politicians sorted by alignment score
- Flip the Adherence Toggle to re-rank by who votes consistently with their stated positions
- Cross-party results: the math doesn't know what party anyone is in
- Pick any two politicians and see a side-by-side radar chart across all 20 dimensions
- Issue-by-issue overlap graph shows exactly where they agree and diverge
- Versus mode shows your alignment against both simultaneously
- Weighted graph: Politicians → Super PACs → Corporate Donors → Kinship ties
- Edges are verifiable-only (financial, employment, family) — no speculation
- Radial layout: politician at center (T1), immediate ties (T2), donor networks (T3/T4)
- Edge thickness encodes influence volume
- Data sourced from OpenFEC campaign finance records
- Generate a base64 profile code from your quiz results
- Import the same code into the Chrome Extension to sync your vector across surfaces
- Double-click any politician name on any webpage to instantly surface their alignment card
- Card shows: % match vs your vector, top aligned and misaligned policy dimensions, top implemented policies derived from legislative record
- Extension syncs your profile vector from the main app via a paste-in import field
- Built on Manifest V3 with a service worker, content script, and popup architecture
| Tool | Version |
|---|---|
| Node.js | 18+ |
| Java | 17+ |
| Maven | 3.8+ |
| Python | 3.10+ |
| MongoDB | 6+ (local or Atlas URI) |
From the repo root:
- macOS/Linux:
chmod +x ./run-all
./run-all- Windows:
.\run-all.cmdOptional flags:
./run-all --backend-port 8080 --frontend-port 3000 --skip-installCopy and fill in the environment file:
cp backend/java-chassis/.env.example backend/java-chassis/.envRequired keys:
MONGODB_URI=mongodb://localhost:27017/civicinfo
ANTHROPIC_API_KEY=...
OPENSTATES_API_KEY=...
CONGRESS_GOV_API_KEY=...
GOOGLE_CIVIC_API_KEY=...
LEGISCAN_API_KEY=...
OPEN_FEC_API_KEY=...
Install Python dependencies:
cd backend/inference-engine
pip install -r requirements.txtcd backend/java-chassis
mvn exec:javaThe Java chassis starts on http://localhost:8080. On first boot it seeds the politician database if MongoDB is empty.
cd frontend/deskApp
npm installOption A — Native desktop window (recommended):
npm run electron:devOpens the app in an Electron window. Next.js dev server and Electron launch concurrently; Electron waits for the server before opening.
Option B — Browser:
npm run devOpen http://localhost:3000 in your browser.
- Open Chrome and navigate to
chrome://extensions - Enable Developer mode (top-right toggle)
- Click Load unpacked and select the
frontend/extension/directory - The Civic Info HUD icon appears in your toolbar
To sync your profile to the extension:
- Complete the quiz in the desktop app
- Go to Compare → Export to Extension and copy the profile code
- Click the extension icon → paste the code → import
| Layer | Technology |
|---|---|
| Desktop Frontend | Next.js 16 (App Router), React 19, TypeScript |
| Styling | Tailwind CSS v4, shadcn/ui |
| Animation | Framer Motion |
| Charts | Recharts |
| Backend Orchestration | Java 17, Maven |
| Database | MongoDB (sync driver 5.2), k-d tree RAM index |
| Inference Engine | Python 3, custom stateless math modules |
| LLM Tagging | Gemini 3.0-flash |
| Chrome Extension | Manifest V3, Service Worker, vanilla JS |
| External APIs | OpenStates, Congress.gov, Google Civic Info, OpenFEC, Legiscan, Wikimedia |
hackabull2026/
├── backend/
│ ├── java-chassis/ # System orchestration, HTTP layer, DB, IPC
│ │ └── src/main/java/com/system/
│ │ ├── controllers/ # HTTP gateway (RequestHandler)
│ │ ├── api/ # Outbound API clients (6 data sources)
│ │ ├── models/ # PoliVector, PoliFigure, UserProfile
│ │ ├── managers/ # LibraryIndexer, SearchController, IngestionRunner
│ │ ├── sampler/ # QuizEngine, userNegPreference
│ │ ├── storage/ # DataManager (MongoDB gateway)
│ │ └── bridge/ # PythonRunner, InferencePayload (IPC)
│ ├── inference-engine/ # Stateless math workers (Python)
│ │ ├── math/ # cosine_sim.py, weight_calculator.py, constraint_discoverer.py
│ │ ├── tagging/ # llm_analyst.py, prompt_builder.py, score_validator.py
│ │ └── inference_manager.py
│ └── shared/
│ ├── taxonomy.json # 20-plank policy space definitions
│ └── vector.schema # 20D vector JSON schema
├── frontend/
│ ├── deskApp/ # Next.js desktop app
│ │ └── src/features/polidex/
│ │ ├── components/ # All views: dashboard, compare, quiz, simulator, landing
│ │ ├── data/ # Politicians seed data, taxonomy mirror
│ │ └── lib/ # API client, display utils, profile import/export
│ └── extension/ # Chrome Extension MV3
│ ├── scripts/ # content.js, background.js, cosine_bridge.js, user_vector_store.js
│ └── ui/ # card.html, popup.js
└── scripts/
└── seed_politicians.py # Politician DB seed script
- Gemini 3.0-flash — LLM tagging pipeline: converts raw legislative text from OpenStates into validated 20D PoliVectors via
llm_analyst.py→score_validator.py - Claude Code — AI-assisted development throughout the build. Commits made with Claude Code assistance are tagged
CLAUDE CODEin the commit history. - Recharts — radar charts and bar graphs for policy visualization across 20 dimensions
- Framer Motion — UI transitions and the adherence toggle animation (dot moving from stated → actual position)
- shadcn/ui + Tailwind CSS v4 — component library and design system
- MongoDB sync driver 5.2 — politician library persistence and user history
Pre-planning is a force multiplier. Designing data contracts (taxonomy.json, vector.schema) and module boundaries before writing a single line of code let the whole team work in parallel without stepping on each other. That architecture held together even when we were refactoring at 3 AM.
Deriving a custom math equation takes real iteration. The weighted cosine similarity formula wasn't pulled from a paper — we designed it from first principles to fit the constraint that policy dimensions have independent variance. Getting the per-dimension adherence weights (
Vector databases are a different mental model. Moving from row-based lookups to spatial nearest-neighbor queries in 20D space required rethinking how retrieval works. Building the k-d tree indexer was one of the harder pieces of the backend.
Modular code is survival at a hackathon. Strict single-responsibility design across every file meant we could hand off a module without a lengthy explanation. That paid off every time we needed to debug or extend something under a time crunch.
Making complex data feel simple is its own hard problem. Computing alignment scores wasn't the challenge — designing a UI where a non-technical user understands what a 20-dimensional vector comparison means was. The radar chart, the adherence toggle animation, and the issue-by-issue overlap graph were each answers to that question.
Desktop-first removes friction. A local app with no accounts and no cloud sign-in means users reach their results immediately. Nothing leaves their machine.
Chrome extensions are their own ecosystem. Manifest V3's service worker model, content script isolation, and the restrictions on what can execute where required a complete context switch from standard web development. Getting the background ↔ content ↔ popup communication right was non-trivial.
Cross-language IPC is unforgiving. Java calling Python via stdin/stdout pipes works, but working directory, path resolution, and the serialization contract all have to be exactly right. One wrong assumption returns empty results with no error — and tracking that down under a deadline is genuinely painful.