# Multi-Agent Workflow Visibility — Lean MVP PRD

> Generated: 2026-05-01
> Source: `ScoredDemands/ai-agent-observability__scored-demand__20260501-0957.md`
> Score: 29/40 | Decision: BUILD
> Stack: Next.js 14 + TypeScript + Supabase + Stripe

---

## 1. Problem & User

**Target User:** Engineering teams (2–12 engineers) building and operating multi-agent AI orchestration systems. They use custom agent frameworks or fragmented stacks (LangChain, CrewAI, custom Python/TypeScript). They are NOT using full enterprise observability platforms.

**Core Pain:** When a multi-agent workflow fails, developers have no way to see which specific agent-to-agent handoff broke, what state was passed, or where responsibility shifted. Existing tools (LangSmith, Helicone, AgentOps) show nested span traces built for single-agent calls — they don't model cross-agent topology or handoff diffs as first-class concepts. Teams are "flying blind."

**User Quote:** *"Multi-agent workflows are exploding in adoption. But debugging them? Still pure chaos for most teams."*

---

## 2. Target Outcome & KPIs

**Primary Outcome:** Engineer reaches Aha Moment — posts one agent run and sees the exact broken handoff — within 5 minutes of signup.

| KPI | Target |
|-----|--------|
| Aha Moment rate (first run posted within 5 min) | >50% of signups |
| Trial-to-paid conversion | >8% within 14 days |
| 7-day retention | >40% |
| Time-to-first-value (first run ingested) | <5 minutes |

---

## 3. MVP Scope (In)

- **Ingestion API:** Single `POST /api/ingest/run` endpoint — accepts run JSON with agents, handoffs, events, and state snapshots
- **Project Dashboard:** List of recent runs per project with status (success / failed / partial)
- **Run Detail Page:** Agent swimlane timeline, handoff table with payload diffs, state JSON diff between consecutive snapshots
- **Failure Localization:** Simple heuristic — highlight the first handoff where state diff shows unexpected change or missing required field
- **Auth & Onboarding:** Email/GitHub sign-in, auto-create first project, show API key + copy-paste curl example
- **Billing:** 14-day free trial (unlimited runs) → paywall at 10k events/month → Stripe checkout → $39/mo
- **Auto-conversion email sequence:** 3 emails triggered on paywall hit

---

## 4. Out of Scope

- Native SDKs / agent framework integrations (ship curl + copy-paste examples only)
- Real-time streaming / live agent monitoring
- Evaluation / LLM quality scoring
- SSO, SOC2, enterprise compliance
- Alert rules or PagerDuty integrations
- Mobile app

---

## 5. User Flow (Happy Path)

```
1. Sign up (GitHub OAuth, 30 seconds)
   ↓
2. Auto-created first project + API key shown inline
   ↓
3. Copy-paste curl example → POST first agent run with 3 agents + 2 handoffs
   [⭐ Aha Moment: Run detail page loads, broken handoff highlighted in red]
   ↓
4. Inspect: swimlane timeline → click handoff → see payload diff → spot the bug
   ↓
5. Continue using free tier (up to 10k events)
   ↓
6. Hit event limit → paywall banner → Stripe checkout → $39/mo subscription
```

---

## 6. Functional Requirements (P0)

| ID | Requirement |
|----|-------------|
| FR-01 | `POST /api/ingest/run` accepts JSON: `{project_id, run_id, agents[], handoffs[], events[], state_snapshots[]}` → returns 201 with run URL |
| FR-02 | Project dashboard lists last 50 runs with: run_id, timestamp, agent count, handoff count, status, duration |
| FR-03 | Run detail page renders agent swimlane (time on X, agent lanes on Y), with each event plotted in its agent's lane |
| FR-04 | Handoff table: source_agent → target_agent, timestamp, payload before/after diff (JSON diff with added/removed/changed highlighted) |
| FR-05 | State snapshot diff: side-by-side JSON diff between consecutive snapshots, with first divergence flagged |
| FR-06 | "Likely failure point" badge: auto-tag the first handoff where payload diff contains null/missing required fields or error keys |
| FR-07 | Auth: GitHub OAuth + email magic link via Supabase Auth |
| FR-08 | Event counter per project with progress bar → 10k monthly limit → paywall modal → Stripe checkout session |
| FR-09 | Post-paywall 3-email sequence: (1) immediate "you're near the limit", (2) +24h "see your top broken agents", (3) +72h "teams using this save 4h/week on debugging" |

