Skip to main content

Advanced

Email Deck a snapshot on a schedule

Anything that updates regularly — your calendar, your CRM, a folder of newsletters — can be turned into a snapshot that emails itself to Deck on a cadence. The next time you ask a question, the freshest version is already there.

This page walks through the pattern, then shows a worked example and the best places to host it.

The pattern

A snapshot job has four steps:

  1. Fetch — pull the latest data from an API (Google Calendar, HubSpot, Notion, your own database).
  2. Format — render it as readable Markdown.
  3. Send — email it to your assistant address with a subject line that routes it.
  4. Replace — tell Deck this version replaces any previous snapshot.

The subject line does the routing. "Brain — Calendar update {date}" lands in the Brain project. "Pipeline — HubSpot snapshot {date}" lands in Pipeline. The body says "this replaces my previous calendar snapshot" so Deck doesn't pile up stale copies.

Build it with your AI tool

If you'd rather not write the script yourself, paste the prompt below into Claude Code, Cursor, Codex, or any AI coding assistant. Adjust the bracketed bits, then ask your tool to scaffold and run it.

Build me a scheduled snapshot job that emails my Deck assistant on a cadence.

Source: [your data source — Google Calendar, HubSpot deals, a Postgres query, a folder of newsletters, etc.]
Destination email: [your Deck assistant address — e.g. your-name@agent.hellodeck.ai]
Cadence: [every 2 hours on weekdays / daily at 6:30am / hourly / etc.]
Where to run it: [GitHub Actions / Modal / a Vercel cron / local crontab / etc.]
Subject prefix: "[Brain | Pipeline | …] — [short description]"
Body should include the phrase "This replaces my previous snapshot." so Deck overwrites the prior file instead of accumulating duplicates.

Set up OAuth or auth tokens, render the data as Markdown, and email it via SMTP or the Gmail API. Add a `.github/workflows/*.yml` (or equivalent host config) so it runs on the cadence above. Print a short log line on each run.

A worked example: Google Calendar → Brain

A Python script that runs every two hours during weekdays, pulls the next seven days of events, and emails a formatted snapshot to your assistant address.

Show the full Python script
calendar_sync.py
from datetime import datetime, timedelta, timezone
from email.mime.text import MIMEText
import base64

from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

DECK_EMAIL = "your-name@agent.hellodeck.ai"

def fetch_events(creds, days=7):
service = build("calendar", "v3", credentials=creds)
now = datetime.now(tz=timezone.utc)
return service.events().list(
calendarId="primary",
timeMin=now.isoformat(),
timeMax=(now + timedelta(days=days)).isoformat(),
singleEvents=True,
orderBy="startTime",
).execute().get("items", [])

def format_markdown(events):
lines = [f"# Calendar snapshot — {datetime.now():%A %b %d}\n"]
for e in events:
start = e.get("start", {}).get("dateTime", e.get("start", {}).get("date", ""))
lines.append(f"- **{start}** — {e.get('summary', '(no title)')}")
return "\n".join(lines)

def send(creds, subject, body):
gmail = build("gmail", "v1", credentials=creds)
msg = MIMEText(body)
msg["to"] = DECK_EMAIL
msg["subject"] = subject
raw = base64.urlsafe_b64encode(msg.as_bytes()).decode()
gmail.users().messages().send(userId="me", body={"raw": raw}).execute()

if __name__ == "__main__":
creds = Credentials.from_authorized_user_file(".tokens.json")
events = fetch_events(creds)
body = (
"Please store this in my Brain project. "
"It replaces any previous calendar snapshot.\n\n"
+ format_markdown(events)
)
send(creds, f"Brain — Calendar update {datetime.now():%Y-%m-%d}", body)

Three things make this work:

  • The subject prefix"Brain — …" routes the email to the Brain project.
  • The phrase "replaces any previous calendar snapshot" — Deck overwrites the prior file instead of accumulating duplicates.
  • One OAuth setupgmail.send + calendar.readonly scopes, authorised once, token stashed locally.

Now ask Deck "am I free Thursday afternoon?" and the latest calendar is already in the project.

Snapshot recipes worth running

SourceWhere it landsCadenceWhat you ask later
Google CalendarBrainEvery 2 hours, weekdays"What's on my calendar this week?"
HubSpot dealsPipelineDaily, 6:45 AM"Which deals are stale? Who needs a follow-up?"
Newsletter inbox (a Gmail label)BrainDaily, 6:30 AM"What did Stratechery say about AI agents this week?"
Notion meeting notesPipelineHourly"What did we agree with Acme on the last call?"
GitHub issues, Linear, JiraProductDaily"What's blocking the launch?"
Stripe / billing exportsPipelineWeekly"Which accounts upgraded last week?"

The script changes; the pattern doesn't. Fetch → format → send with a routing subject.

Where to run it

You don't have to run cron jobs on your laptop. A few options, ordered by how much friction they take to start:

OptionBest forNotes
Local crontabPersonal use, you keep your laptop awakeZero hosting cost. Stops when your machine sleeps. Good for prototyping.
GitHub Actions (scheduled workflows)You already use GitHubFree for personal repos. Secrets stored in repo settings. Five-minute minimum cadence.
ModalPython jobs, want native @modal.function(schedule=…)Best Python developer experience. Free tier covers personal use.
Vercel CronYou already have a Vercel projectLightweight TS/JS handlers. Hobby tier supports daily; Pro for finer cadences.
Cron-job.orgNo code — you only need to hit a URL on a schedulePair with a Pipedream or Cloudflare Worker that does the work.
AWS Lambda + EventBridgeAlready on AWS, want full controlMore setup, more flexible.

Example: same script on GitHub Actions

Show the full GitHub Actions workflow
.github/workflows/calendar-sync.yml
name: calendar-sync
on:
schedule:
- cron: "0 8,10,12,14,16 * * 1-5" # every 2hr, weekdays
workflow_dispatch: # also run on demand
env:
DECK_EMAIL: your-name@agent.hellodeck.ai
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- env:
GMAIL_TOKEN: ${{ secrets.GMAIL_TOKEN }}
run: python calendar_sync.py

The token (JSON blob from the OAuth handshake) goes in GitHub repository secrets. The script reads it from the env var. That's the whole pipeline.

Tips that save you pain later

  • One source per snapshot. Don't mix calendar and CRM in one email — split them so each routes cleanly.
  • Use "replaces previous" phrasing in the body. Otherwise Deck stores both versions and you'll have to clean up.
  • Keep the body small. Tens of KB is fine; if you have huge data, summarize first or split across runs.
  • Log results to a file. When something goes wrong, you want to see "calendar sync at 8:00 sent 14 events" somewhere.
  • One-shot OAuth. Authorise locally once with gmail.send + calendar.readonly, then ship the token to wherever you host.

Common questions

Will Deck reply to every cron run?

It depends on the email. "Please store this in my Brain project" is a filing instruction — Deck stores the snapshot and sends a short confirmation. If you also want analysis, send a separate question email after.

What if the API I want doesn't have an off-the-shelf library?

Same pattern — curl it in your script and pipe the response into the email. Anything you can read with code, you can email to Deck.

Next