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.
- How it works
- Skills
- Requirements
- Setup
- Configuration
- Running the pipeline
- Adapting to your product
- Project layout
- License
- Security
The pipeline runs in three phases, coordinated by an AI agent:
- Fetch — a script pulls active POC deals from HubSpot and per-team usage
metrics from Metabase, and writes a JSON file to
/tmp. - Analyze — the agent reads that data and generates a written health assessment per company (this step is performed by the agent, not a script).
- 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 and each
skill's SKILL.md.
This repo ships two independent skills under .agents/skills/:
| Skill | What it does |
|---|---|
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. |
- Python 3.8+
- No third-party packages
- API credentials for HubSpot, Metabase, and Slack (see Configuration)
- Clone the repo:
git clone https://github.com/warpdotdev/poc-agent-oss.git cd poc-agent-oss - Create your environment file from the example and fill in your values:
cp .env.example .env # then edit .env - 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:
set -a && source .env && set +a
- Run a skill — see Running the pipeline.
All secrets and infrastructure coordinates are supplied via environment
variables. The complete, annotated list lives in
.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 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).
- Dashboard ID: visible in the dashboard URL —
https://metabase.example.com/dashboard/<ID>-... - Parameter IDs:
GET /api/dashboard/{id}→ top-levelparametersarray, each entry has anidfield. - Dashcard / Card IDs:
GET /api/dashboard/{id}→dashcardsarray, each entry hasid(dashcard_id) andcard_id. - Database ID: Metabase Settings → Admin → Databases, or
GET /api/database.
- Pipeline / Stage IDs: HubSpot Settings → CRM → Deals → Pipelines, or
GET /crm/v3/pipelines/deals.
Make sure your environment is loaded first (set -a && source .env && set +a).
# 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# 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.pypoc-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.
Set the env vars for the metric tile you want to track:
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:"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.
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.
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 Metabaseparameter_mappingstargets, discovered viaGET /api/dashboard/{id}. Override the path withMETABASE_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 withDATA_SOURCES_CONFIG; theDB_*env vars override individual tables/columns.
.
├── .env.example # copy to .env and fill in
├── AGENTS.md # agent workflow / repo guidance
├── README.md
├── SECURITY.md
└── .agents/skills/
├── 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
MIT — see LICENSE.
Please see SECURITY.md for vulnerability reporting instructions.