A working system, built and run by Christopher Grant

One quiet control room that runs a whole business, so two people can teach instead of do admin.

Great Energy is a small spiritual-education company: two founders, six websites, about seven thousand students and subscribers, and something to publish nearly every day. GLIV is the place they open each morning. It drafts the content in their own voice, watches every number, remembers every person from first hello to graduate, and quietly does the overnight busywork, so the founders spend their hours teaching, not wrangling tools. Nothing goes out and no money moves without one of them saying yes.

Log in to the live app → See the screens How it's built
Why it exists

Too much to do, and two people to do it.

Running a modern education business means being in a dozen places at once: email lists, five payment systems, Facebook groups, LinkedIn, search rankings, a calendar full of classes, and a steady stream of new people who each need a warm welcome and, sometimes, a reply today. Done by hand it eats the whole week and still leaks. Someone always slips through a crack.

GLIV is the answer to that. It is a single place that watches all of it and does the repetitive parts on its own overnight. It drafts each day's post in the founder's real voice, keeps every subscriber's whole story in one view, flags the person who is waiting on a reply, and refreshes the numbers before breakfast. The founders stay in charge of everything that matters. The rule that never bends: the machine can read and prepare anything, but it never sends a message, posts in public, or moves money without a person saying yes.

  • It does the busywork; you keep the judgment. Drafting, research, and the nightly refresh run on their own. Publishing and spending always wait for a human.
  • Nobody falls through the cracks. Every new person is understood, stranger to student, and the one who emailed and is still waiting is surfaced first.
  • It watches itself. It runs its own nightly checks and tells the founders when something needs a look, instead of failing quietly.
Property surface
  • greatenergy.org — flagship, Squarespace + Cloudflare
  • autoimmunerecoverymethod.com — course + article library
  • learnqigong.com — lead-magnet funnels
  • effortlessmeditation.org — course
  • themidlifementor.org — workshop funnel
  • gliv.ai — this control plane

External systems wired in
Drip (ESP)Stripe ×5SquareSquarespace Google Search ConsoleGA4Bing WMT GmailGoogle CalendarTodoist Facebook GraphLinkedInShutterstock
See it

What the founders actually open every morning.

Real screenshots of the running app. To keep real people private, they are captured from a built-in demo mode, so every name, email, and number here is made up. The software is exactly what the founders use.

GLIV Overview dashboard
Overview — the morning glance: how the launch is tracking, how many people are on the list, whether everything is running, the money, and where everyone sits from newcomer to graduate.
GLIV Customers, who needs you today
Who needs you today — for each person: how warm they are right now, what they just did, what they have spent, and the single next step that helps them along.
GLIV person profile
One person, everything in one place — their tags, their stage, what they have paid over time, every recent open and click, and their orders.
GLIV Morning Brief
The morning brief — today's calendar, who is waiting on a reply, and who is warming up, put in order of who to reach out to first.
GLIV content engine and composer
The content desk — each day a fresh post is drafted in the founder's own voice. They edit it in four simple steps (words, image, where it goes, review) and nothing is published until they approve it.
GLIV Brand Voice registry
Brand voice — the system writes in each founder's actual voice, and learns from every edit they make, so the next draft lands a little closer.
GLIV Funnel, stranger to student
The path from stranger to student — everyone counted once at the furthest step they have reached, so the founders can see where people gather and where they get stuck.
Website traffic (sample)
Aug 1+38% this monthAug 28

How warm the engaged list is (sample)
Hot
312
Warm
726
Cool
1,120
How it's built

For the technically curious.

Everything below is the engineering: the architecture, the data design, the integrations, the automation fleet, the testing, and the security model. All hand-built.

4,157
lines of hand-written control-plane code
114
HTTP routes (54 data · 21 action · 27 ingest)
6,996
subscribers modeled, stranger to student
34
scheduled autonomous agents
99.98%
edge availability (rolling 90d)
31 ms
p50 worker response, global
22
invariants in the self-test harness
0
money moved or messages sent without approval
Code and endpoint counts are from the live repository. Traffic and availability figures are representative sample data.
System architecture

One Worker, three request lanes, one durable spine.

Every request hits the same Cloudflare Worker and is sorted into one of three lanes before anything else runs: a public lane (no auth), an ingest lane (shared-secret, for machine writers), and an authed lane (cookie or IP, for the founders' dashboard). State is Workers KV. Compute is stateless and global.

CLIENTS Founders (browser)cookie session Public visitorsgliv.ai landing + opt-in Drip webhookPOST engagement events Agent fleet (Mac)34 scheduled agentsClaude Agent SDKcurl → ingest secret CLOUDFLARE WORKER · fetch() + scheduled() Router — 114 routes, matched top to bottom PUBLIC LANE (no auth) / landing · /login · /robots.txt · /favicon /img/<id> hosted images · /__optin · static assets served above the gate INGEST LANE (X-Gliv-Ingest shared secret) /__drip/webhook · /__drip/pull · /__ingest/* new-students · brief · tasklog · schedstate · ga4 /__image/upload · /__learn/queue · /__learn/done 27 machine-write endpoints, above the gate ▲ AUTH GATE — if(!authed) return loginPage() AUTHED LANE (cookie / IP allowlist) /__data/* — 54 read endpoints (customers, people, person, engagement, funnel-rollup, drip, goals…) /__action/* — 21 writes (draft, voice-lesson, goals…) SPA shell + all dashboard data SCHEDULED HANDLER — cron */3h + daily connector health probes · snapshot refresh · TTL sweeps DURABLE STATE Workers KV (GLIV_KV) 42 key patterns · eventual cust:<email> (+metadata) eng:<email>:<ts> per-event people:cache · drip:snapshot img:<id> · learn:<id> · TTLs Static assets (ASSETS) EXTERNAL Drip API — token + webhook Stripe ×5 · Square · Sqsp GSC · GA4 · Bing WMT Gmail · Calendar · Todoist Facebook · LinkedIn agents read Gmail / Calendar / Todoist / Drip via MCP, then push summaries to the ingest lane
Request-lane topology. Gold links are HTTP into the Worker and direct token calls out; green links are state and agent flows. The auth gate is the single line every dashboard read sits behind; ingest and public routes are deliberately above it.
Why an edge Worker

No origin to keep alive, no cold starts, global by default, and a security model where one if(!authed) line provably gates every private read. The whole control plane is one deployable artifact shipped with wrangler deploy.

Why KV, and its trap

KV is fast and global but eventually consistent with no atomic read-modify-write. That single fact drove two core design choices: one key per event, and event payloads stored in key metadata so lists never do a read per key.

Why an agent fleet

Anything needing Gmail, a browser, or long-running research runs as a scheduled Claude agent on a Mac, then POSTs a compact result to the ingest lane. The Worker stays fast and stateless; the messy world stays outside it.

The data spine

Designing around eventual consistency, on purpose.

Workers KV has no locks and no atomic read-modify-write. Rather than fight it, the schema is shaped so concurrent writers never collide and reads never fan out. Two techniques carry most of the weight.

Technique 1 — one key per event

Engagement events arrive by webhook and can burst. A shared eng:<email> record would lose writes under KV's last-write-wins. Instead every event is its own key, so two events for one person never clobber each other. Warmth is computed at read time with a 14-day half-life.

// webhook handler — no read, no lock const key = "eng:" + email + ":" + at + "-" + rand(); await KV.put(key, "1", { expirationTtl: 7776000, // 90 days metadata: { t: ev, a: at, u: url } // event lives here });
Technique 2 — payload in key metadata

To browse 6,996 people, a naive read lists keys then GETs each — thousands of subrequests, past the Worker cap, silently truncating. Storing the row in key metadata means one paginated list() returns the data inline. Reads are O(pages), not O(rows).

// list returns name+metadata, zero per-key GETs const l = await KV.list({ prefix: "cust:", limit: 1000 }); for (const k of l.keys) { const m = k.metadata; // {f,s,p,l,st} — filter/sort here rows.push({ e: k.name.slice(5), ...m }); }
KV keyspace (selected)
Key patternHoldsConsistency / TTLRead by
cust:<email>full Drip record + stage; compact row in metadata30d TTL, daily refreshpeople, person, enrich
eng:<email>:<ts>one engagement event in metadata90d TTL, per-eventengagement, person
people:cachelightweight roster for the browser1h TTL, invalidated on pull/__data/people
drip:snapshotactive count + launch-tag count30m TTLOverview
tagcounts:latest / :prevper-tag counts with 24h delta14d, day-over-dayProducts, Rules
learn:<id>before/after voice lesson queue60d TTLvoice write-back agent
img:<id>self-hosted image bytes + content-typeserved at /img/<id>public
needs: / brief: / shipped:Morning Brief + attention queues48h TTLBrief, Overview
42 key patterns in one namespace. Every hot read is cache-first with a short TTL; every write path is idempotent or append-only.
Subsystems

Four tracks, one shared spine.

The platform is organized into four operating tracks. Each is independently scheduled and independently observable, and all read and write the same KV spine through the same lane discipline.

01 · CUSTOMER INTELLIGENCE

Stranger to student

A real-time engagement webhook plus a nightly full-subscriber pull feed one shared journey-stage function (subscriber → lead → live → lowcost → main → graduate). Powers an every-person browser with server-side search, stage/spend filters, a warmth meter, and a click-through profile that joins Drip tags, orders, lifetime value, and engagement history.

webhook pushtoken pullwarmth decayGmail reply-flag
02 · CONTENT ENGINE

Research-driven, never batched

A daily agent researches a fresh topic, drafts in a specific human voice via voice skills, and renders a branded quote graphic with PIL using per-region contrast selection. A four-section composer (Words / Image / Destinations / Review) lets the founder edit any section without losing the others, then approve.

voice skillsPIL quote graphicsV.I.R.A.L. scorertwo-tier voice learning
03 · PUBLISHING

Two lanes, never a double-post

Where an API exists (Facebook Pages, LinkedIn), posts publish with a per-target confirm and a durable one-shot guard. Where it does not (private groups), a browser agent stages the post and stops for the human's final click. Groups can never repost; a rare public double-post is tolerated, a group double-post is structurally impossible.

idempotency guardsper-target confirmhuman clutch
04 · GROWTH & VISIBILITY

SEO, GEO, AEO, and money

Search Console, GA4, and Bing feed a traffic view with finance-style comparison windows. Payments from five Stripe accounts, Square, and Squarespace are de-duplicated into one order stream. Structured data (JSON-LD) and an entity strategy target AI answer engines, not just blue links.

GSC / GA4 / BingStripe ×5 dedupeJSON-LD schemaGEO / AEO
Integration spotlight · the email platform

Two halves make a customer real: pull who they are, push what they do.

The email service (Drip) exposes identity, tags, orders, and lifetime value over its REST API, but deliberately does not serve opens and clicks as pull data. Engagement is only available as outbound webhooks. So the integration is split: a scheduled pull for the slow-moving facts, and a live webhook for the fast-moving behavior.

Drip REST API ──▶ POST /__drip/pull (paged, 3×/call) ──▶ cust:<email> + metadata ──▶ people browser · profile
Drip webhook (12 events) ──▶ POST /__drip/webhook?s=secret ──▶ eng:<email>:<ts> per-event ──▶ warmth meter · timeline
Warmth: a decayed weighted sum

Each webhook event carries a weight; the score decays with a 14-day half-life so a person cools when they go quiet. Computed at read time over the stored events, clamped 0–100. No lead-scoring feature required on the account.

const W = { opened_email:2, clicked_email:5, clicked_trigger_link:6, visited_page:4, became_lead:8 }; const HALF = 14 * 864e5; // 14 days in ms score = events.reduce((s,e)=> s + (W[e.t]||0) * Math.pow(.5, age(e)/HALF), 0);
Hard-won details
  • A Drip webhook created with an empty events array subscribes to nothing. Undocumented; found by end-to-end test. The events must be listed explicitly.
  • The webhook must be received by something always on. The Mac sleeps; the edge does not. So the receiver is the Worker, not an agent.
  • The pull writes each page's records concurrently with Promise.all and pages in small windows, so a 6,996-row refresh never trips the subrequest limit.
  • Secret in the URL is preferred to a header only because the webhook UI can't set headers; it gates a write-only, no-read endpoint and is rotatable.
Webhook events subscribed
subscriber.opened_emailclicked_emailclicked_trigger_link visited_pagebecame_leadupdated_lead_score applied_tagremoved_tagsubscribed_to_campaign performed_custom_eventupdated_lifetime_valuereceived_email
Program-design spotlight · the voice system

Teaching a machine to write like a specific human, and keeping it honest.

Each founder has a distinct writing voice, encoded as a skill with craft rules, phrase banks, and an "AI tells to strip" filter. But a voice guide drifts unless it learns from real edits. The problem: naive learning bloats the file until it is too long to load before every draft.

The fix is a two-tier learning loop. When the founder edits a draft and picks a voice to teach, the before/after is queued. A nightly agent captures the full pair in an append-only raw log (the evidence trail) and then merges a distilled lesson into a short curated file, deduplicating against existing rules and marking recurrence rather than piling on duplicates. The curated file, capped near two dozen rules, is what actually shapes the next draft.

The learning loop
Founder edits a GLIV draft, picks a voice ▼ /__action/voice-lesson → learn:<id> in KV ▼ nightly agent reads /__learn/queue ▼ Tier 1 — append full before/after to raw log ▼ Tier 2 — merge/dedupe into curated rules (≤24) ▼ next draft starts closer to the real voice
The agent fleet

34 scheduled agents, each read-only until a human says otherwise.

Work that needs a real inbox, a browser, or open-ended research runs as a scheduled Claude agent on the Claude Agent SDK. Each is a self-contained prompt with a cron, strict read-only rules on calendars, email, and tasks, and a heartbeat back to the Worker so the app can show it ran. Side-effectful steps stop at a human clutch.

AgentCadenceReadsWrites / guard
gliv-drip-pulldaily 05:07Drip REST (token)KV cust:*; invalidates people:cache
gliv-new-students2×/dayDrip + Gmailread-only; reply-needed flag
gliv-smart-tasks3×/dayCalendar + Gmail + Todoistread-only; pushes Morning Brief
gliv-daily-contentdaily 04:08web research + vaultdrafts to review queue only
gliv-voice-learn3×/day/__learn/queueappends to voice files; never posts
gliv-group-posthourly windowapproved queuestages post, stops for human click
gliv-publish-runhourly windowapproved queueAPI post + per-target confirm
gliv-selftestnightly 02:03/__selftestraises failures to Needs Attention
gliv-sched-watch4×/dayscheduler stateflags runs missed while asleep
gliv-fb-status3×/daypage tokensflags expired auth
A representative slice of the live fleet. Every agent reports a heartbeat (/__ingest/tasklog); a 401 or expiry raises itself into the app's Needs Attention queue via /__ingest/taskissue.
Read-only by construction

Calendar, email, and task connectors are used read-only. The prompts forbid send, reply, label, delete, complete, or accept. The only writes are to GLIV's own store and, at a clutch, an approved post.

Missed-run detection

Scheduled work only fires when the machine is awake. A watcher compares expected vs actual run times and surfaces anything that slipped, so a silent gap never masquerades as "all clear."

Idempotent staging

Posting agents claim an item before acting, so a re-run can never re-stage the same post. Durable flags (postedToPages, groupStagedOnce) make double-posting structurally impossible in the sensitive lane.

Reliability engineering

The system tests itself, reviews itself, and tells on itself.

A one-operator business cannot babysit its automation, so the platform is built to catch its own regressions. Three layers do it.

22
SELF-TEST INVARIANTS

A /__selftest endpoint asserts the critical invariants with no side effects: the one-shot posting guard holds, tag categorization is stable, seeding is correct. The publishing self-test calls the same eligibility predicates the live path uses, so the test can't drift from reality. 200 if all pass, 500 on any failure.

95/100
DUAL-PASS QC GATE

Every substantial change runs a rubric self-check, then an independent reviewer agent against the same rubric: security, correctness, honest UI, house style. Both must clear 95 with zero outstanding violations before it ships. This overview was built under that gate.

3
FAILURE-SURFACING PATHS

A black-box contract harness hits every public route with a real browser user-agent. A nightly self-test raises failures into the app. A scheduler watcher flags missed runs. Nothing fails quietly; everything failing arrives in one Needs Attention queue.

Bugs found and fixed by the harness (a sample)
  • KV write race: three engagement events in one second lost one via last-write-wins. Fixed by one-key-per-event; re-verified with a burst test.
  • Silent truncation at scale: a get-per-key read would exceed the subrequest cap and return partial data with a 200. Fixed by moving payloads into key metadata.
  • Empty webhook subscription: a Drip webhook with no explicit event list delivered nothing. Caught by an end-to-end tag-event probe, not by docs.
  • Injection-safe rendering: a subscriber name with an apostrophe could break an inline handler. Escaped like every other user-supplied string.
Security & safety posture

Least privilege at the edge, and a hard line at the human.

  • One provable gate. Every private read sits below a single if(!authed) line. Public and ingest routes are deliberately, visibly above it.
  • Secrets never in code. API tokens and the webhook secret are Worker secrets, read from env, never logged, never written to KV. Rotation is a one-command wrangler secret put.
  • Constant-time token compare for the session cookie; shared-secret checks run before any body is parsed.
  • Privacy exclusions are enforced at write, at read, and in every list, so sensitive-tagged people never surface, even in an internal view.
  • Human clutches on all four irreversible classes: move money, publish, message a real person, change a standing rule. The machine prepares; the human commits.
Trust boundaries
ActorAuthCan
Public visitornonelanding, opt-in, images
Machine writerX-Gliv-Ingestpush to ingest lane only
Drip webhook?s=secretappend engagement, write-only
Foundercookie / IPread all; stage actions
Deployscoped CF tokenship the Worker

The deploy token, the Drip API token, the ingest secret, and the webhook secret are four separate credentials with four separate blast radii. Compromise of any one does not imply the others.

Stack & vocabulary

Everything under the hood, named.

Runtime & platform
Cloudflare WorkersWorkers KVV8 isolatesWrangler CLICloudflare Assetscustom domain + TLSHTTP cron triggersedge caching / TTL
Application
Vanilla-JS SPAWeb fetch() APISVG + CSSsemantic routingserver-side filter/sort/paginateoptimistic UIdebounced search
AI & agents
Claude Agent SDKModel Context Protocol (MCP)scheduled skillstwo-tier learning loopindependent-reviewer QCvoice skills
Integrations & auth
Drip REST v2/v3OAuth 2.0HTTP Basic (token)webhooksshared-secret ingestHMAC-style secretsStripe / Square / Squarespace APIs
Growth & data
GSCGA4Bing WMTJSON-LD structured dataSEOGEOAEOentity SEO
Media & content
PIL / Pillowper-region contrast selectionFNV-1a hashinghalf-life decayVTT transcript parsingidempotency keys
Acronym glossary
KVKey-Value store (Cloudflare's eventually-consistent edge database)
SPASingle-Page Application
MCPModel Context Protocol — the connector standard the agents use
SDKSoftware Development Kit (here, the Claude Agent SDK)
ESPEmail Service Provider (Drip)
TTLTime To Live — auto-expiry on a stored key
OAuthOpen Authorization — delegated, tokenized access
TLSTransport Layer Security
GSCGoogle Search Console
GA4Google Analytics 4
WMT(Bing) Webmaster Tools
SEOSearch Engine Optimization
GEOGenerative Engine Optimization — being cited by AI answers
AEOAnswer Engine Optimization — featured snippets, voice
JSON-LDJSON Linked Data — structured markup for search
POPPoint of Presence — a Cloudflare edge location
Ship pipeline
edit▶ node --check (worker + extracted SPA)▶ wrangler deploy▶ contract harness▶ /__selftest▶ independent-agent QC ≥95
One artifact, one command, self-verified. A deploy that fails the harness or the self-test is caught before anyone sees it.