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:
- Fetch — pull the latest data from an API (Google Calendar, HubSpot, Notion, your own database).
- Format — render it as readable Markdown.
- Send — email it to your assistant address with a subject line that routes it.
- 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
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 setup —
gmail.send+calendar.readonlyscopes, 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
| Source | Where it lands | Cadence | What you ask later |
|---|---|---|---|
| Google Calendar | Brain | Every 2 hours, weekdays | "What's on my calendar this week?" |
| HubSpot deals | Pipeline | Daily, 6:45 AM | "Which deals are stale? Who needs a follow-up?" |
| Newsletter inbox (a Gmail label) | Brain | Daily, 6:30 AM | "What did Stratechery say about AI agents this week?" |
| Notion meeting notes | Pipeline | Hourly | "What did we agree with Acme on the last call?" |
| GitHub issues, Linear, Jira | Product | Daily | "What's blocking the launch?" |
| Stripe / billing exports | Pipeline | Weekly | "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:
| Option | Best for | Notes |
|---|---|---|
Local crontab | Personal use, you keep your laptop awake | Zero hosting cost. Stops when your machine sleeps. Good for prototyping. |
| GitHub Actions (scheduled workflows) | You already use GitHub | Free for personal repos. Secrets stored in repo settings. Five-minute minimum cadence. |
| Modal | Python jobs, want native @modal.function(schedule=…) | Best Python developer experience. Free tier covers personal use. |
| Vercel Cron | You already have a Vercel project | Lightweight TS/JS handlers. Hobby tier supports daily; Pro for finer cadences. |
| Cron-job.org | No code — you only need to hit a URL on a schedule | Pair with a Pipedream or Cloudflare Worker that does the work. |
| AWS Lambda + EventBridge | Already on AWS, want full control | More setup, more flexible. |
Example: same script on GitHub Actions
Show the full GitHub Actions workflow
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
- Webhook-driven context — react to events instead of running on a clock.
- Project structure — how to design projects so snapshots land where you expect.
- Drive Deck with Claude — let Claude write and run the script for you.