Deep dive2026
Chalk logo

Chalk

Turn any lecture into chapters, notes, and quizzes you can actually study from.

Role
Solo: product, full-stack and AI pipeline

Chalk is an AI lecture-capture tool. Record a class live, upload a file, or paste a YouTube link, and it hands back a clickable table of contents, study notes, per-chapter quizzes, and a tutor you can ask questions. Under the hood it is a serverless media pipeline that survives being killed mid-job, which is a fun property to need.

Overview

Chalk is a monorepo with a Next.js 16 web app that carries the entire backend (36 API routes) and an Expo mobile app that is a pure client of it. Storage is Neon serverless Postgres plus Vercel Blob for media, auth is a custom JWT system, billing is Stripe, and the AI work runs on exactly two pinned OpenAI models: whisper-1 for transcription and gpt-4o for everything language-shaped.

The core promise: a two-hour lecture goes in, and a navigable library item comes out, with chapters that jump the video to the right second.

The problem

Lecture recordings are where studying goes to die. A two-hour video with no structure means scrubbing around hoping to spot the whiteboard changing. Notes apps do not know what was said, and transcription tools give you a wall of text with no map.

Students need the lecture broken into topics, summarized, and quizzable, without doing any of that work themselves. That is a pipeline problem, not a note-taking problem.

The processing pipeline

Every lecture takes one of three doors in. Uploads go straight from the browser to Vercel Blob using short-lived tokens, because serverless request bodies cap out long before video sizes do. Live recordings stream in as segments that get stitched into one file. YouTube links never download video at all: Chalk pulls the video's own caption track and skips transcription entirely, then plays the video through YouTube's embed.

Then the orchestrator takes over: extract mono 16 kHz audio with ffmpeg, transcribe with Whisper, and hand the transcript to gpt-4o to segment into chapters. Processing runs inside Next.js after(), which keeps working after the response is sent, and an atomic database claim stops two instances from processing the same lecture twice.

System map
Web appNext.js 16Mobile appExpo + React NativeVercel Blobclient-direct uploadPipeline orchestratorafter() + claim lockffmpegstatic binaryWhisperwhisper-1gpt-4ochapters, quizzes, tutorYouTube importcaptions onlyNeon Postgresserverless driverStripePro + top-upsCron sweeperdaily + on-load
drag to exploreThree ways in, one pipeline, one library.

Why this stack

Neon's serverless Postgres driver speaks HTTP, which fits functions that appear and vanish constantly. The schema lives in code as a versioned migration array with idempotent DDL, because two racing instances both have to be safe to run the bootstrap. Vercel Blob stores raw media, stitched recordings, exported clips, and thumbnails.

ffmpeg ships as a static binary and gets spawned directly as a CLI, no wrapper library, which means fewer moving parts and no binary-path weirdness on Windows. Auth is deliberately homegrown but small: bcrypt password hashing, HS256 JWTs signed with jose, delivered as an HttpOnly cookie for web and a bearer header for mobile, with a token version claim so plan changes and forced sign-outs propagate within about two minutes.

Fighting the model, politely

Two whole subsystems exist because language models are unreliable narrators. First, timestamps: gpt-4o drifts up to 100 seconds when asked for chapter start times, so Chalk instead asks it to return a verbatim quote from where the chapter begins, then finds that quote in the real transcript to resolve the true time. Second, coverage: the model nondeterministically stops chaptering partway through, so a refill loop re-asks for the uncovered tail up to four times.

Quizzes get a two-pass treatment to kill the AI-quiz smell: a first pass drafts questions in a professor voice with misconception-based wrong answers, then a second pass acts as an exam editor and rewrites anything lazy or guessable. There is also a per-chapter deep dive, a whole-lecture quiz, and an ask-the-video feature that answers free-form questions with clickable timestamp citations.

One lecture, end to end

The browser mints an upload token, pushes the video straight to Blob, creates the lecture row, and pokes the process route. The pipeline downloads to temp storage, checks the duration cap, meters the user's transcription minutes, extracts audio, and transcribes. Files over ten minutes are split into chunks that transcribe four at a time, and every finished chunk is checkpointed to the database.

That checkpointing matters because serverless functions get 300 seconds. If a run dies mid-transcription, the sweeper restarts it and it resumes from the saved chunks instead of paying Whisper twice. Lectures over 90 minutes get map-reduce chaptering in 30-minute windows. When segmentation lands, the lecture flips to ready, an overview generates from the chapter outline, and the viewer shows the clickable TOC.

Security, quotas, and money

Ownership checks live server-side in every route, including anonymous demo lectures that are scoped to a per-browser id. Admin routes sit behind a role gate. Rate limiting is a fixed-window limiter in Postgres that fails open on database trouble, backed by hard ceilings: 2 GB uploads, 4 hour media, 30 minute caps for anonymous users.

Whisper is the expensive step, so it is metered like a utility: free accounts get 300 transcription minutes a month, Pro gets 1500, and top-up packs exist for heavy semesters. Charging is idempotent per lecture, so retries never double-bill. Stripe handles the Pro subscription and one-time credit purchases through a signature-verified webhook that is the only code allowed to grant Pro.

Challenges and honest tradeoffs

The 300-second function ceiling shaped almost everything: the after() processing model, per-chunk checkpoints, claim locks with timeouts, and a daily cron sweeper that revives anything silent for six minutes and gives up after three attempts. There is no queue service because the checkpoints plus the sweeper turned out to be enough, and that is one less thing to run.

YouTube added its own drama by bot-checking datacenter IPs, so the importer requests captions the way a phone would, and the mobile app can even fetch captions client-side on its residential IP and hand them to the server. Chalk also has strong opinions about prose: every model response is banned from using em dashes, enforced in the prompt and then scrubbed with a regex, belt and suspenders. Raw transcripts are exempt because those are the speaker's words, not ours.

Outcomes

Chalk runs in production on Vercel with the web app and a native mobile client sharing one backend. Three intake paths, a crash-tolerant pipeline, metered billing, and a study toolkit on top: chapters, notes, quizzes, deep dives, clip export, and ask-the-video.

The pipeline holds up on real inputs: four-hour lectures chunk, checkpoint, and chapter without babysitting, and the accounting stays correct even when the platform kills the process mid-job.

Built with
Next.js 16React 19TypeScriptOpenAI (whisper-1 + gpt-4o)Neon PostgresVercel BlobffmpegStripeExpoTailwind v4
At a glance
36
API routes in one backend
3
Ways in: record, upload, YouTube
4 hr
Max lecture length, chunked and checkpointed
2
Pinned models doing all the AI work

Want to see more?

Explore the rest of my work, or get in touch about a project.