Beyond Vibe Coding

Workshop

Beyond Vibe Coding

From prototyping to shipping like an engineer

Chris Parsons

QR code for this deck: chrismdp.com/workshop/beyond-vibe-coding/v2Scan for the slides and prompts
chrismdp.com/workshop/beyond-vibe-coding/v2
Before the start · Welcome

Welcome to the workshop.

If you have not started your setup yet, start it now. The next slide has the five checks. Tell me if anything gets stuck.

Today you learn to think like a CTO. You can build a working prototype in an afternoon, but shipping it is a different problem. We set up the foundations that engineers rely on first: source control, deployment, tests, checks and rules for the agent. With those in place, the AI becomes a more reliable partner, and you leave with a real app you can keep building.

The agent writes all the code. You decide what to build and check that it works. Ask questions the whole way through.

Before you start: check your setup

  • A terminal. Mac: Terminal. Windows: the Ubuntu window from wsl --install. Do every step below inside it.
  • Node.js. Run node --version. It prints a version number.
  • GitHub. Run gh auth status. It says you are logged in.
  • Vercel. You can sign in at vercel.com with GitHub. The free Hobby plan is for personal projects. At work, use your company's team plan.
  • Your agent. Start Claude Code or Codex in an empty folder. Ask "What folder am I in?" It answers correctly.
QR code for this deck: chrismdp.com/workshop/beyond-vibe-coding/v2

Follow along and copy the prompts

chrismdp.com/workshop/beyond-vibe-coding/v2

Arrived late? Sit with someone who's set up and pair with them. You'll catch up faster than installing now.

Venue Wi-Fi
Network: 
Password: 

Setup guide: chrismdp.com/workshop/beyond-vibe-coding/v2/setup-guide.html

Something not working? Tell me now, before we start. If it cannot be fixed in time, you pair with someone at your table.

Before the start · on screen while people arrive

Leave this slide up by the door. Show the venue Wi-Fi details while people connect (set them in the event settings at the top of this file). These are the five checks from the setup guide. Walk the room and ask each table: did all five pass? Anyone stuck on a work laptop that blocks installs, or on an agent account with command-line access turned off, pairs now. Anyone who arrives late pairs too: sitting with someone who is set up beats installing mid-session. Pairing is part of the plan. When we start, move on to the show of hands.

What did you try before today?

What I say
  1. Did you build with Lovable, v0, Bolt or Cursor?
  2. Did you run Claude Code or Codex in a terminal?
  3. Did you use your GitHub account more than once?
  4. Did you make a commit and watch a build run?
  5. Did you work on your team's code, beyond side projects?
  6. Did you release software for other people?
  7. Did you release software for paying customers?
  8. Did you use Vercel before today?

Keep your hand up for each question that fits. If you shipped software for paying customers, can you help your table today? If you already know commits and builds, we can spend longer on deployment. If the terminal is new to you, I will talk through the first prompt.

The terminal is awesome

Three commands, then the agent does the rest.

Start here
mkdir lighthouse
cd lighthouse
claude

Using Codex? Type codex instead of claude. Windows: do this inside the Ubuntu window.

What I say

The terminal is the window where you run commands. Open Claude Code or Codex there. If your setup is unfinished, work with someone next to you.

Different types of coding agents

Claude chat or ChatGPT

Can now build a small site that stores data, such as a Claude artifact. It lives inside the chat product, not on your machine or in your repo.

Claude Cowork and other desktop agents

Halfway. Works on files on your computer, but with fewer tools and less control.

Claude Code or Codex in the terminal

The most tools and the most control. Edits files and installs software on your machine. Runs commands and reads the results.

Use Claude Code or Codex for every step today.

What I say

Use the terminal agent today: it has the most tools and gives you the most control. Chat tools can now build small sites that store data, such as Claude artifacts, and ChatGPT has its own equivalents. They are great for a quick tool, but the result lives inside the chat product, not on your machine or in a repo you own. Desktop agents like Cowork sit halfway: they work on local files, with a limited set of tools. Today the agent must run a command and read the result. When a test fails, it can read the error and change the code. Keep the terminal open so you can see that happen.

