diff --git a/.github/workflows/validate-pr-base.yml b/.github/workflows/validate-pr-base.yml new file mode 100644 index 00000000..e903e15d --- /dev/null +++ b/.github/workflows/validate-pr-base.yml @@ -0,0 +1,30 @@ +name: Validate PR base + +on: + pull_request: + types: [opened, edited, reopened, synchronize, ready_for_review] + +permissions: + contents: read + +jobs: + validate-pr-base: + runs-on: ubuntu-latest + steps: + - name: Require staging base + env: + BASE_REF: ${{ github.base_ref }} + HEAD_REF: ${{ github.head_ref }} + run: | + if [ "$BASE_REF" = "staging" ]; then + exit 0 + fi + + if [ "$BASE_REF" = "main" ] && [ "$HEAD_REF" = "staging" ]; then + exit 0 + fi + + echo "PRs must target staging. Promotion PRs from staging to main are allowed." + echo "Current base: $BASE_REF" + echo "Current head: $HEAD_REF" + exit 1 diff --git a/use-case-library-site/Dockerfile b/use-case-library-site/Dockerfile index 67b4f18a..e74b46e9 100755 --- a/use-case-library-site/Dockerfile +++ b/use-case-library-site/Dockerfile @@ -43,7 +43,7 @@ COPY --from=builder /app/bundle ./ RUN mkdir -p /data # Smoke check that the runtime layout is correct before container starts taking traffic. -RUN node -e "require('node:fs').accessSync('./dist/index.js'); require('node:fs').accessSync('./dist/one-pager.html'); require('node:fs').accessSync('./public/index.html')" +RUN node -e "require('node:fs').accessSync('./dist/index.js'); require('node:fs').accessSync('./dist/one-pager.html'); require('node:fs').accessSync('./dist/ai-training-club-marketers-growth.html'); require('node:fs').accessSync('./public/index.html')" HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ CMD wget -qO- "http://127.0.0.1:${PORT}/api/health" >/dev/null || exit 1 diff --git a/use-case-library-site/frontend/public/atc-growth/bg-header.jpg b/use-case-library-site/frontend/public/atc-growth/bg-header.jpg new file mode 100755 index 00000000..18f08f11 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/bg-header.jpg differ diff --git a/use-case-library-site/frontend/public/atc-growth/favicon.svg b/use-case-library-site/frontend/public/atc-growth/favicon.svg new file mode 100755 index 00000000..05d60c8f --- /dev/null +++ b/use-case-library-site/frontend/public/atc-growth/favicon.svg @@ -0,0 +1 @@ + diff --git a/use-case-library-site/frontend/public/atc-growth/motion-presents-black.png b/use-case-library-site/frontend/public/atc-growth/motion-presents-black.png new file mode 100755 index 00000000..9109ab9d Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/motion-presents-black.png differ diff --git a/use-case-library-site/frontend/public/atc-growth/prize-card.png b/use-case-library-site/frontend/public/atc-growth/prize-card.png new file mode 100755 index 00000000..8ca2ec16 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/prize-card.png differ diff --git a/use-case-library-site/frontend/public/atc-growth/runneth-wordmark-white.svg b/use-case-library-site/frontend/public/atc-growth/runneth-wordmark-white.svg new file mode 100755 index 00000000..e6adbc77 --- /dev/null +++ b/use-case-library-site/frontend/public/atc-growth/runneth-wordmark-white.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/use-case-library-site/frontend/public/atc-growth/semicircle-stripes.png b/use-case-library-site/frontend/public/atc-growth/semicircle-stripes.png new file mode 100755 index 00000000..b25981a2 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/semicircle-stripes.png differ diff --git a/use-case-library-site/frontend/public/atc-growth/slack-shot.png b/use-case-library-site/frontend/public/atc-growth/slack-shot.png new file mode 100755 index 00000000..79314fa3 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/slack-shot.png differ diff --git a/use-case-library-site/frontend/public/atc-growth/spk-alysha.jpg b/use-case-library-site/frontend/public/atc-growth/spk-alysha.jpg new file mode 100755 index 00000000..05406a08 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/spk-alysha.jpg differ diff --git a/use-case-library-site/frontend/public/atc-growth/spk-evan.jpg b/use-case-library-site/frontend/public/atc-growth/spk-evan.jpg new file mode 100755 index 00000000..3c3c82e5 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/spk-evan.jpg differ diff --git a/use-case-library-site/frontend/public/atc-growth/spk-jose.jpg b/use-case-library-site/frontend/public/atc-growth/spk-jose.jpg new file mode 100755 index 00000000..6f393e17 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/spk-jose.jpg differ diff --git a/use-case-library-site/frontend/public/atc-growth/spk-rabia.jpg b/use-case-library-site/frontend/public/atc-growth/spk-rabia.jpg new file mode 100755 index 00000000..eef552dd Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/spk-rabia.jpg differ diff --git a/use-case-library-site/frontend/public/atc-growth/title-lockup.png b/use-case-library-site/frontend/public/atc-growth/title-lockup.png new file mode 100755 index 00000000..0b86abe8 Binary files /dev/null and b/use-case-library-site/frontend/public/atc-growth/title-lockup.png differ diff --git a/use-case-library-site/server/package.json b/use-case-library-site/server/package.json index 1b26a774..94a4d136 100755 --- a/use-case-library-site/server/package.json +++ b/use-case-library-site/server/package.json @@ -5,7 +5,7 @@ "type": "module", "main": "dist/index.js", "scripts": { - "build": "tsc -p tsconfig.json && cp src/one-pager.html dist/one-pager.html && cp src/how-to-build-the-brain.html dist/how-to-build-the-brain.html && cp src/how-to-prompt-masterfully.html dist/how-to-prompt-masterfully.html", + "build": "tsc -p tsconfig.json && cp src/one-pager.html dist/one-pager.html && cp src/how-to-build-the-brain.html dist/how-to-build-the-brain.html && cp src/how-to-prompt-masterfully.html dist/how-to-prompt-masterfully.html && cp src/ai-training-club-marketers-growth.html dist/ai-training-club-marketers-growth.html", "start": "node dist/index.js", "dev": "tsc -p tsconfig.json --watch & node --watch dist/index.js" }, diff --git a/use-case-library-site/server/src/ai-training-club-marketers-growth.html b/use-case-library-site/server/src/ai-training-club-marketers-growth.html new file mode 100644 index 00000000..7188d6f2 --- /dev/null +++ b/use-case-library-site/server/src/ai-training-club-marketers-growth.html @@ -0,0 +1,488 @@ + + + + + + + + AI Training Club For Marketers | Runneth + + + + + + + +
+ +
+
+ + AI Training Club, For Marketers +

