Every hour, turns new call transcripts in a Google Sheet into a structured action plan and emails it to the rep who ran the call.

UsesClaudeGmailGoogle Sheets

Turn sales calls into action plans

Every hour, your call log in Google Sheets is read for calls whose transcript has landed but whose plan has not been written yet. For each one, AI turns the transcript into a plan the rep can work from: where the deal stands, what was heard, next steps with an owner and a date, the risks worth acting on, and a draft follow-up email. The plan is emailed to the rep who ran the call, so every rep gets their own calls and nobody else's.

Once the plan is sent, the row's Status cell is marked with the date and recipient, so no call gets two plans. A row with no rep goes to a shared address instead, and so does a row whose Rep Email is not an address, with a note saying which row to fix. If no usable plan comes back, the row is marked for review and nothing is sent; if the email goes out but the row cannot be marked, the run stops and names the row. Five plans go out an hour at most, and each run says how many calls are still waiting. Only your own team is emailed, never the customer, and the AI is told to say something was not stated rather than guess.

You need Google Sheets, Anthropic and Gmail connected, a call log tab with Status, Call Date, Account, Rep Email and Transcript columns in any order, its link, and a shared address for plans with no rep. For one breakdown of every call sent to a manager instead, use 'Email a deal breakdown after every sales call'.

