A personal end-of-day recap agent running on Vercel. Every day at 6pm CT, Vercel Cron triggers a Vercel Workflow that boots a Vercel Sandbox with Claude Code pre-installed, which autonomously reads my Google Calendar, Gmail, Slack, Notion, and GitHub activity for the day and synthesizes a first-person recap into:
- A rich Notion page in a
Daily Briefsdatabase (reading surface) - A markdown file committed to a private archive repo (long-term log)
- A Slack DM with a TL;DR and link to the Notion page (push notification)
Inspired by Drew's "Claude Code as a Cron Job" — adapted for my tool stack (Notion-native, Vercel-native, multi-sink fan-out).
- Public code, private content. The code, infra, and decisions are public. The actual daily recaps live in a separate private archive repo.
- A build-in-public companion artifact. See
ARCHITECTURE.mdfor the narrative,decisions.mdfor the running decision log, andcosts.mdfor what this actually costs to run.
- Next.js (App Router) — the tiny Next app holds the cron route and workflow definitions
- Vercel Cron — schedule trigger
- Vercel Workflow (WDK) — durable, step-based orchestration with retries
- Vercel Sandbox — ephemeral Firecracker microVM running Claude Code
- Claude Code CLI (headless) — the agent itself, invoked with
-pand a JSON schema - MCP servers (inside sandbox): Claude managed Gmail + Calendar connectors, Notion, Slack, GitHub
- Sinks (outside sandbox, from workflow steps):
@notionhq/client,@octokit/rest,@slack/web-api - Zod — output schema validation
Vercel Cron (6pm CT)
→ /api/cron/recap (Next.js)
→ start(dailyRecapWorkflow)
→ [step] runClaudeInSandbox()
- boot sandbox from snap_...
- inject MCP tokens from env
- run: claude -p --output-format json
- return parsed recap JSON
→ Promise.all([
[step] writeNotionPage(recap),
[step] writeArchiveMarkdown(recap),
])
→ [step] sendSlackDM(recap, notionUrl)
→ [step] logRunMetadata(recap)
pnpm install
cp .env.example .env.local # fill in tokens
pnpm devvercel link
vercel env pull
vercel deployManual trigger (to test without waiting for 6pm):
curl -H "Authorization: Bearer $CRON_SECRET" \
https://<your-deployment>.vercel.app/api/cron/recap🚧 Building — see decisions.md for current state and the day-by-day log.