Skip to content

Secrets Layout

Where each credential lives. Use this when "where's the X key" comes up and you need to know whether to look in ~/.zshrc, a wrangler secret, a config file, or somewhere else.

Conventions

  • ~/.zshrc exports → all interactive shells + cron jobs (sourced via eval "$(grep -E '^export NAME=' ~/.zshrc)" early in scripts)
  • wrangler secret put NAME → Worker-only, encrypted at rest by CF
  • App-specific config files → app-only access patterns

Do NOT commit any of these to git. (.gitignore should exclude .zshrc, ~/.GarminDb/, ~/.cloudflared/*.json, ~/.config/rclone/.)

~/.zshrc exports

Var Used by Notes
INTERVALS_ICU_KEY warehouse.py refresh-icu, scanners/comment_scan.py, scripts/cache_for_worker.py API key for athlete i153321. Regenerate at intervals.icu/settings#api if 401s appear.
ANTHROPIC_API_KEY comment_scan.py, data-ingestion/research.py (when not Parallel API), Modal jobs, Worker (also as Worker secret) Standard Anthropic API key
VOYAGE_API_KEY kb/embed.py Voyage embeddings, free tier 50M tokens/mo
R2_ACCESS_KEY_ID daily_sync.sh, rclone R2 S3-compatible cred
R2_SECRET_ACCESS_KEY same
R2_ENDPOINT same account-specific URL like https://a20a70bee90d635ffad79328f3edcd5f.r2.cloudflarestorage.com
TELEGRAM_BOT_TOKEN evening_checkin.py, telegram_listener.py (deprecated), Worker (also as Worker secret) Bot @otq_moonbot
TELEGRAM_CHAT_ID same 8196786680
RESEND_API_KEY notify.py Email via Resend

Cloudflare Worker secrets

Set via wrangler secret put NAME from the Worker project dir. Stored encrypted; not visible after setting.

For otq-checkin Worker: - INTERVALS_ICU_KEY - TELEGRAM_BOT_TOKEN - ANTHROPIC_API_KEY

Inspect via dashboard (Workers → otq-checkin → Settings → Variables) — names visible, values not.

App-specific config

File Contents
~/.GarminDb/GarminConnectConfig.json Garmin SSO username/password + garth_session token (auto-rotated)
~/.cloudflared/cert.pem OAuth-flow cert for cloudflared tunnel login
~/.cloudflared/<TUNNEL_ID>.json Tunnel-specific credentials
~/.config/rclone/rclone.conf rclone [r2] remote config (uses R2_* env vars by default; see file for layout)
~/.modal/config.toml Modal API token

Cloudflare Tunnel

Tunnel auth is via cert.pem from cloudflared tunnel login (OAuth), NOT API token. Two pieces:

  1. ~/.cloudflared/cert.pem — global account cert
  2. ~/.cloudflared/<TUNNEL_ID>.json — per-tunnel JWT

config.yml references the tunnel by ID; cloudflared finds the JSON by ID.

Where things commonly leak

  • Don't paste secrets into Claude Code conversation. Even debug output. Worker secrets can't be re-shown after wrangler secret put, but ENV-loaded ones can leak from shell traces.
  • ~/.zshrc gets backed up by Time Machine. Encrypt the backup destination if this matters.
  • Log files: daily_sync.log and the Worker's CF dashboard logs may capture errors that include URL params with secrets. The ?secret= gate in the Worker uses the last 12 chars of the TG token — avoid pasting that URL anywhere public.

When to rotate

Signal Action
wrangler deploy 400 on auth Re-run wrangler login
GarminDB CLI: "garth session expired" Re-run garmindb_cli.py with --download (prompts for creds, rewrites session)
intervals.icu 401 Regenerate API key in settings, update ~/.zshrc
R2 token compromised Dashboard → R2 → Manage R2 API Tokens → revoke + reissue
Telegram bot token leaked @BotFather → revoke → reissue → update Worker secret + ~/.zshrc