---

## 7. Minimal Data Model

```sql
-- Core tables (Supabase/PostgreSQL)

projects (
  id uuid PK,
  user_id uuid FK,
  name text,
  api_key text UNIQUE,
  monthly_event_count int DEFAULT 0,
  created_at timestamptz
)

runs (
  id uuid PK,
  project_id uuid FK,
  external_run_id text,
  status text,  -- 'success' | 'failed' | 'partial'
  agent_count int,
  handoff_count int,
  duration_ms int,
  failure_handoff_index int,  -- null if no failure detected
  raw_payload jsonb,
  created_at timestamptz
)

agents (
  id uuid PK,
  run_id uuid FK,
  name text,
  role text,
  start_time timestamptz,
  end_time timestamptz
)

handoffs (
  id uuid PK,
  run_id uuid FK,
  seq int,
  source_agent_id uuid FK,
  target_agent_id uuid FK,
  timestamp timestamptz,
  payload_before jsonb,
  payload_after jsonb,
  has_diff_anomaly bool DEFAULT false
)

events (
  id uuid PK,
  run_id uuid FK,
  agent_id uuid FK,
  event_type text,  -- 'llm_call' | 'tool_call' | 'handoff' | 'state_update'
  timestamp timestamptz,
  data jsonb
)

subscriptions (
  id uuid PK,
  user_id uuid FK,
  stripe_customer_id text,
  stripe_subscription_id text,
  status text,
  trial_ends_at timestamptz,
  current_period_end timestamptz
)
```

---

## 8. API / Integration Notes

- **Ingestion:** Single REST endpoint, JSON body, Bearer token (project API key). No SDK required.
- **Auth:** Supabase Auth (GitHub OAuth + magic link)
- **Database:** Supabase PostgreSQL + Row Level Security per user_id
- **Billing:** Stripe Checkout + Webhooks (`customer.subscription.created/updated/deleted`, `invoice.payment_succeeded/failed`)
- **Email:** Supabase Edge Function or Resend for triggered emails
- **JSON Diff:** `jsondiffpatch` npm library for payload/state diffs in the UI

**Sample ingestion payload:**
```json
{
  "run_id": "run_abc123",
  "agents": [
    {"name": "Planner", "role": "orchestrator", "start": "2026-05-01T09:00:00Z"},
    {"name": "Searcher", "role": "worker", "start": "2026-05-01T09:00:05Z"},
    {"name": "Writer", "role": "worker", "start": "2026-05-01T09:00:15Z"}
  ],
  "handoffs": [
    {
      "from": "Planner", "to": "Searcher", "at": "2026-05-01T09:00:05Z",
      "payload_before": {"task": "find competitors", "context": "SaaS space"},
      "payload_after": {"task": "find competitors", "context": null}
    }
  ],
  "events": [...],
  "state_snapshots": [...]
}
```

---

## 9. Acceptance Criteria

1. `POST /api/ingest/run` with valid API key returns 201 and run URL within 500ms
2. Run detail page renders within 2s for a run with 5 agents and 10 handoffs
3. Handoff with `payload_after` containing a null field that was non-null in `payload_before` is flagged as `has_diff_anomaly = true`
4. Monthly event counter increments correctly on each ingestion; reaching 10k displays paywall modal
5. Stripe checkout session creates subscription and `subscriptions` table updates within 5s of webhook
6. All 3 conversion emails deliver within correct time windows (verified in test env)
7. New user can sign up, get API key, POST first run, and see run detail without any manual setup — under 5 minutes

---

## 10. Delivery Plan

### M1 — Ingest + Aha Moment (Day 1, ~8h)

**Goal:** First run can be ingested and viewed.

