Back to skills
SkillHub ClubShip Full StackFull Stack

policyengine-app-skill

Imported from https://github.com/PolicyEngine/policyengine-claude.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
25
Hot score
88
Updated
March 19, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
C67.9

Install command

npx @skill-hub/cli install policyengine-policyengine-claude-policyengine-app-skill

Repository

PolicyEngine/policyengine-claude

Skill path: skills/tools-and-apis/policyengine-app-skill

Imported from https://github.com/PolicyEngine/policyengine-claude.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: PolicyEngine.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install policyengine-app-skill into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/PolicyEngine/policyengine-claude before adding policyengine-app-skill to shared team environments
  • Use policyengine-app-skill for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: policyengine-app
description: PolicyEngine React web application - the user interface at policyengine.org
---

# PolicyEngine App

The PolicyEngine App is the React-based web application that users interact with at policyengine.org.

## For Users πŸ‘₯

### What is the App?

The app at policyengine.org provides:
- Interactive household calculator
- Policy reform creator
- Population impact analysis
- Blog and research hub

**Access:** https://policyengine.org

### App Features

**Calculator:**
- Enter household details
- See tax and benefit calculations
- Visualize marginal tax rates
- Compare scenarios

**Policy designer:**
- Browse all parameters
- Create custom reforms
- Share via URL
- Download charts

**Research hub:**
- Read policy analysis
- Explore modeled programs
- Access documentation

## For Analysts πŸ“Š

### Understanding App URLs

Reform URLs encode all policy changes in the query string, allowing sharing and reproducibility.

**Example URL:**
```
policyengine.org/us/policy?
  focus=policyOutput.policyBreakdown&
  reform=67696&
  region=enhanced_us&
  timePeriod=2025&
  baseline=2
```

**Parameters:**
- `focus` - Which section to display
- `reform` - Reform ID from database
- `region` - Geographic scope (enhanced_us, CA, congressional districts)
- `timePeriod` - Year of analysis
- `baseline` - Baseline policy ID

### Embedding PolicyEngine

**iFrame integration:**
```html
<iframe
  src="https://policyengine.org/us/household?embedded=true"
  width="100%"
  height="800">
</iframe>
```

**Parameter:**
- `embedded=true` - Removes navigation, optimizes for embedding

### URL Structure

**Household calculator:**
```
/us/household?household=12345
/uk/household?household=67890
```

**Policy page:**
```
/us/policy?reform=12345
/uk/policy?reform=67890
```

**Research/blog:**
```
/us/research/article-slug
/uk/research/article-slug
```

## For Contributors πŸ’»

### Repository

**Location:** PolicyEngine/policyengine-app

**Clone:**
```bash
git clone https://github.com/PolicyEngine/policyengine-app
cd policyengine-app
```

### Current Architecture

**To see current structure:**
```bash
tree src/ -L 2

# Key directories:
ls src/
# - pages/         - Page components
# - applets/       - Reusable UI modules
# - api/           - API integration
# - controls/      - Form controls
# - layout/        - Layout components
# - posts/         - Blog posts
# - routing/       - Routing configuration
# - hooks/         - Custom React hooks
# - data/          - Static data
```

### Technology Stack

**Current dependencies:**
```bash
# See package.json for versions
cat package.json

# Key dependencies:
# - React 18
# - React Router v6
# - Plotly.js
# - Ant Design
# - axios
```

### React Patterns (Critical)

**βœ… Functional components only (no classes):**
```javascript
// CORRECT
import { useState, useEffect } from "react";

export default function TaxCalculator({ income }) {
  const [tax, setTax] = useState(0);

  useEffect(() => {
    calculateTax(income).then(setTax);
  }, [income]);

  return <div>Tax: ${tax}</div>;
}
```

**❌ Class components forbidden:**
```javascript
// WRONG - Don't use class components
class TaxCalculator extends Component {
  // ...
}
```

**To find component examples:**
```bash
# Reference components
ls src/pages/
ls src/applets/

# See a complete page
cat src/pages/HouseholdPage.jsx
```

### State Management

**No global state (Redux, Context) - lift state up:**

```javascript
// Parent manages state
function PolicyPage() {
  const [reform, setReform] = useState({});
  const [impact, setImpact] = useState(null);

  return (
    <>
      <PolicyEditor reform={reform} onChange={setReform} />
      <ImpactDisplay impact={impact} />
    </>
  );
}
```

