Back to Post-Meeting Recap & Follow-up

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Post-Meeting Recap & Follow-up

[YourCompany.com] · Sales Department · Prepared by FullSpec · [Today's Date]

This document is the authoritative technical reference for the FullSpec team building the Post-Meeting Recap and Follow-up automation. It covers the current-state process map, all agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. Everything here is derived from the confirmed discovery session and tool-access checks completed with Jordan Miles and Priya Shah. The FullSpec team owns all build, integration, and testing work described below. Your team's responsibility is limited to confirming credentials, reviewing pilot output, and approving the go-live checklist.

01Process snapshot

Step
Name
Description
1
End Meeting and Retrieve Recording
Rep finishes the Zoom call and navigates to the recording or downloads it manually. Skipped entirely for phone or in-person meetings. Time cost: 5 min.
2
Review Meeting Notes or Transcript
Rep reads through handwritten notes or the Fireflies.ai auto-transcript to reconstruct what was discussed and agreed. Quality varies by note discipline. Time cost: 12 min.
3
Write Recap Email Draft
Rep composes a follow-up email covering pain points, agreements, and next steps. Tone, structure, and completeness differ widely between reps. BOTTLENECK. Time cost: 18 min.
4
Review and Edit Recap Email
Rep re-reads the draft, corrects errors, and adjusts tone before sending. Frequently delayed due to back-to-back meetings. Time cost: 7 min.
5
Send Recap Email to Prospect
Rep sends the email to the prospect and any other attendees from the calendar invite. CC fields are often missed for multi-stakeholder meetings. Time cost: 3 min.
6
Update CRM Deal Record
Rep opens HubSpot, locates the correct deal, and logs the meeting outcome, discussion points, and any deal-stage change. Fields are routinely left partial. BOTTLENECK. Time cost: 12 min.
7
Create Follow-up Tasks in CRM
Rep manually creates reminder tasks for agreed next steps such as sending a proposal or booking a demo. Tasks are often vague and lack due dates. Time cost: 8 min.
8
Log Meeting Summary in Team Notes
Rep copies key notes into the shared Notion page so the manager and team have visibility. This step is frequently skipped entirely. Time cost: 10 min.
9
Notify Manager of Deal Update
For high-value deals, the rep sends a Slack message to the sales manager summarising the outcome and flagging blockers. Done ad hoc with no consistent format. Time cost: 5 min.
Time cost summary: Total manual time per meeting cycle is 80 minutes. At approximately 10 meetings per week across a rep pair (40 meetings/month per rep), this equates to roughly 5 hours of admin per rep per week, or 20 hours per 30-day period. The automation replaces steps 1, 2, 3, 6, 7, 8, and 9 entirely. Step 4 (review) and Step 5 (send) are collapsed into a single 60-second rep action on the pre-built Gmail draft. Net manual time after automation: under 5 minutes per meeting.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Meeting Trigger Agent

Monitors Google Calendar for events tagged with a sales label and polls for meeting-end status via the Zoom webhook. When a qualifying sales call reaches its scheduled end time (or the Zoom session closes), the agent filters out internal-only meetings using attendee email domain rules, then packages the calendar metadata and transcript reference into a structured payload and passes it downstream. No AI inference occurs in this agent. It is purely an event-detection and filtering layer. Estimated build time: 5 hours. Complexity: Moderate.

Trigger
Google Calendar event with a sales tag reaches scheduled end time, OR Zoom meeting-ended webhook fires for a matched event ID.
Tools
Google Calendar API (read), Zoom Webhook (meeting.ended event), Fireflies.ai API (transcript fetch by meeting title and participant email).
Replaces steps
Step 1 (retrieve recording) and Step 2 (review transcript).
Estimated build
5 hours — Moderate
// Input
calendar_event_id: string          // Google Calendar event UID
event_title: string                // e.g. 'Discovery Call - Acme Corp'
event_end_time: ISO8601            // scheduled end timestamp
attendees: [{ email, name, domain }]  // all calendar attendees
zoom_meeting_id: string | null     // null if not a Zoom call

// Processing
1. Filter: exclude attendees where domain === internal_domain
2. If external_attendees.length === 0 -> abort, log 'internal-only call'
3. Call Fireflies.ai GET /transcripts?title={event_title}&date={event_date}
4. If transcript not yet ready -> retry after 3 min (max 3 retries)
5. If transcript unavailable after retries -> set fallback_mode = true

// Output
meeting_record: {
  calendar_event_id: string,
  meeting_title: string,
  meeting_date: ISO8601,
  attendees: [{ email, name }],
  transcript_url: string | null,
  transcript_text: string | null,
  fallback_mode: boolean,
  fireflies_meeting_id: string | null
}
  • Google Calendar API requires OAuth 2.0 with scope https://www.googleapis.com/auth/calendar.readonly. The service account must be granted domain-wide delegation if the automation runs under a shared credential rather than each rep's individual account.
  • Zoom webhook must be registered in the Zoom App Marketplace under the account owner's credentials. The meeting.ended event payload includes meeting_id and end_time. Verify that host_id can be mapped to a rep email before the pilot.
  • Fireflies.ai transcript matching uses meeting title and participant email as a composite key. If two meetings share the same title on the same day, the agent must select by closest start_time match and log the ambiguity.
  • Fallback mode (no transcript available) must produce a calendar-only summary containing attendees, meeting title, and date. This reduced payload is passed forward and the Recap Drafting Agent is flagged to use the fallback prompt template.
  • Internal domain list (e.g. @[YourCompany.com]) must be stored as a configurable environment variable, not hardcoded, so the sales manager can update it without a code change.
  • Confirm with Jordan Miles whether Fireflies.ai is already added as a bot participant to Zoom, or whether the Zoom native integration in Fireflies.ai is in use. If neither is configured, the agent cannot fetch transcripts and the build cannot proceed past this point.
Recap Drafting Agent

Receives the meeting record from the Meeting Trigger Agent and calls an LLM to extract key themes, objections, agreements, and named next steps from the transcript. Produces two outputs: a personalised recap email draft saved to the rep's Gmail drafts folder, and a structured Notion summary block appended to the deal's Notion page. If fallback mode is active (no transcript), a shorter template is used that acknowledges the meeting and confirms next steps only. A Slack nudge is sent to the rep immediately after the Gmail draft is created. Estimated build time: 9 hours. Complexity: Moderate.

Trigger
meeting_record payload received from Meeting Trigger Agent, with transcript_text present or fallback_mode === true.
Tools
Fireflies.ai (transcript data already in payload), LLM inference endpoint (prompt-based extraction), Gmail API (draft creation), Notion API (page append), Slack API (nudge message to rep).
Replaces steps
Step 3 (write recap email draft), Step 5 (partial: draft addressed to all attendees), and Step 8 (log to Notion).
Estimated build
9 hours — Moderate
// Input
meeting_record: {
  meeting_title: string,
  meeting_date: ISO8601,
  attendees: [{ email, name }],
  transcript_text: string | null,
  fallback_mode: boolean,
  rep_email: string              // derived from calendar organiser
}

// LLM extraction (prompt fields)
extracted_pain_points: string[]
extracted_agreements: string[]
extracted_next_steps: [{ action, owner, due_date_hint }]
extracted_decision_makers: string[]
deal_stage_keyword: string | null  // e.g. 'proposal', 'demo', 'closed'

// Output
gmail_draft_id: string           // ID of created Gmail draft
gmail_draft_subject: string      // e.g. 'Follow-up: Discovery Call - Acme Corp'
notion_block_id: string          // ID of appended Notion block
slack_nudge_sent: boolean
recap_payload: {
  pain_points: string[],
  agreements: string[],
  next_steps: [{ action, owner, due_date_hint }],
  deal_stage_keyword: string | null,
  meeting_title: string,
  meeting_date: ISO8601,
  attendees: [{ email, name }]
}
  • Gmail API requires OAuth 2.0 scope https://www.googleapis.com/auth/gmail.compose for draft creation. The draft must be addressed to all external attendees (To field) with the rep as sender. Do not use https://www.googleapis.com/auth/gmail.send at this stage as the rep retains send authority.
  • Notion API integration must be connected to the workspace where deal pages live. The page ID for each deal must be resolved by querying the Notion database filtered on meeting_title or a linked HubSpot deal ID. Confirm database ID and property names with Jordan Miles before build.
  • The LLM prompt must include a phrasing-style note if historical rep emails are available. If not, use a neutral professional tone as default. The prompt must be version-controlled and stored as a named template in the automation platform's credential or config store so it can be updated without redeploying.
  • Slack nudge must be sent to the rep's direct message channel, not a shared channel. Use the Slack users.lookupByEmail method to resolve rep_email to a Slack user ID. If the user is not found, fall back to posting in the configured sales channel and log a warning.
  • For fallback_mode === true, the Gmail draft body must use the fallback template and must include a visible note at the top of the draft: '[Auto-draft: no transcript available. Please review before sending.]'
  • Recap quality gate: if extracted_next_steps is empty and extracted_agreements is empty, the agent must flag the draft with a subject-line prefix '[Review needed]' and log the meeting ID to the error table before sending the Slack nudge.
CRM and Task Sync Agent

Receives the recap payload from the Recap Drafting Agent and writes structured data to HubSpot. Updates the deal record with the meeting outcome summary, last-contact date, and deal stage if a stage keyword was detected. Creates dated follow-up tasks for each extracted action item and assigns them to the rep. For deals above the configured value threshold, posts a formatted Slack message to the sales channel tagging both the rep and the sales manager. Estimated build time: 8 hours. Complexity: Moderate.

Trigger
recap_payload received from Recap Drafting Agent, with gmail_draft_id confirmed as created.
Tools
HubSpot CRM API (deal update, note creation, task creation), Slack API (channel post for high-value deals).
Replaces steps
Step 6 (update CRM deal record), Step 7 (create follow-up tasks in CRM), and Step 9 (notify manager via Slack).
Estimated build
8 hours — Moderate
// Input
recap_payload: {
  pain_points: string[],
  agreements: string[],
  next_steps: [{ action, owner, due_date_hint }],
  deal_stage_keyword: string | null,
  meeting_title: string,
  meeting_date: ISO8601,
  attendees: [{ email, name }]
}
rep_email: string
hubspot_deal_id: string          // resolved by contact email lookup
deal_value_usd: number           // fetched from HubSpot deal properties
slack_threshold_usd: number      // env variable, e.g. 5000

// HubSpot operations
PATCH /crm/v3/objects/deals/{deal_id}
  hs_lastmodifieddate: now(),
  hs_deal_stage: mapped_stage_id | unchanged,
  meeting_outcome_notes: formatted_summary_string

POST /crm/v3/objects/notes
  body: full recap text,
  associations: [deal_id, contact_ids]

POST /crm/v3/objects/tasks (one per next_step)
  subject: action string,
  hs_task_body: detail string,
  hs_timestamp: due_date_resolved,
  associations: [deal_id, rep_owner_id]

// Slack (conditional: deal_value_usd >= slack_threshold_usd)
POST /chat.postMessage
  channel: sales_channel_id,
  text: formatted deal-update block with HubSpot deal link

// Output
hubspot_deal_updated: boolean
hubspot_tasks_created: number    // count of tasks written
hubspot_note_id: string
deal_stage_changed: boolean
slack_alert_sent: boolean
run_log: { deal_id, timestamp, status, errors[] }
  • HubSpot Private App token is required with scopes: crm.objects.deals.read, crm.objects.deals.write, crm.objects.notes.write, crm.objects.tasks.write, crm.objects.contacts.read. A HubSpot sandbox account must be used for all testing before any writes touch the production portal.
  • Deal ID resolution: query HubSpot contacts API by attendee email, then traverse associations to find the linked deal. If multiple open deals are found for the same contact, select the most recently modified deal and log an ambiguity warning to the error table. Do not write to multiple deals without explicit config.
  • Deal stage mapping table: deal_stage_keyword values from the transcript (e.g. 'proposal', 'demo booked', 'verbal yes') must be mapped to HubSpot internal stage IDs. This mapping table must be stored as a JSON config object in the automation platform and editable by the sales manager without code access.
  • Due date resolution for tasks: if due_date_hint is a relative expression (e.g. 'end of week', 'next Tuesday'), the agent must convert it to an absolute ISO8601 date using the meeting_date as the reference point. If resolution fails, default to meeting_date + 3 business days and flag the task body with '[Due date estimated]'.
  • Slack threshold (slack_threshold_usd) must be stored as an environment variable. Default value for this build is $5,000 unless Jordan Miles specifies otherwise. The sales channel ID must be confirmed before go-live.
  • Rate limits: HubSpot API allows 100 requests per 10 seconds on the Standard tier. For a batch of 5 tasks plus 1 deal update plus 1 note, this is well within limits at current volume (40 meetings/month). No pagination or retry backoff is needed at this scale, but a simple 3-attempt retry with 2-second delay should be implemented for 429 responses.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow with field names at each agent handoff
// ─────────────────────────────────────────────────────────────────
// TRIGGER: Google Calendar event end time reached OR Zoom webhook
// ─────────────────────────────────────────────────────────────────
INBOUND EVENT:
  source         : 'google_calendar' | 'zoom_webhook'
  calendar_event_id : 'evt_abc123'
  event_title    : 'Discovery Call - Acme Corp'
  event_end_time : '2024-04-25T11:00:00Z'
  attendees      : [{ email: 'priya@yourcompany.com', domain: 'yourcompany.com' },
                     { email: 'buyer@acme.com', domain: 'acme.com' }]
  zoom_meeting_id: '84123456789'

// ─────────────────────────────────────────────────────────────────
// AGENT 1: Meeting Trigger Agent
// ────────────────────────────────────────────────────��────────────
STEP 1.1  Filter attendees by domain -> external_attendees: ['buyer@acme.com']
STEP 1.2  If external_attendees.length === 0 -> ABORT (internal call)
STEP 1.3  GET fireflies.ai/api/transcripts
            ?title='Discovery Call - Acme Corp'
            &date='2024-04-25'
            &participant_email='buyer@acme.com'
STEP 1.4  Retry logic: poll every 3 min, max 3 attempts
STEP 1.5  If transcript unavailable -> fallback_mode = true

HANDOFF A -> Recap Drafting Agent:
  meeting_record: {
    calendar_event_id : 'evt_abc123',
    meeting_title     : 'Discovery Call - Acme Corp',
    meeting_date      : '2024-04-25',
    attendees         : [{ email: 'buyer@acme.com', name: 'Alex Buyer' }],
    transcript_text   : '<full transcript string>' | null,
    transcript_url    : 'https://app.fireflies.ai/view/abc123',
    fallback_mode     : false,
    fireflies_meeting_id: 'ff_789xyz',
    rep_email         : 'priya@yourcompany.com'
  }

// ─────────────────────────────────────────────────────────────────
// AGENT 2: Recap Drafting Agent
// ─────────────────────────────────────────────────────────────────
STEP 2.1  Select prompt template: 'full_transcript' | 'fallback_calendar_only'
STEP 2.2  LLM inference -> extract:
            extracted_pain_points    : ['budget approval needed', 'integration concern']
            extracted_agreements     : ['30-day pilot agreed']
            extracted_next_steps     : [{ action: 'Send proposal', owner: 'Priya', due_date_hint: 'end of week' },
                                         { action: 'Book technical demo', owner: 'Alex', due_date_hint: 'next Tuesday' }]
            extracted_decision_makers: ['Alex Buyer', 'Sarah CFO']
            deal_stage_keyword       : 'proposal'
STEP 2.3  Quality gate: if next_steps.length === 0 AND agreements.length === 0
            -> prefix subject '[Review needed]', log to error table
STEP 2.4  Gmail API POST /gmail/v1/users/priya@yourcompany.com/drafts
            subject : 'Follow-up: Discovery Call - Acme Corp'
            to      : ['buyer@acme.com']
            body    : <rendered recap email from template>
            -> gmail_draft_id: 'draft_def456'
STEP 2.5  Notion API POST /v1/blocks/{deal_page_id}/children
            -> notion_block_id: 'block_ghi789'
STEP 2.6  Slack API POST /api/chat.postMessage
            channel : 'D_priya_slack_id'   // direct message
            text    : 'Your recap draft for Acme Corp is ready. Review and send: [link]'
            -> slack_nudge_sent: true

HANDOFF B -> CRM and Task Sync Agent:
  recap_payload: {
    pain_points       : ['budget approval needed', 'integration concern'],
    agreements        : ['30-day pilot agreed'],
    next_steps        : [{ action: 'Send proposal', owner: 'Priya', due_date_hint: 'end of week' },
                          { action: 'Book technical demo', owner: 'Alex', due_date_hint: 'next Tuesday' }],
    deal_stage_keyword: 'proposal',
    meeting_title     : 'Discovery Call - Acme Corp',
    meeting_date      : '2024-04-25',
    attendees         : [{ email: 'buyer@acme.com', name: 'Alex Buyer' }]
  }
  rep_email         : 'priya@yourcompany.com'
  gmail_draft_id    : 'draft_def456'

// ─────────────────────────────────────────────────────────────────
// AGENT 3: CRM and Task Sync Agent
// ─────────────────────────────────────────────────────────────────
STEP 3.1  HubSpot contacts API -> lookup by 'buyer@acme.com'
            -> contact_id: 'ct_111', associated deal_id: 'deal_222'
STEP 3.2  Fetch deal properties -> deal_value_usd: 12000
STEP 3.3  Map deal_stage_keyword 'proposal' -> hs_dealstage: 'appointmentscheduled'
            (from configurable stage_mapping.json)
STEP 3.4  PATCH /crm/v3/objects/deals/deal_222
            hs_dealstage            : 'appointmentscheduled',
            notes_last_contacted    : '2024-04-25T11:00:00Z',
            meeting_outcome_notes   : '<formatted summary>'
            -> deal_stage_changed: true
STEP 3.5  POST /crm/v3/objects/notes
            body         : '<full recap text>',
            associations : ['deal_222', 'ct_111']
            -> hubspot_note_id: 'note_333'
STEP 3.6  POST /crm/v3/objects/tasks (per next_step):
            Task 1: subject='Send proposal', due='2024-04-26', owner=priya_owner_id
            Task 2: subject='Book technical demo', due='2024-04-30', owner=priya_owner_id
            -> hubspot_tasks_created: 2
STEP 3.7  deal_value_usd (12000) >= slack_threshold_usd (5000) -> true
STEP 3.8  Slack API POST /api/chat.postMessage
            channel : '#sales-channel-id'
            text    : 'Deal update: Acme Corp (Priya) | Stage -> Proposal | Value: $12k'
                      + HubSpot deal link
            -> slack_alert_sent: true

// ─────────────────────────────────────────────────────────────────
// TERMINAL OUTPUT
// ─────────────────────────────────────────────────────────────────
run_log: {
  deal_id              : 'deal_222',
  timestamp            : '2024-04-25T11:08:43Z',
  gmail_draft_id       : 'draft_def456',
  notion_block_id      : 'block_ghi789',
  hubspot_note_id      : 'note_333',
  hubspot_tasks_created: 2,
  deal_stage_changed   : true,
  slack_alert_sent     : true,
  slack_nudge_sent     : true,
  status               : 'success',
  errors               : []
}
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation tool acting as the orchestration layer. Implement one workflow per agent: (1) Meeting Trigger Workflow, (2) Recap Drafting Workflow, (3) CRM and Task Sync Workflow. Credentials for all six tool connections (Google Calendar, Zoom, Fireflies.ai, Gmail, Notion, HubSpot, Slack) must be stored in a shared credential store accessible to all three workflows. No credentials are hardcoded in node logic. Each workflow exposes a webhook or internal trigger that the preceding workflow calls on successful completion.
Webhook configuration
Two inbound webhooks must be registered: (1) Zoom meeting.ended webhook pointing to the Meeting Trigger Workflow endpoint, verified with a Zoom verification token stored as an environment variable. (2) An internal workflow-to-workflow webhook between the Meeting Trigger Workflow and the Recap Drafting Workflow, secured with a shared HMAC secret. Google Calendar polling should use a push notification channel (Google Calendar API watch endpoint) with a 60-second maximum TTL renewal job. Webhook URLs must be HTTPS and hosted on the automation platform's stable domain.
Templating approach
All LLM prompts are stored as versioned string templates in the automation platform's configuration store (not inline in workflow nodes). Minimum two named templates are required: 'recap_full_transcript' (used when transcript_text is present) and 'recap_fallback_calendar_only' (used when fallback_mode is true). The Gmail draft body uses an HTML email template with variable substitution for attendee names, pain points, agreements, and next steps. The Notion block uses a fixed structured schema: heading (meeting title and date), bulleted sections for pain points, agreements, and next steps.
Error logging
All workflow errors, warnings, and ambiguity flags must be written to a Supabase table named automation_run_logs with columns: run_id (uuid), workflow_name (text), meeting_title (text), deal_id (text), timestamp (timestamptz), status ('success' | 'warning' | 'error'), error_message (text), payload_snapshot (jsonb). On any status of 'error', the automation platform must send an alert to support@gofullspec.com and to the configured sales manager email. Warnings (e.g. ambiguous deal match, quality gate triggered) are logged but do not send an alert.
Testing approach
All three workflows must be built and tested in sandbox environments before any production credentials are used. Fireflies.ai sandbox: use a pre-recorded test transcript provided by FullSpec during the pilot setup phase. HubSpot sandbox: use the HubSpot developer sandbox portal linked to the production account. Gmail: test with a designated test rep inbox separate from any active rep mailbox. Slack: use a private #automation-test channel during QA. Only after all three workflows pass end-to-end testing on 5 synthetic meetings should production credentials be rotated in.
Estimated total build time
Meeting Trigger Agent: 5 hours. Recap Drafting Agent: 9 hours. CRM and Task Sync Agent: 8 hours. End-to-end integration testing and error-log setup: 4 hours (included in the 22-hour build effort confirmed in the project snapshot). Pilot monitoring and prompt tuning: within the QA and Pilot delivery stage (week 4). Total build effort: 22 hours.
Before build begins, the following must be confirmed in writing: (1) Fireflies.ai bot is connected to Zoom or added as a participant, and the API key is available. (2) HubSpot Private App token is issued with the scopes listed in the CRM and Task Sync Agent section. (3) Google Calendar service account delegation is approved by the IT administrator or account owner. (4) The deal stage keyword mapping table has been drafted and signed off by Jordan Miles. (5) The Slack value threshold has been confirmed (default $5,000 assumed). Any of these items unresolved at build start will delay the affected agent and must be escalated to support@gofullspec.com immediately.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Post-Meeting Recap & Follow-up.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View