Check what the agent gives you

  • Give the agent one instruction at a time.
  • Look for the check after each step.
  • If you get stuck, work with someone next to you.
  • Ask questions all the way through, of me and of the agent. It can explain any line it wrote.
When the agent asks permission
  • It asks before it edits a file or runs a command.
  • Editing files inside your project folder: fine, accept.
  • Claude Code's auto mode checks each command before it runs, so you see fewer prompts.
  • Anything with sudo runs as admin. Ask me, or the person next to you, before you say yes.
Today's game
Build a text adventure in a lighthouse. Put four rooms on a 2×2 grid. Move with the arrow keys. Each room describes the view and the exits.
You can use your own idea if it follows these rules.
What I say

You can copy each prompt from this page. After the agent finishes, look for the check beside it. If the result differs, tell me. In our game, you can judge the movement by playing it.

Permissions. The agent will stop and ask before it edits a file or runs a command. Accepting file edits inside the project folder is fine. In Claude Code, auto mode checks each command before running it, which cuts the prompts a lot. The one to stop at is sudo: it runs the command as admin on your machine. If you see sudo, put your hand up or ask your neighbour before you say yes.

The practices you will leave with

Each one is something a CTO sets up on day one. Today you set them up yourself, in this order.

1 · Outside inPrototype first. The screen, then the behaviour, then the code.
2 · Source controlEvery change is a save point. Small commits, often.
3 · Automatic deploymentPush to main and it is live. Set up before it matters.
4 · A real app, same railsNext.js and TypeScript inside the pipeline you already have.
5 · Tests and buildsSay what true looks like first. A broken change never ships.
6 · Types and lintingChecks on every line that you did not have to write.
7 · Rules for the agentAGENTS.md carries the standards between sessions.
8 · More featuresPlan, design, test, check, push.
9 · A databaseData that lives outside the browser. For tables that finish early.

On the way: secrets stay out of the code and out of the chat, a bad deploy is one revert away, and you learn when to bring in an engineer.

A break after step 3.

What I say

Do not explain them here. Each gets its own slide after you have done it. Say only: these are the nine steps, you will get through as many as you can, the rest stay on these slides, and none of them needs you to write code.

Step 1

Outside in

Prototype first. The screen, then the behaviour, then the code.

Make a game you can play

Copy to the agent
Create one index.html file for a tiny text adventure set in a lighthouse. Use four rooms on a 2×2 grid. Put the Spiral Stair at the top left and the Lamp Room at the top right. Put the Keeper's Kitchen at the bottom left and the Rocks at the bottom right. Start the player on the Rocks. Show the current room name. Describe what the player can see in two sentences. Show which directions the player can go. Use the arrow keys to move the player. If a direction is blocked, show a short message that says why. Use plain HTML and CSS. Write the game logic in TypeScript and compile it with tsc to a JavaScript file that the page loads. No frameworks. When the page is ready, run the build and open it in my browser.
Check: the page opens. Arrows move you. Walls show a message.

Talk, do not type. Dictate your changes with Wispr Flow, Superwhisper or your computer's own dictation. You say more than you would type, and the agent gets more to work with.

Try these changes, one at a time
Draw an illustration for each room as inline SVG, all in one hand-drawn style, and show it above the description.
(Using Codex? Try first: Generate a real image for each room and show it above the description. If it says it cannot, use the SVG line.)
Give each room a different colour and mood.
Add a small map that marks my room.
Make the rooms fade as I move between them.

Each time, add: Do not make it a full app yet. Keep it a small prototype with no framework, as a reference for the proper app.
After the check

Claude Code cannot generate real images, so its illustrations are SVG drawings. Codex can sometimes make one. If a table gets a real image, show the room. Remind them to dictate their changes with Wispr Flow, Superwhisper or built-in dictation. Speaking gives the agent more detail than typing. Play it before you ask for another change. Does the room name match the map? Does the movement make sense? Give the agent a design change and look again. Leaving it as a design experiment counts as a success. Today we will keep going and put this game online.

Look at what it made

Open the folder. Pick your computer:

Mac
open .
Windows, in Ubuntu
explorer.exe .
Linux
xdg-open .

