Revenue Workflows
126 lines

Plan overview

Pre-Call Prep

Pull the upcoming calendar event, mine every past Avoma meeting with the account, reconcile Salesforce contacts, and synthesize a single pre-call prep document.

Best for

Sales · Account executives · Customer success

Runs with

Google Calendar · Avoma · Salesforce

At a glance

04

Outputs

01

Capabilities

03

Teams

Core outputs

Executive summary

Recurring pain points

Open action items

Recommended agenda

Capability requirements

MCP

What it solves

Reps walk into calls without the history — past conversations, open action items, and CRM gaps live in three systems no one has time to reconcile beforehand.

Turns pre-call prep from a manual scramble into a repeatable service.

Surfaces recurring pain points across the entire relationship history.

Auto-creates missing CRM contacts so the account record stays clean.

Workflow

1

Find the upcoming meeting from the calendar and pull its external attendees.

2

Retrieve and analyze every related Avoma meeting from the last 180 days.

3

Reconcile Salesforce contacts and synthesize an executive prep document.

Implementation

Review the underlying FML plan — the sessions, tools, and typed schemas that define this workflow — and see exactly how it is instructed for repeatable execution.

FML Plan

prep-call-analysis.fml

126 lines

Copy
require mcp Salesforce
require mcp Avoma
require mcp Gcal

parameter("companyDomain", type=string) # Company domain to search in the calendar (e.g., @nextiva.com)

system(`You are an expert Customer Success Manager (CSM) and Account Executive (AE) assistant. Your goal is to thoroughly analyze past interactions and CRM data to prepare a comprehensive pre-call prep document.
`)


transformer("finalize_search_results") {
    onFunctionOutput = "search-contacts"
    jmesPath = "contact_search_results"
}

components {
    schema("event_details") {
        timezone: string # Timezone of the event
        zoom_meeting_id?: string # Zoom Meeting ID extracted from the event details (if applicable)
        external_emails: string[] # List of attendee emails that do NOT end with @barndoor.ai
        invitees: {
            email: string # Email address of the participant
            status?: string # Response status of the participant
            optional?: boolean # Whether the participant is optional
        }[]
        creator_email: string # Email address of the event creator
        start_datetime: string # Start date and time of the event in ISO format
    }
}

session("calendar-details", target="calendar_details") {
    use mcp Gcal {
        allowlist = ["list_events", "get_events"]
    }
    + Search the user's Google Calendar using the domain "{{ .params.companyDomain }}" as the search query.
      Select the most relevant matching upcoming or recent event.
    - Map the retrieved calendar event details to the event_details schema. Be sure to populate external_emails with any attendees not from @barndoor.ai.
    schema $event_details
}

session("find_meetings", target="avoma_meetings_list", after="calendar-details") {
    use mcp Avoma {
        allowlist = ["list_meetings", "get_current_datetime"]
    }
    + 1. Call get_current_datetime to get the current UTC date and time.
      2. Calculate a date roughly 180 days in the past.
      3. Call list_meetings setting from_date (180 days ago) and to_date (current date). Pass the external attendee emails ({{ .context.calendar_details.external_emails }}) in the attendee_emails array.
      4. Retrieve ALL matching meetings.
    - Map all the discovered meetings to the avoma_meetings_list array in the schema. Include the UUID, date, and title for each meeting found.
    schema {
        uuid: string
        date: string
        title: string
    }[] # List of meeting UUIDs found in Avoma over the last 180 days.
}

session("analyze_meetings", target="meeting_analyses", after="find_meetings", iterate=context.avoma_meetings_list) {
    use mcp Avoma {
        allowlist = ["get_meeting_transcript"]
    }
    + Attempt to call get_meeting_transcript for the meeting UUID {{ .it.uuid }}.
      If the tool returns an error (like "resource could not be found" or a 404), accept it as normal and proceed. Do not retry or treat it as a fatal error.
    - You are analyzing a past meeting (Title: {{ .it.title }}, Date: {{ .it.date }}).
      If the transcript was successfully retrieved, extract the summary, pain points, key decisions, and next steps.
      If the transcript was not found or is unavailable, set the summary to "Transcript not available" and return empty arrays for pain points, key decisions, and next steps.
      Output the structured data matching the schema for this specific meeting. Make sure to include the original UUID, date, and title.
    schema {
        date: string
        title: string
        summary: string # Summary of the meeting.
        pain_points: string[]
        key_decisions: string[]
        next_steps: {
            step: string
            owner: string
        }[]
        uuid: string
    }
}

session("missing-contacts", target="crm_report", after="calendar-details") {
    call("queryContact") {
        emails = $(context.calendar_details.external_emails)
        code( (() => {
  if (!args.emails || args.emails.length === 0) return { missing: [], created: [], found: [] };
  let query = "Email IN (" + args.emails.map(email => `'${email}'`).join(", ") + ")";

  const results = runFunction("queryContact", { fields: ["FIELDS(STANDARD)"], where: query });
  const records = results.records || [];
  const found = new Set(records.map(r => r.Email));

  const missing = (args.emails || []).filter(e => !found.has(e));

  const created = missing.map(email => {
    const local = email.split("@")[0];
    const lastName = local.slice(1) || "New";
    const res = runFunction("createContact", { Email: email, LastName: lastName });
    return { email, lastName, id: res.id || res.Id || null };
  });

  return { missing, created, found: Array.from(found) };
})() )
    }
    - Given the contact query results above, map the missing contacts to the crm_report array.
    schema {
        email: string # Email address of the contact.
        was_created: boolean # Whether the contact was created during this run.
        contact_id?: string # Salesforce contact ID.
        salesforce_url?: string # Link to the Salesforce contact page.
    }[]
}

session("generate_prep_report", target="prep_document", after="analyze_meetings", after="missing-contacts") {
    context "Upcoming Call Details: {{ .context.calendar_details }}\nPast Meetings Analysis: {{ .context.meeting_analyses }}\nCRM Contact Status: {{ .context.crm_report }}\n"
    - You are a Customer Success Manager (CSM) or Account Executive (AE) preparing for an upcoming call.
      Review the details of the upcoming call, the historical analysis of all past meetings, and the CRM contact status.
      Synthesize this information into a comprehensive pre-call prep document.
      Focus on providing an executive summary, historical context, recurring pain points across all meetings, open action items that need follow-up, and a recommended agenda for the upcoming call.
    schema {
        recurring_pain_points: string[]
        open_action_items: string[]
        recommended_agenda: string[]
        executive_summary: string
        historical_context: string
    } # The final synthesized pre-call analysis document.
}