HomeVideos

Building a REAL feature with Claude Code: every step explained

Now Playing

Building a REAL feature with Claude Code: every step explained

Transcript

1362 segments

0:00

I've been posting a lot recently about

0:02

things you should do with Claude code

0:04

and mostly I've been approaching it from

0:06

the kind of philosophy angle. In other

0:07

words, kind of everyone's thinking this

0:09

is a new paradigm shift, but actually

0:11

just the stuff we've been doing for 20

0:12

years is really, really good with Claude

0:14

code. You get the most out of it when

0:16

you treat it like someone you would

0:18

delegate to in your team. In other

0:19

words, you focus on the architecture,

0:21

you focus on making sure that you've got

0:23

good feedback loops, you focus on all

0:25

the things we've been doing for the last

0:26

20 years, not planning too much up

0:28

front, all that stuff. And in all the

0:30

comments, people have been saying, "Show

0:31

us something practical. Show Show us you

0:34

doing it." And so this is that video. I

0:36

have no idea how long this video is

0:38

going to be. I have no idea exactly what

0:41

we're going to cover. I'm just going to

0:42

go into actually doing some work with

0:45

Claude code in my work repo and I'm

0:47

going to talk you through it. I'm going

0:48

to show you all of the skills I'm using,

0:50

I'm going to show you my process, and

0:52

we're just going to give you all the

0:53

context you can on how these tools are

0:55

actually used. And if you dig this, then

0:57

I'm running a cohort in a couple of

0:59

weeks for Claude code for real

1:01

engineers. It is 40% off this week and

1:04

it teaches you either teaches you the

1:05

skills that you need to do real

1:07

engineering or it gives you the

1:08

conversion course you need to take the

1:10

existing skills you have and apply them

1:12

to this new age. So if that sounds good

1:14

to you, then the link is below. Okay,

1:16

let's start by understanding the project

1:18

that I'm in and what point it is in in

1:20

its life cycle, all that stuff. This is

1:22

my course video manager. It's It's

1:24

about, you know, 1,200 commit. I've

1:27

closed around what, 637

1:30

issues on this project. And what I'm

1:31

using this for is this is my main kind

1:34

of entry point for anything I do

1:35

regarding creating content. In other

1:37

words, I create videos on here. I

1:39

organize my courses on here. I post

1:41

videos on here. I do thumbnail editing

1:44

on here. I do writing on here. It really

1:46

is my one-stop shop for everything I

1:48

need to do my job and it's amazing. In

1:50

terms of the code, it's a React router

1:52

application which uses TypeScript and

1:55

Node and uses drizzle for the database

1:59

ORM, use Postgres as its database, does

2:02

some a lot of testing with V test. And

2:04

the way I run this is I don't actually

2:05

deploy it, I just basically run it

2:08

locally. So, I just tend to run start. I

2:11

build it and I'm just, you know, run it

2:13

with the start script. This is a

2:15

confusing video for me to make because

2:17

actually right now I'm recording the

2:18

video that I'm making on the course

2:20

video manager. Here you go, this is me,

2:22

this is the clips that are being

2:24

detected from the video that I'm

2:26

recording and there you go, that's the

2:28

previous clip. This is a confusing video

2:29

to me to make, you know what I mean?

2:30

This is just got loads of stuff here.

2:32

This is what the main view looks like.

2:34

We've got courses down the left-hand

2:35

side here, then we've got lessons and

2:37

sections within those courses. And the

2:39

stuff I want to show you is inside the

2:40

free videos over here. Inside the app

2:43

I've got a concept of ghost lessons and

2:45

real lessons, which you can see on the

2:47

filters here. These ghost lessons

2:49

basically don't exist on disk and I need

2:52

to right-click the lesson and say create

2:54

on disk to actually create the lesson

2:57

in like a repo in the disk. And the

3:00

logic for this is fairly complicated

3:01

because I can turn this back into a

3:03

ghost here. So, and then when I do, I

3:06

need to delete all of the files that are

3:07

on the file system, convert it back to a

3:09

ghost. The idea here is that it lets me

3:11

plan and kind of create courses in the

3:14

same UI, which ends up being really,

3:16

really nice. But the thing I want to add

3:17

are some enhancements here. So, I want

3:19

to be able to when I create a lesson, I

3:21

shouldn't just need to create a ghost, I

3:23

should be able to add a real lesson

3:25

instead of a ghost lesson. Same when I

3:27

delete a real lesson, I should be able

3:28

to just delete it instead of needing to

3:30

turn it into a ghost first. So, this one

3:32

here. Now, this part of the code base is

3:34

really well tested and so this should be

3:36

a relatively simple build. But there is

3:37

another thing I want to do as well,

3:39

which is I want to when we go up to

3:41

these courses up here and add a new

3:42

course, I want to be able to basically

3:44

create a ghost course, a course that

3:47

doesn't yet exist on the file system

3:49

because currently every course needs an

3:51

entry in the file system. So, that is my

3:53

idea. I've got a very loose set of

3:55

requirements here, and this is maybe how

3:58

you enter most days as a developer. You

4:00

have some small tweaks that you need to

4:01

make to your application that are based

4:03

on some vague ideas. Maybe those are

4:06

ideas that you've come up with. Maybe

4:07

those are ideas that have come from

4:08

somewhere else. And the first thing you

4:09

need to do is actually road test those

4:11

ideas and harden those ideas. But, the

4:13

first thing we're going to do is open

4:14

this up in VS Code, and we're going to

4:17

um go into this and say "Grill me." I'm

4:21

going to use my dictation tool to

4:22

dictate some stuff into here. The way

4:24

that we handle ghosts in real lessons is

4:26

a little bit cumbersome in places. It's

4:28

annoying that you have to create a ghost

4:31

lesson before you then create a real

4:33

lesson. And it's also annoying that when

4:35

you delete it or delete a real lesson,

4:37

you can't just delete the real lesson.

4:39

You have to turn it into a ghost lesson

4:40

first. Now, at this point, I'm thinking,

4:42

"Do I also in this session want to

4:44

tackle the other thing? Do I want to

4:46

tackle the idea of ghost courses as

4:48

well?" My decision space for that is

4:49

like, "Will this crowd out the grill me

4:53

session, or will it all actually fairly

4:56

seamlessly link together?" Because the

4:57

idea of this grill me session is I'm

4:58

going to create a document out of this

5:01

that I'm then going to use to um

5:03

do future builds on, basically. So,

5:05

that's my decision here is, "Do I want

5:06

to create a PRD, a product requirements

5:09

document that has both of these things

5:10

in, or are these separate concerns that

5:12

I need to separate into separate PRDs?"

5:14

I'm going to say that this stuff

5:15

actually sort of belongs together. But,

5:17

I'm just making that decision kind of

5:19

arbitrarily really. I also want to

5:21

extend the courses functionality so that

5:24

it allows me to create a course without

5:28

having a file path. This would be a kind

5:30

of ghost course, a planned course that I

5:34

haven't actually decided whether I'm

5:35

going to build yet. Now, this second

5:37

section here, I haven't really explained