In Claude Code, put ! in front to run it from the agent's tab. Or tell the agent: "Open this folder for me."

  • index.html: the page. What the browser shows.
  • game.ts: the game logic, in TypeScript. This is the file you can read.
  • dist/game.js: the same logic, compiled for the browser. Never edit this one.
  • package.json and tsconfig.json: the project's name, its build command, its TypeScript settings.
  • node_modules: other people's code the build needs. Do not open it. Do not commit it.
What I say

Walk the folder on the projector. This is a project with several files. One file is the page, one is the logic you described in plain words, one is the compiled copy the browser runs, and two are settings. The agent can pick slightly different names. The files do the same jobs. After the next step a hidden .git folder appears: that is the history.

Step 2

Source control

Every change is a save point.

Sign in to GitHub

  • Create a free account at github.com. Confirm your email.
  • Install gh, the GitHub command. Pick your computer below.
  • Run gh auth login: GitHub.com, HTTPS, Login with a web browser.
  • Check: gh auth status shows that you are signed in.
  • Do this in a new terminal tab (a new Ubuntu tab on Windows). The agent's tab cannot take your typing.
Mac
brew install gh
Windows, in Ubuntu
sudo apt install gh
Linux
sudo apt install gh
Ask the agent for help
Check whether the gh command is signed in to GitHub. If it is not, tell me what to type. Give me one step at a time. Wait for me after each step.
After you sign in
I am signed in to GitHub. Continue.
What I say

If you still need GitHub access, someone at your table can help. The GitHub CLI is the gh command. On Windows, install it inside Ubuntu, the same as Linux. If apt cannot find it, follow the Linux steps at cli.github.com. For gh auth login, choose GitHub.com, HTTPS and Login with a web browser. Copy the code into the browser and finish signing in yourself.

Save your first two versions

Copy to the agent
Set up git in this folder. Add a .gitignore for node_modules and dist first. Make the first commit. If git asks who I am, set my name and my GitHub noreply email for this project and try again. Create a public GitHub repo called lighthouse. Push to the repo. Show me the repo URL.
Check: the GitHub repo contains index.html.
Change the room name, then save
Make the room name bigger. Commit the change. Push it.
Check: GitHub shows two commits. Open the first version.
After the check

Git keeps the history of your files. A repo holds those files and their history. A commit is a save point. Push sends your commits to GitHub. Open the first commit and compare it with the second. Small commits help you find the change you want to undo.

The repo is public on purpose, so you can show it to anyone. Nothing secret goes in it. Step 9 shows where secrets live instead.

Try changes you can undo

  • Return to an earlier version after a mistake.
  • Try a design change with a saved version to return to.
  • Share changes with another person or agent.
  • Read the history to see what changed and why.
What I say

Tools such as Lovable can make commits for you. Open the history yourself and see what each commit changed. Ask the agent for small commits. If a design change makes things worse, you can find it and return to the earlier version.

You do not need to learn git

You need to know what git can do, not how to type it. Ask in plain words, and ask the agent to confirm before it changes anything.

Ask the agent
Show me the last 10 changes, in plain English.
Ask the agent
What changed between the last two versions?
Ask the agent
Undo the change from three changes ago. Tell me what you will do and wait for me to confirm.
Ask the agent
Take the game back to how it looked an hour ago. Confirm before you do it.
Ask the agent
Try this idea on a separate branch, so I can throw it away if I do not like it.
What I say

Try one now: ask for the last 10 changes. Then try the undo, and watch it ask you first. Git has a lot of commands, and you do not need any of them. The agent knows them all. Your job is to know that every version is saved, that any change can be undone, and to ask for a confirmation before anything is thrown away.

Step 3

Automatic deployment

Push to main and it is live. Set it up before it matters.

Connect Vercel to GitHub

First, copy to the agent
Get this project ready to deploy on Vercel. I will connect Vercel to this GitHub repo, and Vercel will run npm run build on every push to main. Make sure npm run build compiles the TypeScript, and that Vercel serves the page and the compiled game from the right folder. Add a vercel.json only if Vercel needs one. Run the build here to check it works. Commit the change. Push it.
Check: GitHub shows the new commit.
  • Sign in at vercel.com with Continue with GitHub. Pick the free Hobby plan.
  • Choose Add NewProject.
  • Find your lighthouse repo and press Import. Not listed? Install the Vercel app on GitHub when it asks, and give it access to lighthouse.
  • Leave the settings as they are. Press Deploy.
