Skip to content

scalekit-inc/meeting-prep-agent-example

Repository files navigation

Meeting Prep Agent (Example)

A small Python agent that scans your Google Calendar for upcoming external meetings, pulls relevant context from HubSpot, Gmail, and Slack, then generates a short pre-meeting brief with Claude and posts it to Slack. Built on the Scalekit Python SDK so you never write OAuth code yourself.

This is a reference example. Read the modules end-to-end and adapt them to your own stack.

What it does

main.py
  -> filter_meetings.py     # Google Calendar: external meetings in next 48h
  -> for each meeting:
       -> lookup_contact.py # HubSpot: contact by email, fallback to company by domain
       -> lookup_gmail.py   # Gmail: recent threads from contact/domain
       -> lookup_slack.py   # Slack: find channel by company name, fetch last 20 messages
       -> generate_brief.py # Anthropic SDK call (claude-sonnet-4-6)
       -> deliver_brief.py  # Print to terminal + send Slack notification

Meetings are processed sequentially. No database, no scheduler, no streaming — run python main.py whenever you want a fresh briefing.

Prerequisites

  • A Scalekit account (free).
  • Python 3.11+
  • An Anthropic API key.
  • Accounts you can authorize in Google Calendar, Gmail, HubSpot, and Slack. Use a workspace where you have read access to the channels you care about.

1. Configure Scalekit connectors

In the Scalekit dashboard, copy your API credentials from Developers → Settings → API Credentials:

  • SCALEKIT_ENV_URL
  • SCALEKIT_CLIENT_ID
  • SCALEKIT_CLIENT_SECRET

Now create four connections. For each one, go to AgentKit → Connections → Create Connection, pick the provider, and set the Connection name exactly as listed below. The code resolves connections by name, so the name in the dashboard must match the constant in the corresponding Python module.

Provider Connection name Used in
Google Calendar meeting-prep-google-calendar filter_meetings.py
HubSpot meeting-prep-hubspot lookup_contact.py
Gmail meeting-prep-gmail lookup_gmail.py
Slack meeting-prep-slack lookup_slack.py, deliver_brief.py

For each provider:

  1. Google Calendar. Create a connection → choose Google Calendar. Scalekit pre-configures scopes (calendar.readonly). Save.
  2. HubSpot. Create a connection → choose HubSpot. Scalekit pre-configures the OAuth app. Save. You can adjust scopes to contacts and companies read.
  3. Gmail. Create a connection → choose Gmail. Default scope (gmail.readonly) is enough. Save.
  4. Slack. Create a connection → choose Slack. Required scopes: channels:read, groups:read, channels:history, groups:history, chat:write. Save.

If you'd rather use different names, edit the CONNECTOR_NAME constant at the top of each module.

You do not need to authorize the connectors yet — the first run of main.py will print a Scalekit authorization URL for each one.

2. Local setup

git clone https://github.com/<your-org>/meeting-prep-agent-example.git
cd meeting-prep-agent-example

python3 -m venv .venv
source .venv/bin/activate

pip install -r requirements.txt

cp .env.example .env
# Fill in the values:
#   SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET
#   SCALEKIT_USER_ID (your email — Scalekit keys connected accounts by this)
#   ANTHROPIC_API_KEY
#   SLACK_NOTIFICATION_CHANNEL_ID (open the channel in Slack -> About -> bottom)

The user's email domain (the part after @ in SCALEKIT_USER_ID) is treated as "internal". Any attendee outside that domain is considered external.

3. Run

python main.py

First run: authorize each connector

On first run, the script checks all four connectors and prints any that still need authorization, then exits:

The following connectors need authorization. Open each link, authorize, then re-run `python main.py`.

  Google Calendar:
    https://auth.<your-env>.scalekit.dev/sso/v1/oauth/.../authorize?...

  HubSpot:
    https://auth.<your-env>.scalekit.dev/sso/v1/oauth/.../authorize?...

  Gmail:
    https://auth.<your-env>.scalekit.dev/sso/v1/oauth/.../authorize?...

  Slack:
    https://auth.<your-env>.scalekit.dev/sso/v1/oauth/.../authorize?...