**To see state patterns:**
```bash
# Find useState usage
grep -r "useState" src/pages/ | head -20
```

### API Integration

**To see current API patterns:**
```bash
cat src/api/call.js      # Base API caller
cat src/api/variables.js # Variable metadata
cat src/api/parameters.js # Parameter metadata
```

**Standard pattern:**
```javascript
import { api call } from "api/call";

// Fetch data
const result = await call(
  `/us/calculate`,
  { household: householdData },
  "POST"
);
```

### Routing

**To see current routing:**
```bash
cat src/routing/routes.js

# Routes defined with React Router v6
# See examples:
grep -r "useNavigate" src/
grep -r "useSearchParams" src/
```

**URL parameters:**
```javascript
import { useSearchParams } from "react-router-dom";

const [searchParams, setSearchParams] = useSearchParams();

// Read
const reformId = searchParams.get("reform");

// Update
setSearchParams({ ...Object.fromEntries(searchParams), reform: newId });
```

### Custom Hooks

**To see PolicyEngine-specific hooks:**
```bash
ls src/hooks/
# - useCountryId.js    - Current country
# - useDisplayCategory.js
# - etc.
```

**Usage:**
```javascript
import { useCountryId } from "hooks/useCountryId";

function Component() {
  const [countryId, setCountryId] = useCountryId();
  // countryId = "us", "uk", or "ca"
}
```

### Charts and Visualization

**Plotly integration:**
```bash
# See chart components
ls src/pages/policy/output/

# Reference implementation
cat src/pages/policy/output/EconomyOutput.jsx
```

**Standard Plotly pattern:**
```javascript
import Plot from "react-plotly.js";

const layout = {
  font: { family: "Roboto Serif" },
  plot_bgcolor: "white",
  // PolicyEngine branding
};

<Plot
  data={traces}
  layout={layout}
  config={{ displayModeBar: false }}
/>;
```

### Blog Posts

**To see blog post structure:**
```bash
ls src/posts/articles/

# Read a recent post
cat src/posts/articles/harris-eitc.md
```

**Blog posts:**
- Written in Markdown
- Stored in `src/posts/articles/`
- Include metadata (title, date, authors)
- Follow policyengine-writing-skill style

**Adding a post:**
```bash
# Create new file
# src/posts/articles/my-analysis.md

# Add to index (if needed)
# See existing posts for format
```

### Styling

**Current styling approach:**
```bash
# See style configuration
ls src/style/

# Colors
cat src/style/colors.js

# Ant Design theme
cat src/style/theme.js
```

**PolicyEngine colors:**
- Teal: `#39C6C0` (primary accent)
- Blue: `#2C6496` (charts, links)
- Dark gray: `#616161` (text)

### Testing

**To see current tests:**
```bash
ls src/__tests__/

# Run tests
make test

# Test pattern
cat src/__tests__/example.test.js
```

**Testing libraries:**
- Jest (test runner)
- React Testing Library (component testing)
- User-centric testing (not implementation details)

### Development Server

**Start locally:**
```bash
make debug
# Opens http://localhost:3000
```

**Environment:**
```bash
# Environment variables
cat .env.example

# Config
ls src/config/
```

### Building and Deployment

**Build:**
```bash
make build
# Creates optimized production build
```

**Deployment:**
```bash
# See deployment config
cat netlify.toml  # or appropriate hosting config
```

## Component Patterns

### Standard Component Structure

**To see well-structured components:**
```bash
# Example page
cat src/pages/HouseholdPage.jsx

# Example applet
cat src/applets/PolicySearch.jsx
```

**Pattern:**
```javascript
import { useState, useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { useCountryId } from "hooks/useCountryId";

export default function MyComponent({ prop1, prop2 }) {
  // 1. Hooks first
  const [state, setState] = useState(initialValue);
  const [countryId] = useCountryId();
  const [searchParams] = useSearchParams();

  // 2. Effects
  useEffect(() => {
    // Side effects
  }, [dependencies]);

  // 3. Event handlers
  const handleClick = () => {
    setState(newValue);
  };

  // 4. Render
  return (
    <div>
      {/* JSX */}
    </div>
  );
}
```

### Component Size Limit

**Keep components under 150 lines after formatting.**