What I say

This is the only setup step in the browser, and you do it once. Vercel's GitHub app watches your repo. After that, every push to main builds and deploys to production. There is no token to copy and no secret to store. The agent prepares the build first, so the first deploy works.

Hobby is free and needs no card, but it is for personal, non-commercial projects. At work, use your company's team plan. If GitHub asks which repos Vercel can see, choosing only lighthouse is fine. If the first build fails, open the build log on Vercel, copy the error into the agent and ask it to fix and push.

Put the game on your phone

Check: Vercel says Ready and shows a .vercel.app address under Domains. It opens on your phone.
Check: on GitHub, your latest commit has a green tick from Vercel.
Change the live page
Set the page title to "Lighthouse, by [your name]". Commit the change. Push it.
Check: reload your phone. The title changes within a minute.
After the check

Share the short address under Domains on the project page. That is your live URL, and it always points at the latest good deployment. Each deployment also gets its own long address, and those can ask for a Vercel login. That is deployment protection, and it is expected. Use the short one.

Open the live URL on your phone. Your phone loads the app from Vercel. After the title change, reload that same address. On GitHub, click the tick beside the commit: it links to the Vercel deployment. If you finish early, ask the agent to explain what Vercel runs on each push, or add a custom domain.

Deploy while the app is small

  • Each push to main sends the app to Vercel.
  • Set up deployment while the app is small.
  • Use the same setup as the app grows.
  • Share the live URL to show your latest change.
  • This is continuous deployment: shipped on every push. The checks come after the break.
  • No token, no secret: Vercel's GitHub app does the deploy. A bad deploy is one revert away.
What I say

Vercel builds the app and sends it live after each push to main. We set it up while the app is small, when it is easy. After the break, we will add checks to stop a broken change going live.

If the live site shows an error, copy the error, paste it into the agent and ask it to fix it. Then push. The same setup takes the fix live.

Check all three before the break

1Check: your GitHub repo has at least three commits.
2Check: the live .vercel.app URL opens on your phone.
3Check: your last push changed the live page.

If a check is missing, tell me. If all three pass, help the next table.

What I say

Open the repo and the live URL beside each other. If you are stuck connecting Vercel to GitHub, tell me and I will come over. Before we start again, everyone must have these three checks or work with someone who does.

Take a break

Come back for a real app, tests and types.

Step 4

A real app, same rails

Next.js and TypeScript inside the pipeline you already have.

Turn it into a real app

Copy to the agent
Create a new Next.js app in TypeScript with create-next-app. It needs an empty folder, so create it in a new folder first, then move it into this project. Keep the git history. Rebuild the game inside it, using the prototype as the reference. Keep the design unchanged. Vercel runs Next.js natively, but it imported this project as a plain site. So set "framework": "nextjs" in vercel.json, and remove the old build and output settings from it. Run the app locally and open it in my browser. Wait for me to check it. When I say it looks right, commit the changes, push them and give me the live URL.
Check it locally first. That is your preview. Say go only when it looks right.
Check: Next.js serves the same design at the same live URL.
After the check

Use Next.js: it is the framework the agent knows best. The design, the URL and the deployment have not changed, and underneath there is now a Next.js app in TypeScript. That is the scaffold the page promised, done in one prompt because the rails were already there.

Why bother with a real app?

  • It is optional. The prototype game works as it is.
  • Next.js handles a lot of the caching, the routing and the build for you.
  • It gives the app a standard React structure. Not necessarily the best framework, but the one the AI knows best, and the agent is doing the work.
  • When the app gets more complex, or the design work gets serious, the agent has a real structure to hang that work off.
  • I prefer it to vibe-coding plain JavaScript apps with no shape to them.

From now on you see every change on your own laptop before it goes live. The local copy is your preview. Nothing reaches the live URL until you say go. Vercel also gives every branch you push its own preview URL, so later you can share a change with someone before it goes live.

