Skip to content

Case study · Built by Brian Gonzalez

Taking a one‑teacher yoga school off manual work.

A client engagement with a yoga teacher in Rishikesh. Four systems that now run without anyone at a keyboard, the places where a person deliberately stays in the loop, what broke once they ran unattended, and the membership platform they feed.

One click, no card, no email. Opens the full library for a day.

31

class write-ups drafted from their own transcripts

18×

smaller per class, 4.0GB to 220MB

$0.015

to draft each class's notes

15

teachers listed across 6 countries

38

days of TikTok posts scheduled from 326 ranked reels

13 / 13

lifecycle checks passing on production

The client

Parveen Nair teaches embodied yoga from Rishikesh to a paying audience on Patreon, with a small volunteer team. Every weekly class meant pulling a 4GB file off the camera, compressing it, writing a title and description, numbering it into the right series, uploading it and telling the team. Teachers asking to join the directory arrived by email. Social posting was by hand. None of it was difficult; all of it was recurring, and it competed with teaching.

What runs on its own now

The class pipeline

Starts when
A recording lands in a Google Drive folder.
Does
Runs every hour on GitHub Actions. Pulls the file through the Drive API, compresses it with ffmpeg, transcribes it with Whisper, and has Claude draft the title, focus and sequence from what was said. Works out the next number in the series, files it, attaches the description, and emails the team.
Human
A person posts the drafted class to Patreon from the email.
Costs
About $0.015 a class to draft, a few pence to transcribe.

The teacher directory

Starts when
A teacher applies through a form on the client's site.
Does
Screens each application for profanity, spam patterns, missing training dates and daily volume, then emails one reviewer signed approve and decline links. Approving commits the teacher's entry and photograph to the site's repository and the site rebuilds.
Human
One click from the reviewer, because it publishes a stranger's details on the client's site.
Costs
Free tier throughout.

Social distribution

Starts when
A one-off run, then a schedule.
Does
Ranked 326 Instagram reels by views, captioned the strongest 38 and scheduled them as a 38-day TikTok run through Publer's API, then rebuilt the run for YouTube Shorts alongside five free full-length classes described from their own transcripts.
Human
None once scheduled.
Costs
The client's existing Publer plan.

Kula, the platform

Starts when
A member joins a school.
Does
Schools get their own page, price and colour. Members subscribe through Stripe, video is authorized on every request, membership is written only by Stripe's signed webhook, and members can search the library by what was said in each class.
Human
None. A browser coming back from checkout is never trusted on its own.
Costs
Cloudflare free tiers, including Workers AI; Stripe's fee per payment.

Where a person stays in the loop

The rule is that autonomy follows reversibility. Filing a class is private and easy to undo, so nobody checks it. Publishing a stranger's photograph and biography on the client's site is public and hard to take back, so it waits for one click from one person. Posting to the paying audience waits for a person too. Payment is the strictest: the only thing that can grant a membership is an event signed by Stripe, because a browser arriving at a success page proves it came back, not that anyone paid.

What broke once it ran unattended

Connecting the services was the easy part. The work was in the failures that only appear when nobody is watching, and each one got a guard rather than a patch.

What happenedWhyWhat changed
Uploads failed with a storage quota errorGoogle service accounts have no storage quota, so the robot could read the Drive and make folders but not write a single file.Replace the contents of an existing file instead of creating one. Ownership never changes, so the quota never applies. It removed a second storage service from the design.
Compression quietly did nothingGoogle Drive reports a file's full size before it has downloaded any of it, so the file looked ready when it was not.Wait for readable bytes, not for the size to look right.
Three scheduled runs died on their last lineMoving from a Mac to a Linux runner left a macOS-only notification command behind. The failure was in the part that reports failures, so nothing said so.Announcing is now non-fatal, and anything stuck for six hours raises its own alert.
Runs broke halfway when the laptop lost wifiThe first version ran on a laptop.Check Google and Anthropic are both reachable before starting, then move the whole job to GitHub Actions so no laptop is involved.
Email sending returned 403, which read like a bad keyThe email provider sits behind Cloudflare, which rejects requests with no User-Agent.Send one. It is a one-line fix that took the longest to find.
The contact form had never sent a messageThe form service's free tier refuses server-side calls, and it had been failing since launch.Replaced with direct sending through Resend on a verified domain.

Why build Kula

Patreon keeps around a tenth of every payment before processing fees, owns the viewing experience, and has no way to represent a school with several teachers. Kula is the alternative: each school lives at its own address with its own price and colour, members subscribe to a school rather than to a platform, and a membership at one school opens nothing at another. Video streams through the server rather than from a shareable link, so access is checked on every request, including every time someone skips ahead.

It is checked the way it would be in production. A script walks the whole membership lifecycle against the live site through real systems: a real checkout session, a real test subscription, a webhook that rejects a forged signature and accepts a real one, a real sign-in email read back from the mail provider, the paid class streaming for the member and refused for a stranger, then a cancellation that Stripe itself signs and delivers, revoking access. All 13 checks pass. Stripe's hosted checkout was also driven by hand with the test card to confirm the payer comes back signed in.

Ask the library

Members can describe what they want to practise in their own words, such as humming bee breath, or tight hips from sitting all day, and get the three classes that fit best. Each class is cut into passages, its notes plus overlapping windows of what the teacher said in the recording, 634 in all, embedded with Workers AI into a Vectorize index. The best passage per class decides the ranking. A small model then writes one line per class on why it fits, using only that class's notes and the passage that matched.

The model explains a ranking it did not make, so a weak sentence costs a sentence, not a wrong class. Its output is tidied in code rather than trusted to the prompt. Transcripts never leave the server whole: members see a 28-word snippet of the passage that matched, visitors see none. And a daily ceiling counted in the database bounds what a public demo can spend on models, whatever the account's plan.

How I work

I direct coding agents rather than typing most of the code myself. Here that was Claude Code, with me owning the client conversations, the architecture, which failures were worth a guard, and the call on every trade-off. The working rule is that nothing is done until it has been checked against the running system, which is why the figures on this page are measured rather than estimated.

See it

The client's siteWhere the teacher directory and contact form live.

31 real classes with their real titles and notes. Video in this demo is short excerpts, and payments run in Stripe test mode.