**If component is too large:**
1. Extract sub-components
2. Move logic to custom hooks
3. Split into multiple files

**To find large components:**
```bash
# Find files >150 lines
find src/ -name "*.jsx" -exec wc -l {} \; | sort -rn | head -20
```

### File Naming

**Components:** PascalCase.jsx
- `HouseholdPage.jsx`
- `PolicySearch.jsx`
- `ImpactChart.jsx`

**Utilities:** camelCase.js
- `formatCurrency.js`
- `apiUtils.js`
- `chartHelpers.js`

**Hooks:** camelCase.js with 'use' prefix
- `useCountryId.js`
- `usePolicy.js`

## Common Development Tasks

### Task 1: Add New Page

1. **See page structure:**
   ```bash
   cat src/pages/HouseholdPage.jsx
   ```

2. **Create new page:**
   ```javascript
   // src/pages/MyNewPage.jsx
   export default function MyNewPage() {
     return <div>Content</div>;
   }
   ```

3. **Add route:**
   ```bash
   # See routing
   cat src/routing/routes.js

   # Add your route following the pattern
   ```

### Task 2: Add New Chart

1. **See chart examples:**
   ```bash
   ls src/pages/policy/output/
   cat src/pages/policy/output/DistributionalImpact.jsx
   ```

2. **Create chart component:**
   ```javascript
   import Plot from "react-plotly.js";

   export default function MyChart({ data }) {
     return (
       <Plot
         data={traces}
         layout={{
           font: { family: "Roboto Serif" },
           plot_bgcolor: "white"
         }}
       />
     );
   }
   ```

### Task 3: Add Blog Post

1. **See post structure:**
   ```bash
   cat src/posts/articles/harris-eitc.md
   ```

2. **Create post:**
   ```bash
   # Create markdown file
   # src/posts/articles/my-analysis.md

   # Follow policyengine-writing-skill for style
   ```

3. **Images:**
   ```bash
   # Store in public/images/posts/
   # Reference in markdown
   ```

## API Integration Patterns

### Fetching Data

**To see API call patterns:**
```bash
cat src/api/call.js
```

**Standard pattern:**
```javascript
import { call } from "api/call";

const fetchData = async () => {
  const result = await call(
    `/us/calculate`,
    { household: data },
    "POST"
  );
  return result;
};
```

### Loading States

**Pattern:**
```javascript
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);

useEffect(() => {
  setLoading(true);
  fetchData()
    .then(setData)
    .catch(setError)
    .finally(() => setLoading(false));
}, [dependencies]);

if (loading) return <Spin />;
if (error) return <Error message={error} />;
return <Data data={data} />;
```

## Performance Patterns

### Code Splitting

**To see code splitting:**
```bash
grep -r "React.lazy" src/
```

**Pattern:**
```javascript
import { lazy, Suspense } from "react";

const HeavyComponent = lazy(() => import("./HeavyComponent"));

function Page() {
  return (
    <Suspense fallback={<Spin />}>
      <HeavyComponent />
    </Suspense>
  );
}
```

### Memoization

**Use React.memo for expensive components:**
```javascript
import { memo } from "react";

const ExpensiveChart = memo(function ExpensiveChart({ data }) {
  // Only re-renders if data changes
  return <Plot data={data} />;
});
```

## Accessibility

**Requirements:**
- Semantic HTML elements
- ARIA labels for complex widgets
- Keyboard navigation
- Color contrast (WCAG AA)

**To see accessibility patterns:**
```bash
grep -r "aria-" src/
grep -r "role=" src/
```

## Country-Specific Features

### Country Switching

**To see country switching:**
```bash
cat src/hooks/useCountryId.js
```

**Usage:**
```javascript
import { useCountryId } from "hooks/useCountryId";

function Component() {
  const [countryId] = useCountryId();  // "us", "uk", or "ca"

  // Load country-specific data
  const data = countryId === "us" ? usData : ukData;
}
```

### Country-Specific Content

**Conditional rendering:**
```javascript
{countryId === "us" && <USSpecificComponent />}
{countryId === "uk" && <UKSpecificComponent />}
```

**To find country-specific code:**
```bash
grep -r "countryId ===" src/
```

## Development Workflow

### Local Development

**Start dev server:**
```bash
make debug
# App runs on http://localhost:3000
# Connects to production API by default
```