5:39

the why. That's something that's on my

5:40

mind now. I've sort of like I've

5:42

explained what I want the feature to do,

5:44

but I haven't explained why I want the

5:46

feature to exist. It's always really

5:48

important when you enter these sessions

5:49

that you explain the why to the LLM

5:51

because

5:53

sure, if the LLM has the what, then it

5:55

understands what you want to build, but

5:57

if it doesn't know the why, then it

5:58

can't suggest alternatives. The reason I

6:00

want this is so that I can plan courses

6:03

freely without needing to commit to an

6:05

exact shape on the file system.

6:07

Initiating new repositories is kind of

6:09

cumbersome, and I sometimes just like to

6:11

prefer or I prefer building stuff in

6:14

empty space instead of having to commit

6:17

to an actual shape. Ghost courses would

6:18

have slightly different constraints on

6:20

them. Ghost courses would likely have to

6:24

No, I guess ghost courses could have

6:25

real lessons. It's just the moment that

6:27

they have a real lesson inside them,

6:30

then they become a real course, and

6:32

you're then required to put it in the

6:34

file system, I guess. Or I don't know,

6:36

I'm not sure about that flow. Maybe we

6:38

can work on that together. Notice how

6:39

rough this is. This is just a super

6:41

hashed-out sort of idea that I'm kind of

6:44

you know, just spewing out the LLM and

6:46

making it do all the work. If you've not

6:48

seen my Grill Me skill, then head to my

6:51

I'll I'll send it in a link below. It's

6:52

in my top five skills article. But

6:54

you'll be able to see what it does. Here

6:55

it is. Really, really cool. Okay, it's

6:57

going to do an explore phase. I'm going

6:59

to

7:00

head and get a glass of water. And by

7:02

the way, if you don't know what explore

7:04

is, explore is it's basically invoking a

7:06

sub-agent. So it's essentially just

7:09

passing a message to another agent to

7:11

say explore this codebase. That agent

7:13

then

7:14

explores it within its own context

7:16

window, and then it takes that context

7:19

it takes a sort of summary of that, and

7:20

it hands it back to the parent agent. So

7:22

it allows you to get a lot of juice out

7:24

of an explore phase because the explore

7:26

can just go bam, bam, bam, bam, bam,

7:27

read tons and tons of files, and then

7:29

the parent agent only gets a summary of

7:31

it. So it's very token efficient. But

7:32

anyway, I need a glass of water. Okay,

7:34

Grill Me has come back with a let me

7:36

challenge your framing of the current

7:37

pain points. It says that looking at the

7:39

code delete lesson in in course right

7:41

service already handles both ghost and

7:43

real lessons directly. If it's real, it

7:45

deletes the directory and renumbers. If

7:47

it's ghost, it just removes the DB row.

7:49

So, you can delete a real lesson without

7:51

converting to ghost first. Is there

7:52

something in the UI that forces the

7:54

convert to ghost then delete flow? Well,

7:56

yeah, there is. Yeah, in the UI there's

7:58

no option to delete the lesson

8:01

immediately. And

8:03

what I mean by deleting a real lesson is

8:05

it would both delete the entry from the

8:07

database and um purge the on-disk

8:12

representation. I'll ping this off while

8:14

I explain something very cool that I've

8:15

just recently started doing. I've been

8:17

reading a book called um

8:19

domain-driven design. And in this book,

8:21

they talk about how important it is that

8:23

you maintain a sense of a sort of

8:26

glossary of all of the terms that you

8:29

use to describe the system. This

8:30

ubiquitous language can then be used

8:33

basically to um bridge the gap between

8:36

uh devs and domain experts, the thing

8:38

the people you're actually building it

8:39

for. So, I love this because this is

8:41

exactly what the LLM has to have with

8:44

me. I'm the domain expert and the LLM is

8:46

the dev. And we need some kind of shared

8:48

language so that we can talk together

8:50

precisely. So, for instance, here we

8:51

have a concept of a ghost lesson, a

8:54

lesson that exists on whoopsie, a lesson

8:56

that exists on the database. Where is

8:59

it? Yeah, a lesson that exists on the

9:00

database but not yet on the file system.

9:03

And so, whenever the LLM is searching

9:04

for stuff about ghost lessons, it's

9:05

going to come up come across this

9:08

ubiquitous language file. Okay, so it

9:10

has come back and it said, "Yeah, the UI

9:11

currently only exposes convert to ghost

9:13

for real lessons, not a direct delete

9:15

entirely option. That's a

9:16

straightforward UI gap." Okay, that's

9:18

useful. Let's quickly talk about like

9:19

the way it's using service here and um

9:22

what this actually means in my code

9:23

base. I might actually try the new um by

9:26

the way side question thing here. This

9:28

is really useful when you just want to

9:30

ask a quick question and you don't want

9:31

it to kind of enter into the chat

9:34

history. Describe what's going on with

9:35

the course right service. uh describe

9:38

the shape of it, describe its

9:39

capabilities. Let's see what it comes

9:41

back with here. The reason I'm uh asking

9:43

about this and want to show you what it

9:45

is is that um I'm really proud of the

9:48

way that I've designed this repo. I

9:50

mean, there's definitely stuff in there

9:52

that definitely needs to be um looked

9:55

at, but the way I've done this service,

9:57

I think is quite nice. And the course

10:00

right service is the main business logic

10:02

layer for mutating course data, the

10:03

right side of the system. It coordinates

10:05

between the database, the file system,

10:06

and the path numbering and renumbering

10:08

logic. It's got a really clear interface

10:10

here, like you can add ghost lessons,

10:12

you can materialize a ghost, so convert

10:15

a ghost lesson to a real lesson, uh

10:17

convert it to ghost again, uh delete

10:19

lesson, etc. So, this is a big, big blob

10:22

of functionality. And the tests for this

10:24

course right service are all in one

10:26

place. So, course right service.test.ts.

10:29

Oh, no, okay, it used to be there, not

10:31

anymore. Yeah, here they are, course

10:32

right e2e.test.ts.

10:34

And this actually creates a test

10:36

database, it sets up a temporary Git

10:38

repo, and so it tests all of the

10:40

synchronization between this. This repo

10:42

is using effect, and effect makes it so,

10:44

so nice to create these kind of like

10:47

units within your system that you can

10:49

test really easily. Other languages have

10:51

this as a first-class thing, but effect

10:54

um sort of bolts that on on top of

10:55

TypeScript in a really beautiful way.

10:57

I've made a video about effect before on

10:58

this channel, just one video, and uh

11:01

suffice to say I still love it, and I

11:03

use it for literally everything. Or at

11:04

least every back end thing that I build

11:07

is all in effect. Anyway, this huge

11:09

service, the course right service, uh

11:11

where is it? DB function service, here

11:13

it is, the course right service. It just

11:15

lives in here. So, it's a file with

11:17

essentially a bunch of methods inside

11:20

here, and these methods, like

11:21

materialize ghost, like add ghost

11:23

section, add ghost lesson, delete

11:25

lesson, etc. This is what we're talking

11:27

