Skip to main content
Glama
README.md
# Frontline Copilot

**AI-powered review triage for retail store managers.**

An always-on system that ingests customer reviews from any source, uses Claude
to classify them by category and severity, and routes actionable ones to the
store manager's Airtable task list — with real-time Slack alerts for critical
issues (food safety, staff conduct, health risks).

Also ships as an **MCP server** so store managers can query and triage
conversationally from Claude Desktop.

> Inspired by the emerging category of AI copilots for store operations.

---

## The problem

Store managers at multi-location retail chains drown in signal from customer
reviews. Most are noise (praise or minor grumbles). A few are urgent (food
safety, discrimination, injury risk). Most tools require the manager to *read*
everything to find the few that matter — a losing battle at scale.

Frontline Copilot inverts this. Claude reads everything; the manager only sees
what needs action.

---

## How it works

```
┌────────────┐   ┌──────────────┐   ┌────────────┐   ┌────────────┐
│  Reviews   │──▶│ Classifier   │──▶│  Airtable  │──▶│   Slack    │
│  (JSON /   │   │ (Claude API, │   │  (task     │   │  (critical │
│   Google)  │   │  tool use)   │   │  tracker)  │   │   alerts)  │
└────────────┘   └──────────────┘   └────────────┘   └────────────┘
                        │
                        ▼
                 ┌──────────────┐
                 │  MCP server  │◀── Claude Desktop, Cursor, ...
                 │  (3 tools)   │
                 └──────────────┘
```

Each review is classified into one of nine categories with a severity from
1 (positive) to 5 (critical). Reviews at severity ≥ 3 become Airtable tasks;
severity ≥ 4 additionally fire a Slack alert.

---

## Screenshots

### End-to-end pipeline run
21 reviews processed in ~60 seconds. 7 tasks created, 4 real-time critical alerts.

![Terminal](screenshots/terminal.png)

### Airtable — task board
Tasks sorted by severity, colored by category. This is what a store manager sees.

![Airtable board](screenshots/airtable.png)

### Airtable — Kanban view
Same data, grouped by category. Distribution of issues at a glance.

![Airtable Kanban](screenshots/kanban.png)

### Slack — real-time critical alerts
Block Kit cards with action-first layout and direct link to the Airtable task.

![Slack alerts](screenshots/slack.png)

---

## Tech stack

- **Python 3.10+** — dataclasses, `str | None` union types, pathlib
- **Anthropic Claude API** — classification via tool use (`claude-haiku-4-5`)
- **Airtable REST API** — task tracker, called with raw `requests`
- **Slack Incoming Webhooks** — Block Kit for rich alert cards
- **MCP (Model Context Protocol)** — conversational interface via FastMCP
- **Adapter pattern** for review sources (Mock ships; Google Places stubbed)

Only three third-party deps: `anthropic`, `requests`, `mcp`. Everything else
is standard library.

---

## Quick start

```bash
# 1. Clone and install
git clone https://github.com/miguelpomarm/frontline-copilot
cd frontline-copilot
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 2. Configure secrets
cp .env.example .env
# ... edit .env with your keys (see setup section below)

# 3. Run the pipeline
python triage.py

# 4. Launch as an MCP server (optional)
python mcp_server.py
```

---

## Setup (one-time, ~10 minutes)

### 1. Anthropic API key

Get one at <https://console.anthropic.com/>. The free tier is enough for demo
runs — 21 reviews cost ~$0.03.

### 2. Airtable base

Create a new base with a table named `Tasks` and these fields (exact names):

| Field | Type |
|---|---|
| Review ID | Single line text (primary field) |
| Store | Single line text |
| Category | Single select — populate with the 9 taxonomy values |
| Severity | Number (integer) |
| Summary | Long text |
| Review Text | Long text |
| Author | Single line text |
| Date | Date |
| Status | Single select — `Open`, `In Progress`, `Resolved` |

Then generate a personal access token at <https://airtable.com/create/tokens>
with `data.records:read` and `data.records:write` scopes on your base. Copy
the token and the base ID (starts with `app...`, found in the URL of your base).

### 3. Slack Incoming Webhook

Create a Slack app at <https://api.slack.com/apps>. Enable Incoming Webhooks,
add a new webhook pointing to whichever channel should receive critical
alerts, and copy the webhook URL.

### 4. Fill in `.env`

```bash
ANTHROPIC_API_KEY=sk-ant-...
AIRTABLE_API_KEY=pat...
AIRTABLE_BASE_ID=app...
AIRTABLE_TABLE_NAME=Tasks
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
```

### 5. First run

```bash
python triage.py --limit 3 --dry-run   # sanity check, no side effects
python triage.py --limit 3             # small live run
python triage.py                       # full 21 reviews
```

---

## MCP integration (Claude Desktop)

Add this to
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) and
restart Claude Desktop:

```json
{
  "mcpServers": {
    "frontline-copilot": {
      "command": "python",
      "args": ["/absolute/path/to/frontline-copilot/mcp_server.py"]
    }
  }
}
```

Then, inside Claude Desktop:

> *"How is Aurora Times Square doing right now?"*

Claude will invoke `get_store_health("times_square")`, hit Airtable, and
respond with the current snapshot — open tasks, critical count, top category.

---

## Design decisions

Deliberate choices worth calling out to a reviewer:

**Closed taxonomy + `Other` bucket**
Categories are a fixed enum, not free-form. This guarantees consistent routing
and metrics. `Other` is the escape hatch — reviewed periodically to expand the
taxonomy based on real data instead of upfront guessing.

**Tool use over prompt engineering**
Claude returns structured output via a tool schema with enum enforcement.
This eliminates parsing bugs and prevents the LLM from hallucinating a
category outside the taxonomy.

**Haiku 4.5 as the default model**
For a well-scoped classification task, Haiku is fast (sub-second), cheap
(~$0.001 per review), and accurate enough. In production this decision alone
saves thousands of dollars/month at moderate volume.

**Adapter pattern for review sources**
`ReviewSource` is an abstract interface. Ships with `MockSource` and a
documented `GooglePlacesSource` stub. Swapping to Yelp, TrustPilot, or a
proprietary feed is a new subclass — the rest of the pipeline is untouched.

**Idempotency by review ID**
Reprocessing the same reviews doesn't create duplicate tasks. Airtable is
checked before every create.

**Severity thresholds as tunable constants**
`ACTION_THRESHOLD` and `ALERT_THRESHOLD` are module-level. Customers with
different tolerances change two numbers, not code.

**Sync over async for the MVP**
Processes 21 reviews sequentially in ~40s. The async variant is ~15 lines to
swap (`AsyncAnthropic` + `asyncio.gather` with a semaphore for rate limits).
For this volume, readability wins over speed.

**Text over stars**
The prompt explicitly tells Claude to weigh the review text over the star
rating. A 4-star review mentioning food safety is severity 5, not 2.

---

## Roadmap (not implemented)

- **FastAPI webhook endpoint** (`POST /webhook/review`) for real-time ingestion
  instead of batch runs.
- **`GooglePlacesSource`** — the adapter interface is done, live implementation
  is ~1 hour of API integration + retry logic.
- **Rate-limit-aware async batching** for high-volume production.
- **End-to-end tests** (Playwright / pytest with recorded API interactions)
  verifying the Airtable/Slack side effects.
- **Per-customer configurable thresholds** via `config.yaml`.

---

## License

MIT — see [LICENSE](LICENSE).

---

Built by [Miguel Pomar Martínez](https://linkedin.com/in/miguelpomarm) as a
technical portfolio piece.