**Connect to local API:**
```bash
# See environment configuration
cat src/config/environment.js

# Or set environment variable
REACT_APP_API_URL=http://localhost:5000 make debug
```

### Testing

**Run tests:**
```bash
make test
```

**Watch mode:**
```bash
npm test -- --watch
```

**Coverage:**
```bash
npm test -- --coverage
```

### Linting and Formatting

**Format code (critical before committing):**
```bash
make format

# Or manually
npm run lint -- --fix
npx prettier --write .
```

**Check linting (CI check):**
```bash
npm run lint -- --max-warnings=0
```

## Current Implementation Reference

### Component Structure

**To see current page structure:**
```bash
ls src/pages/
# - HouseholdPage.jsx
# - PolicyPage.jsx
# - HomePage.jsx
# - etc.
```

**To see a complete page:**
```bash
cat src/pages/PolicyPage.jsx
```

### API Call Patterns

**To see current API integration:**
```bash
cat src/api/call.js      # Base caller
cat src/api/variables.js # Variable metadata fetching
cat src/api/parameters.js # Parameter metadata fetching
```

### Routing Configuration

**To see current routes:**
```bash
cat src/routing/routes.js
```

### Form Controls

**To see PolicyEngine-specific form controls:**
```bash
ls src/controls/
# - InputField.jsx
# - SearchParamControl.jsx
# - etc.
```

### Chart Components

**To see chart implementations:**
```bash
ls src/pages/policy/output/
# - BudgetaryImpact.jsx
# - DistributionalImpact.jsx
# - PovertyImpact.jsx
# - etc.
```

**Reference chart:**
```bash
cat src/pages/policy/output/DistributionalImpact.jsx
```

## Multi-Repository Integration

### How App Relates to Other Repos

```
policyengine-core (engine)
    ↓
policyengine-us, policyengine-uk (country models)
    ↓
policyengine-api (backend)
    ↓
policyengine-app (you are here)
```

**Understanding the stack:**
- See `policyengine-core-skill` for engine concepts
- See `policyengine-us-skill` for what variables/parameters mean
- See `policyengine-api-skill` for API endpoints the app calls

### Blog Posts Reference Country Models

**Blog posts often reference variables:**
```bash
# Posts reference variables like "income_tax", "ctc"
# See policyengine-us-skill for variable definitions
cat src/posts/articles/harris-eitc.md
```

## Common Development Tasks

### Task 1: Add New Parameter to UI

1. **Understand parameter:**
   ```bash
   # See parameter in country model
   cd ../policyengine-us
   cat policyengine_us/parameters/gov/irs/credits/ctc/amount/base_amount.yaml
   ```

2. **Find similar parameter in app:**
   ```bash
   cd ../policyengine-app
   grep -r "ctc.*amount" src/pages/policy/
   ```

3. **Add UI control following pattern**

### Task 2: Add New Chart

1. **See existing charts:**
   ```bash
   cat src/pages/policy/output/DistributionalImpact.jsx
   ```

2. **Create new chart component**

3. **Add to policy output page**

### Task 3: Fix Bug in Calculator

1. **Find relevant component:**
   ```bash
   # Search for the feature
   grep -r "keyword" src/pages/
   ```

2. **Read component code**

3. **Make fix following React patterns**

4. **Test with dev server:**
   ```bash
   make debug
   ```

## Build and Deployment

**Production build:**
```bash
make build
# Creates optimized bundle in build/
```

**Deployment:**
```bash
# See deployment configuration
cat netlify.toml  # or appropriate config
```

**Environment variables:**
```bash
# React env vars must have REACT_APP_ prefix
REACT_APP_API_URL=https://api.policyengine.org

# Or use config file pattern (recommended)
cat src/config/environment.js
```

## Style Guide

**Follow policyengine-standards-skill for:**
- ESLint configuration
- Prettier formatting
- Component size limits
- File organization

**Follow policyengine-writing-skill for:**
- Blog post content
- Documentation
- UI copy

## Resources

**Repository:** https://github.com/PolicyEngine/policyengine-app
**Live app:** https://policyengine.org
**Staging:** https://staging.policyengine.org (if applicable)

**Related skills:**
- **policyengine-api-skill** - Understanding the backend
- **policyengine-us-skill** - Understanding variables/parameters
- **policyengine-writing-skill** - Blog post style
- **policyengine-standards-skill** - Code quality