about when we talk about this service.

11:29

So, then I can exit out of this by the

11:30

way thing by just pressing space, enter,

11:32

or escape, and now I'm back here. So,

11:34

this is a great question. What flow do

11:36

you actually want here? Are you saying

11:37

you want to create a lesson action that

11:39

immediately creates the directory on

11:40

disk, skipping the go step entirely? Or

11:42

is the pain more that the two-step

11:43

process, create ghost and then

11:44

materialize, feels like unnecessary

11:46

ceremony when you already know you want

11:48

a real lesson? Yes, exactly, the

11:49

two-step process feels unnecessary. And

11:51

it says, "Okay, so you want a single

11:53

create lesson action that creates both

11:55

the DB entity and the on-disk directory

11:57

in one shot when you already know that

11:59

it's going to be real." Yep. Okay, and

12:00

now it's gone to the bigger topic, ghost

12:02

courses. Yeah, here we go. Then you said

12:04

something interesting and immediately

12:05

hedged on it. Ghost courses could have

12:07

real lessons, and when they do, they

12:08

become a real course and you're required

12:10

to put it in the file system. Let me

12:11

break this apart. First question, a

12:12

ghost course has no file path, so it has

12:14

no Git repo. Sections and lessons inside

12:17

it would all be ghost by necessity.

12:18

There's no way to put them on disk. When

12:20

you say a ghost course could have real

12:21

lessons, what does real mean without a

12:22

file system? Right, so here what it's

12:24

doing is it's fleshing out my kind of

12:26

woolly language a little bit and forcing

12:28

me to be a bit more specific. This is an

12:30

easy question for me to answer. I don't

12:32

want them to have some kind of

12:33

intermediate status, like flesh more

12:36

fleshed out than a ghost. What a great

12:38

phrase. But yeah, A is pretty obviously

12:40

the thing here. Adding a real lesson to

12:41

a ghost course is the trigger that

12:42

forces you to assign a file path and

12:44

materialize the course. Now, I'm already

12:46

thinking from a UI point of view, what's

12:48

going to be the easier thing to do, or

12:50

rather the most obvious thing for the

12:52

user, the cleanest UI? Either when we

12:54

create a like real lesson inside a ghost

12:58

course, we basically say, "No, you can't

13:01

do that. to choose a thing in disk

13:03

first, and then you need to click away."

13:05

Or we create a kind of integrated flow

13:08

where you say, "Okay, you're writing

13:10

this to disk. When you do that for the

13:12

first time inside a ghost course, you

13:14

need to choose a place that it's going

13:16

to live." I think I'm like veering

13:18

towards the second because it's not that

13:20

complicated to do that in terms of UI,

13:23

and

13:24

I think it'll would a nicer flow. So,

13:26

let's say that to it. Yeah, we're going

13:28

to choose A here um and I think it makes

13:31

sense that when you press um convert to

13:35

or convert reveal in file system or

13:37

whatever the button is, whenever you

13:39

make it and material

13:42

Notice here, this is where the

13:43

ubiquitous language comes in really

13:44

handy because I was just sort of

13:46

fluffing around there, but what I mean

13:49

is that when I materialize a ghost

13:51

lesson, when you materialize a ghost

13:53

lesson, you should have a modal pop-up

13:56

that forces you to materialize the

13:58

course as well. Look how clean like how

14:00

much cleaner that language is because

14:03

I've got a concept of materializing and

14:05

the word agreed on between me and the

14:06

LLM. Anyway, let's fire this off and see

14:08

what happens. Right, yeah, we've got a

14:09

concept of um versions inside the

14:12

application, so course versions. This is

14:15

really important for me because I have a

14:17

team of people who actually apply the

14:18

course to the CMS and so I have a course

14:21

and a change log. For instance, here in

14:22

my Claude Code Cohort, I've got several

14:25

versions here and

14:28

like the sooner I approach the cohort,

14:29

the more I'm sort of fixing bugs or like

14:31

um switching out videos, that kind of

14:33

thing. The latest version is always the

14:35

draft version and then I can like

14:37

publish that draft version and add a

14:39

commit message to it and it goes into

14:41

the change log. Here you go, this is the

14:42

UI for publishing the new version and

14:44

here's a preview of the change log. So,

14:46

yeah, I'm pretty sure that the schema

14:48

that we rely on needs the ghost course

14:50

to still have versions. Yeah, I'm fairly

14:52

sure that the schema that we need um

14:54

will require us to have versions because

14:57

versions are needed in order to have

15:00

sections and lessons and stuff inside

15:02

them. However, it makes zero sense to be

15:05

able to publish a ghost version, so we

15:08

should just hide the bits of UI that's

15:10

um and the actions in the menu that

15:12

allow you to publish. So, let's fire

15:13

this off. I can see in my video editor

15:15

that we're about like 15 minutes in and

15:17

just notice like how long we're spending

15:19

here on fleshing out these ideas. The

15:21

more we do here, the less we're going to

15:24

end up needing to do

15:25

when we actually guide the LLM. Okay,

15:27

let me push on the file assignment

15:29

moments. When you materialize a ghost

15:31

course cuz you're materializing a lesson

15:32

inside of it, you need to give it a file

15:34

path. Either the repo already exists or

15:36

the repo doesn't exist yet. When you

15:37

assign a file path to a ghost course,

15:39

should the app handle repo creation for

15:41

you? No, it shouldn't handle repo

15:43

creation. It's just pointing at an

15:44

existing directory. That's an easy one

15:46

to figure out there. Okay, this is such

15:49

a lovely smart question that it's given

15:51

us here. It's laying out what you're

15:53

asking for. Direct delete for real

15:54

lessons, direct create for real lessons,

15:57

ghost courses, and then materializing a

16:00

lesson in ghost courses. Question, does

16:02

direct create apply inside ghost

16:04

courses, too? That's so freaking smart.

16:06

That's such a nice question. I can

16:08

imagine my old boss, Willow Reagan,

16:11

asking that question, who is the guy I

16:13

learned a lot of this lead developer

16:15

stuff from. He had this incredible

16:16

ability to just basically sit in a

16:18

meeting and ask smart questions for

16:21

hours and hours and hours. And this is

16:23

exactly what the AI is doing here. It's

16:24

asking really smart questions at the

16:26

right point in the process. So, if

16:28

you're inside a ghost course and you hit

16:29

create lesson, should that immediately

16:31

trigger the assigned file path modal and

16:33

create it on disk? Now, again, there's a

16:35

trade-off here, and instead of me

16:37

thinking about this in my own head,

16:39

which is not particularly fun viewing,

16:41

why don't we model what it might look

16:42

like if I sort of work this through with

16:44

the LLM? Can you give me the trade-offs

16:46

of both of these approaches? Okay, so

16:48

it's saying on option A, create lesson

16:51

inside a ghost course always creates a

16:52

ghost ghost lesson. Keeps the ghost

16:54

course as a pure planning space. The

16:55

assigned file path moment only happens

16:57

when you explicitly choose to

16:58

materialize, which is a clear deliberate

16:59

