Analyze pipeline health with a 0-100 score, deal prioritization matrix, risk flags, hygiene audit, and weekly action plan. Use when the user says "/pipeline-review", "review my pipeline", "pipeline health", "score my deals", "deal prioritization", "pipeline hygiene", "which deals should I focus on", or provides pipeline data and asks for a health assessment.
Analyze pipeline health with a composite 0-100 score, deal prioritization matrix, risk flags, hygiene audit, pipeline shape analysis, and weekly action plan. Works with any pipeline data source: CSV export, pasted deals, verbal description, or live Salesforce pull.
Accept pipeline data in one of four modes. Reference pipeline-data.md for parsing rules, stage normalization, and SOQL queries.
"$100,000.00"), detect headers automatically.$50K, $1.2M) and relative dates ("no activity in 3 weeks").Dispatch salesforce-researcher with the Extended SOQL query from pipeline-data.md (includes LastActivityDate, LastModifiedDate, CreatedDate). After SF data is parsed, run Multi-Source Enrichment (Step 2) to cross-reference Obsidian, Gmail, and Slack for each account.
| Agent | Role | max_turns | Wave | Condition |
|---|---|---|---|---|
salesforce-researcher | Pull live pipeline data with activity dates and Type field | 8 | 1 | Connected mode only |
obsidian-locator | Find transcript paths per account in Regal/Granola/ | 5 | 1 | Connected mode only |
obsidian-analyzer | Read account files for deal intel and contact names | 6 | 2a | Connected mode: per-account enrichment |
transcript-locator | Discover transcript locations per account | 7 | 1 | Connected mode: co-dispatched with obsidian-locator |
transcript-analyzer | Extract intent signals from locator-discovered transcripts | 8 | 2a | Connected mode: gated on transcript-locator results |
google-workspace-researcher | Search Gmail and Calendar with email direction tracking | 8 | 2a | Connected mode: per-account enrichment |
slack-researcher | Search Slack for momentum signals | 6 | 2a | Connected mode: per-account enrichment |
company-researcher | Research external triggers (funding, hiring, exec changes) | 12 | 2b | Connected mode: top accounts by deal value |
deep-research-agent | Deep competitive intelligence and industry shift analysis for top accounts | 8 | 2b | Connected mode: only when user explicitly requests competitive analysis or industry context |
Determine which input mode the user is providing:
/pipeline-review without specifying a source: Connected mode (dispatch salesforce-researcher). This is the default when no input is provided.Parse the input using the corresponding rules from pipeline-data.md. Extract for each deal:
If any required field is missing across multiple deals, ask the user once for the pattern rather than per-deal.
Connected mode only. Cross-reference Salesforce data against Obsidian, Gmail, Slack, meeting transcripts, and external sources. Enrichment findings are NOT optional supplementary data. They are co-equal with SF data and feed directly into all four health score dimensions (Step 3), dead weight detection (Section 10), Opp Velocity (Step 4), and recommended SF updates (Section 11).
Pre-dispatch setup: Run rm -rf /tmp/pipeline-review/ && mkdir -p /tmp/pipeline-review/ before dispatching any agents.
Dispatch prompt rubrics for each agent are in references/enrichment-rubrics.md. Reference that file for the full prompt templates; the summaries below describe each agent's role and key outputs.
Dispatch salesforce-researcher first. Once it returns and you have account names, dispatch obsidian-locator. obsidian-locator requires the top account names from SF data to search — it cannot run in parallel with salesforce-researcher.
salesforce-researcher: Pull pipeline data with the Extended SOQL query from pipeline-data.md, THEN run the Account Contacts query (also in pipeline-data.md) to get all Contacts on pipeline Accounts. Returns deal data including Type field for renewal filtering, plus per-account contact lists for multi-threading baseline. Write to /tmp/pipeline-review/salesforce-data.md.
obsidian-locator: Search Regal/Accounts/<Account Name>/ for account files (briefs, deal docs) matching the top 10-15 account names by deal value. Return file paths and dates only. Do NOT read file contents. Write to /tmp/pipeline-review/obsidian-paths.md.
transcript-locator: Search transcript-pipeline SQLite, vault-search, and Regal/Granola/ for transcript files matching the top 10-15 account names by deal value. Return file paths, meeting IDs, and source types only. Do NOT read transcript contents. Write to /tmp/pipeline-review/transcript-locator.md.
Wait for Wave 1 to complete before dispatching Wave 2. Read /tmp/pipeline-review/transcript-locator.md to get transcript locations for transcript-analyzer. Apply three-state locator failure handling:
Total: 0): skip transcript-analyzer. Note [NO TRANSCRIPT DATA] and proceed with other Wave 2 agents.tool_uses: 0): note [TRANSCRIPT LOCATOR FAILED] and proceed without transcript data. Do NOT retry.Dispatch exactly 4 agents in parallel (max concurrent agent limit). Each agent includes the WRITE EARLY persistence instruction from enrichment-rubrics.md.
transcript-analyzer: Provide the transcript-locator output path from Wave 1 (/tmp/pipeline-review/transcript-locator.md). Extract intent signals using the 6-signal-type rubric (verbal buying language, budget/timeline, champion ID, competitive eval, multi-stakeholder, deal progression). Also extract negative signals. Output: per-account structured format with signal type, quote, date, speaker. Write to /tmp/pipeline-review/transcript-enrichment.md. Gated: only dispatch if transcript-locator returned 1+ entries (see three-state handling above).
google-workspace-researcher: Search Gmail for the top account names. Track email direction (buyer-initiated vs seller-initiated), extract contacts ([email protected]), flag substantive buyer content. Write to /tmp/pipeline-review/gmail-enrichment.md.
slack-researcher: Search Slack for the top account names. Classify momentum signals (positive/negative/neutral), flag internal urgency. Write to /tmp/pipeline-review/slack-enrichment.md.
obsidian-analyzer: Read Regal/Accounts/<Account Name>/ for the top accounts. Extract contacts with roles, deal sizing references, competitive intel, qualification data. Write to /tmp/pipeline-review/obsidian-enrichment.md.
Dispatch separately because Wave 2a already uses 4 concurrent agent slots.
company-researcher: Research external triggers for the top 5-10 accounts by deal value. Search for funding events (90 days), executive hiring, expansion signals, contraction signals. This is the ONLY enrichment agent that uses web search (brave/tavily). Write to /tmp/pipeline-review/external-triggers.md.
deep-research-agent: Conditional. Dispatch alongside company-researcher ONLY when the user explicitly requests competitive analysis, industry context, or market intelligence beyond standard external triggers. This is the narrowest dispatch condition in the toolkit. Read tools/references/deep-research-dispatch.md for query construction. Write findings to /tmp/pipeline-review/deep-research-agent.md.
Truncation detection: After all agents return, check each result. If any agent returns <500 chars but reported tool_uses >5, its output was truncated by the 32K cap. Read the file it wrote to /tmp/pipeline-review/ instead. If neither the return nor the file has data, log "ENRICHMENT GAP: [agent] output lost" and note which accounts lack enrichment.
After all agents return, read each enrichment file from /tmp/pipeline-review/. Build a per-deal enrichment record that includes:
| Category | What to Compare | Example Discrepancy |
|---|---|---|
| Sizing | Agent count or volume in external sources vs. SF Amount | Obsidian says "1,000 agents" but SF shows 100 |
| Timeline | Verbal close timeline vs. SF CloseDate | Transcript: "sign in 2 weeks" but SF close date is 3 months out |
| Stage | Deal progress signals vs. SF StageName | Email shows signed BAA but SF still in Scoping |
| Stakeholder | Contacts in transcripts/emails vs. SF Account Contacts | Transcript mentions VP Engineering but no matching Account Contact in SF |
| Activity | Recent meetings/emails found vs. SF LastActivityDate | Gmail shows reply yesterday but SF last activity is 3 weeks ago |
Store the enrichment record for use in Step 3 (health scoring), Step 4 (Opp Velocity justification), and Step 5 Section 11 (recommended SF updates).
Standalone mode: Skip this step. Intent Signals and Deal Quality dimensions score as "N/A (external sources unavailable)". Opp Velocity relies solely on SF data patterns.
Compute a composite health score across four equally-weighted dimensions (25 points each = 100 total). See references/health-score-methodology.md for the detailed scoring rubrics, deduction formulas, and edge case rules for each dimension.
Measures deal momentum using velocity ratios against org-specific benchmarks from pipeline-data.md and cross-source multi-threading signals.
days_in_current_stage against the Stale Threshold from the Stage Velocity Benchmarks table in pipeline-data.md. Deduct based on the velocity ratio (see methodology file for tier thresholds).Type = 'Renewal' deals from velocity scoring. Do NOT penalize stage skipping.Measures depth and recency of two-way engagement with step-function decay weighting.
LastActivityDate only with the same decay thresholds.Measures prospect buying intent from transcript analysis, email content, and external triggers. Connected mode only.
Cross-source data integrity. Requires Step 2 enrichment data.
When a dimension is unavailable, adjust the denominator accordingly. A pipeline scored out of 50 (standalone) with 42 points reports as "42/50 (84%)".
Rank all deals using a 5-factor weighted framework:
| Factor | Weight | Scoring Logic |
|---|---|---|
| Opp Velocity Score | 30% | Measures deal momentum. See scoring rubric below. |
| Deal Size | 25% | Largest deal = 100. Others proportional: (deal_amount / max_amount) * 100 |
| Stage | 20% | Later stages score higher: Negotiation 100, Proposal 80, Evaluation 60, Discovery 40, Prospecting 20 |
| Activity | 15% | Most recent activity = 100. Decay: -5 per day since last activity. Floor at 0. |
| Risk | 10% | Fewer risk flags = higher score. 0 flags = 100, 1 flag = 50, 2+ flags = 0 |
Score each deal 0-100 based on observable momentum signals, then provide a 1-2 sentence Opp Velocity Justification explaining the score.
Quantitative signals (from SF data):
Cross-source signals (from Step 2 enrichment, connected mode only):
Cap at 100, floor at 0. Deals with no data default to 30 (neutral).
Opp Velocity Justification: For each deal, write 1-2 sentences citing the specific signals that drove the score. Example: "Score 75: Stage advanced from Scoping to Tech Validation on Feb 20. Gmail shows buyer sent integration docs unprompted on Feb 25. 4 activities in last 30 days."
User overrides: If the user says "focus on big deals" or "I need quick wins," adjust the weights:
Sort deals by composite score descending.
Produce the report with all sections below. Every section is required.
Pipeline Review: [Date]
Data Source: [CSV upload / Manual input / Salesforce]
Deals Analyzed: [X]
Total Pipeline Value: $[X]
| Dimension | Score | Key Signals |
|---|---|---|
| Stage Progression | X/25 | X deals stalling (velocity ratio > 1.5); X single-threaded deals > $50K |
| Engagement Quality | X/25 | X deals with no activity in 30+ days; avg two-way ratio X; X seller-dominated deals |
| Intent Signals | X/25 | X deals with 4+ buying signals; X deals with negative signals; X external triggers found |
| Deal Quality | X/25 | X deals with cross-source discrepancies |
| Total | X/100 |
If a dimension is N/A, show "N/A" in Score and explain why in Key Signals.
The top 3 deals by priority score. For each:
Group deals into three buckets based on priority score and velocity:
High Velocity (Focus Time Here): Deals with Opp Velocity Score 60+ and in Stage 2+. Active (Keep Warm): Deals with Opp Velocity Score 30-59 or in earlier stages with recent activity. Stalled (Intervention Needed): Deals with Opp Velocity Score below 30 or no activity in 14+ days.
Each bucket as a table: Deal, Amount, Stage, Velocity Score, Velocity Justification, Next Action.
Only in connected mode (when Step 2 enrichment ran). For each deal where cross-source discrepancies were found, show:
| Deal | Category | SF Says | External Source Says | Source | Action |
|---|
Example rows:
If no discrepancies found, state "Deal Quality: All deals aligned across sources" and move on.
See Section 11 (Recommended Salesforce Updates) for specific CRM actions derived from these findings.
Five risk categories, each as its own table. "Last Activity" must reflect the most recent touchpoint from ANY source (SF, Gmail, Slack, transcripts), not just SF LastActivityDate.
Cooling (15-30 Days No Activity Across Any Source): Deal, Amount, Last Activity (Source), Days Silent, Engagement Score, Recommendation (send check-in / schedule call).
Stale (31-60 Days No Activity Across Any Source): Deal, Amount, Last Activity (Source), Days Silent, Engagement Score, Recommendation (escalate outreach / involve manager).
At Risk of Loss (60+ Days No Activity Across Any Source): Deal, Amount, Last Activity (Source), Days Silent, Engagement Score, Recommendation (qualify out / one-last-try executive outreach).
Stuck Deals (Same Stage 30+ Days): Deal, Amount, Stage, Days in Stage, Recommendation (Push / Multi-thread / Qualify out).
Negative Intent Detected: Deal, Amount, Signal, Source, Quote, Recommendation (address objection / re-qualify). Only populated when enrichment found negative signals (budget freeze, competitor selected, "not a priority"). Connected mode only.
If a category has no flagged deals, omit that table.
| Issue | Count | Deals | Action |
|---|---|---|---|
| Missing amount | X | [list] | Estimate or qualify |
| Missing next step | X | [list] | Define next action |
| No primary contact | X | [list] | Assign contact |
Only include rows where count > 0.
Two views of pipeline distribution:
By Stage: Stage, # Deals, Value, % of Pipeline
By Deal Size: Bucket ($100K+, $50K-100K, $25K-50K, <$25K), # Deals, Value
This Week: 3 specific action items (checklist format) tied to named deals.
This Month: 2 strategic actions (pipeline building, hygiene cleanup, etc.)
Flag deals that may be dead weight. In connected mode, "activity" includes ALL sources from Step 2 enrichment (Gmail, Slack, transcripts, Obsidian), not just SF LastActivityDate. A deal with a stale SF record but active Gmail threads or Slack discussions is NOT dead weight. NEVER recommend removing a deal based solely on SF activity dates.
Criteria (ALL must be checked against cross-source data when available):
Table: Deal, Amount, Reason, Sources Checked, Recommendation (Mark closed-lost / Qualify out)
If no deals qualify, state "No dead weight detected" and move on.
Connected mode only. Convert cross-source discrepancies and enrichment discoveries into specific, actionable SF update recommendations. This section turns the data quality findings from Section 5 into a concrete CRM maintenance checklist.
Five sub-categories, each as a sub-table. Omit any sub-table with no recommendations.
Missing Contacts: Contacts found in enrichment sources (transcripts, Gmail, Obsidian) that do NOT exist as Account Contacts in Salesforce. Compare enrichment contact names against the Account Contacts query results. Only flag contacts with no match on the Account.
| Deal | Contact Name | Role/Title | Source | Action |
|---|---|---|---|---|
| [deal] | [name] | [role] | [transcript/email] | Add as Contact on Account |
ContactRole Coverage (positive signal): Deals where OpportunityContactRoles are linked. This is uncommon in this org and indicates above-average deal management hygiene. List these deals as a positive note, not a remediation item.
| Deal | ContactRoles Linked | Note |
|---|---|---|
| [deal] | [count] | Good CRM hygiene |
Amount Updates: Deal sizing found in external sources that differs from SF Amount.
| Deal | SF Amount | External Signal | Source | Action |
|---|---|---|---|---|
| [deal] | $X | [sizing data] | [source] | Update Amount to $X |
Stage Updates: Signals suggesting deal is further along (or behind) than SF Stage.
| Deal | SF Stage | Signal | Source | Action |
|---|---|---|---|---|
| [deal] | [stage] | [signal] | [source] | Advance to [stage] / Regress to [stage] |
Missing Activities: Recent meetings or emails found externally but not logged in SF.
| Deal | Activity Type | Date | Source | Action |
|---|---|---|---|---|
| [deal] | [meeting/email] | [date] | [source] | Log [type] activity for [date] |
If no recommendations across all categories, state "Salesforce data aligned with external sources" and move on. Omit this section entirely in standalone mode.
ALWAYS save the full pipeline review to Obsidian after generating the report. No confirmation needed.
Obsidian MCP unavailable fallback: If obsidian_list_files_in_dir fails with "Connection refused", write directly to the filesystem. Vault root: /Users/nick.yebra/Library/Mobile Documents/iCloud~md~obsidian/Documents/Core Vault. Full path: $VAULT_ROOT/Regal/Pipeline/MM.DD-MM.DD/Pipeline Review.md.
Regal/Pipeline/MM.DD-MM.DD/ where MM.DD-MM.DD is the Monday-Friday range of the current work week (e.g., Regal/Pipeline/02.23-02.27/)Pipeline Review.mdCheck-before-write (mandatory): obsidian_append_content silently appends to existing files instead of creating new ones. You MUST check for conflicts before writing.
Regal/Pipeline/MM.DD-MM.DD/ using obsidian_list_files_in_dir (if the directory doesn't exist yet, proceed directly to write)Pipeline Review.md already exists in the listingPipeline Review (2).md, Pipeline Review (3).md, etc. until a filename is availableobsidian_append_content with the final unique filepathPost-enrichment addendums: When adding supplementary data to an existing review document (e.g., after re-running a failed enrichment agent post-OAuth-refresh), ALWAYS use obsidian_append_content to append a labeled ## ADDENDUM: [Agent] (post-[reason]) section. Do NOT use obsidian_patch_content to update specific sections — heading target matching is fragile and fails silently when headings don't exactly match the stored document text.
After presenting and saving the review, offer these options:
max(0, 25 - total_deductions) after summing all deductions for a dimension. This prevents negative scores when multiple deduction categories overlap on small pipelines./tmp/pipeline-review/ instead. If no file exists either, note the enrichment gap and do NOT penalize those deals in scoring.run_in_background: true is banned for sub-agents (MCP tools unavailable in background)./tmp/pipeline-review/ to prevent context pollution. Max 4 concurrent agents per dispatch wave./tmp/pipeline-review/ with mkdir -p before dispatching any agents.