Smart Meeting-to-Ticket Pipeline PRD (V2)
TL;DR
Extend the existing meeting-to-ticket pipeline with two key capabilities: (1) cross-reference against existing Linear tickets to prevent duplicates and update existing tickets instead, and (2) route pending tickets to Slack for engagement planner approval with one-click actions. This builds on the working V0 platform UI.
Summary
This PRD defines enhancements to the existing meeting-to-ticket pipeline. V0 already works: meetings are ingested, action items are extracted into linear_ticket_generations with pending status, and a platform UI allows reviewers to edit titles, descriptions, priorities, and assignees before creating tickets in Linear.
What V1 adds:
- Cross-reference engine — Before staging tickets, check against existing open Linear tickets in participants’ teams. Classify items as CREATE (new), UPDATE (add comment to existing), or NEEDS_REVIEW (ambiguous match).
- Slack approval workflow — Push pending tickets to Slack for review, routed to the right people based on meeting type. Enable Approve/Reject/Reassign directly in Slack.
Prompt management is already handled in Langfuse. Documentation for how to edit prompts will be added to brainforge-playbook.
Background and Context
What Already Exists (V0 — Working)
Supabase Table: linear_ticket_generations (2,585 records)
Current schema:
| Column | Type | Notes |
|---|---|---|
| id | uuid | Auto-generated primary key |
| meeting_id | uuid | FK to zoom_meeting_recording_files |
| title | text | Action item title |
| description | text | Action item description |
| team_id | text | Linear team ID |
| team_name | text | Linear team name |
| assignee_id | text | Linear user ID (nullable) |
| assignee_name | text | Assignee display name (nullable) |
| status | text | ’pending’ (default), ‘approved’, ‘declined’ |
| linear_issue_id | text | Populated after creation in Linear |
| linear_issue_url | text | Linear ticket URL |
| linear_issue_identifier | text | e.g., “OPS-123” |
| created_in_linear_at | timestamp | When ticket was created in Linear |
| generation_metadata | jsonb | Extraction metadata |
| links | jsonb | Related links (defaults to []) |
| preferred_state | jsonb | Preferred Linear state |
| created_at, updated_at | timestamp | Timestamps |
Current Status Distribution:
- pending: 2,557
- approved: 25
- declined: 3
Working Flow:
- Meeting ingested →
zoom_meeting_recording_files - Extraction service → action items written to
linear_ticket_generations(status: pending) - Platform UI → reviewer edits title, description, assignee, priority
- Approve → ticket created in Linear,
linear_issue_idpopulated, status → approved - Decline → status → declined, no Linear ticket created
Prompt Management:
- Prompts are managed in Langfuse (not a custom UI)
- Documentation needed in
brainforge-playbookfor how to edit prompts
What V0 Lacks (The Problem)
- No deduplication: System creates new tickets even when similar tickets already exist in Linear
- No cross-referencing: Action items don’t check against open tickets before staging
- No Slack integration: Reviewers must go to the platform to review; no push notifications
- No comment updates: Cannot add meeting context as comments to existing tickets
Result:
- Ticket overload in Linear backlogs
- Duplicate tickets for the same work item
- Meeting context lost instead of appended to existing tickets
- Reviewers forget to check platform; pending tickets pile up (2,557 pending)
Problem and Value
Specific Pain Points:
| Pain Point | Quantified Impact |
|---|---|
| Duplicate tickets created | Manual cleanup; cluttered Linear backlogs |
| No cross-reference with existing tickets | Same action item creates new ticket instead of updating existing |
| Reviewers must visit platform | No push notification; 2,557 pending tickets piling up |
| Multi-project standups | Cross-project action items may duplicate work already tracked |
Stakeholder Value:
| Stakeholder | Value |
|---|---|
| Engagement Planners | Slack push notifications; one-click approve without leaving Slack |
| Service Leads | Cleaner backlogs; existing tickets enriched with meeting context |
| Individual Contributors | Existing tickets updated with new info instead of duplicate tickets |
Goals and Non-Goals
Goals (What V1 Adds):
- NEW: Cross-reference extracted action items against open Linear tickets in participants’ teams
- NEW: Classify items as CREATE (new ticket), UPDATE (add comment to existing), or NEEDS_REVIEW (ambiguous)
- NEW: Route pending tickets to Slack based on meeting type (standup → team channel; client call → planner DM)
- NEW: Enable Approve / Reject / Reassign actions directly in Slack
- NEW: Add comments to existing Linear tickets when UPDATE is approved
- EXISTING (unchanged): Action item extraction from transcripts (already works)
- EXISTING (unchanged): Platform UI for detailed editing (already works)
- EXISTING (unchanged): Prompt management via Langfuse (document in playbook)
Non-Goals (Explicit Exclusions):
- Rebuilding the extraction pipeline (already works in V0)
- Rebuilding the platform review UI (already works in V0)
- Building a prompt editing UI (use Langfuse; document workflow in playbook)
- Historical backfill of existing 2,557 pending tickets
- Automatic approval without human review
- Replacing platform UI with Slack (Slack is for quick approval; platform remains for detailed edits)
Staged Milestones
V0: Existing System (Already Complete)
What’s Working:
- Meeting ingestion pipeline (Zoom → Supabase)
- Action item extraction from transcripts (LLM-based, prompts in Langfuse)
- Staging in
linear_ticket_generationswithpendingstatus - Platform UI for review: edit titles, descriptions, priorities, assignees
- Approve action creates ticket in Linear
- Decline action marks as declined
What’s Missing:
- No cross-reference against existing Linear tickets
- No Slack notifications or approval workflow
- No ability to update existing tickets with meeting context
POC: Cross-Reference Engine
Goal: Validate that semantic similarity can reliably match action items to existing Linear tickets.
Scope:
- Build similarity matching function (embeddings or keyword-based)
- Fetch open tickets from Linear via MCP (scoped to participant teams)
- Test on 20 sample meetings with known duplicates
- Measure precision/recall of duplicate detection
Success Criteria:
- 80%+ of known duplicates correctly identified
- False positive rate less than 15%
Timeline: [TBD, needs technical review]
V1: Cross-Reference + Slack Approval
Goal: Add cross-reference deduplication and Slack-based approval workflow to the existing pipeline.
Scope (Cross-Reference Engine):
- Participant-aware ticket lookup (assignee teams + all participant teams as fallback)
- Similarity scoring against open Linear tickets
- Classification logic: CREATE / UPDATE / NEEDS_REVIEW
- Store classification in
linear_ticket_generations(new columns)
Scope (Slack Integration):
- Meeting type classification based on folder name patterns
- Routing: internal meetings → per-team Slack channels (tag participants)
- Routing: client meetings → DM to engagement planner (from mapping table)
- Interactive Slack messages with Approve / Reject / Reassign buttons
- Webhook handler for Slack button actions
- On CREATE approval: create new Linear ticket (existing behavior)
- On UPDATE approval: add comment to existing Linear ticket (new behavior)
Scope (Config Tables):
-
project_planner_mapping: project → engagement planner Slack user -
team_slack_channels: Linear team → Slack channel -
meeting_type_patterns: folder name patterns for internal vs. external
Scope (Documentation):
- Document Langfuse prompt management workflow in
brainforge-playbook
Not in V1:
- Configurable similarity thresholds (use fixed 80%/50%)
- Historical backfill of existing pending tickets
Success Criteria:
- 90%+ of items correctly routed to the right Slack destination
- 50%+ reduction in duplicate tickets created
- Reviewer can complete review in less than 30 seconds per item
Timeline: [TBD, needs technical review]
V2: Analytics and Tuning
Goal: Add pipeline analytics and enable threshold tuning.
Scope:
- Dashboard showing pipeline throughput (items created, updated, rejected)
- Configurable similarity thresholds per project
- Optional: retroactive backfill tool for historical meetings
Timeline: [TBD, needs technical review]
Technical Approach
Architecture Overview
V0 (Existing Flow):
Meeting Ingested → Extraction Service (Langfuse prompts) → linear_ticket_generations (pending)
↓
Platform UI (review/edit)
↓
Linear (create ticket)
V1 (Enhanced Flow):
Meeting Ingested → Extraction Service (unchanged)
↓
┌──────────────────────┐
│ Cross-Reference │ ← NEW: Check against open Linear tickets
│ Engine │ (scoped to participant teams)
└──────────────────────┘
↓
┌──────────────────────┐
│ Classification │ ← NEW: CREATE / UPDATE / NEEDS_REVIEW
└──────────────────────┘
↓
linear_ticket_generations (pending, with action_type + linked_issue)
↓
┌──────────────────────┐
│ Slack Router │ ← NEW: Route based on meeting type
└──────────────────────┘
↓ ↓
Internal mtg Client mtg
↓ ↓
Team channel Planner DM
↓ ↓
[Approve] [Reject] [Reassign]
↓
Linear MCP
(create_issue OR create_comment)
Key Components
| Component | Status | Technology | Notes |
|---|---|---|---|
| Meeting Ingestion | EXISTING | Zoom pipeline | Triggers on new recording |
| Action Extraction | EXISTING | LLM + Langfuse | Prompts managed in Langfuse |
| Staging DB | EXISTING | Supabase | linear_ticket_generations table |
| Platform Review UI | EXISTING | Web app | Edit/approve pending tickets |
| Cross-Reference Engine | NEW | Linear MCP + similarity | Fetches open tickets, computes match |
| Classification Logic | NEW | Service code | CREATE / UPDATE / NEEDS_REVIEW |
| Slack Router | NEW | Service code | Determines channel/user by meeting type |
| Slack Integration | NEW | Slack Block Kit API | Interactive messages with buttons |
| Comment Addition | NEW | Linear MCP | create_comment on existing tickets |
| Config Tables | NEW | Supabase | Routing rules, planner mappings |
Data Model
Schema Changes to linear_ticket_generations (ADD columns):
ALTER TABLE linear_ticket_generations
ADD COLUMN action_type TEXT DEFAULT 'create', -- 'create', 'update', 'needs_review'
ADD COLUMN linked_linear_issue_id TEXT, -- existing ticket ID if UPDATE
ADD COLUMN linked_linear_issue_identifier TEXT, -- e.g., "ABC-123"
ADD COLUMN similarity_score FLOAT, -- match confidence
ADD COLUMN slack_message_ts TEXT, -- Slack message timestamp
ADD COLUMN slack_channel_id TEXT, -- where Slack message was sent
ADD COLUMN reviewed_by TEXT, -- who clicked approve/reject
ADD COLUMN reviewed_at TIMESTAMPTZ; -- when review happenedNote: status column already exists with values: pending, approved, declined
New Config Tables:
-- Project to engagement planner mapping
CREATE TABLE project_planner_mapping (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_identifier TEXT NOT NULL, -- folder name pattern or client name
planner_slack_user_id TEXT NOT NULL,
planner_name TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Team to Slack channel mapping (for standups)
CREATE TABLE team_slack_channels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
linear_team_id TEXT NOT NULL,
linear_team_name TEXT,
slack_channel_id TEXT NOT NULL,
slack_channel_name TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Meeting type classification patterns
CREATE TABLE meeting_type_patterns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
pattern TEXT NOT NULL, -- regex or contains pattern
meeting_type TEXT NOT NULL, -- 'internal' or 'external'
description TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);Functional Requirements
Cross-Reference Logic
- For proposed assignee → fetch their Linear team memberships
- For all meeting participants → fetch their Linear team memberships (fallback scope)
- Fetch open tickets from Linear in those teams (status != Done, Canceled)
- Compare each action item against open tickets using similarity scoring
- Classify:
- Similarity > 80% → UPDATE (link to matched ticket)
- Similarity < 50% → CREATE (new ticket)
- Similarity 50-80% → NEEDS_REVIEW (flag for human decision)
Slack Routing Logic
- Check meeting folder name against
meeting_type_patternstable - If matches “internal” pattern (e.g., contains “Standup”, “Sync”, “Daily”):
- Route to per-team Slack channel (from
team_slack_channelstable) - Tag meeting participants
- Route to per-team Slack channel (from
- Else:
- Lookup project from meeting context
- Route to designated engagement planner (from
project_planner_mappingtable)
Slack Message Actions
- Approve (CREATE): Create new Linear ticket (existing behavior)
- Approve (UPDATE): Add comment to existing Linear ticket with meeting context
- Reject: Mark status = declined, no Linear action
- Reassign: Update assignee, then approve
Assumptions
-
Linear team memberships are accurate and up-to-date.
- Risk if wrong: Cross-reference scope will miss relevant tickets.
-
Meeting folder names follow consistent patterns.
- Risk if wrong: Routing logic will misclassify meetings.
-
Slack users can be mapped to Linear users reliably.
- Risk if wrong: Reassign action won’t work correctly.
-
80%/50% similarity thresholds are reasonable starting points.
- Risk if wrong: Too many false positives or missed duplicates.
-
Langfuse is the source of truth for prompts.
- Risk if wrong: Prompt changes won’t be tracked properly.
Open Questions
| Question | Owner | Needed By | Status |
|---|---|---|---|
| Which Slack channels exist for each team? | Ops | V1 start | Open |
| What folder name patterns indicate internal meetings? | Ops | V1 start | Open |
| How to handle meetings with no clear project association? | Product | V1 start | Open |
| Should there be a timeout for pending reviews? | Product | V1 | Open |
| What happens if a participant is not in Linear? | Engineering | V1 | Open |
Success Metrics
| Metric | Target | How Measured |
|---|---|---|
| Duplicate tickets prevented | 50%+ reduction | Compare pre/post ticket counts |
| Review completion time | < 30 seconds per item | Slack sent → action clicked |
| Routing accuracy | 90%+ correct | Manual audit of 50 meetings |
| Pending ticket backlog | < 500 at any time | Count of status=‘pending’ |
| Pipeline reliability | < 5% error rate | Error logs / retry counts |
Timeline Summary
| Phase | Scope | Duration | Status |
|---|---|---|---|
| V0 | Extraction + Platform UI | Complete | DONE |
| POC | Cross-reference engine validation | [TBD] | Not started |
| V1 | Cross-reference + Slack approval | [TBD] | Not started |
| V2 | Analytics + threshold tuning | [TBD] | Not started |
References
Existing Infrastructure (V0):
- Supabase project:
internal-zoom(viqeppmsqvwpslpvttkk) - Meeting data:
zoom_meeting_recording_files(3,894 records) - Pending tickets:
linear_ticket_generations(2,585 records, 2,557 pending) - Prompt management: Langfuse (document in playbook)
- Platform review UI: [URL TBD - ask team for location]
External APIs:
- Linear MCP: Available in Cursor (list_issues, create_issue, create_comment)
- Slack Block Kit: https://api.slack.com/block-kit
- Slack Interactivity: https://api.slack.com/interactivity