action. There's downside if you've

17:01

already decided this course is real and

17:03

you're just adding lessons, you're back

17:04

to the two-step annoyance you're trying

17:05

to fix. Option B, create lesson inside a

17:07

ghost course triggers the

17:08

materialization cascade. Yeah, it's

17:10

saying option A is the obvious choice

17:11

given your stated goal. The two-step

17:13

annoyance you described is specifically

17:14

about real courses where the file system

17:16

exists and you want a real lesson. Yeah,

17:18

I probably agree with it. If we want a

17:19

consistent UI, then we do want the

17:22

ability to both create real lessons and

17:24

create ghost lessons

17:26

at whatever stage the course is at,

17:27

whether it's real or ghost. That will

17:29

mean a bit less work in the front end

17:31

because we don't want to or won't need

17:33

to conditionally show things. Blah blah

17:35

blah blah blah. Yes, this makes sense to

17:36

me. Option A sounds good. I think it

17:38

mostly makes sense in the context of

17:40

having

17:42

two buttons, one to create a real lesson

17:44

and one to create a ghost lesson. Could

17:46

you just talk me through the UI a little

17:48

bit and how this is going to look?

17:49

Notice that I'm driving this a little

17:51

bit more now. That's okay, too. The

17:53

is nice and flexible so that you can

17:55

drive sometimes and the AI can drive.

17:57

This is nice, too. It's actually

17:58

checking the current UI for lesson

18:00

creation first. This is part of the

18:01

skill is I get it to, instead of asking

18:04

me questions about everything, if it's a

18:06

question that can only be answered by or

18:07

can be answered by looking at the code,

18:09

it should look at the code first. I do

18:11

wish that explore was faster. Explore is

18:12

the thing that's like, you need it in

18:14

every single session, sometimes multiple

18:16

times a session, and I just wish it was

18:18

quicker. Okay, so here's how the current

18:20

UI works. You right-click a section

18:22

header, you add a lesson, right-click an

18:24

existing lesson, add lesson before, add

18:26

lesson after, also creates a ghost.

18:28

Inside a real course, you right-click a

18:29

section, you'd see add ghost lesson and

18:32

add lesson. Inside a ghost course,

18:34

right-click a section, you'd only see

18:35

add ghost lesson. Yeah, right. That's

18:37

the question. Inside a ghost course, do

18:39

you want the create real lesson button

18:40

to exist at all? Now, at this point, I

18:42

don't know. Like, I'm imagining this UI

18:44

is going to get pretty crowded with this

18:46

like, cuz you're going to have multiple

18:48

buttons there. You're going to have

18:49

like, add a lesson

18:51

before this one, and then do you make it

18:54

ghost or real?

18:56

I guess like, oh man, this is actually

18:58

quite gnarly. I'm thinking, do I

19:00

actually want a prototype of this so I

19:02

can sort of see how it looks? Because

19:04

there's multiple ways that we could

19:05

fiddle with this and and get it like,

19:08

nice. You could have it where you add a

19:10

lesson, then it opens a modal, and you

19:12

whether um

19:13

it's a ghost lesson or a real lesson. I

19:15

think probably what I'm going to do is

19:16

I'm just going to build it one way and

19:18

then maybe offer feedback afterwards.

19:20

So, let's say yes, inside a ghost course

19:23

let's have the create real lesson

19:25

button. You know, I could like stop this

19:27

whole grilling session. I could go into

19:28

prototyping mode here where I just sort

19:31

of prototype, you know, three different

19:32

versions, five different versions of

19:34

this just to see what the UI would look

19:35

like, but I'm quite keen to get into

19:37

implementation now. Okay, so create real

19:39

lesson inside a ghost course triggers

19:40

the full cascade. Modal asks for file

19:42

path, course becomes real, section

19:44

materializes, lesson gets created on on

19:46

disk, all in one flow. That's right.

19:48

That modal is doing a lot of work.

19:50

Correct. It needs to grab the lesson

19:52

title and the course file path. Yeah,

19:54

that's it. Correct. That's it. We just

19:55

need the lesson title and the course

19:57

file path. That's it. I can feel it.

19:58

We're getting to the end of this

19:59

grilling session. Oh, maybe not.

20:02

It's asking about section behavior,

20:04

sections inside ghost courses, and the

20:06

state of a section is basically just

20:07

derived from um

20:09

the lesson. If there were any ghost

20:11

lessons inside a section, then it's

20:13

going to be a ghost. Oh, sorry. If there

20:15

are any real lessons inside a section,

20:18

then it's a real section on disk. A

20:20

section basically looks like this. It's

20:22

just essentially a directory on disk.

20:23

You can rename it and rename the

20:25

directory or you can add things to it,

20:27

but that's basically it. Section logic

20:29

should obey the current rules that we

20:31

already have. There's nothing really new

20:32

about sections. For instance, when we're

20:34

inside a ghost course and we create a

20:37

real lesson inside that section, then we

20:41

basically flow all the way up so it

20:43

becomes a real section, becomes a real

20:45

lesson, and becomes a real course. Here

20:47

we go. Let's keep going. Let me switch

20:49

to the database schema. Right now,

20:51

courses table has a file path as a

20:52

required text field. For ghost courses,

20:55

this would need to be nullable. That is

20:56

the only schema change I'm envisioning.

20:58

Yeah, just going to say yes to this.

21:00

It's going to grill me on a tricky edge

21:02

case. I see. Have a real course with a

21:03

file path. It has some real lessons and

21:05

some ghost lessons. You delete all the

21:07

real lessons or convert them all to

21:08

ghost, does the real course become a

21:10

ghost course? Again, this is like a

21:12

classic Willow Reagan question. It's

21:14

fantastic, really, really good. No, the

21:16

real course does not become a ghost

21:19

course. Once a course has a file path,

21:21

it stays real forever because the thing

21:23

that's on disk is not going anywhere.

21:24

Yeah, I was thinking about that before

21:26

and so I'm super glad that it answered

21:27

it because now it's in the context and

21:29

it's spelled out. Another edge case, you

21:30

have a ghost course, you materialize a

21:32

lesson, you assign a file path,

21:33

everything becomes real. Now the course

21:34

has a file path but no real lessons. I

21:36

feel like we just answered that, right?

21:38

That's a weird one. I mean, I don't

21:39

think Willow Reagan would ask that

21:40

question. Yeah, let me move to the

21:41

deletion side. You want to direct delete

21:43

action for real lessons in the UI.

21:45

Currently, the context menu for real

21:46

lessons shows convert to ghost but no

21:48

delete. Yeah, this is a UI thing. Should

21:50

real lessons have both options, convert

21:52

to ghost and delete?

21:53

I think we need

21:56

both. Okay, we're getting there, we're

21:58

getting there. I think I've covered the

21:59

main branches. Let me lay out the full

22:01

scope as I understand it and you tell me

22:02

if I'm missing anything. Courses file

22:04

path becomes nullable, ghost course

22:06

creation, a new course creation flow

22:08

that only asks for a name, no file path,

22:10

correct. Ghost course UI, hide the

