Agent: read this first
You're working in the Post-call CRM update and follow-up agent workspace at trydock.ai/<org>/post-call-crm-update-agent.
## Your role
Catches each Fireflies webhook (or processes pasted transcripts manually), extracts call data via Claude, creates a CRM meeting note tied to the contact and deal, writes one Calls row, appends to Activity log, drafts the follow-up email. Never sends the email without explicit opt-in.
## Cadence, when to update Dock
- After EVERY tool call that changes state (row create / update, doc append), append an entry to the **Status** surface.
- After every milestone, update the canonical doc surface for that work.
- When you start a session, READ the last 5 Status entries first to know what happened since you last worked.
## User-loop protocol
- End EVERY reply to the user with: "Check Dock for the latest at trydock.ai/<org>/post-call-crm-update-agent."
- If you make a decision the user might want to override (priority, scope cut, tone change), append to **Status** AND mention it in your reply: "Decided X. If you'd rather Y, edit [surface] and I'll re-plan."
- If you're blocked, post to Status with prefix `BLOCKED:` and ask one specific question.
## Don't touch
- Canonical phase / column / surface titles.
- Anything in a section titled "Locked" or "Decisions sealed."
- The agentPrompt itself (this section).
## First tool calls
1. `list_surfaces(workspace_slug="post-call-crm-update-agent")`
2. `get_doc(workspace_slug="post-call-crm-update-agent", surface_slug="status")`
3. `list_rows(workspace_slug="post-call-crm-update-agent", surface_slug="calls")`
---
# Post-call CRM update and follow-up agent
A webhook-driven workflow. Every completed call your recording tool produces flows in automatically. Open in Dock and you get four surfaces seeded:
- **Calls** (table) one row per processed call: Call Date, Rep, Contact, Account, Sentiment, Summary, Next Steps, Stage Change, Email Status, CRM Meeting ID, Transcript Source.
- **Setup guide** (doc) how the agent connects to the CRM + the call recording tool + the Python recipe for the webhook handler and manual paste path.
- **Activity log** (doc) a running narrative log of every processed call. Useful for sales managers reviewing the day's rep activity.
- **Status** (doc) the agent's working session log. End of every webhook batch or manual run: 1 paragraph of what was processed, what was skipped.
## Bring your own agent
Connect one agent to this workspace (Claude in Cursor, Claude Code, Codex, any MCP client). The agent processes each Fireflies webhook as it fires, no manual trigger needed once the webhook is wired.
## The user-loop protocol
Your agent proposes; you decide.
- Webhook path (primary): Fireflies POSTs to the CueAPI endpoint when a transcript is ready. The handler fetches the full transcript, runs extract_call_data() via Claude, looks up the contact + deal in the CRM, creates a meeting note, writes a Calls row, appends to Activity log.
- Manual fallback: paste a transcript into post_call_update.py. Same downstream flow.
- Follow-up email: agent generates a 3-4 paragraph follow-up. If AUTO_SEND_EMAIL=true the agent sends; if false (default) the email is saved to follow_up_draft.txt for the rep to review and send.
- Agent NEVER deletes meeting notes. Agent NEVER changes deal Amount or Owner.
- End of every working session, agent writes 1 paragraph to **Status**: calls processed, follow-ups drafted vs sent, any contacts not found.
## First run
1. Confirm CRM + call recording tool with the operator. HubSpot + Fireflies is the default; Salesforce / Pipedrive / Gong / Zoom AI are documented in Setup guide.
2. Open Setup guide and follow the install steps. Configure .env with CRM token + Fireflies API key + Anthropic + Dock.
3. Paste a real transcript into post_call_update.py once. Confirm Calls + Activity log + Status populated, plus a follow_up_draft.txt on disk.
4. Wire the Fireflies webhook to the CueAPI endpoint for hands-off operation.
## Status
### [00:00 UTC] seeded by Dock
Workspace created from the post-call CRM update agent template. Agent: read the Setup guide, then confirm CRM + recording tool + Anthropic key with the operator before the first call.
Next: confirm CRM + recording tool + Anthropic key.
Outcome
A workspace where every sales call from your recording tool flows into the CRM as a meeting note with contact + deal + next steps + stage change, lands a draft follow-up email for the rep to send, and shows up as a Calls row in Dock for the manager.
Estimated time: 45 min setup, ongoing zero touch (webhook path) or ~30 sec per call (manual paste)
Difficulty: intermediate
For: Sales teams at $5M-$50M revenue companies using Fireflies / Gong / Zoom AI plus HubSpot / Salesforce / Pipedrive.
What you'll need
Pre-register or install before you start.
- Dock (Free plan covers this template; Pro $19/mo unlocks more workspaces.) — The workspace itself, the Calls table, the Activity log doc surface, the Status surface.
- Anthropic API (Pay per token, ~$0.01-$0.03 per call.) — Claude extracts contact + summary + next steps + stage change + follow-up email from the transcript.
- Fireflies.ai (or Gong / Zoom AI) (Fireflies Pro $18/user/mo; Gong $1.2k+/user/yr; Zoom AI bundled with Zoom Business.) — Call recording + transcript. Fireflies has a webhook out; Gong and Zoom AI are documented as alternatives in Setup guide.
- HubSpot / Salesforce / Pipedrive API (Free with existing CRM seat.) — Look up contact + deal, create meeting note, optionally update deal stage. Script ships with HubSpot defaults; Salesforce and Pipedrive paths in Setup guide.
- CueAPI (recommended) (Free tier covers per-call webhook volume.) — Webhook endpoint that receives Fireflies notifications and triggers the handler. Without it, the manual paste fallback still works.
The template · 5 steps
Step 1: Confirm CRM access + recording tool + AUTO_SEND policy
Estimated time: 10 min
Three decisions up front: which CRM, which recording tool, and whether follow-up emails send automatically or draft for review. The default (AUTO_SEND_EMAIL=false) is right for most teams during the first week. Flip to true once the reps trust the email quality.
Tasks
- Ask which CRM. HubSpot + Salesforce + Pipedrive paths documented; script defaults to HubSpot.
- Ask which recording tool. Fireflies has the cleanest webhook story; Gong + Zoom AI require manual export or a polling job.
- Generate CRM token. HubSpot Private App scopes: crm.objects.deals.read + write, crm.objects.contacts.read, crm.objects.meetings.write.
- Generate Fireflies API key. Fireflies dashboard, Integrations, API.
- Pick AUTO_SEND_EMAIL=false for week one; flip to true after quality check.
[!CAUTION] Gotchas
- Data handling note. Transcripts go through the Anthropic API. Anthropic does not train on API data, but if your company has confidentiality policies, confirm with the operator before the first call.
- Stage mapping. Claude extracts stage_update as a display name (Contract Sent). The script maps it to the internal CRM stage ID via STAGE_NAME_TO_ID. Populate that dict before going live or stage updates silently no-op.
Step 2: Wire .env + the Python script
Estimated time: 20 min
One script: post_call_update.py handles both webhook and manual paste. It reads a transcript, extracts structured data via Claude, looks up contact + deal in the CRM, creates a meeting note, writes a Calls row, drafts the follow-up. Same extraction code on both paths.
Tasks
- Open Setup guide (doc) and copy post_call_update.py into a local folder
- Run pip install anthropic requests python-dotenv
- Create .env with DOCK_API_KEY, DOCK_WORKSPACE_SLUG, ANTHROPIC_API_KEY, HUBSPOT_ACCESS_TOKEN, FIREFLIES_API_KEY, AUTO_SEND_EMAIL=false, SMTP_HOST + SMTP_USER + SMTP_PASS (if sending), CLAUDE_MODEL=claude-sonnet-4-6
- Populate STAGE_NAME_TO_ID with your CRM's stages. HubSpot: GET /crm/v3/pipelines/deals returns one entry per pipeline with stage IDs.
- Generate a Dock API key at trydock.ai/settings/api
[!CAUTION] Gotchas
- STAGE_NAME_TO_ID is the most common silent failure. Claude says 'Contract Sent', the dict doesn't have that key, the script logs and moves on. Walk through your pipeline stages and populate the dict end-to-end before the first call.
- Multiple open deals per contact. Default: script uses the most recent. Override via DEAL_ID env var when the wrong deal gets updated.
Step 3: Test with one real transcript (manual paste path)
Estimated time: 20 min
Before wiring the webhook, run one real transcript through the manual path. This confirms extraction quality + CRM write + Dock write + email draft all work end-to-end. The reps see exactly what gets created in the CRM.
Tasks
- Pick a real call from the last week. Export the transcript from Fireflies / Gong / Zoom AI as a .txt file.
- Run python post_call_update.py path/to/transcript.txt
- Walk through with a rep: does the meeting note in the CRM look right? Does the Calls row have the right contact + summary + next steps? Does follow_up_draft.txt sound like the rep?
- If the email draft is off, edit the prompt in generate_followup_email() to add tone guidance + sender name + signature template.
[!CAUTION] Gotchas
- Contact not found. The script looks up by email. If the prospect email wasn't in the transcript, pass it as a 2nd CLI argument: python post_call_update.py transcript.txt prospect@company.com.
- Quality of extraction depends on transcript quality. Very short calls (under 5 min) often miss next steps. Have the rep eyeball the first 3-5 runs before trusting the automation.
Agent prompt for this step
Run a first call through the manual paste path. Read the transcript file passed in. Run extract_call_data() to get contact + summary + next steps + stage update + follow-up email. Look up contact in the CRM by email; if found, get the most recent open deal; create a meeting note tied to both. Write a Calls row in Dock. Append the call summary to Activity log. Save the follow-up to follow_up_draft.txt (don't send unless AUTO_SEND_EMAIL=true). Post a Status entry: call processed, follow-up status, any lookup failures.
Step 4: Wire the Fireflies webhook (primary path)
Estimated time: 15 min
Once manual paste works, switch to webhook so the workflow is zero-touch. CueAPI receives the Fireflies POST, the handler fetches the full transcript via Fireflies GraphQL, runs the same downstream flow. Reps stop running the script entirely.
Tasks
- pip install cueapi cueapi-worker
- cueapi login
- cueapi create --name 'post-call-update' --transport webhook --payload '{"task": "post_call_update"}'
- Copy the CueAPI webhook URL into Fireflies, Settings, Integrations, Webhooks, Add new
- cueapi-worker start --task post_call_update --handler ./post_call_update.py
- Update the if name == 'main' block in post_call_update.py to accept the Fireflies webhook payload, fetch the transcript via fetch_latest_fireflies_transcript(transcript_id), and run the same downstream flow.
[!CAUTION] Gotchas
- Verify cueapi-worker flag syntax at docs.cueapi.ai before shipping.
- Webhook duplicates. If Fireflies retries on a 5xx, the same transcript ID can arrive twice. The handler must dedupe by transcript ID before processing (the script ships with processed_transcripts.json).
Step 5: Decide on AUTO_SEND_EMAIL after week one
Estimated time: 5 min decision + ongoing
Default is false. After the first 5-10 calls, walk through the follow-up drafts with the reps. If quality is consistent, flip AUTO_SEND_EMAIL=true and the workflow becomes fully zero-touch (call ends, CRM updated, follow-up sent, rep gets a Slack ping with a copy).
Tasks
- Audit follow_up_draft.txt for the first 5-10 calls. Confirm tone, sign-off, no hallucinated context.
- Adjust the prompt in generate_followup_email() if needed (add sender name + signature template + tone guidance).
- Flip AUTO_SEND_EMAIL=true in .env when confident.
- Optional: keep AUTO_SEND_EMAIL=false but add a Slack ping with the draft, so the rep can review on mobile and tap-send.
[!CAUTION] Gotchas
- Flipping AUTO_SEND_EMAIL too early. A weird follow-up sent automatically to a prospect creates a credibility problem. Keep false until quality is boring.
- Edge case: contact_email empty. The script falls back to OVERRIDE_EMAIL_TO if set, otherwise writes a draft to disk. Never silently fails to send.
Hand the template to your agent
Paste the prompt below into your agent's permanent system prompt so the agent reads, writes, and maintains this workspace as you work through the steps.
You are the agent running on the "Post-call CRM update and follow-up agent" template workspace, connected via MCP at your-org/post-call-crm-update-agent.
Your job: for every completed call (Fireflies webhook or pasted transcript), extract the call data via Claude, create a meeting note in the CRM tied to contact + deal, write a Calls row, append to Activity log, draft a follow-up email. Never send the follow-up without explicit opt-in. Never edit deal Amount or Owner.
User-loop protocol:
- You propose. The rep decides. Never send the follow-up email unless AUTO_SEND_EMAIL=true is set. Never edit deal Amount, Owner, or contact identity in the CRM.
- Webhook path (primary): when the Fireflies webhook fires, fetch the full transcript via Fireflies GraphQL, run extract_call_data() via Claude, look up contact by email + deal by association, create CRM meeting note, write Calls row, append to Activity log doc.
- Manual paste fallback: if a rep runs post_call_update.py with a transcript file, run the same downstream flow.
- Stage change: if Claude extracted deal_stage_update, look up the stage_id in STAGE_NAME_TO_ID and PATCH the deal. If the stage is not in the dict, log to Status (don't error, don't guess).
- Follow-up email: always generate the 3-4 paragraph draft. If AUTO_SEND_EMAIL=true and contact_email is present, send via SMTP. Otherwise write to follow_up_draft.txt for the rep.
- End of every working session, write 1 paragraph to Status: calls processed, follow-ups drafted vs sent, contacts not found.
Don't touch:
- Contact identity (firstname, lastname, email). If the contact doesn't exist, log to Status and have the operator create them first.
- Deal Amount or Owner. Those are rep decisions.
- CRM meeting notes from prior runs. Never edit or delete a meeting note the agent (or the rep) already wrote.
First MCP tool calls:
1. list_surfaces(workspace_slug="post-call-crm-update-agent")
2. list_rows(workspace_slug="post-call-crm-update-agent", surface_slug="calls")
3. get_doc(workspace_slug="post-call-crm-update-agent", surface_slug="status")
FAQ
Do I need Fireflies, or can I use Gong / Zoom AI?
Any transcript source works. Fireflies has the cleanest webhook out (recommended). Gong requires admin access to the REST API plus a polling job to find new calls. Zoom AI exports transcripts manually from the Zoom portal. The Setup guide doc has all three paths.
What if the prospect's email is not in the transcript?
Two paths. Pass it as a 2nd CLI argument: python post_call_update.py transcript.txt prospect@company.com. Or set OVERRIDE_EMAIL_TO in .env as the fallback. Either way the contact lookup runs and the meeting note ties to the right CRM record.
Does this send follow-up emails automatically?
Only if AUTO_SEND_EMAIL=true is set in .env. Default is false: the agent generates the draft and writes it to follow_up_draft.txt for the rep to review and send. Flip the flag after the first week once you trust the email quality.
What happens if the deal stage Claude extracted isn't in our CRM?
The script logs the mismatch to Status and skips the stage update (rest of the flow continues). Open run_pipeline_report.py and add the missing display name + internal ID to STAGE_NAME_TO_ID. Run the MCP stage query if you need the IDs.
Can a manager review what got processed each day?
Yes. The Activity log doc surface has a running narrative log: one section per processed call with rep, contact, summary, next steps, and meeting note link. Managers open the doc and walk through the day's activity end-to-end.