Step by step · With analogies
How we built
Morning Brief
Every step explained in plain English — what we ran, why we ran it,
and what real-world thing it's most like. No technical background needed to follow this.
Before we could do anything, we needed to install Node.js on the laptop.
Node.js is a program that lets your computer run JavaScript outside of a browser.
Wrangler (the tool we use to talk to Cloudflare) is written in JavaScript —
so Node.js is what makes Wrangler work on your machine.
The analogy
Node.js is like the engine in a car. You needed it installed to drive,
but you don't think about it while driving. Once it's there, it just works in the background.
You install it once and never touch it again.
Why we needed it
Wrangler is the tool that sends our code to Cloudflare. Wrangler is a JavaScript program.
To run JavaScript programs on your laptop (outside a browser), you need Node.js.
Without it, Wrangler simply won't start.
We went to nodejs.org, downloaded the LTS version, ran the installer with all defaults, and confirmed it worked:
Terminal / PowerShell
$ node --version
v24.15.0
Wrangler is Cloudflare's command-line tool. It's what lets you send your code
from your laptop to Cloudflare's computers. You type one command and it
packages your code, uploads it, and activates it — all in under 10 seconds.
The analogy
Wrangler is the delivery truck. You write the recipe (code) on your laptop.
Wrangler picks it up and delivers it to Cloudflare's kitchen (their servers).
Once it's delivered, the truck goes home. Cloudflare cooks from there.
Terminal / PowerShell
$ npm install -g wrangler
$ wrangler --version
4.83.0
The -g flag means "install globally" — meaning Wrangler is available
everywhere on your laptop, not just in one folder.
Wrangler needed to know which Cloudflare account to deploy to.
This command opened a browser window, asked us to log in to Cloudflare,
and then connected that account to Wrangler on the laptop permanently.
The analogy
Like giving the delivery truck driver the address of your specific warehouse.
Without this step, the truck has no idea where to go.
You do this once — after that, Wrangler always knows where to deliver.
Terminal / PowerShell
$ wrangler login
This command created a folder on the laptop with the basic structure
Cloudflare expects: a code file and a settings file. Think of it as
Cloudflare handing you a blank template and saying "write your instructions here."
The analogy
Like getting a blank instruction card from the sorting office manager.
The card has a space for your name at the top (the settings file)
and lines to write the instructions on (the code file).
We just filled in the blanks.
Terminal / PowerShell
$ mkdir morning-brief && cd morning-brief
$ npm create cloudflare@latest .
It asked a few questions. We answered:
-
Q
What would you like to start with? → Hello World example
-
Q
Which language? → JavaScript
-
Q
Use git? → No
-
Q
Deploy now? → No (we weren't ready yet)
This created two important files: src/index.js (where the code goes)
and wrangler.jsonc (the settings — name, schedule, etc).
We replaced the default code in src/index.js with the Morning Brief
Worker — the actual logic that runs every morning. This file contains all the instructions:
get a Gmail access token, find the NB Projects label, pull emails from the last 24 hours,
send to Claude, post to Slack.
The analogy
The default code is like an empty instruction card that just says "Hello."
We replaced it with the actual standing instructions:
"Every morning, go to the mailroom, pick up the red-tagged pile,
give it to the colleague in the next room, and pin what she writes
to the noticeboard." Step by step, in order.
We also updated wrangler.jsonc to set the schedule:
wrangler.jsonc — the settings file
{
"name": "morning-brief",
"main": "src/index.js",
"compatibility_date": "2024-01-01",
"triggers": {
"crons": ["30 4 * * 1-5"]
}
}
What the cron means
30 4 * * 1-5 reads as: "at minute 30, hour 4, any day of month,
any month, Monday through Friday." Cloudflare uses UTC time — 4:30am UTC is
10:00am IST. So the alarm rings every weekday morning at 10am your time.
The Worker needs permission to get into Gmail, talk to Claude, and post to Slack.
Those permissions come as API keys — long strings of letters and numbers that act
like passwords. We stored them in Cloudflare's encrypted secret vault using
five separate commands.
The analogy
Imagine a keycard system. The sorting office worker needs a keycard
to get into the mailroom (Gmail), another to talk to the senior colleague (Claude),
and another to access the noticeboard (Slack). We put all three keycards
in Cloudflare's safe. The Worker knows to use them — but the card numbers
are never written anywhere visible. Even if someone reads the code,
they see no passwords. Just "use the keycard."
Terminal / PowerShell — run each one separately
$ wrangler secret put ANTHROPIC_API_KEY
$ wrangler secret put SLACK_WEBHOOK_URL
$ wrangler secret put GMAIL_CLIENT_ID
$ wrangler secret put GMAIL_CLIENT_SECRET
$ wrangler secret put GMAIL_REFRESH_TOKEN
Why not just write them in the code?
If API keys are written in the code file, anyone who reads the file
can steal them and use your Gmail, run up your Claude bill, or post to your Slack.
Cloudflare's secret store keeps them encrypted. The Worker can use them at runtime
without anyone — including us — being able to see them afterwards.
The Gmail credentials were the same ones already stored in the SHI v2 Worker —
we found them in the Cloudflare dashboard under Workers & Pages → shi-worker → Settings → Variables and Secrets.
One command. Wrangler took everything — the code, the settings, the schedule —
and uploaded it to Cloudflare's servers. From this moment, the Worker existed
on Cloudflare's infrastructure, not just on the laptop.
The analogy
The delivery truck picks up the instruction card, drives to Cloudflare's sorting office,
hands it to the manager, and comes home. The sorting office now has the instructions.
The truck's job is done. The Worker runs from Cloudflare's building from now on.
Terminal / PowerShell
$ wrangler deploy
Deployed morning-brief triggers (8.08 sec)
https://morning-brief.rey619-ms.workers.dev
schedule: 30 4 * * 1-5
What the output means
The URL is the manual trigger — hit it in a browser any time to run the pipeline on demand.
The schedule line confirms the cron is active — Cloudflare will wake the Worker at 10am IST
every weekday without any further input from anyone.
We didn't wait for 8am to see if it worked. We opened a browser and hit the Worker URL.
In about 15 seconds, the Morning Brief appeared in Slack — exactly as designed.
The analogy
Like pressing the test button on a fire alarm right after installation.
You don't wait for an actual fire — you just verify the system works.
The Worker URL is the test button. Hit it any time to run the full pipeline immediately,
regardless of what time it is.
Browser URL — manual trigger
https://morning-brief.rey619-ms.workers.dev
From this point on
The Worker runs automatically every weekday at 10am. Nobody presses anything.
The brief arrives whether you're in a meeting, on a call, or still asleep.
The manual URL still works any time you want an on-demand brief —
before a client call, mid-afternoon, whenever.