22:12

publish and export actions, correct.

22:14

Create a real lesson button available in

22:16

both real and ghost courses. In a real

22:18

course, creates on disk immediately. In

22:20

a ghost course, triggers modal asking

22:22

for the file path first then cascades

22:23

materialization. That looks good. Create

22:25

ghost lesson works as today, available

22:27

everywhere. Delete action for real

22:28

lessons purges from the disk and the

22:30

database in one step. Yes. Delete action

22:32

for ghost lessons already unchanged. And

22:35

finally, convert to ghost stays for real

22:37

lessons that you want to keep planning

22:39

but remove from the disk. Exactly. So,

22:41

we've got that. This was essentially the

22:43

eight bullet points that we just spent

22:45

whoa, 22 minutes of video just uh trying

22:49

to get. This to me feels really, really

22:51

familiar. This is how I'm working with

22:53

AI a lot. I, you know, block out half an

22:55

hour in my calendar to work out exactly

22:57

the feature I want and from here it's

22:59

pretty much all on rails. Like we have

23:01

done the hard bit now. We have done the

23:03

human in the loop bit. What I do next is

23:05

I now I've been trying this for a few

23:07

days. I get it to update my ubiquitous

23:10

language documents to basically just

23:13

keep it up to date with any of the ideas

23:15

that I've got in here. For instance,

23:16

we've got some new terminology now.

23:17

We've got this idea of

23:19

ghost courses, which is new. Let's see

23:22

what edit it decided to make In In fact,

23:24

I'm just going to accept it and review

23:25

it afterwards. So, there we go. We can

23:27

see it's updated its idea of ghost

23:28

entities here. It's got ghost lessons,

23:30

ghost sections, and ghost courses. The

23:32

verb materialize is now properly in

23:34

here. The act of transitioning a ghost

23:35

entity to a real entity by creating its

23:37

on disk representation. I like too that

23:39

it has this create on disk and realize

23:42

like the aliases to avoid. That's really

23:44

cool. And it's even got a concept for

23:45

the materialization cascade. The chain

23:47

reaction when materializing a lesson

23:49

inside a ghost course. It signs file

23:51

path to course, materializes section,

23:52

then materializes lesson. I freaking

23:54

love this because later on I can say,

23:55

"Yeah, there's a bug inside the

23:57

materialization cascade." And it knows

23:58

exactly what I'm talking about. commit

24:00

this. Update to the ubiquitous language

24:02

document. Look at this. Yeah, sometimes

24:04

I am actually committing code myself.

24:06

Okay, so it's gone back to the grilling.

24:08

Yeah, it's now just sort of repeated the

24:09

eight sections. The existing plan entity

24:11

is a separate disconnected planning

24:13

tool. Yeah, I did used to have a

24:15

separate planning area, but then I sort

24:17

of used this ghost concept to integrate

24:19

it into my actual courses thing.

24:22

I've got it inside the ubiquitous

24:23

language inside here down here. A plan,

24:27

a plan section, and a plan lesson there.

24:29

But this is basically deprecated. I am

24:31

going to remove this at some point. And

24:33

so, we can say plans are deprecated and

24:36

ghost courses are the new way to do it.

24:38

And in fact, I think I'm going to go

24:39

ahead and say I'm satisfied. Let's and

24:43

I'll invoke my next skill, which is

24:44

let's write a PRD. So, if we think about

24:47

the conversation that we've just had

24:49

with the LLM, it's incredibly good

24:52

fodder for just turning this into a sort

24:55

of more

24:56

concise summary document of everything

24:59

that we want to build. I freaking love

25:00

question and answer because it

25:01

co-locates the question with the answer.

25:03

I know that sounds like such a sort of

25:05

basic thing to say, but the way that

25:07

these attention mechanisms work is that

25:09

stuff that's close together tends to

25:12

like it sort of shows up as a hot spot

25:15

for the LLM in terms of its attention

25:16

mechanism, just like it does for humans.

25:19

And what this ends up meaning is that

25:21

this is such a rich document for it to

25:23

pour through. Now, it's doing another

25:25

explore phase. We should probably do

25:26

like a cursory check on our context

25:28

window down here. We're currently only

25:30

at like 40K tokens, which is pretty

25:32

impressive given how long we've spent

25:35

with the LLM working on this stuff. A

25:36

lot of folks have asked me why my grill

25:37

me skill doesn't use the ask user

25:39

question tool. Like we weren't actually

25:42

sort of like using Claude's built-in

25:45

mechanism for asking questions. And the

25:47

reason for that is that I don't really

25:49

like that UI, first of all. And second,

25:51

like if you have a choice between

25:53

calling a tool and not calling a tool,

25:56

then like not calling a tool is always

25:58

going to be more token efficient because

26:00

every time you call a tool, you need to

26:01

wrap it in JSON, you need to do various

26:03

things. Okay dokey, we can see here that

26:06

okay, it's now sketching out the major

26:08

modules before writing the PRD. I've

26:10

talked before on this channel on how

26:11

important I think

26:14

modules are and like understanding the

26:17

modules in your code base without

26:19

necessarily needing to look inside them.

26:21

Like the course write service that we

26:23

looked at before, that's a big testable

26:26

module that I was very careful in

26:28

designing and designing the interface

26:29

for. And I think this is so important

26:31

that I've baked it into my write a PRD

26:33

skill. So, it sketches out the modules

26:36

and surfaces them to you. I don't

26:37

necessarily need to look inside these

26:39

modules. I just want to know how they're

26:40

changing. For instance, here I can see

26:42

something that's a bit dodgy, right? It

26:43

wants it to make a new method on the

26:45

course write service, materialize course

26:48

and lesson. Reuses the existing

26:50

materialize ghost and section

26:51

materializing logic internally. I'm

26:53

thinking about whether it could just

26:54

instead use the existing materialize

26:56

ghost and pass it like an additional

26:59

parameter,

27:00

but I think that would be a little bit

27:02

dodgy API API wise. So, I think it is

27:05

probably right. I think it should have a

27:06

new method. Notice how I'm thinking

27:08

about the interface more than I'm

27:09

actually thinking about the

27:10

implementation here. The implementation

27:12

I don't really care about, but I want to

27:14

make sure that this is testable and um

27:16

you know that the rest of the um

27:18

kind of repo and any future AI agents

27:20

can understand what it's doing. And

27:21

again, notice how easy these functions

27:23

are to name because we've got this

27:25

concept of the ubiquitous language. So,

27:27

module one is the ghost course schema DB

27:29

operations. That seems fine. The

27:31

materialization cascade service. That

27:33

seems fine. It's just a new method on

27:35

the course right service. Here we've got

27:36

two new API routes, which makes sense

27:39

because we're doing direct real lesson

27:41

creation, direct real lesson deletion. I

27:43

could um put them into like other API

27:47

routes, but because this is just an

27:48

internal tool, I don't really care about

27:50

what my API like looks like from the

27:53

outside, then I don't really care about

27:56

um how many API routes I have or what

27:58

they look like. It's just an

27:59

implementation detail. Now it's talking

