skills/tools-and-apis/policyengine-api-skill/SKILL.md
PolicyEngine API - Flask REST service powering policyengine.org and programmatic access
npx skillsauth add policyengine/policyengine-claude policyengine-apiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The PolicyEngine API is a Flask-based REST service that provides tax and benefit calculations for the web app and programmatic users.
When you use policyengine.org, the API processes your calculations on our servers.
API base: https://api.policyengine.org
What it does:
The API is publicly accessible with rate limits:
Try it:
curl https://api.policyengine.org/us/policy/2
OpenAPI spec: https://api.policyengine.org/docs
Interactive docs: Swagger UI at API docs endpoint
Option 1: Python client (recommended)
# Use the policyengine package
# See policyengine-python-client-skill
Option 2: Direct API calls
import requests
# Calculate household impact
response = requests.post(
"https://api.policyengine.org/us/calculate",
json={
"household": household_situation,
"policy_id": None # or reform_id
}
)
result = response.json()
Household calculations:
POST /us/calculate
POST /uk/calculate
Policy management:
GET /us/policy/{policy_id}
POST /us/policy
Economy impacts:
GET /us/economy/{policy_id}/over/{baseline_policy_id}
Metadata:
GET /us/parameters
GET /us/variables
GET /us/parameter/{parameter_name}
GET /us/variable/{variable_name}
Rate limits:
Response times:
Optimization:
Location: PolicyEngine/policyengine-api
Clone:
git clone https://github.com/PolicyEngine/policyengine-api
cd policyengine-api
To see current structure:
tree policyengine_api/
# Key directories:
ls policyengine_api/
# - endpoints/ - HTTP endpoint handlers
# - routes/ - Route registration
# - services/ - Business logic
# - compute_api/ - Calculation services
# - economy_api/ - Economy impact calculations
# - utils/ - Helpers (caching, validation)
# - data/ - Static data
Reference endpoint (read this first):
cat policyengine_api/endpoints/economy.py
This demonstrates:
To find other endpoints:
ls policyengine_api/endpoints/
# - household.py
# - policy.py
# - economy.py
# - metadata.py
# - etc.
from flask import Blueprint, request, jsonify
from policyengine_api.utils import cache
blueprint = Blueprint("my_endpoint", __name__)
@blueprint.route("/us/calculate", methods=["POST"])
def calculate():
"""Standard pattern: validate, cache-check, compute, cache, return."""
try:
# 1. Get and validate input
data = request.json
if not data:
return jsonify({"error": "No data provided"}), 400
# 2. Generate cache key
cache_key = f"calc_{hash(str(data))}"
# 3. Check cache
cached = cache.get(cache_key)
if cached:
return jsonify(cached)
# 4. Compute
result = perform_calculation(data)
# 5. Cache result
cache.set(cache_key, result, expire=3600)
# 6. Return
return jsonify(result)
except Exception as e:
return jsonify({"error": str(e), "status": "error"}), 500
Current implementation details:
# See actual endpoint for current pattern
cat policyengine_api/endpoints/household.py
To see current caching implementation:
# Redis configuration
cat policyengine_api/utils/cache.py
# Find cache usage
grep -r "cache\." policyengine_api/endpoints/
Pattern:
For long-running calculations (population impacts):
To see current implementation:
# RQ (Redis Queue) usage
grep -r "@job" policyengine_api/
# Job patterns
cat policyengine_api/economy_api/
Pattern:
How API loads country packages:
cat policyengine_api/country.py
Pattern:
Business logic separated from endpoints:
ls policyengine_api/services/
Pattern:
# endpoints/household.py
from policyengine_api.services import household_service
@app.route("/us/calculate", methods=["POST"])
def calculate():
result = household_service.calculate(data)
return jsonify(result)
# services/household_service.py
def calculate(data):
# Business logic here
simulation = create_simulation(data)
return simulation.calculate(...)
When to delegate to policyengine.py:
The API should return None for dataset selection in most cases, allowing policyengine.py to choose the appropriate default dataset. This creates better separation of concerns.
Pattern:
# In economy_service.py _setup_data() method:
# ❌ DON'T: Explicitly specify datasets the API shouldn't control
if region == "ny":
return "gs://policyengine-us-data/some_dataset.h5"
# ✅ DO: Return None to let policyengine.py choose the default
if region in US_STATES:
return None # policyengine.py handles state-specific datasets
# ✅ DO: Only specify datasets for special cases the API needs to control
if region == "nyc":
return "gs://policyengine-us-data/pooled_3_year_cps_2023.h5" # NYC exception
Why this matters:
When to see this pattern:
policyengine_api/services/economy_service.py_setup_data() methodTo see current test patterns:
ls tests/
cat tests/test_household.py
Run tests:
make test
# Specific test
pytest tests/test_economy.py -v
# With coverage
make test-coverage
Start locally:
make debug
Test endpoint:
curl http://localhost:5000/us/policy/2
To see deployment configuration:
# Google Cloud Platform
cat app.yaml # App Engine config
cat cloudbuild.yaml # Cloud Build config
# Environment variables
cat .env.example
Current deployment:
To see versioning strategy:
grep -r "version" policyengine_api/
Current approach:
User/App → API Gateway → Flask App → Country Package → Core Engine
↓
Redis Cache
↓
Background Job (if needed)
↓
PostgreSQL (storage)
policyengine-core
↓
policyengine-us, policyengine-uk, etc.
↓
policyengine-api (you are here)
↓
policyengine-app (consumes API)
To understand dependencies:
policyengine-core-skill for engine patternspolicyengine-us-skill for country model usagepolicyengine-app-skill for how app calls APIStudy reference implementation:
cat policyengine_api/endpoints/economy.py
Create new endpoint file:
# policyengine_api/endpoints/my_endpoint.py
# Follow the pattern from economy.py
Register route:
# See route registration
cat policyengine_api/routes/__init__.py
Add tests:
# Follow test pattern
cat tests/test_economy.py
See current caching:
cat policyengine_api/utils/cache.py
Common changes:
To see how versions are managed:
# Requirements
cat requirements.txt | grep policyengine-
# Update and deploy
# See deployment docs in README
Always validate:
See validation examples:
grep -r "validate" policyengine_api/endpoints/
Standard error response:
return jsonify({
"error": "Error message",
"details": additional_context,
"status": "error"
}), status_code
See error patterns:
grep -A 5 "jsonify.*error" policyengine_api/endpoints/
To see logging configuration:
cat policyengine_api/gcp_logging.py
Pattern:
Repository: https://github.com/PolicyEngine/policyengine-api Live API: https://api.policyengine.org Documentation: https://api.policyengine.org/docs Status: https://status.policyengine.org
tools
ONLY use this skill when users explicitly ask about the PolicyEngine Python package installation, REST API endpoints, API authentication, rate limits, or policyengine.py client library. DO NOT use for household benefit/tax calculations — ALWAYS use policyengine-us or policyengine-uk instead. This skill is about the API/client tooling itself, not about calculating benefits or taxes.
development
ALWAYS USE THIS SKILL for PolicyEngine microsimulation, population-level analysis, winners/losers calculations. Triggers: microsimulation, share who would lose/gain, policy impact, national average, weighted analysis, cost, revenue impact, budgetary, estimate the cost, federal revenues, tax revenue, budget score, how much would it cost, how much would the policy cost, total cost of, aggregate impact, cost to the government, revenue loss, fiscal impact, poverty impact, child poverty, deep poverty, poverty rate, poverty reduction, how many people lifted out of poverty, SPM poverty, distributional impact, state tax, state-level, California, New York, UBI, universal basic income, flat tax, standard deduction, winners and losers, winners, losers, inequality, Gini, decile, SALT, marginal tax rate, effective tax rate. NOT for single-household calculations like "what would my benefit be" - use policyengine-us or policyengine-uk for those. Use this skill's code pattern; explore codebase for parameter paths if needed.
development
PolicyEngine API v2 - Next-generation microservices architecture with monorepo structure
development
ALWAYS LOAD THIS SKILL before setting up any Python environment or installing packages. Defines the standard: uv, Python 3.13, uv pip install, .venv at project root. Triggers: "set up python", "install python", "create a venv", "virtual environment", "pip install", "install packages", "uv pip", "uv venv", "python version", "VIRTUAL_ENV", "venv conflict", "which python", "activate", "deactivate", "run the script", "run with uv", "uv run", "pyproject.toml", "install dependencies", "install requirements", "install the package", "editable install", "pip install -e", "latest package", "latest version", "current version", "newest version".