Why a framework, and why this one

  • Optional. The prototype game works as it is.
  • Next.js does the caching, the routing and the build for you.
  • It is the React setup the agent knows best, and that matters more than which framework is best.
  • When the app grows, or the design work gets serious, it gives the agent a structure to hang the work on.
  • Better than a pile of vibe-coded JavaScript.
  • Some choices are hard to undo: the framework, the database, sign-in, the shape of your data. Take your time on those. Change the rest freely.
What I say

Use Next.js: it is the framework the agent knows best, and that matters more than which framework is best. Strictly optional, but useful. Next.js handles a whole bunch of static caching for you. It builds a standard React structure into your app. Not necessarily the best framework, but the one the AI knows best, and that is what matters when the agent is doing the work. When you make something much more complex, or want to do a lot of design work, it gives the agent a real structure to hang that work off. I prefer this to vibe-coding plain JavaScript apps with no shape to them.

Step 5

Tests and builds

Say what true looks like first. A broken change never ships.

Test the locked door first

Copy to the agent
Add this rule: the Lamp Room door stays locked until the player visits the Keeper's Kitchen. Put the room-movement rules in a plain function that does not need a browser. First, write a failing test for this behaviour. At the start, pressing up from the Rocks must leave the player on the Rocks. The message must be "The lamp room door is locked." After visiting the Keeper's Kitchen, pressing up from the Rocks must take the player into the Lamp Room. Run the test. Show me that it fails. Then change the code to make it pass.
Check: the test fails first, with red output.
Check: the same test passes after the code changes.
Run the tests before every deploy
Make the build run the tests first. Change the build script in package.json so it runs the tests, then builds the app. If a test fails, the build must fail, so Vercel keeps the last good version live. Run the build here to check it. Commit the change. Push it.
Check: open the deployment on Vercel. The build log shows the tests passing before the app builds.
What I say

The game lets you enter the Lamp Room today. Our new rule must fail its first test because we have not added the lock. Read the failure before the agent fixes it. The game must remember a visit to the Keeper's Kitchen. Then the build runs the tests before every deploy. Vercel runs the build on every push, so a failing test fails the build and nothing goes live. Lint and the type check join the build in step 6.

Check behaviour without reading code

  • Write down the behaviour you expect.
  • See the test fail before the agent changes the code.
  • Run the same test after later changes.
  • Stop deployment when a check fails.
What I say

You chose a rule you can check by playing the game. The test checks that rule after later changes too. A green tick proves the rules were followed, and says nothing about the design. You still choose what the game does and whether it is worth keeping. If you need help before shipping, ask an engineer.

Why this is useful: tests matter most for complex checks, where the only other way to know is to read the code. Developers still write them for important step-by-step things like sign-in, and for complex code they could not follow otherwise. They do not bother for trivial or low-risk systems. So match the checks to the risk.

Stop a broken change
going live

This error is planned. It is the input to the next step.

Remove the lock
Change the code so the Lamp Room door never locks. Leave the test unchanged. Commit the change. Push it.
Check: Vercel shows the deployment failed, and the commit on GitHub has a red cross.
Check: reload your phone. The live game still locks the door.
Give the agent the failed build
The Vercel build failed. Run the build here to see the same failure. Restore the lock. Do not change the test. Push the fix.
Check: the commit on GitHub has a green tick, Vercel says Ready, and the fix goes live.
After the check

This error is planned. It is the input to the next step. Open the failed deployment on Vercel and read the build log: the test named the broken rule. Then play the live game. The door must still lock there, because a failed build never replaces the live version. Some machines pass first time and some show a different error. That is normal variation. Read the failure you have before you ask the agent to fix it. You can also paste the Vercel build log straight into the agent.

Some agents refuse to remove the lock, because the instruction contradicts the test. That is a good sign, and it is fine. Tell it: "This is a deliberate demo. Do it anyway."

Step 6

Types and linting

Checks on every line that you did not have to write.

Break the types, then run the linter

Make a type error
Change the move function to take a number for the direction instead of a word. Leave the code that calls it unchanged. Run the type check. Show me the result.
Check: the type check names the error. Then restore the function.
Break the linter, on purpose
Add an unused variable near the top of the game component. Run the linter. Show me what it reports. Then remove the variable, run the linter again and show me it is clean.
Check: the linter names a file and a line. Then it reports nothing.
Add both to the build
Add lint and the type check to the build script, before the tests. If lint, the type check or the tests fail, the build must fail, so nothing goes live. Run the build here to check it. Commit the change. Push it.
Check: the Vercel build log shows lint, the type check and the tests passing before the app builds.
After the check

