Skip to main content

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

Email delivery mode (optional): GP_DELIVERY_MODE defaults to capture (no real sends) so new installs don't send email until you explicitly enable it. Set to live to send via Postmark.

  • capture (default) – No real sends; emails are recorded in memory for inspection (e.g. tests, CI).
  • redirect – All recipients are rewritten to the comma-separated addresses in GP_TEST_RECIPIENTS; subject is tagged with [TO: original].
  • live – Production behavior via Postmark (set explicitly to send real email).

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 schema (Postgres + Alembic required)

GovPal Reach requires PostgreSQL and Alembic for Identity (OTP), queue path, and production use. There is no non-Alembic schema path.

  1. Set DATABASE_URL in your environment (e.g. in .env).

  2. In your host app's Alembic setup, add the library's versions path to version_locations so one alembic upgrade head applies both your app's and GovPal Reach's schema. Example in env.py:

    from govpal.alembic import get_versions_path
    reach_versions = str(get_versions_path())
    # Prepend or append to version_locations (e.g. [reach_versions, "alembic/versions"])
    config.set_main_option("version_locations", ...)
    
  3. Run migrations: alembic upgrade head (or your app's equivalent, e.g. python run_migrations.py).

Migrations are idempotent: after updating the govpal-reach library, running alembic upgrade head again applies any new schema changes and is safe when nothing has changed. You do not need to check whether the library had schema updates.

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 govpal in 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=1 and 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.2.4"

# 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.2.3"

Replace YOUR_ORG and the tag (v0.2.3) 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 (multi-module flows; no DB/API needed for composed-flow tests)
uv run pytest -m integration
# With DATABASE_URL and schema applied, the worker integration test also runs; without it that test is skipped.

# 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: push a v* tag and CI publishes to PyPI (Trusted Publishing), see section 13

License

MIT

Metadata

Release files for govpal-reach 0.2.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for govpal-reach 0.2.5
File Size Uploaded
govpal_reach-0.2.5.tar.gz 56.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for govpal-reach 0.2.5
File Interpreter ABI Platform
govpal_reach-0.2.5-py3-none-any.whl Python 3 none any Details

Total release size: 129.1 kB

Release files / govpal_reach-0.2.5.tar.gz

Download URL govpal_reach-0.2.5.tar.gz
Size 56.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b68ed1bcc31a10047a4b312c0d0eab07fe528a02bae5b7a40bbcbe8261d5837e
BLAKE2b-256 checksum
How to use checksums
c4d76c61668883d846668b88a5408b1f214b0d8378f1d3a6b270f618ded2c5ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 21, 2026.

Transparency log

Release files / govpal_reach-0.2.5-py3-none-any.whl

Download URL govpal_reach-0.2.5-py3-none-any.whl
Size 72.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e60ff90f7a94236c6c05f53ddbd7bb3d27597bb8fea3f93d6265bb50776e351
BLAKE2b-256 checksum
How to use checksums
f5124804ec535a59b5fece882b66c7f65c467226563e1f3fbafe681c87744919
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.5 This release

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page