A free 5-week program where you actually build AI into your marketing work, one 10-minute lesson at a time.

+
+
10 minutes
One short, hands-on lesson every week. Watchable on your phone.
+
weekly coaching calls
A live group coaching call every week to ask your specific questions and go deeper.
+
$0
Free to sign up. No catch. Slack community and prizes included.
+
+ Save my free spot +

Starts August 4th at 1PM EST. Free & virtual event.

+
+
+
+ + +
+
+

Five weeks. Five real skills you'll actually walk away with.

+

No concepts explained and forgotten. Each session ends with a tangible deliverable built on your own work.

+
+
+ 1Conduct a review audit +
+
Topic
Run a gap analysis on your own customer reviews to surface winning ad angles.
+
Takeaway
You leave with a working "analyst" that reads your reviews and hands you angles.
+
In your work
Stop guessing at messaging. Pull proven angles straight from what customers already tell you.
+
+
+
+ 2Get AI to script in your own voice +
+
Topic
The AI-scripting myth, busted. Good scripts come from iteration and voice training, not one magic prompt.
+
Takeaway
A voice doc and a workflow that writes scripts that actually sound like you.
+
In your work
Turn around on-brand scripts in minutes instead of starting from a blank page.
+
+
+
+ 3Build the ultimate creator report +
+
Topic
Analyze which creators are working and why, by audience segment, format, product, and pain point.
+
Takeaway
A clear read on which creators to double down on, delivered as a simple write-up you can act on.
+
In your work
Spend your creator budget on the ones actually driving results.
+
+
+
+ 4Get AI to QA your creative for you +
+
Topic
Train AI to evaluate and QA creative, using a video use case, so it catches issues the way you would.
+
Takeaway
A real feel for what it means to train AI, plus a QA pass you can reuse.
+
In your work
Catch problems before creative ships, not after it flops.
+
+
+
+ 5Launch your ads from Slack +
+
Topic
Start from a ready asset and apply a naming convention in an instant, then launch the ad using AI.
+
Takeaway
A clean, repeatable naming and launch process you can run every time.
+
In your work
Ship organized, trackable ads without the manual mess.
+
+
+
+
+
+ + +
+
+

Train with the best minds in the industry.

+

The people teaching each week have built this for a living, and they'll be right there in the community with you.

+
+
+ Alysha Boehm +
Alysha Boehm
+
Creative Strategist at Motion
+

Alysha is working in the frontier of AI-native creative strategy and will teach the most up-to-date techniques for orchestrating ad production at speeds that were impossible to imagine even six months ago.

+
+
+ Evan Lee +
Evan Lee
+
Head of Partnerships at Motion
+

Evan has worked with hundreds of our best customers at Motion and led countless events, livestreams, and training sessions. Evan will be teaching sessions and cheering you on in our private community.

+
+
+ Jose Garcia +
Jose Garcia
+
Creative Strategist at Motion
+