Just use TypeScript: it is easier for the agent to get right. A type says what kind of value the code expects. Our move function expects a direction word. We changed it to expect a number, but the caller still sends a word. Read the line named by the type check. Then tell the agent: "Restore the move function to take a word for the direction." Lint is the same idea for style and common mistakes: it reads every line, and the agent fixes what it names. Last, both go into the build, next to the tests from step 5. Now one failing check stops the deploy.

Checks you did not write

  • Find mismatched values before deployment.
  • Read the error to find the line that failed.
  • Give the agent the error so it can fix the code.
  • Lint applies your conventions on every line. Nobody reviews style by eye.
What I say

Just use TypeScript: it is easier for the agent to get right. The type check found a mismatch before you played the game. The agent can use that error to find the line and fix it. TypeScript adds checks throughout the code, like tests you did not write. Types cannot tell you whether the door locks at the right time. Your test from step 5 already covers that rule.

Step 7

Rules for the agent

AGENTS.md carries the standards between sessions.

Keep the rules between sessions

Copy to the agent
If this project already has an AGENTS.md, keep what is there and add these rules to it. If not, create one with these rules. Before changing behaviour, write a failing test. Before saying a change is done, run tests, lint and the type check. If a check fails, do not push. Commit after each small change. Ask before adding a library. Before you push, run the app locally and wait for me to check it. Then make sure there is a CLAUDE.md that points at AGENTS.md with the line @AGENTS.md, so Claude Code reads the same rules.
Check: restart the agent. Ask for the rules. It lists your six.
After the check

Close the agent and start a new session. Ask: "Which project rules must you follow?" Listen for all six rules. Many agents, including Codex and Cursor, read AGENTS.md. Claude Code reads CLAUDE.md, so a CLAUDE.md that points at AGENTS.md gives every agent the same rules from one file. The file gives the next session the same instructions. Add rules for choices that the automated checks cannot make.

Step 8

More features

Plan, design, test, check, push.

Build a feature of your own

Before anything
I want to build: ______. Ask me one question at a time until you have enough information to build it. Then tell me your plan. Do not change any code until I say go.
  • Design the screen. Use fixed example data. Change the look first.
  • Test the behaviour. Write a failing test, then change the code.
  • Check it locally. Look at it on your laptop. Change it until it is right.
  • Put it online. Commit and push. Check the live URL.
Choose an idea
Add a fifth room with its own rule.
Pick up a key in the Keeper's Kitchen. Show it in an inventory.
Remember my room when I reload the page.
Redraw the room illustrations in a style you choose. Art-direct the agent.
What I say

Spec first. The agent asks one question at a time, so you answer each in a sentence and nothing gets missed. When it has enough, it tells you the plan. Correct it in plain words, then say go. The answers are the spec, and the design and the test do the rest. Start with the screen: "Add a screen for X. Hard-code the data. Open it in my browser." The hard-coded version will look wrong in places, because the data is fake. That is expected until the behaviour lands. Change the design until it looks right. Then ask: "Write a failing test for X. Change the code to make it pass." Finish with: "Commit the change. Push it." If you finish early, go on to step 9.

Step 9

A database

Data that lives outside the browser. For tables that finish early.

What I say

Optional. If your feature is done and pushed, carry on here. The game's rooms move out of the code and into a Neon Postgres database, added from Vercel.

Move the rooms into a database

Copy to the agent
Move the rooms into the Neon Postgres database I added in Vercel. Link this folder to my lighthouse project with the Vercel CLI, then run vercel env pull so DATABASE_URL is in .env.local. Check that .env.local is in .gitignore. Never print the connection string or put it in the code. Write a migration to create a rooms table and add the four rooms. Store each room's name, description and grid position, and work out the exits from which rooms sit next to each other, so one new row adds a room and its doors. Read the rooms from the database on every request, not once at build time. Keep the movement rules pure so the existing tests still pass. Make the build run the migrations after the checks pass and before it builds the app. Run the migration now. Commit the changes. Push them. Give me the live URL.
  • In Vercel, open your lighthouse project. Choose StorageCreate DatabaseNeon. Pick the free plan and connect it to this project.
  • In a new terminal tab, inside the lighthouse folder, run npx vercel login. Sign in with GitHub. If no browser opens, copy the link it prints.
  • Then give the agent the prompt.
