Conestoga · Research Infrastructure

grenamer · hybrid cloud architecture

Author jschipper@conestogacapital.com
Drafted 2026-04-29
Status deployed · phases 1+2 live, mac syncers staged

Keep the runner where OneDrive already lives. Move the public surface, the run log, and the served archive to Cloudflare. Cost stays inside the free tier; the Mac stops being load-bearing for any external observer.

monthly run-rate cost

$0–4/ mo

R2 + D1 + Workers stay free at this volume. Mac runs on existing hardware.

OneDrive rewrite

0lines

Hybrid keeps OneDrive sync via the local filesystem. No Microsoft Graph build.

public availability

≈100%CF edge

API + run log + archive served from Cloudflare. Mac downtime ≠ user downtime.

TRIGGERS CLOUDFLARE · PUBLIC SURFACE MAC RUNNER curl / iOS Shortcut grenamer alias · /loop ChatGPT Action triggerGrenamerRun Claude Code skill /grenamer slash command Cron · scheduled CF Cron Trigger · 03:30 OneDrive sentinel !triggers/run.flag (fallback) research.alpha7.io Worker · grenamer-api POST /run · GET /runs · GET /runs/:id · GET /archive/* Auth: bearer + CF Access (@conestogacapital.com) for browser D1 · grenamer_runs id · mode · status · pid started_at · ended_at · log_tail files_touched · errors Mirror of local SQLite · 5GB free R2 · cca-research-archive {ticker}/{date}_{broker}.pdf _industry/... · _logs/... presigned URL on demand Zero egress · 10GB free Queue · jobs debounce + retry + DLQ 1M ops/mo free CF Tunnel com.cloudflare.research-api Worker → Mac · no inbound port Pages · grenamer.ccaresearch.com live run feed · last 50 runs · search archive · trigger button reads from D1 + R2 via the same Worker CF Access gate · same email policy as research-dashboards grenamer (rename pass) launchd · :8002 SQLite (canonical) /Volumes/M4E/grenamer/data Gemini · LLM extract title / ticker / broker / date d1-syncer (new) push run rows to D1 hourly r2-archiver (new) copy filed PDFs → R2 OneDrive (synced volume) !Inbox/ · #Research/ !triggers/ · industry/ file-system source of truth 1 2 3 4 5 6 7 read
1 trigger → Worker (HTTPS) 2 Worker → D1 (write run row) 3 Worker → Queue (debounce) 4 Queue → Tunnel → Mac (job) 5 Mac ↔ OneDrive (filesystem) 6 r2-archiver → R2 (copy filed PDFs) 7 d1-syncer → D1 (status updates) read Pages → Worker → D1/R2 fallback OneDrive sentinel → Mac

Build phases · pick a stopping point

Phase 1 · ~30 min

low riskreversible
R2 archive bucket

Create cca-research-archive on R2. Add a Mac-side r2-archiver that copies filed PDFs after each successful run. Public-but-CF-Access-gated read URL.

  • One wrangler r2 bucket create
  • One small Python uploader, hooked into the existing post-run callback
  • Mac stays canonical — R2 is just a mirror

Phase 2 · ~1 hr

low riskwrites data
D1 run-log mirror

Create grenamer_runs table on D1. Add a d1-syncer that pushes new rows + tail logs every minute. Worker exposes GET /runs backed by D1 instead of the tunnel.

  • Schema mirrors local SQLite 1:1
  • Sync is one-way (Mac → D1)
  • Status calls stop depending on the Mac being up

Phase 3 · ~2 hr

mediumreplaces tunnel-only path
Worker as primary API

Rebuild POST /run on the Worker itself: write to D1, push a Queue message, Tunnel delivers to Mac. Keep current direct-tunnel route as a backup. Add grenamer.ccaresearch.com dashboard.

  • API surface no longer requires Mac uptime to respond
  • Queue gives debounce + retry + DLQ for free
  • Browser dashboard with live feed + trigger button

Cost · expected free-tier headroom

ServiceFree tierExpected use$/mo at 10×
Workers100k req/day~50 req/day$0.00
D15 GB · 5M reads/day<100 MB · ~1k reads/day$0.00
R2 storage10 GB~5 GB (12 mo of PDFs)$0.00
R2 Class A ops1M / mo~3k / mo$0.00
R2 egressunlimitedwhatever the team views$0.00 no egress fees
Queues1M ops / mo<5k / mo$0.00
Pagesunlimited staticone site$0.00
Tunnelalready runningunchanged$0.00
Gemini APIbudget already setunchanged— existing

What you keep

  • OneDrive as the canonical filesystem — no Microsoft Graph rewrite
  • Existing Mac-side Python + SQLite + launchd jobs run unchanged
  • Sentinel-file trigger fallback stays in place
  • Bearer-token API + ChatGPT Action keeps working through the migration

What you gain

  • Public surface decoupled from Mac uptime — status endpoint always answers
  • Searchable PDF archive at a CF Access-gated URL the team can hit
  • Run log queryable from anywhere, not just the M4E volume
  • One tunnel-down event no longer means "no grenamer for the day"

Risks worth flagging

Live endpoints

Trigger · unchanged

existing

$ grenamer
$ curl -X POST research.alpha7.io/grenamer/run
~/!Inbox/!triggers/run.flag (sentinel)
ChatGPT Action triggerGrenamerRun