Civic engagement library: address → reps → delivery
Project description
GovPal Reach
Civic engagement library: discover representatives from an address and deliver messages via email or web forms. Resistbot-like functionality with modular, pluggable architecture.
Project overview
GovPal Reach maps address → representatives (federal, state, local) and supports message delivery via email (Postmark) or web forms (Playwright). Users onboard via SMS/OTP (Twilio Verify, or Plivo).
- Discovery: Geocode address (Census Geocoder), then look up reps (Google Civic, Open States, LA local).
- Delivery: Send messages via email or submit web forms; PGQueuer for durable queue.
- Identity: User profiles, PII encryption, SMS OTP (Twilio primary, or Plivo).
- Orchestrator: High-level API composing discovery and delivery.
Quick start
1. Install
Requires uv (install: curl -LsSf https://astral.sh/uv/install.sh | sh).
uv sync
2. Configure environment
Copy .env.example to .env and fill in values. See SETUP.md for how to obtain credentials.
cp .env.example .env
# Edit .env with your credentials
3. Run a simple example
The library is intended to be imported by a host app. Example usage:
from govpal.orchestrator.api import discover_reps_for_address, send_message_to_representatives
# Discover reps for an address
reps = discover_reps_for_address("123 Main St, Los Angeles, CA 90012")
# Send a message to one or more representatives (library adds preamble + closing)
# body = middle content only; subject, profile, phone, and list of reps
results = send_message_to_representatives(
"Your message body here.",
"Subject line",
profile, # constituent profile (first_name, last_name, email, full_address_for_display)
phone,
reps, # list of rep dicts with contact_email
)
# results = [(rep, success), ...]
4. Database (optional)
Apply the schema if using Postgres (Identity module requires 002 for OTP):
psql $DATABASE_URL -f schema/001_initial.sql
psql $DATABASE_URL -f schema/002_verify_session_uuid.sql
Modules
| Module | Responsibility |
|---|---|
| Discovery | Address → reps (Google Civic, Open States, Census) |
| Delivery | Email (Postmark), web forms (Playwright), queue |
| Identity | Users, PII, SMS OTP (Twilio or Plivo) |
| Orchestrator | High-level API: discovery, send_message_to_representatives (preamble + closing) |
How to run the system
- As a library: Import
govpalin your app; configure env vars; use orchestrator API. - Production queue path: For durable delivery, use the queue path: create_message → optional update_message → enqueue_messages_for_address. Set
GOVPAL_USE_REAL_QUEUE=1and run the GovPal delivery worker so jobs are processed:uv run pgq run govpal.delivery.worker:create_pgqueuer --max-concurrent-tasks 2. See SETUP.md (PGQueuer section) for create_message/update_message usage and worker run command. - Railway: Deploy with Postgres; run the queue worker as a separate process or worker dyno; env vars set in Railway dashboard.
Using in another project
Install GovPal Reach as a dependency from PyPI (recommended for released versions):
# With uv (recommended)
uv add "govpal-reach>=0.1.0"
# Or with pip
pip install govpal-reach
To pin to a specific GitHub tag (e.g. before a version is on PyPI or to try a release tag):
uv add "govpal-reach @ git+https://github.com/YOUR_ORG/govpal-reach@v0.1.0"
Replace YOUR_ORG and the tag (v0.1.0) as needed. The import name is govpal:
from govpal.orchestrator.api import discover_reps_for_address, create_message, update_message, enqueue_messages_for_address
How to test
# Unit tests (runs in project .venv)
uv run pytest
# With coverage
uv run pytest --cov=govpal --cov-report=term-missing
# Integration tests (uses VCR cassettes; no live API calls by default)
uv run pytest -m integration
# Linter
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
Full test suite (lint + pytest + coverage): see TEST_PLAN_SUMMARY.md.
Documentation
- RESEARCH_SUMMARY.md – APIs, data sources, architecture research
- PLAN_SUMMARY.md – Implementation plan, beads, schema, modules
- TEST_PLAN_SUMMARY.md – Testing strategy per phase
- SETUP.md – External services, credentials, permissions; Releasing (PyPI and GitHub) in section 13
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file govpal_reach-0.1.0.tar.gz.
File metadata
- Download URL: govpal_reach-0.1.0.tar.gz
- Upload date:
- Size: 40.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8904dba7c700d46400be67775cfa17a3f88d0c6471233d3102373a04404490f4
|
|
| MD5 |
6b4704662f129dc3d71cfc4a8720c660
|
|
| BLAKE2b-256 |
ae676dcce909f0b80535968417255c0d9b8a2eeaf62a81064d23fb98f033e667
|
Provenance
The following attestation bundles were made for govpal_reach-0.1.0.tar.gz:
Publisher:
release.yml on BruceAndTyler/govpal-reach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
govpal_reach-0.1.0.tar.gz -
Subject digest:
8904dba7c700d46400be67775cfa17a3f88d0c6471233d3102373a04404490f4 - Sigstore transparency entry: 946798810
- Sigstore integration time:
-
Permalink:
BruceAndTyler/govpal-reach@50a0d365eb7599b962353a6ed23df5129ff88350 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/BruceAndTyler
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@50a0d365eb7599b962353a6ed23df5129ff88350 -
Trigger Event:
push
-
Statement type:
File details
Details for the file govpal_reach-0.1.0-py3-none-any.whl.
File metadata
- Download URL: govpal_reach-0.1.0-py3-none-any.whl
- Upload date:
- Size: 51.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f29547ebd9f92329e934acf13d6fe5ad0469d488985ed59faf75ad02ba95ec08
|
|
| MD5 |
edad40c405e2b71d15b550f9833d877d
|
|
| BLAKE2b-256 |
c4e84d914205ac14d51a4cad35b94539224ae6401abb03f230ad2e886441e42f
|
Provenance
The following attestation bundles were made for govpal_reach-0.1.0-py3-none-any.whl:
Publisher:
release.yml on BruceAndTyler/govpal-reach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
govpal_reach-0.1.0-py3-none-any.whl -
Subject digest:
f29547ebd9f92329e934acf13d6fe5ad0469d488985ed59faf75ad02ba95ec08 - Sigstore transparency entry: 946798814
- Sigstore integration time:
-
Permalink:
BruceAndTyler/govpal-reach@50a0d365eb7599b962353a6ed23df5129ff88350 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/BruceAndTyler
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@50a0d365eb7599b962353a6ed23df5129ff88350 -
Trigger Event:
push
-
Statement type: