ecom -- Ecommerce Business Review Toolkit
D2C ecommerce analytics system. The Python backend computes KPIs, runs health checks, and scores performance from order transaction data; you (Claude) interpret the numbers and write the human-readable report.
Input: Order transaction data only (CSV).
Quick Reference
| Command | What it does | Output |
|---|---|---|
| /ecom review | Full business review (auto-selects periods from data) | REVIEW.md |
| /ecom review 30d | Focused on the last 30 days | REVIEW_30D.md |
| /ecom review 90d | Focused on the last 90 days | REVIEW_90D.md |
| /ecom review 365d | Focused on the last 365 days | REVIEW_365D.md |
| /ecom review [question] | Answers a specific question from the data | Inline response |
One command. Two modes: full report or focused answer.
Response Modes
Mode 1: Full Review (default)
Triggered when: no natural-language question in the user's input. Output: REVIEW.md (or REVIEW_{PERIOD}.md for period-specific runs) following the full 6-part structure defined below.
Examples: /ecom review, /ecom review 30d, /ecom review 365d
Mode 2: Focused Query
Triggered when: user's input includes a natural-language question or topic. Output: inline conversational response (no file creation).
Examples:
- "how was last month?" → extract from monthly_trend
- "how was last year?" → 365d data
- "how was Q4 last year?" → extract from monthly_trend
- "how's retention looking?" → customer metrics focus
Query-to-Period Mapping
| Query pattern | Data source |
|---|---|
| last 30 days | --period 30d |
| last 3 months / last 90 days | --period 90d |
| last year / this year | --period 365d |
| last month / specific month name | full run, extract from monthly_trend |
| Q1-Q4 / specific quarter | full run, extract from monthly_trend |
Calendar-month questions ("last month", "January") use the 365d monthly_trend, NOT a 30d trailing window. Use --period 30d only when the user explicitly asks for "last 30 days".
Fallback when 365d coverage is unavailable: Calendar-month and quarter queries require 365d monthly_trend data. If 365d coverage is missing (data < 400 days):
- Answer from the best available trailing window data
- State that exact calendar-month/quarter breakdown is not available
- Suggest running a full review for deeper analysis
monthly_trend limitation: no year-over-year comparison by month/quarter monthly_trend covers only the most recent 12 months. Comparing "Q4 this year vs Q4 last year" is not possible. Instead:
- Present absolute values (revenue, orders) for the requested period
- Calculate its share of annual revenue (seasonality concentration)
- Compare against Q1-Q3 average for relative scale
- Add 365d overall YoY growth rate as context
- Do not mention the absence of YoY comparison (follow Handling Incomplete Data rules — omit what you can't measure)
If the query doesn't map to a clear period, run full (no --period flag) and answer from the most relevant data.
Focused Query Response Format
- Direct answer (2-3 sentences with key numbers from review.json)
- Supporting context (1-2 observations that add nuance — tensions, comparisons)
- One actionable takeaway (if warranted by the data)
Total: 10-30 lines. Headings, KPI tree, and Finding format are NOT required. Use whatever structure best fits the answer. For example, "what's the new vs returning split?" is clearest as a partial KPI tree. Apply the same data rules: all numbers from review.json only, match user's language. Do NOT create a REVIEW.md file.
Data Input
Order transaction data (CSV). Each row = one order or line item.
Required columns:
- Order ID, Order date, Customer ID (or email)
- Revenue (after discounts, before tax/shipping)
- Quantity, SKU/Product ID
- Discount amount (if available)
~/.claude/skills/ecom/bin/ecom review orders.csv --output <output-dir>
~/.claude/skills/ecom/bin/ecom review orders.csv --period 90d --output <output-dir>
Workflow
Phase 1: Compute (Python)
~/.claude/skills/ecom/bin/ecom review orders.csv --output <output-dir>
The engine internally:
- Period analysis -- computes KPIs for each time period (30d, 90d, 365d) with prior-period comparisons, decompositions, and trend detection.
- Health checks -- evaluates ~30 checks across Revenue, Customer, and Product. Each check produces a pass/watch/fail signal with severity weighting. These power the 🟢/🟡/🔴 markers in the KPI tree.
Output: review.json (or review_{period}.json for period-specific runs). See Schema section below.
Phase 2: Interpret (You -- Claude)
- Read
review.json(orreview_{period}.jsonfor period-specific runs) - Load reference files on demand (see Reference Files below)
- Write REVIEW.md (or
REVIEW_{PERIOD}.md) following the Output Format below
Your job is to weave trends and diagnostics into one coherent story. Period analysis tells you where things are heading. Health checks tell you what's broken right now. The report combines both.
review.json Schema
This is the data contract between Python and Claude. Every field below is guaranteed to exist in the output. Claude reads this structure; Claude does NOT invent data that isn't here.
{
"version": "0.1.0",
// --- Metadata ---
"metadata": {
"generated_at": "2026-03-05T18:00:00Z",
"data_start": "2025-01-01",
"data_end": "2025-12-31",
"total_orders": 5784,
"total_customers": 2765,
"total_revenue": 1383651,
"currency": "USD",
"revenue_definition": "Net sales after discounts, before tax and shipping"
},
// --- Data quality warnings (empty array = no issues) ---
"data_quality": [
// Example entries (only present when issues detected):
// { "type": "partial_period", "period": "2026-02", "days_with_data": 3,
// "message": "Latest month (2026-02) has only 3 days of data. MoM comparisons use prior complete months." }
// { "type": "short_data_span", "days": 45, "message": "Data spans only 45 days..." }
// { "type": "limited_data_span", "days": 200, "message": "Data spans 200 days (<1 year)..." }
],
// --- Data coverage: which periods are available ---
"data_coverage": {
"30d": true, // true if >=45 days of data exist
"90d": true, // true if >=120 days of data exist
"365d": true // true if >=400 days of data exist
},
// --- Period metrics (one block per available period) ---
"periods": {
"30d": {
"summary": {
"revenue": 98000,
"revenue_change": -0.003, // vs prior 30d
"orders": 412,
"orders_change": -0.03,
"aov": 238,
"aov_change": -0.001,
"customers": 287,
"customers_change": -0.05
},
"kpi_tree": {
"new_customer_revenue": 38000,
"new_customer_revenue_share": 0.388,
"new_customers": 95,
"new_customers_change": -0.08,
"new_customer_aov": 400,
"returning_customer_revenue": 60000,
"returning_customer_revenue_share": 0.612,
"returning_customers": 192,
"returning_customers_change": -0.03,
"returning_customer_aov": 312
},
"drivers": {
"aov_effect": 1200, // revenue change attributable to AOV
"volume_effect": -1500, // revenue change attributable to order count
"mix_effect": 0 // revenue change attributable to new/returning mix shift
}
},
"90d": { /* same structure */ },
"365d": {
/* same structure as 30d (summary, kpi_tree, drivers) plus: */
"repeat_purchase_rate": 0.38, // only in 365d block
"monthly_trend": [
{ "month": "2025-01", "revenue": 95000, "orders": 420, "aov": 226, "customers": 310, "new_customers": 180, "returning_customers": 130, "days_with_data": 31 },
// ... only months wit