> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kairn.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# RevOps Pipeline

> A pipeline assistant that updates your CRM from call notes and surfaces stale deals automatically.

## The problem

Sales reps forget to update the CRM after calls. Deals go stale. Managers chase updates manually. Pipeline data is always wrong when you need it most.

**What Kairn enables:** An agent that reads call notes, extracts structured deal data, updates memory automatically, and surfaces the right deal at the right moment — without the rep doing admin.

***

## Setup

**1. Define the soul**

```ts theme={null}
await kairn.souls.create({
  name: 'revops',
  label: 'Pipeline Assistant',
  soulMd: `
    You are a pipeline assistant for a B2B SaaS sales team.

    Your job:
    - Help sales reps update and track their deals
    - Surface stale deals that need attention
    - Summarise call notes and extract next actions
    - Flag deals at risk based on inactivity or signals

    Behaviour rules:
    - Always check memory before asking the rep for context you already have
    - Extract structured data from unstructured call notes (stage, next step, risk flags)
    - When updating a deal, confirm the change before writing to memory
    - Keep a rep-specific deal list in memory — update it after every interaction
    - Be direct and efficient — reps are busy, not looking for chat

    Deal stages: prospect → qualified → demo → proposal → negotiation → closed_won | closed_lost
  `,
  defaultModel: 'anthropic/claude-sonnet-4-6',
})
```

**2. Seed rep context from your CRM**

```ts theme={null}
async function seedRepContext(repId: string) {
  const rep   = await crm.users.get(repId)
  const deals = await crm.deals.listByOwner(repId, { status: 'open' })

  const dealMemory: Record<string, string> = {
    rep_name:        rep.name,
    rep_quota:       String(rep.quotaUsd),
    rep_attainment:  String(rep.attainmentPct),
    open_deal_count: String(deals.length),
  }

  for (const deal of deals) {
    const p = `deal_${deal.id}`
    dealMemory[`${p}_name`]          = deal.companyName
    dealMemory[`${p}_stage`]         = deal.stage
    dealMemory[`${p}_value`]         = String(deal.valueUsd)
    dealMemory[`${p}_last_activity`] = deal.lastActivityDate
    dealMemory[`${p}_next_step`]     = deal.nextStep ?? ''
    dealMemory[`${p}_contact`]       = deal.primaryContactName ?? ''
  }

  await kairn.memory.set(repId, 'default', dealMemory)
}
```

**3. Process call notes automatically**

```ts theme={null}
// POST /api/revops/call-notes
export async function POST(req: Request) {
  const { repId, dealId, notes } = await req.json()

  const result = await kairn.invoke({
    agent: 'revops',
    userId: repId,
    input: `
      I just got off a call with ${dealId}.
      Here are my notes:

      ${notes}

      Extract:
      1. Current deal stage (if mentioned or implied)
      2. Next step and owner
      3. Risk signals (budget concern, competitor, delay, no decision)
      4. A one-line summary

      Then update memory with the extracted values under deal_${dealId}_*.
      Confirm what you updated.
    `,
  })

  // Optionally sync back to your CRM
  if (result.memoryDelta) {
    await syncDealMemoryToCRM(dealId, result.memoryDelta)
  }

  return Response.json({ summary: result.output, updated: result.memoryDelta })
}
```

**4. Create a morning brief mandate**

Every morning, the agent reviews each rep's pipeline and surfaces what needs attention.

```ts theme={null}
await kairn.mandates.create({
  userId: repId,
  soul: 'revops',
  label: 'Morning pipeline review',
  taskPrompt: `
    Review the rep's open deals in memory.
    Identify deals with no activity in the last 7+ days.
    For each stale deal, write a nudge under "nudge_{deal_id}".
    Write a summary under "morning_brief" with:
    - Total open deals
    - Deals needing attention (stale or no next step)
    - Top 3 deals to focus on today (by value and stage)
  `,
  trigger: {
    type: 'cron',
    cron: '0 8 * * 1-5', // 8am Monday–Friday
  },
})
```

**5. Surface the morning brief in your dashboard**

```ts theme={null}
export async function getRepBrief(repId: string) {
  const memory  = await kairn.memory.get(repId, 'default')
  const dealIds = Object.keys(memory)
    .filter(k => k.match(/^deal_(.+)_name$/))
    .map(k => k.replace(/^deal_(.+)_name$/, '$1'))

  const deals = dealIds.map(id => ({
    id,
    name:         memory[`deal_${id}_name`],
    stage:        memory[`deal_${id}_stage`],
    value:        Number(memory[`deal_${id}_value`]),
    lastActivity: memory[`deal_${id}_last_activity`],
    nextStep:     memory[`deal_${id}_next_step`],
    nudge:        memory[`nudge_${id}`] ?? null,
  }))

  return {
    repName:      memory.rep_name,
    morningBrief: memory.morning_brief ?? null,
    deals:        deals.sort((a, b) => b.value - a.value),
  }
}
```

***

## Example conversation

```
Rep:   Just got off the call with Globex. They love the demo but budget
       isn't approved until Q3. Competitor is Salesforce.

Agent: Got it — here's what I extracted from the Globex call:

       Stage: proposal (unchanged)
       Risk flags: budget delay (Q3), competitor: Salesforce
       Next step: follow up in 6 weeks when budget cycle opens
       Summary: Strong interest post-demo, blocked on budget until Q3;
                Salesforce is in play — needs competitive positioning.

       Updated memory. Want me to set a reminder for the follow-up?

Rep:   Yes, flag it for June 2nd.

Agent: Done — I've written "follow_up_june_2: Globex budget opens,
       re-engage with competitive positioning against Salesforce"
       to your deal notes. I'll surface it in your morning brief on June 2nd.
```

The rep never opened the CRM. The deal was updated, flagged, and scheduled — from a two-sentence summary.

***

## What this unlocks

> [card] Pipeline accuracy without admin
>
> Reps talk in plain language. The CRM updates. No copy-paste, no form filling.

> [card] Proactive deal risk detection
>
> Stale deals flagged before they die quietly. Mandate runs every morning without anyone asking.

> [card] Rep-specific context
>
> Agent knows every deal, every stage, every blocker — per rep. No context switching.

> [card] Manager visibility
>
> The morning brief is readable by both rep and manager dashboards from the same memory keys.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.