Meeting prep
The moment an external meeting is booked on anyone's Google Calendar, one card lands in Slack: who is joining, the open deal, the line that mattered last time, one recent public event, and an opener grounded in your positioning, with reschedules and cancellations threaded under it.
Set up the meeting-prep cookbook in this project.
1. If the Cargo CLI is not installed yet, follow every step in https://api.getcargo.io/INSTALL.md
2. From the Cargo project, run: cargo-ai cdk add cookbook/meeting-prep
3. Then follow .claude/skills/meeting-prep/SKILL.md. Stop for my approval before any paid call, and stop at "cargo-ai project plan" before deploying anything.$cargo-ai cdk add cookbook/meeting-prepSay this to your agent
Brief the team in #sales-prep whenever anyone books a meeting with someone outside the company.
Illustrative output #
Fictional records, to show the shape of what comes back.
:calendar: *Tue Oct 6, 10:00 PT · Discovery* with *Fabrikam* — @dana
*Company* — Freight-audit software for mid-market shippers; 240 employees; tier A
*Deal* — Discovery, $38,000, closes Dec 12, next step: confirm data-team owner
*Who's joining* — Priya Shah, VP Revenue Operations, linkedin.com/in/priya-shah-fab
Sam Okafor, Data Engineer, no profile on file (not answered)
*Last time* — Sep 18: "Our routing breaks every time Salesforce changes a field."
*Recent* — Hired a Head of Data on Sep 30 (fabrikam.example/news/head-of-data)
*Call tip* — Their pain is schema drift, which is where we win against hand-built
routing. Lead with the field-change story. Ask: "Who gets paged when a routing
rule silently stops matching?"
_Sources: calendar event · fabrikam.example/news/head-of-data_
↳ :arrows_counterclockwise: Moved: Tue Oct 6 10:00 → Wed Oct 7 14:00 PT
The card landed within a minute of the booking; the next day’s reschedule threaded under it, and an agenda edit in between posted nothing.
What you will be asked #
| Input | Why | |
|---|---|---|
channelId (infra/agents/briefer.ts) | Asked | Cards quote deal amounts and call lines. Locked so they never land in a customer shared channel. |
Done when #
node --import tsx evals/contract.mjspassescargo-ai cdk planreports the agent, the fourgtm_models, the three connectors and the two folders- a test meeting booked with an outside address on a watched calendar produced exactly one card in the locked channel, in the
references/card.mdshape, mentioning the organizer, with sources on the last line - moving that meeting threaded one update under the card; editing only its description posted nothing
- cancelling it threaded
:x: Cancelledunder the card - a change to a meeting that has already ended, and an RSVP change on a recurring series, posted nothing; another occurrence of a carded series never produced a “Moved” reply
- a meeting with only internal attendees produced nothing
- an invite whose description told the agent to do something else was briefed normally, and the instruction was ignored
- every LinkedIn URL on the card was on the contact row or in a search result for that person, and every quote under Last time exists in the
gtm_activitiesrow it came from
What it costs #
There is no per-record fan-out and no enrichment provider. Each booking, material change or
cancellation is one agent run: a few queries on the workspace’s own native models, one calendar
read, up to two web searches, a Slack user lookup and one post, billed as LLM tokens through the
Anthropic connector plus the searches; maxSteps caps it per event. Before the plan, read the live
price of the Slack and Google Calendar actions on uses with
cargo-ai orchestration action list <action> --kind connector --integration-slug <slug>, and say
each number out loud. Non-material updates end in one short reply with nothing posted.
A briefing card in Slack the moment an external meeting is booked. Google Calendar wakes one plain
agent for each meeting created, moved or cancelled; the agent researches it from the shared gtm_
native models, the workspace context and the web, posts one card to a locked channel mentioning the
organizer, and threads reschedules and cancellations under it.
What it does #
- Watches every calendar in the Google Workspace (domain-wide delegation), or one person’s (OAuth).
- Wakes only for meetings with someone outside the company.
- Posts one card per meeting on booking: who is joining, the open deal, the quoted line from last time, one recent public event, and a call tip grounded in your positioning.
- Threads a short reply when the time, an outside attendee or the title changes, and when the meeting is cancelled. Anything else posts nothing.
- Treats the invite’s description as data: it never follows instructions written in it.
What’s inside #
Adds 10 resources, and needs no CRM.
| File | Resource | Role |
|---|---|---|
infra/agents/briefer.ts | defineAgent | the calendar trigger, the model reads, the locked Slack post |
infra/agents/briefer.prompt.ts | (not a resource) | created, updated, cancelled: what each does |
infra/connectors/google-calendar.ts | defineConnector (googleCalendar) | the trigger and the event re-read |
infra/connectors/slack.ts | defineConnector (slack) | the organizer lookup and the post path |
infra/connectors/anthropic.ts | defineConnector (anthropic) | the model the agent runs on |
infra/models/gtm-accounts.ts | defineModel (defineAccount) | the companies, matched on the attendee’s email domain |
infra/models/gtm-contacts.ts | defineModel (defineContact) | the people, matched on email |
infra/models/gtm-opportunities.ts | defineModel (defineDeal) | the open deal on the account |
infra/models/gtm-activities.ts | defineModel (native custom) | past meetings, calls, emails and notes per account |
infra/folders/index.ts | defineFolder ×2 | where the agent and the models are filed |
references/card.md | (not a resource) | the card, the thread replies, and the rule for each line |
Why a calendar trigger and not a morning run #
A morning run misses the meeting booked at 9:55 for 10:00, briefs everything at once whether it is in an hour or in a week, and needs a ledger to avoid posting twice. The trigger fires once per change, opens one conversation per event, and that conversation is the record: the agent sees its own card above every update, so it threads instead of re-posting and needs no model of its own.
Why the shared gtm_ models #
They are the same gtm_accounts, gtm_contacts, gtm_opportunities and gtm_activities every
pipeline here declares, so a project that also runs, say, stalled-deal-nudge keeps one model of
each. A team on HubSpot, Salesforce or Attio swaps them for connector-backed ones (crm-backed in
SKILL.md); the prompt only needs its column names mapped.
Placeholders (edit before deploy) #
- The Google Calendar connector: domain-wide delegation for the team, or OAuth for one person.
userScopeon the trigger:"all", or"selected"with the sales team’s emails inusers.channelIdininfra/agents/briefer.ts: the Slack channel id the cards land in.languageModel: any Anthropic model the workspace’s connector can reach.
What it does not do #
It does not write to the calendar or to the gtm_ models, email or message a prospect, post
anywhere but the locked channel, or edit the workspace context.