# poc-bot
An AI-orchestrated pipeline that analyzes the health of active POC (proof of
concept) pilots and posts per-company summaries to Slack.
**No build system or package manager** — every script uses the Python 3 standard
library only.
## Contents
- [How it works](#how-it-works)
- [Skills](#skills)
- [Requirements](#requirements)
- [How to deploy](#how-to-deploy)
- [Configuration](#configuration)
- [Finding Metabase IDs](#finding-metabase-ids)
- [Finding HubSpot IDs](#finding-hubspot-ids)
- [Running the pipeline](#running-the-pipeline)
- [Adapting to your product](#adapting-to-your-product)
- [Project layout](#project-layout)
- [License](#license)
- [Security](#security)
## How it works
The pipeline runs in three phases, coordinated by an AI agent:
1. **Fetch** — a script pulls active POC deals from HubSpot and per-team usage
metrics from Metabase, and writes a JSON file to `/tmp`.
2. **Analyze** — the agent reads that data and generates a written health
assessment per company (this step is performed by the agent, not a script).
3. **Post** — a script posts the results to a configured Slack channel.
```
HubSpot ─┐
├─▶ fetch script ──▶ /tmp/*.json ──▶ agent analysis ──▶ post script ──▶ Slack
Metabase ┘
```
For the full step-by-step agent instructions, see [AGENTS.md](AGENTS.md) and each
skill's `SKILL.md`.
## Skills
This repo ships three skills under `.agents/skills/` — one for deployment and
two independent reporting pipelines:
| Skill | What it does |
|---|---|
| `setup` | Guided deployment — clones the repo if needed, builds `.env`, discovers IDs, verifies API access. |
| `poc-analysis` | End-to-end POC health analysis — one detailed Slack message per company. |
| `poc-not-customer-usage` | 30-day primary-metric usage for active-enterprise PoCs not yet closed-won — one ranked Slack summary. |
## Requirements
- Python 3.8+
- No third-party packages
- API credentials for HubSpot, Metabase, and Slack (see [Configuration](#configuration))
## How to deploy
### With an agent (recommended)
Paste this prompt into Warp (or any agent that supports `.agents/skills/`):
```
Set up poc-bot: clone https://github.com/warpdotdev/poc-agent-oss.git if it
isn't already cloned, then run the setup skill.
```
The [`setup` skill](.agents/skills/setup/SKILL.md) walks the agent through the
whole deployment: cloning (or reusing an existing clone), creating `.env`,
collecting credentials, discovering your HubSpot/Metabase IDs via their APIs,
loading the environment, and running read-only verification checks against
each service. It is safe to re-run to finish a partial setup.
### Manually
The same steps, by hand:
1. Clone the repo:
```bash
git clone https://github.com/warpdotdev/poc-agent-oss.git
cd poc-agent-oss
```
2. Create your environment file from the example and fill in your values
(see [Configuration](#configuration) for what goes where):
```bash
cp .env.example .env
# then edit .env
```
3. Load the variables into your shell. The scripts read from the process
environment — there is **no dotenv auto-loader** — so export them before
running anything:
```bash
set -a && source .env && set +a
```
4. Run a skill — see [Running the pipeline](#running-the-pipeline).
## Configuration
All secrets and infrastructure coordinates are supplied via **environment
variables**. The complete, annotated list lives in
[`.env.example`](.env.example) — copy it to `.env` and fill in your values.
**Never commit `.env`** (it is gitignored; only `.env.example` is tracked).
At a minimum you must set:
| Variable | Used by | Purpose |
|---|---|---|
| `HUBSPOT_ACCESS_TOKEN` | both | HubSpot private app token (deals read scope) |
| `HUBSPOT_POC_PIPELINE_ID` / `HUBSPOT_POC_STAGE_ID` | poc-analysis | Which pipeline/stage to pull deals from |
| `METABASE_BASE_URL` / `METABASE_API_KEY` / `METABASE_DASHBOARD_ID` | both | Metabase instance + dashboard |
| `METABASE_PARAM_DATE_RANGE_ID` / `METABASE_PARAM_TEAM_ID_ID` | both | Dashboard parameter IDs |
| `METABASE_DB_ID` / `METABASE_PRIMARY_METRIC_DASHCARD_ID` / `METABASE_PRIMARY_METRIC_CARD_ID` | poc-not-customer-usage | Native-query DB + primary-metric tile |
| `POC_BOT_SLACK_TOKEN` / `SLACK_CHANNEL` | both | Slack bot token + target channel |
See [`.env.example`](.env.example) for every optional variable (display labels,
cohort filters, warehouse overrides, owner enrichment).
Structural configuration — which Metabase cards to query, their parameter
bindings, and warehouse table/column names — lives in per-skill JSON files
instead of code (see [Adapting to your product](#adapting-to-your-product)).
### Finding Metabase IDs
- **Dashboard ID**: visible in the dashboard URL — `https://metabase.example.com/dashboard/<ID>-...`
- **Parameter IDs**: `GET /api/dashboard/{id}` → top-level `parameters` array, each entry has an `id` field.
- **Dashcard / Card IDs**: `GET /api/dashboard/{id}` → `dashcards` array, each entry has `id` (dashcard_id) and `card_id`.
- **Database ID**: Metabase Settings → Admin → Databases, or `GET /api/database`.
### Finding HubSpot IDs
- **Pipeline / Stage IDs**: HubSpot Settings → CRM → Deals → Pipelines, or `GET /crm/v3/pipelines/deals`.
## Running the pipeline
Make sure your environment is loaded first (`set -a && source .env && set +a`).
### poc-analysis
```bash
# 1. Fetch HubSpot deals + Metabase metrics → /tmp/poc_data.json
python3 .agents/skills/poc-analysis/scripts/fetch_poc_data.py
# 2–3. The agent reads /tmp/poc_data.json, analyzes each company per
# .agents/skills/poc-analysis/SKILL.md, and writes /tmp/poc_analysis.json
# 4. Post /tmp/poc_analysis.json to Slack
python3 .agents/skills/poc-analysis/scripts/post_to_slack.py
```
### poc-not-customer-usage
```bash
# 1. Fetch the active-enterprise PoC cohort + 30-day usage → /tmp/poc_not_customer_usage_data.json
python3 .agents/skills/poc-not-customer-usage/scripts/fetch_poc_not_customer_usage_data.py
# 2. Build the Slack report → /tmp/poc_not_customer_usage_report.json
python3 .agents/skills/poc-not-customer-usage/scripts/build_report.py
# 3. Post the ranked summary to Slack
python3 .agents/skills/poc-not-customer-usage/scripts/post_to_slack.py
```
## Adapting to your product
poc-bot is built around a configurable **primary metric** — the single number
that best signals product value for a given POC: API calls, pipeline runs, MAU,
credits, etc. Out of the box everything ships with generic labels and
placeholder IDs — point it at any scalar Metabase card.
### 1. Change the primary metric
Set the env vars for the metric tile you want to track:
```bash
METABASE_PRIMARY_METRIC_DASHCARD_ID=<your dashcard ID>
METABASE_PRIMARY_METRIC_CARD_ID=<your card ID>
PRIMARY_METRIC_LABEL=API calls # default: "primary metric"
PRIMARY_METRIC_EMOJI=:zap: # default: ":bar_chart:"
```
### 2. Update the analysis methodology
Edit `.agents/skills/poc-analysis/config/methodology.md` to describe:
- Which JSON path holds your primary metric
- What your secondary metrics mean
- The column names and thresholds for user tier classification
- How summaries should be framed for your CS or sales context
This file is read by the agent before it analyzes each company — it is the
complete description of your deployment's POC health playbook.
### 3. Update the dashboard schema doc
Replace `.agents/skills/poc-analysis/references/metabase_config.md` with the
column names and metric definitions from your own Metabase dashboard. The agent
references this file to interpret the raw data returned by each card query.
### 4. Wire up your dashboard and warehouse in the JSON configs
No code edits required — each skill reads its structural configuration from a
JSON file in its `config/` directory:
- `.agents/skills/poc-analysis/config/metabase_cards.json` — the cards to
query (dashcard/card IDs), the output label for each card, and the exact
Metabase `parameter_mappings` targets, discovered via `GET /api/dashboard/{id}`.
Override the path with `METABASE_CARDS_CONFIG`.
- `.agents/skills/poc-not-customer-usage/config/data_sources.json` — the
parameter targets for the primary metric card, plus your warehouse table
names and a logical→physical column mapping for the teams facts, service
agreements, and deals tables (including the type/status values that mark an
active enterprise agreement). Override the path with `DATA_SOURCES_CONFIG`;
the `DB_*` env vars override individual tables/columns.
## Project layout
```
.
├── .env.example # copy to .env and fill in
├── AGENTS.md # agent workflow / repo guidance
├── README.md
├── SECURITY.md
└── .agents/skills/
├── setup/
│ └── SKILL.md # guided deployment (see How to deploy)
├── poc-analysis/
│ ├── SKILL.md
│ ├── config/ # metabase_cards.json, methodology.md
│ ├── references/ # metabase_config.md (schema doc)
│ └── scripts/ # fetch_poc_data.py, post_to_slack.py
└── poc-not-customer-usage/
├── SKILL.md
├── config/ # data_sources.json, methodology.md
└── scripts/ # fetch_*, build_report.py, post_to_slack.py
```
## License
MIT — see [LICENSE](LICENSE).
## Security
Please see [SECURITY.md](SECURITY.md) for vulnerability reporting instructions.