Check: in Vercel, SettingsEnvironment Variables lists DATABASE_URL.
Check: the live URL shows the same four rooms, now loaded from the database.
Check: .env.local is not in your GitHub repo.
Step 9 · optional · What I say

Neon is a Postgres database. Adding it from Vercel's Storage tab needs no card on the free plan. Vercel puts the connection string into the project's environment variables as DATABASE_URL, and vercel env pull copies it to .env.local on your laptop. That file is gitignored, so it never reaches GitHub.

Secrets never go in the code, public repo or private. That is one of the rules of a twelve-factor app, at 12factor.net/config: settings and secrets live in the environment, outside the code. The connection string is a password to your data. It lives in Vercel's settings and in one ignored file on your laptop, never in the repo and never pasted into a chat. That is why a public repo costs you nothing.

Neon stores the room data outside the browser for the first time. Keep movement rules pure: they take values and return results without reading the database. The page must read the rooms on each request; if it reads them at build time, the Cellar will not appear until the next deploy. If it fails, ask the agent to remember your room after a reload instead.

Add a room without deploying

Copy to the agent
Add a fifth room called the Cellar below the Keeper's Kitchen. Use one SQL insert against the database in .env.local. Do not change any code. Do not deploy.
Check: reload the live URL. The Cellar appears without a deployment.
Step 9 · optional · What I say

No code changed and nothing was deployed, but the game has a new room. The rooms are data now, so the world can grow without a release. Your laptop and the live site use the same database here, which is why one insert shows up live.

Change rooms without changing code

  • Keep the room data outside the browser.
  • Show each player the same set of rooms.
  • Add the Cellar with one SQL insert.
  • Change the room data without deploying new code.
What I say

If you tried the database, show us the Cellar at your live URL. A database stores data that the app reads. Neon holds the rooms in a table outside the browser. One SQL insert adds the Cellar to that table. The app reads the extra room without a new deployment. Your position and visited rooms still stay in the browser.

Change the shape with a migration

  • A migration is a small numbered file that changes the database's shape. For example, it adds a table or a column.
  • It lives in git, next to the code.
  • It runs in order, the same on your laptop and on the live site.
  • Your build applies it before each deploy, so the database and the code stay in step.
  • Shape goes through migrations. Content, like the Cellar, can go straight in.
Step 9 · optional · What I say

You wrote a migration in the database prompt: it created the rooms table. Every change to the shape of the database goes the same way. Each one is a new numbered file, committed to git and run by the build before it deploys. Nobody changes the live database's shape by hand, because then your laptop and the live site no longer match. Adding the Cellar was different: that was content, not shape, so one insert was fine.

Data is harder to undo than code

  • Code goes back with one revert. Deleted data does not.
  • A migration that drops a column deletes that data for good.
  • Neon can restore the database to any moment in the last 6 hours on the free plan, and further back on paid plans.
  • For a copy you keep, pg_dump saves a Postgres database to a file. Ask the agent to run it.
  • Store data about people, and you are responsible for it: what you keep, who can see it, how you delete it. That is GDPR.
Step 9 · optional · What I say

Everything today could be undone with git. Data is the exception. Before a migration that removes anything, make a backup: ask the agent to export the database first. Neon also keeps a short history you can restore from, but a restore takes the whole database back, including anything people added since. The bigger line is people. The lighthouse stores rooms. The moment your app stores names, emails or anything about a person, the stakes change, and that is a conversation with an engineer before you ship.

Story: bad data outlasts the outage. On 8 September 2026, a software defect at NATS produced corrupted flight data in a millisecond. The system was back that evening, but more than 2,000 flights were cancelled, and it took airlines over two more days to get planes and crews back in place. The 2023 NATS failure was the same shape: about four hours down, around 1,600 cancellations, 700,000 people affected, and disruption until the weekend. The fix was quick. Clearing up after bad data was not. Bigger version: the TSB banking migration in 2018, where moving customer data to a new system caused problems that ran for months.