ScheduleRun every hour.Run every hour.
ValuesSet spreadsheetUrl to blank.Set spreadsheetUrl to blank.
ValuesSet sheetName to Calls.Set sheetName to Calls.
ValuesSet defaultRecipient to blank.Set defaultRecipient to blank.
ValuesSet maxPerRun to 5.Set maxPerRun to 5.
ValuesSet minTranscriptChars to 400.Set minTranscriptChars to 400.
Google SheetsGoogle SheetsRead the rows of spreadsheetUrl. Save it as sheet.Read the rows of spreadsheetUrl. Save it as sheet.
ValuesSet headers to sheet.headers.Set headers to sheet.headers.
Decisions & LoopsIf headers doesn't contain StatusIf headers doesn't contain Status
Yes
Decisions & LoopsStop and report a problem: This sheet has no 'Status' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.Stop and report a problem: This sheet has no 'Status' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.
No
No steps
Decisions & LoopsIf headers doesn't contain Call DateIf headers doesn't contain Call Date
Yes
Decisions & LoopsStop and report a problem: This sheet has no 'Call Date' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.Stop and report a problem: This sheet has no 'Call Date' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.
No
No steps
Decisions & LoopsIf headers doesn't contain AccountIf headers doesn't contain Account
Yes
Decisions & LoopsStop and report a problem: This sheet has no 'Account' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.Stop and report a problem: This sheet has no 'Account' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.
No
No steps
Decisions & LoopsIf headers doesn't contain Rep EmailIf headers doesn't contain Rep Email
Yes
Decisions & LoopsStop and report a problem: This sheet has no 'Rep Email' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.Stop and report a problem: This sheet has no 'Rep Email' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.
No
No steps
Decisions & LoopsIf headers doesn't contain TranscriptIf headers doesn't contain Transcript
Yes
Decisions & LoopsStop and report a problem: This sheet has no 'Transcript' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.Stop and report a problem: This sheet has no 'Transcript' column. The tab needs these column headers in row 1, in any order: Status, Call Date, Account, Rep Email, Transcript.
No
No steps
ValuesSet rows to sheet.rows.Set rows to sheet.rows.
ValuesSet plansSent to 0.Set plansSent to 0.
ValuesSet waitingCount to 0.Set waitingCount to 0.
Decisions & LoopsFor each row in rows:For each row in rows:
TextTrim row.Status and save it as rowStatus.Trim row.Status and save it as rowStatus.
Decisions & LoopsIf rowStatus isn't emptyIf rowStatus isn't empty
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextTrim row.Transcript and save it as transcript.Trim row.Transcript and save it as transcript.
Decisions & LoopsIf the length of transcript is less than minTranscriptCharsIf the length of transcript is less than minTranscriptChars
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
Decisions & LoopsIf plansSent is greater than or equal to maxPerRunIf plansSent is greater than or equal to maxPerRun
Yes
ValuesAdd 1 to waitingCount.Add 1 to waitingCount.
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextTrim row.Account and save it as account.Trim row.Account and save it as account.
Decisions & LoopsIf account is emptyIf account is empty
Yes
ValuesChange account to Unnamed account.Change account to Unnamed account.
No
No steps
TextTrim row["Call Date"] and save it as callDate.Trim row["Call Date"] and save it as callDate.
Decisions & LoopsIf callDate is emptyIf callDate is empty
Yes
ValuesChange callDate to Not recorded.Change callDate to Not recorded.
No
No steps
TextTrim row["Rep Email"] and save it as repEmail.Trim row["Rep Email"] and save it as repEmail.
ValuesSet sendTo to defaultRecipient.Set sendTo to defaultRecipient.
ValuesSet recipientNote to blank.Set recipientNote to blank.
Decisions & LoopsIf repEmail isn't emptyIf repEmail isn't empty
Yes
Decisions & LoopsIf repEmail is a valid email addressIf repEmail is a valid email address
Yes
ValuesChange sendTo to repEmail.Change sendTo to repEmail.
No
TextJoin [This plan came to you because the Rep Email cell on row , row.row_number as text, of your call log holds , @repEmail, ", which is not an email address. Put the rep's address in that column so their next plans go to them.Join [This plan came to you because the Rep Email cell on row , row.row_number as text, of your call log holds , @repEmail, , which is not an email address. Put the rep's address in that column so their next plans go to them. ] with nothing and save it as recipientNote.
No
No steps
ClaudeClaudeAsk Claude: 'You are a sales operations analyst writing the action plan a rep works from after a call. You are given the transcript of a single sales call.Ask Claude: 'You are a sales operations analyst writing the action plan a rep works from after a call. You are given the transcript of a single sales call. Account: account Call date: callDate Transcript: <<< transcript >>> Write the plan in Markdown using exactly these five sections, in this order, and nothing outside them. ## Where the deal stands Two or three sentences on what this call changed about the opportunity: what moved forward, what stalled, and how likely this is to close on the timeline discussed. Say plainly if the call revealed the deal is weaker than it looked. ## What we heard One bullet each, in this order, using the customer's own words in quotes wherever you can: - Pain: the problem they are trying to solve, and what it costs them today. - Impact: what changes for them if it is solved, in their numbers if they gave any. - Decision process: who signs, what steps come before that, and any procurement, security or legal review named. - Budget: any figure, range, or budget-cycle detail stated. - Timeline: the dates or events they tied a decision to. - Stakeholders: everyone named on the call or referred to, with their role and where they stand. - Objections and competition: what they pushed back on, and any other vendor or in-house option mentioned. ## Next steps One line per action, formatted exactly as: owner - action - due date. The owner is a named person from the call. Include only actions that were agreed on the call or that follow directly from an explicit commitment. If a date was not given, write no date agreed rather than inventing one. If no next step was agreed at all, write a single line saying so and nothing else, because that is the most important thing this plan can tell the rep. ## Risks The two or three things most likely to stall or lose this deal, each with what the rep should do about it. Base each one on something in the transcript, not on general sales advice. ## Suggested follow-up email A short draft the rep can send to the main contact: subject line, then the body. Recap what was agreed, confirm the next step and its date, and ask for anything you need from them. Six sentences at most. This is a draft for the rep to review and send themselves; it is not sent by this workflow. Rules: - Use only what is in the transcript. Never invent a name, number, date, company or commitment. - Where the transcript does not cover a field, write Not stated on this call for that field. Do not fill a gap with an inference and do not drop the bullet. - Do not open with a preamble, close with a summary, or restate these instructions.'. Save it as plan. Maximum response length: 4000
TextTrim plan.response_text and save it as planText.Trim plan.response_text and save it as planText.
Decisions & LoopsIf the length of planText is less than 200If the length of planText is less than 200
Yes
Google SheetsGoogle SheetsSet Status: Needs review - no plan came back from the AI on row row of sheetName in spreadsheetUrl.Set Status: Needs review - no plan came back from the AI on row row of sheetName in spreadsheetUrl.
ValuesAdd 1 to plansSent.Add 1 to plansSent.
Decisions & LoopsWait for 2 seconds.Wait for 2 seconds.
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextReplace ]( with ( in planText and save it as planOpenLinks.Replace ]( with ( in planText and save it as planOpenLinks.
TextReplace [ with in planOpenLinks and save it as planPlainLinks.Replace [ with in planOpenLinks and save it as planPlainLinks.
TextReplace ** with in planPlainLinks and save it as planUnbolded.Replace ** with in planPlainLinks and save it as planUnbolded.
TextReplace "Replace - with • in planUnbolded and save it as planBulleted.
TextBuild the text @recipientNoteAction plan from the call with @account on @callDate. @planBulleted and save it as planIntroduced.Build the text @recipientNoteAction plan from the call with @account on @callDate. @planBulleted and save it as planIntroduced.
TextSplit planIntroduced by "Split planIntroduced by ## and save it as planSections.
ListsAdd [Written by Claude from the call transcript in row , row.row_number as text, of your call log. Check it against the recording before you act on anything that commits you to a date or a price.] joined by nothing to the end of planSections and save it as planParts.Add [Written by Claude from the call transcript in row , row.row_number as text, of your call log. Check it against the recording before you act on anything that commits you to a date or a price.] joined by nothing to the end of planSections and save it as planParts.
TextJoin planParts with "Join planParts with ────────────────────────────── and save it as emailBody.
GmailGmailSend an email to sendTo.Send an email to sendTo. Subject: Action plan: account - callDateemailBody
Decisions & LoopsIf a step below fails, save the error as markErrorIf a step below fails, save the error as markError
Try
Google SheetsGoogle SheetsSet Status: [Plan sent , today's date, to , sendTo] joined by nothing on row row of sheetName in spreadsheetUrl.Set Status: [Plan sent , today's date, to , sendTo] joined by nothing on row row of sheetName in spreadsheetUrl.
On error
Decisions & LoopsStop and report a problem: [The action plan for row , row.row_number as text, (, account, ) was emailed to , sendTo, , but the row could not be marked as sent: , markError.message, . Type anything into that row's Status cell (for example Plan sent), or the same plan will be sent again next hour.] joined by nothing.Stop and report a problem: [The action plan for row , row.row_number as text, (, account, ) was emailed to , sendTo, , but the row could not be marked as sent: , markError.message, . Type anything into that row's Status cell (for example Plan sent), or the same plan will be sent again next hour.] joined by nothing.
ValuesAdd 1 to plansSent.Add 1 to plansSent.
Decisions & LoopsWait for 2 seconds.Wait for 2 seconds.
ValuesShow in the output: [Action plans sent this run: , plansSent as text, . Calls still waiting for a later run: , waitingCount as text, .] joined by nothing.Show in the output: [Action plans sent this run: , plansSent as text, . Calls still waiting for a later run: , waitingCount as text, .] joined by nothing.