Minimum Wage Monitor
Code location: product/mr-people-agents/minwage/
Linear ticket: MRP-110
Status: Built, awaiting decisions on cadence and jurisdiction scope
Uses AI: Yes. One Claude call per statute page (data extraction, not conversation).
What it does
MR has employees in multiple states and cities, each with different minimum wage laws. Before this agent, no system at MR watched wage law changes. If a state raised its minimum wage, someone would have to notice, manually check which employees were affected, and route pay adjustments. This agent automates that surveillance.
It does two things:
- Watches public government wage-law pages and extracts the current minimums
- Compares employee pay rates against those minimums and flags anyone who's below or will be soon
How it works
Step 1: Statute parsing
The agent fetches public web pages from government labor departments:
- California DIR (Department of Industrial Relations)
- Washington L&I (Labor & Industries)
- Colorado CDLE (Colorado Department of Labor and Employment)
- San Francisco OLSE (Office of Labor Standards Enforcement)
- US DOL (Department of Labor, for federal minimums)
For each page, it makes one Claude API call that extracts structured data:
{
"jurisdiction": "California",
"dimension": "hourly",
"new_floor": 16.50,
"effective_date": "2025-01-01",
"source_url": "https://dir.ca.gov/..."
}
The prompt is narrow and strict: extract these four fields as JSON. If the model can't parse the page or returns malformed data, the agent fails loudly (no silent degradation).
Step 2: Threshold state machine
Extracted wage floors don't go live immediately. They enter a staging pipeline:
parse → pending-confirm → (human reviews) → live
→ rejected
needs-human → (human investigates) → live
→ rejected
| State | What it means |
|---|---|
pending-confirm | Agent extracted a value; a human needs to verify it's correct |
needs-human | Agent couldn't confidently extract the data; human must look at the source |
live | Human confirmed; this threshold is now used for comparisons |
rejected | Human reviewed and said it's wrong; ignored in comparisons |
superseded | A newer threshold for the same jurisdiction replaced this one |
Nothing the agent writes goes directly into the comparison. A human always ratifies first.
Step 3: Wage comparison
Using only live thresholds, the agent compares employee pay against legal minimums:
- Hourly employees: Is hourly rate >= the floor for their work location?
- Salaried employees: Does salary meet the FLSA (Fair Labor Standards Act) salary threshold for their exemption classification?
- Lookahead: Flags employees who will fall below a new minimum within a configurable window (default: 60 days)
Violations and upcoming changes route to the Job Change workflow. The agent flags; a human enters the pay adjustment in Paylocity.
Four dimensions of comparison
The wage comparison handles four dimensions simultaneously:
- Federal — FLSA federal minimum wage and salary thresholds
- State — State-specific minimums (CA, WA, CO, etc.)
- Local — City/county minimums (San Francisco, potentially LA, West Hollywood, Santa Monica)
- Employment type — Different thresholds for full-time vs part-time, hourly vs salaried
The highest applicable floor wins (an employee in San Francisco must meet the SF minimum, not just the California or federal one).
Data flow
Government wage-law websites (public)
↓ Agent fetches page text
Claude API (one call per page)
↓ Extracts jurisdiction, dimension, floor, effective_date
Thresholds tab in spreadsheet (pending-confirm state)
↓ Human reviews, flips to live or rejected
Live thresholds
+ Employee current rates (Paylocity CSV export from Drive)
↓ Wage comparison
Exception Queue (violations + upcoming changes)
↓ Routes to named reviewer
Job Change workflow in Paylocity (human enters the fix)
Open decisions
These need to be resolved before the agent goes live:
| Decision | What it means | Who decides |
|---|---|---|
| Cadence (Q8) | How often does the agent run? Monthly (mid-month) or quarterly? The code accepts either; installTriggers(cadence) takes it as an argument. | Shlanda / Syra |
| Jurisdiction list (Q9) | Which locations to watch. Confirmed: CA, WA, CO, SF. Candidates: LA City, LA County, West Hollywood, Santa Monica. | Shlanda |
| FLSA salary dimension scope | Which salary thresholds MR needs to track (some FLSA exemption levels may not apply to MR's workforce) | Grecia |
| Confirm-gate owner (Q13) | Who ratifies pending-confirm rows before they become live? | Shlanda |
Key files
| File | What it does |
|---|---|
minwage_lib.js | Pure logic: threshold merging, deduplication, state machine transitions, wage comparison, exception fragment construction |
Code.gs | I/O: fetches web pages, calls Claude, validates JSON output, writes thresholds and exceptions to the spreadsheet |
statute_prompt.js | The prompt and JSON schema for the bounded Claude call |
Spreadsheet tabs
| Tab | Purpose |
|---|---|
| Config | Key/value settings (lookahead_days, etc.) |
| Sources | URLs and jurisdictions to watch |
| Thresholds | State machine: each row is a wage floor with status (live/pending-confirm/needs-human/rejected/superseded) |
| Jurisdictions | Maps employee work locations to jurisdictions (e.g., "San Francisco HCB" maps to SF local + CA state + federal) |
| Routing | Exception type to reviewer email |
| Exception Queue | Flagged violations and upcoming changes |
| Audit Log | Append-only record of every parse, comparison, and routing |