Open each URL in your browser, complete the OAuth flow for each provider, then run python main.py again. Scalekit stores refresh tokens, so you only do this once.

4. Expected output

Terminal

[2026-05-21 18:02:11 UTC] Fetching external meetings in the next 48 hours...
[2026-05-21 18:02:13 UTC] Found 2 external meeting(s).
[2026-05-21 18:02:13 UTC] START Acme - Discovery
[2026-05-21 18:02:13 UTC]   HubSpot lookup for jane@acme.com...
[2026-05-21 18:02:14 UTC]   Gmail thread search...
[2026-05-21 18:02:16 UTC]   Slack channel search for 'Acme Inc'...
[2026-05-21 18:02:18 UTC]   Generating brief...
[2026-05-21 18:02:23 UTC]   Delivering brief...

============================================================
Brief for Acme Inc - Jane Doe - May 22
============================================================
## Quick Facts
- Role: VP Engineering at Acme Inc
- HubSpot: https://app.hubspot.com/contacts/12345
- Relationship signal: Existing contact

## Email History
- Jane raised a question about SSO pricing in last week's thread "Re: Acme - Q3 rollout". She asked for SAML + SCIM bundled.
- Open commitment from your side: send revised quote by Friday (thread "Quote follow-up", May 18).

## Slack Context
- Internal channel #acme-deal: solutions team flagged that Acme's IdP is Okta; integration scoped at ~3 days.
- Discussion of contract length — Acme pushed for 1-yr term over 2-yr.

## Talking Points
- Walk through the revised SSO + SCIM bundle pricing.
- Confirm Okta integration timeline and any blockers.
- Reopen the 2-yr vs 1-yr term discussion now that pricing is finalized.
- Ask Jane about Acme's rollout calendar before Q3.
- Offer a paid pilot if procurement is slow.
============================================================

[2026-05-21 18:02:24 UTC] DONE Acme - Discovery
[2026-05-21 18:02:24 UTC] All meetings processed.

Slack notification

The same brief is posted to the channel you set as SLACK_NOTIFICATION_CHANNEL_ID:

Meeting brief: Acme - Discovery (May 22) Contact: Jane Doe · Company: Acme Inc

Quick Facts

How to extend

  • Add another connector. Create a new connection in Scalekit, add a lookup_*.py module that mirrors the existing ones (set up the client, ensure the account is active, call execute_tool), and add a step inside process_meeting() in main.py. See Scalekit's connector catalog for available tool names.
  • Change the brief format. Edit PROMPT_TEMPLATE in generate_brief.py. The function returns a markdown string — everything downstream is format-agnostic.
  • Swap the LLM. generate_brief.py calls the Anthropic SDK. Replace the Anthropic(...) client with OpenAI / your provider of choice; the rest of the pipeline doesn't care.
  • Run on a schedule. Wrap python main.py in cron, GitHub Actions, or any scheduler. The script is idempotent within a 48-hour window but does not deduplicate across runs — add your own state file or DB if you only want each meeting briefed once.

Troubleshooting

  • KeyError: 'SCALEKIT_ENV_URL' — copy .env.example to .env and fill in the values.
  • ConnectionError or requests.exceptions.ConnectionError — the Scalekit client authenticates on import. Check SCALEKIT_ENV_URL for typos and confirm the environment is reachable from your machine.
  • Connector keeps showing "not active" — open the authorization link in the same browser session as your Scalekit account. After authorizing, run python main.py again.
  • No external meetings found — the script only looks ahead 48 hours and skips meetings where every attendee shares your SCALEKIT_USER_ID domain. Add an external attendee to a test event in Google Calendar.
  • Slack notification didn't arrive — confirm the bot user installed by your Slack connection is a member of the target channel. The Slack OAuth flow only grants access to channels the authorizing user is in.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages