⚗️ The Apothecary

The Apothecary is the operating manual for The Herbalist's v2 storefront: how the new AI-natively-controlled Hydrogen site works next to the current GemPages site, every tool connected to it, how changes ship, and what we do if anything goes wrong. The cutover programme itself lives in the 🎯 Game Day tab: everything that must be built, connected, tested and verified before the switch. Written for every member of the digital marketing team. Sections 1 to 8 each end with a Technical details button for the deeper detail that developers and agents need.

Owner: Ismaeel Approver: Matt Status: Pre-game · nothing live has changed Stack verified: 21 Aug 2026 (from the live site's own code)

1 · Start here

For years The Herbalist website has run on Shopify's standard theme system with GemPages, a visual page builder. It is manual but easy: anyone can log in, drag things around, and press publish. We are replacing it with a Hydrogen storefront: a custom-coded site that we fully own, that AI agents can build, test and improve continuously, and that will become the foundation for CRO experiments, A/B testing and our own custom apps.

That is a big step. The current site takes roughly R3.3-4.6M per month in orders. So this document exists to make the switch boring: every risk identified, every integration reconnected, every check written down, and a tested way back if anything misbehaves.

Zero downtime is the rule. The switch itself is a domain reassignment inside Shopify admin, not a DNS migration. The old site stays fully intact and publishable the whole time. If anything goes wrong we point the domain back and we are on the old site again within minutes.
Checkout never changes. Both the old and new site hand customers to the exact same Shopify checkout. Payments, shipping rates and order processing are untouched by this project.
Humans keep the judgement. Agents build, test and monitor. People approve. Nothing reaches the live site without a human saying so on a staging preview first.
Nothing important lives only in chat scrollback. This document is the source of truth for the cutover and for how the site is run afterwards. If a decision changes, this page changes.

Who does what

PersonRole on this project
IsmaeelResponsible for the whole cutover: builds, integrations, testing, the Game Day run itself, and day-2 operations.
MattApproves the go-live decision and production deploys. Runs deploys from his terminal until automatic deploys (CI) are set up, because the Shopify login for deploying is tied to his machine. Owns the Google Ads side.
KellySigns off content parity and the new content-editing workflow (section 8). Owns email, promos and the marketing calendar around the switch date.
Agents (Claude Code + Herbie/Hermes)Do the heavy lifting: porting code, wiring integrations, running test suites, monitoring after launch. Always through the pipeline in section 6, never straight to production.

Start here: technical context

The v2 codebase lives at github.com/The-Herbalist-SA/storefront (private): split out of the growth-harness monorepo's storefront/ folder on 21 Aug 2026 with its full 45-commit history, from branch storefront-v2 (Ismaeel's variant/live-clone, harness commit 4079289). The harness itself now lives at The-Herbalist-SA/the-herbalist-growth-harness and keeps all archived storefront builds. Local clone: ~/Projects/the-herbalist-storefront (carries the .env and Shopify link files). Stack: Shopify Hydrogen 2026.4.2, React Router 7.14, Vite, deployed to Shopify Oxygen (edge workers). CLI: @shopify/cli 3.93.2.

Three prior audits are required reading for any agent working on this project. They currently exist in the harness working tree on Matt's machine only (untracked); committed to the harness repo alongside this doc since 21 Aug, so clones (including Hermes on the VPS) can see them:

  • audits/2026-07-27-hydrogen-storefront-parity-gaps.md: main-build vs live site.
  • audits/2026-07-29-live-clone-vs-main-storefront-comparison.md: Ismaeel's build vs Matt's build, and the port list.
  • audits/2026-08-12-live-clone-production-readiness.md: the 8-agent production readiness audit. The Game Day checklist in section 5 is derived from it.

Known hard rules that bind every agent: never advertise or merchandise Kratom beyond live parity decisions recorded here; mutations and deploys are human-approved; ZAR only; the Google Ads account is the database for ads data.

2 · Old site vs new site

Think of the current site as a house we rent with furniture included: Shopify renders every page for us, GemPages lets us redecorate visually, and apps bolt features on by injecting their own code. The new site is a house we built ourselves: we write every page, which means total control and speed, but features that used to "just appear" from apps now have to be deliberately built in and connected.

Current live site (v1)Hydrogen storefront (v2)
What it isShopify Online Store theme + GemPages page builderCustom-coded Hydrogen app we own end to end
Who edits itAnyone, visually, in GemPagesAgents + developers through code, via the pipeline in section 6 (content workflows for the team are in section 8)
How apps workApps inject their own scripts and widgets automaticallyEvery integration is deliberately wired in by us (section 4)
SpeedHeavy: ~15 third-party scripts load on every pageServer-rendered and lean; we choose exactly what loads
CheckoutIdentical Shopify checkout for both. Nothing changes.
Products, prices, stock, ordersBoth read the same Shopify store. One catalog, one admin.
AI-nativeNo: agents cannot safely edit GemPagesYes: agents build, test, deploy and monitor through the pipeline

Architecture comparison

v1: Shopify's Online Store channel renders Liquid theme templates server-side. GemPages stores page layouts and renders them through theme sections; its assets come from assets.gemcommerce.com and ucarecdn.com (Uploadcare). Apps use theme app extensions and script tags, which is why they work without anyone wiring them. Shopify web pixels (app pixels + custom pixels) run via the Online Store pixel loader.

v2: Hydrogen app on Oxygen edge workers. Pages are React Router routes in storefront/app/routes/, data comes from the Storefront API (products, cart, policies, pages, blog) and the Customer Account API (login, orders). Server-side rendering with a strict Content-Security-Policy defined in app/entry.server.jsx: any third-party script domain must be explicitly allowlisted there or the browser silently blocks it.

Critical difference for tracking: the Online Store pixel loader does not exist on Hydrogen pages. App and custom web pixels only fire at checkout. All storefront-side pixels (GA4, Meta, TikTok, Klaviyo onsite, Clarity, Triple Whale) must be wired into the app: base scripts with the CSP nonce in app/root.jsx, plus a subscriber component using useAnalytics().subscribe() to forward Hydrogen's page_viewed / product_viewed / product_added_to_cart events to each vendor. The Shopify-native analytics wiring in v2 is already correct and complete (verified 12 Aug); it is the third-party layer that must be built.

Checkout handoff: v2 links to cart.checkoutUrl from the Storefront API. Checkout remains Shopify-hosted, so checkout-scoped pixels (including the Google purchase conversion via the Google channel app) keep firing unchanged. Verify this on the first staging test order anyway.

3 · Every site we have, and what happens to each

Over the past months we built several versions of the storefront to explore designs. As of 21 Aug 2026 one build is promoted and everything else is archived, so there is never confusion about which site is "the one".

Site / buildWhat it isStatusWhat happens to it
theherbalist.co.zaThe live GemPages site (v1)Live productionStays exactly as-is until Game Day. After cutover it remains published on the Online Store channel as our instant rollback for at least 30 days.
storefront-v2 branchIsmaeel's live-clone build: the chosen v2 base (was variant/live-clone)PromotedSplit into its own repo on 21 Aug: The-Herbalist-SA/storefront (main = production, staging). All Game Day build work happens there; the harness keeps the archived builds.
Matt's build (repo main)First Hydrogen build; currently on the stable Oxygen preview URLArchivedTagged archive/main-storefront-build. Not deleted: it is the parts shop. Reviews data, Buy More & Save, SEO library, contact page and tests get ported from it into storefront-v2.
variant/momentousMomentous-style design explorationArchivedPreserved in the archive folder: archive/* branches plus archive/variant-* tags (pushed 21 Aug). Nothing is deleted; the old variant/* names remain as duplicates and can be tidied later if we ever choose to.
variant/bioteenBioTeen-style design explorationArchived
variant/hybrid-premiumPremium-minimal design explorationArchived
variant/organics-oceanOrganics-Ocean-style design explorationArchived
PR #7 (header logo size)Ismaeel's open PR against the archived main buildDecisionRecommend closing as superseded (the v2 base has its own header). Ismaeel closes it with a one-line comment.
herbalist-nextjs-demo.catalystlabs.co.zaEarly Next.js design prototype (separate project, not Shopify-connected)ArchivedKeep as a design reference or take the deployment down; either way it plays no role in Game Day.

Branch and deployment mechanics

All storefront builds are the same app at storefront/; the "sites" are git branches of the harness monorepo. The Shopify/Oxygen link lives in untracked working-tree files (storefront/.shopify/project.json, storefront "Herbalist Hydrogen (in development)", plus the pulled storefront/.env), so whatever branch is checked out deploys to the same Oxygen storefront. Deploy auth is interactive browser OAuth: agents cannot deploy headlessly today; Matt runs deploys until GitHub CI is connected (section 6).

Archive markers created and pushed 21 Aug 2026: annotated tags archive/variant-bioteen, archive/variant-hybrid-premium, archive/variant-momentous, archive/variant-organics-ocean, archive/main-storefront-build, and new branch storefront-v2 tracking the old variant/live-clone tip (4079289).

Archive mechanics: each old variant lives at archive/<name> (branch, the "archive folder" in the GitHub branch list) and archive/variant-<name> (annotated tag). The original variant/* branches were kept per Matt's call; if we ever tidy them, everything is already duplicated so nothing can be lost.

DONE 21 Aug 2026: storefront/ was split into its own repository with full history (git subtree split): The-Herbalist-SA/storefront, branches main (production) and staging, identical at rest. The growth harness moved to The-Herbalist-SA/the-herbalist-growth-harness and keeps every archived build. Note: branch protection on main needs the org upgraded off the GitHub Free plan (or the repo made public); until then the PRs-only rule is discipline, not enforcement.

4 · The connected stack: every tool on the live site

This list was built by reading the live site's own page code on 21 Aug 2026, so it is the real list, not a from-memory one. Every tool below currently loads on theherbalist.co.za. For each one: what it does for us in plain language, and what has to happen before or during Game Day.

Survives keeps working by itself   Rebuild we build it into v2 ourselves   Reconnect the tool stays, its script must be wired into v2   Decide needs a business decision before Game Day   Retires deliberately ends with the old site

Money and selling

ToolWhat it does for usPlan
Shopify checkout + paymentsTakes the money. Cards, shipping rates, order creation.Survives Same checkout for both sites. Verify with one staging test order.
Kaching BundlesThe "Buy More & Save" 1/3/6-bottle offers on product pages. A proven basket-size booster.Rebuild Native version already exists in the archived main build, including the automatic 5% multi-pack discount. Port it, and confirm the discount still exists in Shopify admin.
Bold Subscriptions (+ legacy Spurit scripts)The "Once a month" subscribe option on product pages, roughly R20-50K/mo.Decide Bold does not use Shopify's native selling plans (verified: the API returns none), so v2 cannot simply query it. Options: Bold's headless integration, migrating to a native selling-plan app, or launching v2 without subscriptions and keeping existing subscribers billing through Bold. Quantify revenue first; this is the biggest open product decision.
BOGOS free giftsRuns free-gift-with-purchase offers (our BOGO promos).Decide Widget will not load on v2. Check with Kelly whether any BOGO offer is scheduled near Game Day; either rebuild as native discounts or time the cutover between promos.
Rebuy"You may also like" recommendations and upsells sitewide.Decide v2 has its own related-products carousel. Pull Rebuy's attributed-revenue number from its dashboard; if material, rebuild smarter recommendations natively or via Rebuy's API. Otherwise cancel the subscription after cutover.

Tracking and marketing data

ToolWhat it does for usPlan
Google tag (GA4 + Google Ads)Feeds Google Ads conversions, remarketing lists and Smart Bidding signals, plus GA4 analytics and the intel warehouse.Reconnect Highest-stakes item for our ad account. Wire the tag into v2 and verify remarketing events fire before cutover. Purchase conversions at checkout keep working regardless.
Triple Whale (Tixel)Attribution: tells us which ads actually drive orders.Reconnect Add the Tixel/headless snippet to v2 and confirm events in the Triple Whale dashboard from staging.
Meta pixelFacebook/Instagram ads tracking and audiences (managed outside our remit, but fed by the site).Reconnect Wire base pixel + events; confirm with whoever runs Meta that events arrive.
TikTok pixelTikTok ads tracking and audiences.Reconnect Same treatment as Meta.
Microsoft ClaritySession recordings and heatmaps for CRO.Reconnect One script. (Roadmap: PostHog may replace it, section 9.)
Klaviyo onsiteEmail capture and browse tracking; powers browse-abandonment flows and "Active on Site" segments.Reconnect Load Klaviyo JS and wire the footer "Holistic Wellness Course" form to the real Klaviyo form (the form ID is documented in the code). Without this, list growth stops on day one.
t.trackmytarget.comUnidentified tracker found in the live code (likely an affiliate network).Decide Identify who added it and why. If it earns nothing, retire it; if it is an active affiliate program, reconnect it.

Experience and content

ToolWhat it does for usPlan
LooxCollects and shows customer reviews (6,000+), and feeds star ratings to Google.Rebuild + Survives Review display is rebuilt natively fed by real Loox data (we already sync the full review set via the Loox API). Review-request emails are triggered by orders, not the theme, so collection continues; verify with a staging test order that a request gets scheduled.
GemPagesThe page builder the whole v1 site is built in.Retires Do not cancel billing until 30+ days after cutover (it powers the rollback site). First: rebuild its landing pages natively (six benefit pages + contact page are on the checklist) and self-host the handful of images v2 currently borrows from GemPages' CDN.
BSS Store LocatorThe stockists map/list (77 stores).Rebuild Already done: v2 has a native Store Locator with all 77 stockists. Retire the app after cutover. Decide the update path for new stockists (section 8).
PushOwlWeb push notifications to subscribed browsers.Decide Push subscriptions are tied to the site's service worker. Check subscriber count and revenue in PushOwl; if material, integrate PushOwl on v2; if not, retire.
Visually.ioA/B testing and personalisation on the live site.Decide Check with Kelly what experiments are running. Conclude or pause them before cutover. Roadmap replacement is PostHog (section 9).
WhatsApp chat buttonThe floating green chat bubble; daily customer support channel.Rebuild Small native component linking wa.me with the support number. Not built yet; on the checklist.

Stack: verification evidence and wiring notes

How this list was produced (repeatable): fetched https://theherbalist.co.za/ and /products/ashwagandha on 21 Aug 2026, extracted every external script src domain and grepped vendor signatures. Domains found: app.gettixel.com (Triple Whale), assets.gemcommerce.com + ucarecdn.com (GemPages), cdn-spurit.com (Spurit recurring-order scripts), cdn.bogos.io (BOGOS), cdn.rebuyengine.com (Rebuy), live.visually-io.com (Visually), loox.io (Loox), static.klaviyo.com (Klaviyo), t.trackmytarget.com (unidentified), www.clarity.ms (Clarity), www.googletagmanager.com (Google tag). Signal counts also showed Kaching, BSS store locator, PushOwl, Meta (fbq), TikTok. Subscription vendor: 244 "bold subscription" matches on the PDP; Admin API sellingPlanGroups returned empty (21 Aug), proving no native selling plans are exposed.

Wiring pattern for all pixels on v2 (one implementation serves GA4/Ads, Meta, TikTok, Klaviyo, Clarity, Tixel):

  1. Base snippets rendered with the CSP nonce (useNonce()) in app/root.jsx.
  2. A ThirdPartyAnalytics component inside Analytics.Provider subscribing to page_viewed, product_viewed, collection_viewed, product_added_to_cart, search_viewed and forwarding to each vendor's API (gtag, fbq, ttq, klaviyo, clarity).
  3. CSP allowlist additions in app/entry.server.jsx for every vendor domain (scriptSrc, connectSrc, imgSrc, frameSrc as needed). The CSP currently blocks all of them; this step is mandatory, not polish.
  4. Set PUBLIC_CHECKOUT_DOMAIN in the Oxygen environment (currently missing; its absence degrades Shopify consent + attribution).

Exact tag IDs (GTM/GA4 container, Meta pixel ID, TikTok pixel ID, Klaviyo company ID, Clarity project, Tixel key) must be extracted from the live theme and vendor dashboards during Phase 2 and recorded in the repo (IDs are not secrets, keys are: keys go in Oxygen env vars only).

Klaviyo form: footer band posts to Klaviyo form WuG7qZ (ID already noted in Footer.jsx). Either mount the embedded form or POST to Klaviyo's client subscribe endpoint.

Loox: live PDP aggregate for Ashwagandha showed ~1,754 reviews (12 Aug) vs our Apr snapshot's 521: regenerate v2's review data from the API sync (loox-reviews-exports/api-sync/, 6,156 reviews, credentials in ~/.config/loox/) as a launch-week task and schedule a recurring refresh.

5 · 🎯 Game Day: the cutover checklist

Everything that must be built, configured, tested and verified, in order. A phase only starts when the one before it is done (Phases 1 and 2 can overlap). This is the master list; it should be mirrored into ClickUp tasks so progress is visible to everyone. Nothing in Phases 1-4 touches the live site.

Phase 0 · Decisions Each item names its driver

  • Ismaeel: pull the real monthly subscription revenue number, then Matt picks the Bold path (headless integration, app migration, or launch without and phase in).
  • Ismaeel: check the Rebuy, PushOwl, BOGOS, Visually and trackmytarget dashboards for revenue/usage; Matt + Kelly then mark each one Reconnect / Rebuild / Retire in section 4.
  • Kelly: sign off the content editing workflow after launch (section 8).
  • Matt: kratom on the storefront: match live (catalog grid shows it) or restrict. Record the decision; hidden b2b collections stay hidden either way.
  • Decided + done (21 Aug): storefront/ split into The-Herbalist-SA/storefront with history; growth harness moved into the org alongside it.
  • Matt + Kelly: pick the target cutover window: off-peak, no promo running, Kelly's calendar clear, everyone available for the following 48h.

Phase 1 · Build: make v2 content-true and feature-complete Ismaeel + agents

  • Done (21 Aug): this doc, the three audits and the cutover queries are committed to the harness repo (The-Herbalist-SA/the-herbalist-growth-harness, commit f120b8c), and the docs site auto-deploys from it on every push to main.
  • Replace all sample review data with the real Loox dataset; remove invented reviewer cards entirely; products with no reviews show no stars.
  • Correct every product page's dosage, size and spec copy verbatim against the live site (4 of 5 curated products currently differ; liquid extracts are wrongly described as capsules).
  • Fix the subscribe option: it currently looks real but adds a one-time purchase. Hide it until the Phase 0 subscription decision lands, then implement that decision.
  • Port Buy More & Save (1/3/6 bottles) from the archived main build; verify the automatic 5% discount exists in admin.
  • Build the six benefit landing pages (sleep, stress-relief, concentration-cognitive, fitness-performance, hormones, immunity-adaptogens): currently blank because GemPages renders them on v1.
  • Build the contact page; redirect the three legacy policy URLs to the working policy pages.
  • Port from main: cart free-shipping progress bar, styled checkout button, add-to-cart double-click lock, SEO library (titles, meta descriptions, canonicals, product JSON-LD), branded 404 page.
  • Fix the sitemap (currently emits fake foreign-language URLs), set country to ZA, add mobile hero images, restore the kratom/b2b merchandising guard per the Phase 0 decision, add the WhatsApp button, self-host the footer social icons.
  • Restore the test suites from main (unit + Playwright) and get them green.

Phase 2 · Connect: tracking and integrations Ismaeel + agents

  • Extract every tag ID from the live theme (Google tag, Meta, TikTok, Clarity, Klaviyo, Tixel) and record them in the repo.
  • Wire the pixel layer + CSP allowlist (one build covers all vendors; pattern in section 4's technical details).
  • Wire the Klaviyo newsletter form. Set PUBLIC_CHECKOUT_DOMAIN and all production environment variables in Oxygen.
  • Register the production domain with the customer login system (Customer Account API callback URIs) so account login works on theherbalist.co.za.
  • Set up error monitoring (Sentry) and an external uptime probe with alerts to Slack/ClickUp.

Phase 3 · Pipeline: staging and production Ismaeel + Matt

  • Done (21 Aug): repo created with main + staging. Still open: branch protection on main (needs a paid GitHub plan for private repos; upgrade the org or enforce PRs by discipline).
  • Connect GitHub to the Hydrogen channel so every push auto-deploys: staging branch to the staging environment URL, production branch to the production URL.
  • Mirror all environment variables into both Oxygen environments. Verify staging and production render identically from the same commit.

Phase 4 · Test: prove it end to end on staging Ismaeel + agents, Kelly for content sign-off

  • Full automated suite green (unit + Playwright end-to-end).
  • Place a real test order on staging with UTM parameters: verify checkout completes, the order lands correctly attributed in Shopify, every pixel fired (Google, Meta, TikTok, Tixel, Klaviyo), and Loox schedules a review request for it.
  • Verify every Google Ads final URL resolves: re-run the three saved checks in queries/cutover_*.gaql and fetch every URL against staging. On 12 Aug all ~60 ad URLs, 17 PMax asset-group URLs and the sitelinks passed with zero 404s. The four sitelinks that 404 on live today (unpublished blog articles, an open Ads-side bug) must be fixed in the Ads account first, then re-crawled.
  • Lighthouse performance + accessibility pass on home, product, collection, cart (mobile and desktop). Target: beat the live site.
  • Cross-device sweep (iPhone, Android, tablet, desktop; Safari + Chrome) of the money path: home, product, add to cart, checkout entry.
  • Kelly walks the staging site against the live site page by page and signs off content parity.
  • Merchant Center: fetch every landing URL in the feed against the staging build; all must return 200 with price, availability and product data rendered to match the feed. Record the run date. (Merchant Center itself crawls only the live domain, so this staging check is the early warning; re-verify in Phase 6.)

Phase 5 · Game Day: the cutover Ismaeel runs it, Matt approves, Kelly on standby

  • Freeze: no deploys, no promos, no catalog changes during the window.
  • Deploy the approved staging commit to production; smoke-test the production URL directly.
  • Go/no-go check with Matt. Then: Shopify admin → Settings → Domains → point theherbalist.co.za at the Hydrogen storefront. No DNS changes. Old site stays published on the Online Store channel.
  • Immediately verify: homepage loads on the domain, product page loads, add to cart, reach checkout, customer login works, pixels fire on the live domain, SSL valid.
  • Place one real order end to end. Watch it arrive in Shopify admin correctly attributed.
  • Announce internally. Start the 48-hour watch (Phase 6).

Phase 6 · The 48-hour watch Ismaeel + agents

  • Monitor: error rate, uptime probe, conversion rate vs the trailing 7-day baseline, checkout entries, pixel event volumes, Google Ads spend and conversion delivery, Klaviyo flow triggers.
  • Compare hour-by-hour orders to the same weekday last week. A sustained conversion drop is a rollback trigger (section 7).
  • Confirm the intel warehouse dashboards still populate; confirm Loox review requests are sending; confirm Merchant Center shows no new disapprovals.
  • Day 30: if all healthy, retire the decided apps (Rebuy, BSS, GemPages billing per section 4) and close the rollback window.

Checklist: sources and verification commands

Phase 1 items trace 1:1 to the blockers and musts in audits/2026-08-12-live-clone-production-readiness.md, which carries file:line evidence for each (e.g. fabricated reviews in app/lib/loox-data.js and the filler cards in products.$handle.jsx; the cosmetic subscribe option in ProductForm.jsx:22-25; blank benefit pages verified as empty page bodies via the Admin API).

Ads URL verification (Phase 4): the three GAQL checks are saved as queries/cutover_ad_final_urls.gaql, queries/cutover_pmax_asset_group_urls.gaql and queries/cutover_sitelink_urls.gaql (each with a sibling .md). Run them via the run-gaql skill, fetch every returned URL against staging, require 200s. All passed with zero 404s on 12 Aug. The four sitelink 404s (unpublished blog articles) are an OPEN Ads-side bug: fix before cutover, then re-run the sitelink check.

Attribution test order (Phase 4): land with ?utm_source=cutover-test, then inspect the order's customerJourneySummary and source_name via Admin API; expected channel is the headless storefront's custom app channel, not Online Store: confirm the intel warehouse pipeline handles the new channel value.

Domain cutover (Phase 5) is: Shopify admin → Settings → Domains → theherbalist.co.za → "Change target" → select the Hydrogen storefront. SSL auto-provisions. GoDaddy DNS is untouched (the domain already points at Shopify). Rollback is the same screen in reverse.

6 · How changes ship after launch

Once v2 is live, no one edits the live site directly, ever. Every change (a headline tweak, a new landing page, a bug fix, an experiment) travels the same road. This is what makes the site safe to hand to agents:

1 · BranchCreate a feature branch off staging. Build the change with Claude Code or Hermes.
2 · Test locallyRun the site and the test suite on the builder's machine. Everything green.
3 · StagingMerge to the staging branch. It auto-deploys to the staging site, an exact mirror of production.
4 · ApproveA human reviews the change on the staging URL and approves the PR.
5 · ProductionMerge staging into production. Auto-deploy. Verify on the live domain.
Staging and production are identical at rest. The only time they differ is while a change is being tested. Then it either goes to production or gets removed from staging. Staging is never a junk drawer.
Every production deploy is reversible. Each deploy is kept forever with its own URL; rolling back is redeploying the previous one. Roughly two minutes.
Agents propose, humans approve. Claude Code and Hermes can do steps 1-3 autonomously. Step 4 always has a human name on it: Ismaeel for routine changes, Matt for anything touching money paths (checkout links, pricing display, subscriptions, tracking).

Pipeline implementation

Branches (in The-Herbalist-SA/storefront): main is production (deploys to the Oxygen production environment, which owns theherbalist.co.za after cutover) and staging deploys to a stable staging URL. Feature branches: feat/*, fix/*. Merges to main come only from staging, ideally fast-forward so the two are byte-identical at rest. Branch protection on main: PR required, checks required (unit + Playwright + build), no force pushes; enforcement needs the org on a paid plan, discipline until then.

CI: connect the GitHub repo in Shopify admin → Hydrogen channel → the storefront → GitHub. Oxygen then builds and deploys each pushed branch to its own environment automatically, replacing Matt's interactive CLI deploys. With the app now at the root of its own repo, the generated workflow needs no monorepo edits: connect The-Herbalist-SA/storefront and each pushed branch gets its own environment. Until CI is connected, deploys are manual:

cd ~/Projects/the-herbalist-storefront
npx shopify hydrogen deploy          # choose Preview = staging-style URL
npx shopify hydrogen deploy --env production   # production (Matt only)

Environments: both Oxygen environments carry the full env var set (the 8 existing vars plus PUBLIC_CHECKOUT_DOMAIN; add vendor keys as Phase 2 lands them). npx shopify hydrogen env pull syncs a local .env.

Agent access: Claude Code works on Matt's machine and in this repo. Hermes (Herbie VPS) gets a clone of the storefront repo and the same rules: branch, build, test, push to staging, never merge to production without a human approval recorded on the PR. Hermes must not hold Oxygen deploy credentials while deploys are CLI-interactive; once GitHub CI exists, "deploy" for agents means "merge after approval", which is exactly the control we want.

Tests as the gate: the suites restored in Phase 1 (unit + Playwright) run on every PR. A red suite blocks staging and production merges. Add a smoke spec that hits /, one PDP, one collection, cart, and asserts the checkout link resolves.

7 · Emergencies: what we do when something breaks

Three levels. Know which one you are in, act, then write down what happened.

LevelLooks likeWhat to do
Sev 1
Site down or can't buy
Site not loading, checkout unreachable, prices wrong, sustained conversion collapseRoll back first, debug later. Point the domain back at the Online Store (old site) in Shopify admin: minutes, no DNS. Or redeploy the previous production deployment if the domain is fine but the latest deploy is bad. Tell Matt + Kelly immediately.
Sev 2
Something important is broken, sales still flow
A page erroring, a pixel gone quiet, login failing, layout broken on mobileFix through the pipeline (hotfix branch → staging → verify → production). If the bad change is known, revert it the same way. No cowboy edits to production.
Sev 3
Cosmetic or minor
Typo, spacing issue, slow pageTicket it in ClickUp, fix in the normal flow.

Who to call

First responder: Ismaeel. Approver and Ads side effects: Matt. Customer communications if the outage is customer-visible: Kelly. Platform or checkout incidents: Shopify Plus support. Phone numbers live in the team Slack channel topic, not only in this document.

Rollback triggers during the 48-hour watch

Agreed in advance so nobody debates them at 11pm: conversion rate down more than 30% vs the same hours last week for 2+ hours, checkout unreachable for more than 5 minutes, error monitoring shows a sustained spike we cannot explain, or payments failing. Any one of these = Sev 1 = roll back.

The old site is the parachute. It stays published, untouched and paid for until at least 30 days after a healthy launch. Nobody edits or unpublishes it during that window.

Emergency runbook detail

Full rollback (Sev 1, site-level): Shopify admin → Settings → Domains → theherbalist.co.za → change target from the Hydrogen storefront back to Online Store. Propagation is near-immediate (same Shopify edge). Verify homepage + checkout on the domain. Post in Slack what was seen, when, who flipped it.

Deploy rollback (bad deploy, domain stays): Hydrogen channel → the storefront → Deployments → previous good deployment → redeploy/promote. Every Oxygen deployment is immutable with its own URL, so "previous good" is always one click away. Equivalent CLI: check out the previous production commit and deploy.

Diagnosis order for "site is slow/erroring": 1) uptime probe + Sentry dashboard, 2) Oxygen deployment logs in the Hydrogen channel, 3) Shopify status page (Storefront API incidents affect v2 but usually also checkout), 4) recent merges to production (git log). The most likely self-inflicted causes: a missing env var after an environment edit, a CSP change blocking a script, or a Storefront API query error on a route loader.

Contacts: Ismaeel (first responder), Matt (approver, Ads side effects), Kelly (customer comms if outage is customer-visible), Shopify Plus support (checkout/platform incidents). Keep phone numbers in the team Slack channel topic, not only in this doc.

After any Sev 1/2: a short post-mortem note in storefront-docs/incidents/: what broke, when, how long, root cause, the fix, what prevents recurrence. Agents append; humans review.

8 · Upkeep: content, updates and upgrades

On the old site, Kelly edits pages in GemPages and presses publish. On v2, content lives in two places, and it matters which:

ContentWhere it lives on v2How it gets changed
Products, prices, stock, discountsShopify admin (unchanged)Exactly as today. v2 reads it live; no deploy needed.
Blog postsShopify admin blogKelly publishes as today. (v2 currently pins the 5 live articles in code; the checklist adds an automatic fallback so new posts appear without a deploy.)
Legal policiesShopify admin policiesAs today; v2 reads them live.
Homepage banners, landing pages, FAQ copy, stockistsThe storefront codeRequest via ClickUp → an agent or Ismaeel makes the change → staging preview link for approval → production. Turnaround target: same day. (Roadmap: move the most-edited pieces to Shopify metafields so the team can edit them in admin directly.)

Recurring jobs

  • Weekly: refresh review counts and quotes from the Loox sync; check Sentry + uptime + Lighthouse trend; dependency security alerts.
  • Monthly: Hydrogen/CLI version upgrade on a branch, through the pipeline like any change; re-run the Ads final-URL check; verify staging == production.
  • When Kelly publishes a blog post or a stockist changes: until the metafield/API work lands, create a ClickUp task from the "sync content" template, assigned to Ismaeel; an agent picks it up and ships the update through staging.

Upkeep implementation

Review refresh: source of truth is the Loox API sync in the harness (loox-reviews-exports/api-sync/, creds ~/.config/loox/, User-Agent header required). A small script regenerates v2's reviews module from it; run weekly by an agent, shipped through staging like any change. Never hand-edit review numbers.

Blog fallback: add a Storefront API article(handle:) fallback in the news article route and render the blog index from the API list, so newly published articles appear without deploys. Until then the static list must be updated per post.

Stockists: currently a static module (77 entries, matching the live BSS dataset). Options: keep static with an agent update task, or read from a metaobject Kelly can edit in admin. Decide in Phase 0 of the content workflow discussion.

Upgrades: npx shopify hydrogen upgrade on a branch; read the release notes (the CLI prints them); run the full suite; staging soak for a day before production. Pin exact dependency versions; no auto-merge of dependency PRs.

Doc upkeep: this page is the operating manual. Agents editing the system update storefront-docs/index.html in the same PR as the change; merging to main auto-redeploys the docs site.

9 · What comes next (after a healthy launch)

The reason for all of this. Once v2 is stable, the site becomes a platform we can compound on:

  • PostHog: product analytics, session replay, feature flags and experiments in one tool we own. Replaces Clarity (and Visually's role) with something agents can query and act on directly.
  • CRO agents: agents watching funnels and session data, proposing changes with evidence, shipping them as A/B experiments through the same staging pipeline, and reporting lift.
  • A/B testing: PostHog feature flags on v2 routes; every experiment is a branch + a flag, evaluated against real conversion data.
  • Custom apps: subscriptions done our way, bundles, loyalty, quiz funnels: anything the app store used to gate, built natively on our own storefront.
  • Content system: the most-edited content moved to metafields/metaobjects so the team edits in Shopify admin and v2 renders it live: GemPages' convenience without GemPages.

Each of these gets its own plan when its time comes. None of them start before the 48-hour watch closes green.

10 · Glossary

HydrogenShopify's framework for building fully custom storefronts in code.
OxygenShopify's hosting for Hydrogen storefronts. Where v2 runs. Included with our plan.
HeadlessThe site's front (what customers see) is separate from Shopify's back (products, orders). v2 is headless; v1 is not.
Storefront APIHow v2 reads products, prices, cart and content from Shopify, live.
StagingA private, exact copy of the production site where changes are tested and approved first.
DeployPublishing a version of the site's code. Every deploy is kept and can be returned to.
Pixel / tagA small piece of tracking code a marketing tool asks us to run on the site (Google, Meta, TikTok, Klaviyo, etc.).
CSPContent-Security-Policy: v2's allowlist of which outside scripts may run. Blocks anything we didn't approve.
Selling planShopify's native way of describing a subscription. Our current subscription app (Bold) doesn't use it, which is why subscriptions are a Game Day decision.
CutoverThe moment the domain switches from the old site to the new one. The actual "Game Day".
RollbackSwitching back to the old site (or the previous deploy). Minutes, practiced, shame-free.
BranchA separate working copy of the site's code where a change is built without touching what's live.
PR (pull request)A request to bring a branch's change into staging or production, reviewed and approved by a person before it merges.
MergeAccepting a change into a branch. "Merge staging into production" = release the approved changes.
TagA permanent bookmark on a version of the code. Our archive/ tags preserve the old builds forever.
CIContinuous integration: the automation that tests and deploys a branch automatically when it changes.
DNSThe internet's address book, pointing theherbalist.co.za at a server. Game Day does not touch it: the domain already points at Shopify and stays there.
For agents. Canonical source of this document: storefront-docs/index.html in the harness repo (The-Herbalist-SA/the-herbalist-growth-harness, committed 21 Aug). Treat section 4's stack list and section 5's checklist as state: update them in the same PR as the work they describe, keep verification dates current, and republish the artifact after merge. The three audits in audits/ hold the file:line evidence behind every claim here. Do not mark a checklist item done without a verification method actually run. Hosting: the public site is herbie.storefront.catalystlabs.co.za on Vercel, auto-deployed from the harness repo exactly like the Greenhouse: edit this file, commit, push to main, and Vercel rebuilds the live site by itself (its build runs python3 build.py, which prepends the doctype the artifact wrapper normally supplies, and serves deploy/). No manual deploy step.