Scheduled jobs & email¶
An optional add-on that runs recurring, headless tasks — like a weekly literature digest drafted to your inbox — without you being at the keyboard. It's off by default; nothing is scheduled until you enable a job and activate it yourself.
How it works¶
You declare jobs in research-config.yml; a generator turns the enabled ones into runner
scripts + a launchd agent (macOS) or a cron line (Linux). Each job is a headless
claude -p "<slash-command>" (or a plain script) that logs to outputs/_logs/.
scheduler:
platform: launchd # launchd (macOS) | cron (Linux) | none
jobs:
weekly_digest:
enabled: true
day: "Mon"
at: "08:47"
nightly_memory:
enabled: false
at: "02:30"
weekly_digest→ runs/lit-digest(a cross-paper literature sweep → a digest + an optional Gmail draft).nightly_memory→ runsnpm run memory:audit(a corpus-memory health check).
Set it up¶
- Enable a job and set its time in
research-config.yml(above), and setscheduler.platformtolaunchdorcron. - Generate the runners:
This writes
./setup.sh --with-schedule # or: python3 scripts/setup/install_scheduled.pyscripts/scheduled/<job>.sh(+ a.pliston macOS) and prints the exact command to activate it — it never registers the job for you. - Run that activation command (
launchctl load …on macOS, or paste the line intocrontab -eon Linux). - Test it immediately, without waiting for the schedule:
bash scripts/scheduled/weekly_digest.sh
Full activate / test / disable steps: scripts/scheduled/README.md.
Email (the Gmail draft)¶
The digest can draft itself to your inbox — as a draft, never sent.
- Connect a Gmail MCP in your Claude account (Claude's Gmail connector, or a community Gmail MCP server).
- Set
integrations.gmail.enabled: trueand re-run the generator.
The generator then adds the Gmail draft tool to that job's --allowedTools. This is the one
subtle gotcha: a headless run silently skips any step whose tool isn't listed by its exact
name. The default is Claude's connector tool mcp__claude_ai_Gmail__create_draft; if your
Gmail MCP exposes its draft tool under a different name, edit the generated runner's
--allowedTools to match.
Cross-platform notes¶
- macOS uses launchd; Linux uses cron;
nonegenerates the runners but registers nothing (run them by hand or wire your own scheduler). - Desktop notifications use
terminal-notifierif present (macOS); everywhere else, runs still log tooutputs/_logs/andRUNNING.md. - launchd does not wake a sleeping Mac — a missed run fires on next wake.