28:00

about the

28:01

ghost course UI new add ghost course

28:03

option in the sidebar. Yep, that seems

28:05

fine. A materialization model two lesson

28:08

creation buttons in context menus and a

28:09

delete action. And then module six, the

28:11

plans deprecation. Hey, I mean I do want

28:14

to deprecate the plans at some point,

28:15

but I don't think I want to deprecate

28:17

plans now, certainly not as part of this

28:19

PRD. And it's asking me a second

28:21

question, which modules do you want

28:22

tests for? I want tests in the places

28:26

that we already have test harnesses. So,

28:28

for the course right service,

28:30

definitely. And if we have some stuff

28:32

for direct deletion, I think that would

28:34

be as part of the course right service,

28:36

too, right? So, let's see what it says

28:38

here. Now, this is funny. It's saying

28:39

there's no existing test harness for

28:41

course right service. The tests in the

28:43

repo are mostly for pure functions and

28:45

reducers. That is rubbish. So, I'm going

28:47

to do a Rafiki and I'm going to say,

28:48

"Look harder." And there we go. There

28:50

they are, a whole suite of them split by

28:52

concern.

28:53

Okay, and it's satisfied it has

28:55

everything it's needed. It's now going

28:56

to write the PRD and submit it as a

28:59

GitHub issue. This is what I do with my

29:00

PRDs. This is what I do with all of my

29:02

issues. I stick them in GitHub because

29:04

then when we go to actually implement

29:06

this with an AFK agent, the AFK agent is

29:08

going to pull down all of the GitHub

29:10

issues, choose the one it's going to

29:12

work on, and then just work on that one.

29:14

Now, a question becomes, am I going to

29:15

review this PRD? And no, I'm not going

29:19

to. LLMs are really, really good at

29:21

summarizing things. And so, I know that

29:23

this PRD will probably be a pretty good

29:25

summarization of this conversation. So,

29:27

I'm just going to accept it on faith,

29:29

and I'm then going to say, "PRD to

29:31

issues." So, it's now time to break this

29:33

PRD down into individual issues. The

29:36

benefit of doing this is that this now,

29:38

the PRD is already in its context from

29:40

having written it, and so we get to just

29:42

break the issues down straight from

29:43

there. These all have blocking

29:44

relationships in, so it's blocked by

29:46

nothing. This one's blocked by number

29:48

one. This one's also blocked by nothing.

29:49

That's cool. Now, let's just see how

29:51

many there are here. Six does feel about

29:55

right, I think. And what I mean by that

29:57

is this is going to get picked up by a

29:58

Ralph loop. And so, it's going to just

30:00

sort of work through each of these tasks

30:02

sequentially. And so, I want to pick

30:04

tasks that are not too big and not too

30:07

small because if they're too small, then

30:09

we pay the cost of like having to kick

30:12

up an entire agent just to do like

30:14

number two here, hide the publish export

30:16

UI on ghost courses. This is a tiny task

30:19

and it can be melded in with something

30:21

else. But maybe ghost course creation,

30:23

maybe no, that seems like decently sized

30:26

because it touches the UI, it touches

30:27

the schema, it touches the API. Two

30:29

lesson creation buttons, create ghost

30:31

lesson and create real lesson. This

30:32

seems super small. And actually, I think

30:34

it has broken them down a little bit too

30:37

far except maybe the materialization

30:38

cascade. That needs to live in its own.

30:41

So, I think maybe we just merge two and

30:44

three together and I think we'll be

30:46

happy. So, let's go down to the bottom.

30:47

Let's say merge two and three together.

30:49

Okay, now we got four slices. There goes

30:51

course creation, the UI stuff, the

30:53

direct delete action, and the

30:54

materialization cascade. Good stuff.

30:56

Let's go. Let's create the issues. Am I

30:57

going to review these issues? Absolutely

30:59

not. I understand like I've already sort

31:02

of pre-reviewed them. It's just

31:04

expanding out stuff that's in the PRD

31:06

and then, you know, putting them in

31:07

issues. This will be fine. just show you

31:10

one of them just to sort of see what

31:11

they look like. It links to the parent

31:13

PRD. It says exactly what to build. It

31:15

gives some acceptance criteria. Says

31:17

what it's blocked by and it also says

31:19

the user stories that are addressed in

31:21

the parent PRD. If the parent PRD is the

31:23

kind of destination, then these things

31:25

are the journey to get there. And notice

31:27

the PRD just has a bunch of user

31:29

stories, some implementation decisions,

31:32

and testing decisions as well. All of

31:34

this stuff essentially just comes from

31:36

the skills that I've put together and I

31:37

found that they're good enough to keep

31:39

the LLM on rails. I really like adding

31:41

in the testing decisions because it

31:43

means that it's more likely to follow

31:44

TDD and do some

31:47

um kind of create some feedback loops as

31:49

it's going, which is great. So, all

31:51

right. We have now set everything up so

31:53

make our AFK agent to give it the best

31:56

chance possible to produce good work.

31:58

Now, I've been like cooking my setup for

32:00

this a little bit over the last 24 hours

32:02

and I've sort of built like a mini

32:04

library to um

32:07

make it work better than I had it

32:09

before. The provisional name for this is

32:11

Sandcastle and we have a like a

32:13

Dockerfile here. It's going to spin up a

32:15

Docker container. It's going to mount

32:17

the

32:18

working directory inside this

32:20

Dockerfile. And then it's going to any

32:22

commits that are made then inside the

32:24

Dockerfile by Claude, which is going to

32:26

run in there, it's then going to patch

32:28

those out. So, pull out those commits as

32:30

patches and apply them to my local

32:33

repo. I found that this setup is just

32:34

like super flexible. I have a Dockerfile

32:36

and a prompt here and I can just run a

32:38

Ralph loop again and again and again,

32:40

passing in a bunch of issues and passing

32:42

in like the last X number of commits.

32:44

But, you can check out the repo to sort

32:46

of see the most up-to-date file on this.

32:49

I'm going to run, where is it? I think

32:52

it's PNPM Ralph. So, I'll run PNPM

32:54

Ralph. This is going to now spin up my

32:57

AFK agent with a max number of

32:58

iterations of 100. What it should do is

33:01

it will run out of GitHub issues because

33:03

it's going to close the GitHub issues as

33:05

it creates commits for them. But, at

33:07

this point, I can essentially just walk

33:08

away because, you know, we can see it's

33:10

like doing things in the terminal. It's

33:12

saying looking at the issues, directed

33:13

lead to action for Ralph, blah blah blah

33:14

blah. But, I can now have a cup of tea,

33:16

or I can go make a coffee or something,

33:18

or have my lunch. Or more likely, I can

33:20

just open up another terminal and enter

33:22

another grilling session. So, for folks

33:24

who say this approach seems really,

33:25

really slow, what you need to understand

33:27

is that it's slow because you're trying

33:30

to extract ideas out of your human

33:32

brain. And while this is happening,

33:34

you've got AFK agents running in the

33:35

background implementing your previous

33:37

grilling sessions. This is why this is

33:39

revolutionary because, like, once we've

33:42

completed thinking through the idea, our

33:44

work is kind of done until we actually

33:46

QA the outputs. My friend Jaman on

33:48

Twitter called this the day shift and

33:50

the night shift, where I'm doing the day

33:52

shift, I'm like, you know, thinking of

33:54

ideas, I'm grilling with the LM, I'm

33:57

turning this into PRDs, and turning

33:58

those PRDs into issues. And then the LM

34:00

takes the night shift. Claude goes and

34:02

actually implements this stuff AFK. So,

34:04

I'm going to take a little break. I

34:05

might even go for a little walk, and I'm

34:08

going to just wait and check back in

34:10

with this once it's done.

34:12

Okay, we are back. It is like an hour

34:13

and a half later. I, you know, went for

34:15

a walk. I went and had a cup of tea with

34:17

my parents. Uh, yeah. Let's see what

34:19

it's done. So, we can see that the agent

34:20

signaled completion after five

34:23

iterations. So, we essentially ran

34:25

cleared Claude code agent five times in

34:27

the repo, and it should have produced

34:29

for us, yeah, I think six commits here.

34:33

I think those commits, one of them might

34:34

be one that I just haven't pushed up

34:36

yet. Yeah, we can see the entire like

34:38

commit history here. It's been leaving

34:40

really nice detailed commit messages for

34:42

us, and it should be yeah. I think this

34:44

was the update that I pushed before or

34:47

haven't pushed so far. So, at this point

34:48

in the process, I need to um kind of

34:51

look back over these commits. I'm kind

34:53

of tempting to look over the code, but I

34:56

think I just want to review the

34:57

implementation first. going to open up a

35:00

new Claude session, and I haven't come

35:03

up with a skill for this yet. I so, I'm

35:04

just going to sort of free blast it. So,

35:06

I'm going to say, "Take the last five

35:09

commits and create a QA plan for me.

35:11

Save that QA plan in a GitHub issue. The

35:14

QA plan should give me a step-by-step

35:15

guide on how to test every single part

35:18

of the new implementation." This is

35:20

something I've been sort of playing

35:21

around with adding into my skills

35:23

because I think it does make sense

35:24

almost in every single sort of uh

35:27

user-facing change. And while it's doing

35:28

this, I'm going to rebuild the

35:29

application and rerun it locally so that

35:31

we can see exactly what's happening with

35:33

it. Okay, so it has created for us a QA

35:36

plan. Beautiful. Now, I have to say

35:38

there is nothing more boring than

35:39

watching else or watching someone else

35:41

do QA. So, what I'm going to do is just

35:43

walk through this um myself, and I will

35:45

come back to you if I have any issues.

35:48

Okay, the first one actually came super

35:49

early on, which is pressing this add

35:51

course modal. I can see now there's two

35:53

tabs in here. I actually really hate

35:55

this. Like, I just want uh every time

35:58

you add a new course, it should be a

36:00

ghost course, and I don't really like

36:01

the ghost course terminology appearing

36:03

in the UI. So, what I'm going to do is

36:04

exit out of this, and I'm I've got a

36:06

little feedback button here, which you

36:08

can see if I just remove myself there.

36:10

This feedback button, I can just

36:11

describe my feedback in detail, and then

36:14

it will create a GitHub issue for me,

36:16

which can then be picked up by the Ralph

36:19

loop. So, I'm going to say, "When I open

36:21

the add course modal, I want the only

36:24

option to be to add a ghost course. And

36:28

I don't want the ghost course to appear

36:30

in the UI. It should just look like

36:32

we're creating a course and then it

36:34

creates a ghost course. So, I'll submit

36:36

this and when I go to the GitHub issues,

36:38

we can see that we've now got a new

36:40

issue saying hide ghost course option

36:42

and add course model create ghost course

36:44

silently. So, I actually used high code

36:46

to generate me a title here and then

36:47

we've got the route it was submitted

36:49

from and then what I said in the

36:51

feedback button. This is how I do QA.

36:52

This information is enough for Ralph

36:55

[snorts] to do a really nice job here.

36:56

So, I'm actually going to start my Ralph

36:58

loop as I'm going here. I'm going to go

37:00

back to the QA plan and I'm just going

37:02

to add a comment to this and I'm going

37:04

to say Ralph loops should not work on

37:06

this one. This is a human in the loop

37:08

task only. Well, in fact, I'm just going

37:10

to rename that first one to AFK in fact.

37:12

I've got something in my prompt that

37:13

says if there's a human in the loop like

37:15

label on it or it looks like it's for

37:17

humans, don't work on it. And so, let's

37:19

go back in here. Let's run PNPM Ralph

37:21

again and it's going to actually work on

37:23

that issue while we're QAing other

37:25

stuff. So, I'll go back to doing a bit

37:26

of QA and I'll see you in a second.

37:28

Okay, a new thing is when I create a

37:30

ghost course here and I say new fun

37:32

course for instance, then when I press

37:34

create ghost course, nothing appears to

37:36

happen. But actually, as you can see in

37:38

the top left, oh, first of all, we get

37:40

the weird minified React error. So, I'll

37:42

just copy and paste that for the

37:45

feedback form later. It does actually

37:47

create the course, but we don't go to

37:49

the course and the model doesn't close.

37:51

So, let's add this back into feedback.

37:53

When I create a ghost course, it doesn't

37:55

direct me to the new page and it shows

37:57

this error. There's also no loading

37:58

state present on the button, which looks

38:00

confusing uh from the user's

38:02

perspective. So, let's submit that

38:03

again. The agent that we kicked off to

38:05

fix the previous bug is actually already

38:07

finished, so let's just kick it off

38:08

again and I'll keep QAing. This time I

38:10

won't interrupt. I'll just kind of keep

38:12

going through the issues and uh

38:14

attempting to fix them with Ralph in the

38:15

background.

38:16

Okay, this one I did think was showing

38:18

off here or worth showing off rather.

38:20

When I see a new ghost section inside a

38:24

ghost course and I right click here,

38:26

this create ghost lesson and create real

38:28

lesson doesn't seem right to me. I feel

38:31

like when I go into like create ghost

38:33

lesson here or create I just want an add

38:36

lesson kind of thing. We've already got

38:38

a modal here. What we should do is just

38:40

have a checkbox that says also create

38:43

this on the file system. So this is

38:44

something that came up in our early

38:45

discussions about this feature that kind

38:48

of like I couldn't get of sense for

38:51

which way to go until I saw it in

38:52

reality. So that's the way that

38:54

something's go sometimes. We could have

38:55

had an extra design phase or we could

38:57

have had an extra prototype phase, but

38:58

you know, I don't mind just jumping to

39:00

code and fixing it there. So I will add

39:02

some feedback for that, but I'll spare

39:04

you hearing my dictation.

39:06

All right then, I've walked through the

39:07

QA plan and I have created uh seven

39:11

issues here over the last uh or six

39:13

issues over the last 8 minutes. We can

39:14

see that while I've been QAing, Ralph

39:16

has been going in the background and is

39:17