| File | Action |
|------|--------|
| `prisma/schema.prisma` | Define all 6 tables |
| `supabase/migrations/001_init.sql` | Generated migration |
| `lib/ingest.ts` | Parse and validate run payload, write to DB |
| `app/api/ingest/run/route.ts` | `POST` handler — auth API key, call ingest, return run URL |
| `app/dashboard/page.tsx` | Project list + run list per project |
| `app/runs/[id]/page.tsx` | Run detail: swimlane timeline + handoff table + state diff |
| `components/AgentSwimlane.tsx` | SVG-based timeline with agent lanes |
| `components/HandoffTable.tsx` | Table with jsondiffpatch diff rendering |
| `lib/diffEngine.ts` | Anomaly detection: flag first handoff with null-diff |

**Exit criteria:**
- `POST /api/ingest/run` returns 201 with correct run URL
- Run detail page renders swimlane and handoff diff for sample payload
- Broken handoff highlighted in red with "likely failure" badge

---

### M2 — Auth + Billing + Conversion Sequence (Day 2, ~6h)

**Goal:** End-to-end PLG flow — signup to paywall to paid.

| File | Action |
|------|--------|
| `app/api/auth/[...nextauth]/route.ts` | GitHub OAuth + magic link via Supabase Auth |
| `middleware.ts` | Protect dashboard routes, redirect unauthenticated |
| `lib/stripe.ts` | `createCheckoutSession`, `createPortalSession` |
| `app/api/billing/checkout/route.ts` | Create Stripe session |
| `app/api/billing/webhook/route.ts` | Handle subscription lifecycle events |
| `lib/eventCounter.ts` | Increment counter on ingest, check vs 10k limit |
| `components/PaywallModal.tsx` | Triggered when limit hit, links to checkout |
| `lib/email.ts` | Resend/Supabase Edge: 3-email sequence trigger |
| `app/api/billing/emails/route.ts` | Cron/webhook endpoint to send scheduled emails |

**Exit criteria:**
- New user signs up, creates project, gets API key in <2 minutes
- 10k event limit triggers paywall modal
- Stripe test checkout completes and subscription status updates in DB
- Email #1 fires immediately on paywall hit (verified in test)

---

### M3 — Polish + Launch (Day 3, ~6h)

**Goal:** Production-ready, load-tested, deployed.

| File | Action |
|------|--------|
| `app/onboarding/page.tsx` | Post-signup: show API key + copy-paste curl command |
| `components/CopyButton.tsx` | One-click copy for API key and curl example |
| `app/api/projects/route.ts` | CRUD for projects (create, list, delete) |
| `lib/rateLimit.ts` | Basic rate limiting on ingest endpoint (100 req/min per project) |
| `app/error.tsx` + `app/not-found.tsx` | Error boundary pages |
| `__tests__/ingest.test.ts` | Integration test: POST run → verify DB state |
| `__tests__/billing.test.ts` | Integration test: Stripe webhook → subscription status update |
| `.github/workflows/deploy.yml` | Vercel deploy on push to main |

**Exit criteria:**
- New user completes full flow (signup → ingest → view run → hit paywall → checkout) in <15 minutes
- Integration tests pass in CI
- `wrangler deploy` or Vercel deploy succeeds without errors
- Lighthouse performance score >80 on run detail page

---

## 11. Risks & Mitigations

| Risk | Mitigation |
|------|------------|
| Complex runs with 50+ agents/events make the swimlane unreadable | Cap MVP render at 20 agents, paginate events; add "collapse minor events" toggle |
| Users send malformed JSON (missing required fields) | Validate strictly on ingest; return 400 with field-level errors and example payload |
| Supabase jsonb queries slow on large run payloads | Store full payload in Supabase Storage (file), keep indexed fields in relational table |
| Stripe webhook replay causes double-subscription | Idempotency key on webhook handler; check existing subscription before creating new |
| Low trial-to-paid because free tier is too generous | Monitor conversion at 7 days; if <5%, reduce free limit to 3k events |

---

## 12. Chargeability Rationale

Engineering teams lose hours per incident on multi-agent debugging today; a single resolved incident in under 10 minutes instead of 4 hours pays for a year of $39/mo subscriptions — making this an obvious ROI purchase for any team shipping agents to production.

---

*Pricing: $39/mo per team · 10k events/month · 14-day free trial*
*PLG funnel: Aha Moment <5min → free tier → paywall at 10k events → Stripe → 3-email auto-conversion*