A workflow for your next project

  • Prototype the screen as a small page, no framework. Change the look until it is right.
  • Put it in git. Push it to GitHub.
  • Deploy on every push, while the app is small.
  • Make it a typed app. Same workflow, same URL.
  • Write the failing test for the next rule. Make it pass. The build runs tests, lint and types, so only a passing change deploys.
  • Write the project rules in AGENTS.md.
  • Every feature: design, then test, then check it locally, then push.

What the page said you would leave with:

  • A Next.js + TypeScript application built on production-ready foundations
  • A GitHub repository with CI configured
  • Automated testing and linting workflows
  • A reusable AGENTS.md setup
  • A workflow you can immediately apply to future projects

This page stays up at chrismdp.com/workshop/beyond-vibe-coding/v2. Your app is in your GitHub and on your Vercel. chrismdp.com/coding-with-ai has the longer version.

What I say

This list is the workflow. On Monday it is the same for a real product as it was today for a lighthouse. The order matters more than the tools. Next: when to talk to an engineer.

When to talk to an engineer

You can build and ship this far on your own. Bring in an engineer before any of these:

  • Sign-in, or anything where people have accounts.
  • Payments.
  • Storing names, emails or anything else about a person.
  • Other people depend on it staying up.
  • A change to your data that you cannot undo.
  • Costs that grow with use.
  • The agent goes round in circles on the same error.
Bring them
The live URL.
The GitHub repo.
The tests for the behaviour you want.
Name someone to talk to
Before I ship this, I must speak to ______.
What I say

Everything today was safe to try alone: one game, no users, no personal data, and every change could be undone. Real products cross lines where a mistake costs more than a morning. Those are the moments to bring in an engineer. Sign-in is the big one. The moment the app has a login, you hold other people's accounts and you decide who can see what.

You do not arrive empty-handed. A live URL, a repo and tests for the behaviour you want give an engineer something concrete to work with. Write the name of one person you will speak to before you ship.

What you learned

Each one is something a CTO sets up on day one. You set up as many as you reached; the rest are on these slides.

1 · Outside inYou designed the lighthouse as a small prototype before the real app.
2 · Source controlEvery change you made is saved, and any of them can be undone.
3 · Automatic deploymentEvery push went live at your own URL.
4 · A real app, same railsThe game became a Next.js app in TypeScript, at the same URL.
5 · Tests and buildsThe locked door went red, then green. A broken change stopped before it went live.
6 · Types and lintingThe checks caught mistakes you never wrote a test for.
7 · Rules for the agentAGENTS.md carries your rules to the next session.
8 · More featuresYou planned, designed, tested, checked and pushed a feature of your own.
9 · A databaseIf you got this far, the rooms moved into a database, and the Cellar arrived without a deploy.

You just did what a CTO does on day one of a product. The agent typed and you judged.

What I say

These are the same nine cards as the start. Then they were a promise. Now the ones you reached are things you did, and the rest are on these slides to finish at home. None of them needed you to write code. Then we have time for questions. There is more at chrismdp.com/coding-with-ai.

Thank you

Any questions?

Chris Parsons
chrismdp.com
linkedin.com/in/chrisparsons

This page stays up: chrismdp.com/workshop/beyond-vibe-coding/v2

What I say

Thank you. Any questions? Scan the QR code to connect with me on LinkedIn, and there is more on my website. This page stays up, so you can come back to the prompts.

Shortcuts. They work in either window, and both windows move together.

  • Space PageDown next slide
  • PageUp previous slide
  • Home first slide · End last slide
  • Type a number, then Enter: go to that slide
  • Esc clear a number you are typing, or leave fullscreen
  • P switch this window between notes and slides
  • N open the notes window
  • ? show or hide this help
  • F fullscreen: hide the top bar and footer
  • D switch between deck and one long page
  • Reload either window and the other reloads too
  • Click a picture below to go to that slide

© Chris Parsons

change slide · N notes window · ? help · F fullscreen · D switch view · Home go to start