fixing the issues. Most of these issues

39:19

are bugs, but some of them are features

39:21

that we just didn't think about. So for

39:23

instance, when we're deleting real

39:24

lessons, we want to add a confirmation

39:26

model to make sure that it doesn't just,

39:28

you know, like um

39:29

we don't accidentally click it and it

39:31

deletes or whatever. There were

39:31

certainly some showstopper bugs here.

39:33

For instance, if there's if it's not a

39:35

Git repo, uh then it gets into a super

39:38

weird state. Yeah, if the course repo's

39:40

not a Git repository and anything about

39:41

that fails, then we should walk back the

39:42

creation of the directory inside it

39:44

since the directory and file system and

39:45

the database will then be out of sync.

39:48

something again we didn't think about in

39:49

the grill me session at the start, so

39:51

we're now having to find out about it in

39:52

QA. It's this kind of stuff this kind of

39:55

stuff that makes me think that like the

39:57

specs to code approach is just never

39:59

going to work because when you're in

40:00

there, when you're in the QA loop, when

40:02

you're iterating towards something, you

40:04

are going to find little weird edge

40:05

cases like this that is really hard to

40:07

plan for before. Anyway, rant's over.

40:09

The point here is that I've now done a

40:11

extra QA step. Uh Ralph is now going to

40:13

chew through these issues. I can

40:15

probably actually close this QA plan. on

40:18

I might want to reopen it if I like um

40:21

sort of want to redo it, let's say, but

40:23

the behavior has slightly changed. So,

40:25

I'm closing it to take it out of Ralph's

40:28

or or rather the agent that I'm using's

40:30

context, so it doesn't look at this as

40:32

like the the source of truth for what

40:34

it's supposed to be building. Either

40:35

way, I'm going to go do something else,

40:36

and then we'll see what happens to Ralph

40:38

when it comes back.

40:39

Okay, we're back, and we've got

40:41

iteration eight, which is very nearly

40:43

complete. This looks like the final

40:45

issue here where it's just adding the

40:46

confirmation modal with file details

40:48

when deleting real lessons. We can see

40:50

we're up to 14 commits that have been

40:51

added kind of in this entire feature

40:54

build as we've been going along. And the

40:55

issues here are very nearly closed. You

40:58

can see I last opened this one 30

41:00

minutes ago, so that's how long it's

41:01

been running kind of. One thing I would

41:03

like to add here is potentially

41:04

parallelizing these Ralph loops and sort

41:06

of having like a team of agents working

41:09

on it at once. But to be honest, it's

41:11

quite nice having these gaps because it

41:13

means that I get to do some deep focus

41:15

on something, for instance, like

41:17

grilling me on something, and then later

41:19

I can come back and sort of come back to

41:21

code and do a big QA session, send it

41:24

off again, you know, you get the idea.

41:25

Something that's crucial to the success

41:27

of these Ralph loops is making sure it

41:28

runs tests and types on every single

41:31

commit. We can see that in most of these

41:33

loops it's adding tests, too, so it's

41:35

updating the reducer test to cover the

41:36

new action. Now, it's committing and

41:38

closing the issue, so we should be

41:39

nearly there. Okay, and we are good to

41:41

go. I'm going to

41:43

rerun the build, and let's do a little

41:46

bit more QA. And I'll spare you the

41:48

extra QA step here, but suffice to say

41:51

what I would do from this point on is I

41:53

would go back here and I would continue

41:55

QAing it, find more bugs, and at some

41:58

point I would call this done, and I

42:00

would stop working on it. One thing

42:01

that's great about having this really

42:02

flexible backlog approach is that

42:03

anytime I could just queue up a bunch of

42:05

bug fixes, and it would go in and fix

42:07

them. Let's just check one thing, which

42:08

is we can see that the add lesson now it

42:11

no longer says ghost lesson and real

42:12

lesson and we can see here it's saying

42:14

create on file system in a little

42:16

checkbox. If I go foobar and I say

42:19

create on file system, then it's going

42:20

to add the lesson and we should be able

42:22

to see once that's done. It's quite slow

42:25

that, isn't it? I'm interested in why

42:27

that's quite slow, especially because

42:28

this is all local. It should now be

42:31

complete and it creates that foobar as

42:33

the second lesson. So there we go. We

42:34

are, by my count, which is not entirely

42:36

accurate, it'll be about 42 minutes into

42:38

the video at this point.

42:40

If you're here, thank you so much for

42:42

watching all the way to the end. What I

42:43

hope you take out of this video, I'm not

42:45

sure to be honest. Like this is so much

42:47

looser than the videos I usually put

42:49

together, which are usually fairly

42:50

tight, focused on a specific goal. I

42:53

hope that you're able to pick up some

42:54

vibes from me in terms of how much

42:57

detail and how in-depth I look at the

42:59

stuff that I'm producing. You can also

43:02

notice how little I looked at the code

43:04

really. Like what I'm doing here is I'm

43:05

reviewing inputs and outputs. I'm

43:07

interested in the code, absolutely. I'm

43:09

interested in how the interfaces are

43:10

changing, I'm interested in how the

43:11

modules what the modules are sort of

43:13

looking like. And every so often I'll go

43:15

and have a little poke around in the

43:16

code just to make sure it's on the right

43:18

track. But for me really, what I'm doing

43:19

is reviewing the outputs that come from

43:22

AI, passing more information to it and

43:24

getting into a tight loop with it. And

43:26

crucially, because I'm able to run the

43:28

run Claude AFK, I'm able to parallelize

43:31

my own QA with the fixing of the bugs,

43:34

you know, which is just amazing. I

43:35

imagine though you have just dozens and

43:37

dozens of questions. Um feel free to

43:39

ping them into the comments below. Or if

43:40

you want to learn this from the ground

43:42

up instead of just diving through this

43:43

messy video, then the cohort is the

43:45

place. This one starts on March 30th,

43:48

but if you're seeing this sometime in

43:49

the future, then there'll probably be a

43:50

place you can sign up for the next one,

43:52

too. This has been the last kind of two

43:53

months of my life really, full-time

43:55

working on this. And I'm so proud of how

43:56

it's come together because everything

43:58

that you see here in this sort of big

44:00

video has come from me thinking about

44:02

this stuff deeply and the cohort is the

44:06

kind of perfect encapsulation, the

44:08

easiest way to learn this from the

44:10

ground up. Anyway, thank you so, so much

44:12

for watching. Thank you for getting to

44:13

this point, and I'll see you in the next

44:15

one.

Interactive Summary

The video demonstrates a practical, end-to-end workflow of using Claude Code to build new features in a React-based course management application. The host emphasizes a 'day shift/night shift' approach, where he spends time 'grilling' the LLM to refine requirements, establish a ubiquitous language, and produce a PRD and GitHub issues, while offloading the actual implementation and testing (the 'night shift') to an autonomous agent running in the background. The video highlights the importance of deep architectural planning and feedback loops with AI over raw coding, showcasing a workflow that moves from vague ideas to implemented, tested features through iterative human-AI collaboration.

Suggested questions

3 ready-made prompts