Jose has spent years helping brands and agencies turn creative into measurable ROAS, first on the paid social and creator side at Insense, a TikTok and Meta partner, and now at Motion.

+
+
+ Rabia Sohail +
Rabia Sohail
+
Customer Success Manager at Motion
+

Rabia came up through the creator and agency world, running influencer partnerships at Viral Nation and building communities in Toronto before joining Motion.

+
+
+
+
+ + +
+
+

Built for the people too buried in the work to go all in on AI.

+

You're not behind on AI because you're bad at it. You're just too busy doing the work.

+
+
+

This is for you if

+
    +
  • You're on a growth or creative performance team and want to level-set your AI skills on real, everyday use cases.
  • +
  • You feel like you're falling behind on AI.
  • +
  • Your boss keeps saying "go use AI" with no roadmap.
  • +
  • You've always wanted to pull off certain AI use cases but never knew how.
  • +
  • You just want to see what "good" looks like in 2026.
  • +
+
+
+

Probably not for you if

+
    +
  • You're already an AI power user who has gone all in.
  • +
  • You want theory and frameworks more than something built.
  • +
  • You're looking for a generic "intro to AI" course.
  • +
+
+
+
+
+ + +
+
+

How each week actually runs

+

Two short touchpoints a week. Designed to fit around your work, not add to it.

+
+
+
Your Tuesday class
+
+
Duration10 minutes, instructional
+
Time1:00PM EST / 10:00AM PST
+
+

We open with the finished product, then walk the roadmap of how to set it up with AI. You'll see exactly what's involved, what actually matters, and how to get to a working setup fast. You leave with real marketing work built.

+
+
+
Your Thursday coaching session
+
+
DurationAs long as vibes are high
+
Time1:00PM EST / 10:00AM PST
+
+

No set length, we just hop on a call and get to work. Our team answers your questions, plus your peers show what they built that week, so you get the push to finish yours. Live coaching and peer-to-peer learning.

+
+
+
+ Watchable on your phone + Slack community support + Prizes along the way +
+
+
+ + +
+
+
+

Get AI-fluent in time for BFCM

+

We've timed the club so you're all prepped ahead of Black Friday. Come out the other side with real systems built and running, one 10-minute lesson at a time.

+ Save my free spot +
+
+
+ + +
+
+

Join our Slack community

+
+
    +
  • Join 13,500 creative strategists
  • +
  • Local chapters for LA, NYC, Toronto
  • +
  • Find jobs, ask our coaches, and get peer-to-peer advice
  • +
+ Runneth Slack community threads +
+
+
+ + +
+
+
+
+

Win prizes along the way

+

Show up and build. We're handing out prizes through the series for the people putting the lessons into practice. Turn up each week, ship the deliverable, and you're in the running.

+
+ AI Training Club prize card +
+
+
+ + +
+
+

Sick of hearing about AI? Come actually build with it.

+
+
+ +
+ + +
+
+ + + + diff --git a/use-case-library-site/server/src/index.ts b/use-case-library-site/server/src/index.ts index 7978f296..465abde6 100755 --- a/use-case-library-site/server/src/index.ts +++ b/use-case-library-site/server/src/index.ts @@ -70,6 +70,7 @@ const PUBLIC_DIR = resolve(__dirname, '..', 'public') const ONE_PAGER_HTML = readFileSync(resolve(__dirname, 'one-pager.html'), 'utf-8') const HOW_TO_BUILD_THE_BRAIN_HTML = readFileSync(resolve(__dirname, 'how-to-build-the-brain.html'), 'utf-8') const HOW_TO_PROMPT_HTML = readFileSync(resolve(__dirname, 'how-to-prompt-masterfully.html'), 'utf-8') +const ATC_GROWTH_HTML = readFileSync(resolve(__dirname, 'ai-training-club-marketers-growth.html'), 'utf-8') const server = Fastify({ logger: { level: process.env.LOG_LEVEL ?? 'info' } }) @@ -434,6 +435,16 @@ server.get('/how-to-prompt-masterfully/', async (_, reply) => { reply.header('cache-control', 'public, max-age=300') return HOW_TO_PROMPT_HTML }) +server.get('/ai-training-club-marketers-growth', async (_, reply) => { + reply.header('content-type', 'text/html; charset=utf-8') + reply.header('cache-control', 'public, max-age=300') + return ATC_GROWTH_HTML +}) +server.get('/ai-training-club-marketers-growth/', async (_, reply) => { + reply.header('content-type', 'text/html; charset=utf-8') + reply.header('cache-control', 'public, max-age=300') + return ATC_GROWTH_HTML +}) // CSM roster — used to validate path params on /how-to-build-the-brain/:csm // and to render the dashboard tabs. Keep alphabetical. const CSM_ROSTER = ['ale', 'aoife', 'carissa', 'josh', 'krishna', 'quinn', 'rabia', 'sophia'] as const