YouTube2Text

How Senior Engineers Actually Build With AI in 2026 | Build a Full Stack Systems Architecture App — Transcript

by JavaScript Mastery · 40,317 words · 6,166 segments · language en · Watch on YouTube

Full transcript

  1. 0:00It's 2026 and most of the senior
  2. 0:02engineers I know aren't really writing
  3. 0:05code anymore. They design the systems
  4. 0:07and let AI handle the implementation.
  5. 0:09And the gap between developers who can
  6. 0:11do that and developers who can't is
  7. 0:14dividing the industry right now. This
  8. 0:16app is what that looks like when you do
  9. 0:18it well. Real-time multiplayer SaaS, AI
  10. 0:21agents running in the background, full
  11. 0:23production code, and I didn't write a
  12. 0:26single line of it. An agent built the
  13. 0:28whole thing. And by the end of this
  14. 0:30video, you'll have built it, too. The
  15. 0:32same app, the same stack, the same way I
  16. 0:36did. And here's what makes this
  17. 0:37different from other AI build tutorials.
  18. 0:40I built this app using the exact
  19. 0:42methodology the app itself is designed
  20. 0:45to teach. Specs first, architecture
  21. 0:48defined, every feature planned before we
  22. 0:51start building. I've been doing this
  23. 0:52architecture work by hand before every
  24. 0:55serious project for years. And at some
  25. 0:58point, it hit me. I'm a developer. Why
  26. 1:01am I doing all of this manually when I
  27. 1:03could build the tool that does it with
  28. 1:05me? So, I did. This is Ghost AI, a
  29. 1:09real-time collaborative workspace where
  30. 1:11you describe a system in plain English
  31. 1:14and then AI agent maps it onto a shared
  32. 1:17canvas live. Your team edits the design
  33. 1:20together and when it's ready, the app
  34. 1:23generates a complete technical
  35. 1:24specification you can build from.
  36. 1:27Now, if you've tried building anything
  37. 1:29serious like this with AI, you already
  38. 1:31know the wall.
  39. 1:33The first few hours feel incredible and
  40. 1:35then a week later, the agent has
  41. 1:37forgotten every decision you've made,
  42. 1:39one new feature breaks three others, and
  43. 1:42the code base you were excited about
  44. 1:44just starts fighting you.
  45. 1:45That's not an AI problem. It's an
  46. 1:48architecture problem. And it's the same
  47. 1:50wall all of you are hitting in your
  48. 1:52careers where the senior dev advice
  49. 1:54online sounds great as long as you're
  50. 1:57already senior. The developers who win
  51. 2:00in this market aren't avoiding AI, and
  52. 2:03they're not handing everything over to
  53. 2:05it, either.
  54. 2:06They're learning to think like senior
  55. 2:08engineers, and then using AI to build at
  56. 2:11the speed of one. And that's what this
  57. 2:13video teaches. By the end, you'll know
  58. 2:16how to design a system before writing
  59. 2:19any code, how to use the six-file
  60. 2:21context system I write before every
  61. 2:24project, and how a senior engineer
  62. 2:27actually thinks when working with AI.
  63. 2:29Oh, and that six-file context system I
  64. 2:31just mentioned, I've packaged it into a
  65. 2:34free guide you can grab and use on any
  66. 2:36of your upcoming projects, not just this
  67. 2:38one. The link is down in the
  68. 2:39description. Next, the stack is Next.js,
  69. 2:43React 19, Liveblocks for real-time
  70. 2:46collaboration with agents, Trigger.dev
  71. 2:49for background work with AI agents,
  72. 2:51Clerk for auth and user management,
  73. 2:54Prisma and Postgres for data, Vercel
  74. 2:57Blob for storage, all production grade
  75. 3:00and deployed by the end of the video.
  76. 3:03So, one person with the right system can
  77. 3:06now build what used to take a team. And
  78. 3:09by the end of the next few hours, that
  79. 3:11person is you.
  80. 3:12So,
  81. 3:13let's build it.
  82. 3:17Before we open up a single tool, I want
  83. 3:19to spend the next 10 minutes on the part
  84. 3:22of the video that I think is most
  85. 3:24important, and that decides whether what
  86. 3:27you're building ships or falls apart in
  87. 3:30the third week. There's going to be no
  88. 3:32syntax and no code in this section.
  89. 3:35Rather, what I'm teaching you is the way
  90. 3:37that I think before I write a single
  91. 3:40prompt, and the way I plan a build
  92. 3:43before I touch the agent, and the system
  93. 3:46that I use to keep AI from drifting
  94. 3:48halfway through a project.
  95. 3:50So that by the end, you'll know the
  96. 3:52conversations to have before you build
  97. 3:55the six-file context system that turns
  98. 3:57an AI agent from a guesser into a
  99. 4:00developer who already knows your
  100. 4:02codebase,
  101. 4:03and how to break any project into units
  102. 4:06the agent can ship cleanly one at a
  103. 4:08time. So, if you've been frustrated by
  104. 4:11AI breaking your code,
  105. 4:13then this is the video that fixes it.
  106. 4:14The intro touched on something I want to
  107. 4:17sit with for a minute.
  108. 4:19You heard me say senior engineers a lot.
  109. 4:22And if you're early in your career, that
  110. 4:24framing probably hit a nerve. So, let me
  111. 4:27be direct about what I mean.
  112. 4:29The job market for developers right now
  113. 4:32is harder than it was 2 years ago.
  114. 4:35Some entry-level work has been
  115. 4:37automated. Clients who used to hire
  116. 4:39freelancers for straightforward projects
  117. 4:42are now doing it themselves. And a lot
  118. 4:44of people who learn to prompt without
  119. 4:47learning how to think are now flooding
  120. 4:49the market. So, if you're worried about
  121. 4:51that, you're not wrong to be worried.
  122. 4:54But the developers getting squeezed
  123. 4:56aren't the ones who learned deeply.
  124. 4:59They're the ones who learned just enough
  125. 5:01to execute without understanding the
  126. 5:03system behind it. That was always a
  127. 5:06fragile place to be.
  128. 5:08And AI just made that fragility visible
  129. 5:11faster.
  130. 5:12So, the way through is to learn the kind
  131. 5:15of thinking that AI cannot replace. The
  132. 5:18architectural thinking, the
  133. 5:20systems-level judgment, and then use AI
  134. 5:23to build at the speed of someone twice
  135. 5:25your experience. The clearer your
  136. 5:28understanding of what you're building,
  137. 5:30the better the AI output. Which means
  138. 5:32that learning properly isn't a waste of
  139. 5:35time in the AI era. It's the best
  140. 5:37investment that makes everything else
  141. 5:39possible.
  142. 5:41So, when I say things like think like a
  143. 5:44senior engineer in this video, I don't
  144. 5:46mean you need 10 years of experience to
  145. 5:48apply this.
  146. 5:50These are learnable habits and you can
  147. 5:52start building them today on this
  148. 5:54project. And here's something most
  149. 5:56developers outside of Big Tech don't
  150. 5:58really know. At Google, Amazon, and
  151. 6:01Netflix, before any serious project
  152. 6:04starts, engineers spend weeks writing
  153. 6:07documents and sometimes months.
  154. 6:10Design docs, one-pagers, RFCs, the
  155. 6:14format changes by company, but the
  156. 6:16principle is the same.
  157. 6:18Figure out what you're building before
  158. 6:21you build it.
  159. 6:22And senior engineers at these companies
  160. 6:24sometimes go months without writing
  161. 6:26production code. They're designing
  162. 6:28systems, making architectural decisions,
  163. 6:31reviewing what other engineers ship. So,
  164. 6:34software engineering has never really
  165. 6:36been about typing the most lines per
  166. 6:38day.
  167. 6:39It's always been about thinking clearly
  168. 6:41about what should exist before you build
  169. 6:44it.
  170. 6:45And AI didn't invent that discipline. It
  171. 6:48just made it the most important skill in
  172. 6:49the room. And that's the whole
  173. 6:51foundation for the spec-driven agentic
  174. 6:54development course that I've been
  175. 6:55developing for a long time now. So, if
  176. 6:58you want to stay up-to-date on how
  177. 7:00that's going and receive an occasional
  178. 7:01email where I share my thoughts at the
  179. 7:03current state of the industry, I'll
  180. 7:05leave the link down below so you can
  181. 7:06subscribe for the newsletter. But, let
  182. 7:08me immediately make it concrete in this
  183. 7:10video.
  184. 7:11Here are two different prompts that two
  185. 7:14different developers might write to
  186. 7:16build the same feature.
  187. 7:18The first one says, "Build me a SaaS app
  188. 7:21with authentication and a real-time
  189. 7:23canvas."
  190. 7:24And the second one says,
  191. 7:25"I'm adding a LiveBlocks room provider
  192. 7:28to the workspace route.
  193. 7:29Auth is already handled by Clerk
  194. 7:31middleware. The canvas uses React Flow.
  195. 7:35Room tokens should be issued only after
  196. 7:38verifying project membership. Wire the
  197. 7:41provider into the existing workspace
  198. 7:43layout without touching the sidebar or
  199. 7:45navbar. Both developers want roughly the
  200. 7:49same thing.
  201. 7:50But the second prompt reveals a
  202. 7:52developer who knows their auth layer,
  203. 7:54understands their component boundaries,
  204. 7:57and knows what should and shouldn't be
  205. 7:58touched. They've thought about the
  206. 8:00system, so they're communicating
  207. 8:02decisions and not wishes.
  208. 8:04So, the AI isn't smarter when it reads
  209. 8:07the second prompt. The developer is.
  210. 8:10And that is the difference between vibe
  211. 8:12coding and what I'm going to teach you,
  212. 8:14which is spec-driven development, which
  213. 8:17is also the premise behind that
  214. 8:19spec-driven agentic development course
  215. 8:21that I'm actively developing. Vibe
  216. 8:23coding focuses on the outcome.
  217. 8:26You describe what you want, let the
  218. 8:28agent run, and react to whatever comes
  219. 8:31out.
  220. 8:32For a weekend prototype, that's fine.
  221. 8:35But for anything you're going to
  222. 8:36maintain, it just collapses.
  223. 8:39New features break the old ones, the
  224. 8:42code base starts contradicting itself,
  225. 8:44and you spend more time untangling AI
  226. 8:46mistakes than actually building.
  227. 8:49Spec-driven keeps the thinking with you
  228. 8:52and gives the agent a system to execute
  229. 8:55against.
  230. 8:56You stay the architect and the agent
  231. 8:59becomes the implementation engine. So,
  232. 9:01how do you actually build that system?
  233. 9:03Because that's the part that nobody
  234. 9:05really teaches. It starts before you
  235. 9:07open up any AI coding tool, with a
  236. 9:10conversation. When I get an idea for
  237. 9:12something I want to build, I open up a
  238. 9:15planning AI, ChatGPT, Claude, or Gemini,
  239. 9:18whichever's on hand, and I talk through
  240. 9:20it. What does this thing actually do?
  241. 9:22Who uses it? What are the core flows?
  242. 9:25Where are the complex patterns, and what
  243. 9:26could go wrong?
  244. 9:28I push back on the answers and let AI
  245. 9:31pressure test my thinking until the
  246. 9:33system becomes clear in my head. This
  247. 9:36conversation is the work. It's what
  248. 9:38senior engineers do before they build,
  249. 9:41except they usually do it in their head
  250. 9:43or on a whiteboard. But, doing it with
  251. 9:45AI externalizes it and makes it faster.
  252. 9:49When the system is clear, you write it
  253. 9:51down. And that's where the six-file
  254. 9:53context system comes from.
  255. 9:54Not from sitting at a blank page trying
  256. 9:56to write documentation, but from taking
  257. 9:59the output of the architectural
  258. 10:01conversation and organizing it into
  259. 10:03documents that travel with the project
  260. 10:06for its entire life. For Ghost AI, I
  261. 10:09organized everything into one folder
  262. 10:11called context.
  263. 10:13Six files, and what matters is that
  264. 10:15before your AI agent writes anything, it
  265. 10:18already knows what you're building, how
  266. 10:20it fits together, what the rules are,
  267. 10:22and where things stand right now. That's
  268. 10:24what you're going to learn about in this
  269. 10:26video. But, very quickly, here's what
  270. 10:28each one of them does at a glance.
  271. 10:31The project overview covers what the
  272. 10:34product is, who is it for, the core
  273. 10:36flows, and what's deliberately out of
  274. 10:39scope.
  275. 10:40The architecture file defines the tech
  276. 10:42stack, the boundaries between layers,
  277. 10:45and the invariants the codebase must
  278. 10:47never break. The code standards keeps
  279. 10:50the agent consistent across every unit
  280. 10:52of the build with shared TypeScript and
  281. 10:55Next.js conventions. The AI workflow
  282. 10:58rules keep the agent disciplined,
  283. 11:00defining how to scope work and what to
  284. 11:02do when something needs a decision.
  285. 11:05The UI context holds design tokens and
  286. 11:08component conventions, so the UI stays
  287. 11:11coherent across every page the agent
  288. 11:13ships.
  289. 11:14And the progress tracker, which is the
  290. 11:16one most developers skip and most need,
  291. 11:19holds the current phase, what's in
  292. 11:21progress, what's complete, and the
  293. 11:23architectural decisions made along the
  294. 11:25way. It's the only file that actually
  295. 11:27updates constantly throughout the build.
  296. 11:30And it's how the agent picks up exactly
  297. 11:32where you left off in a single prompt.
  298. 11:34These six files are what make the
  299. 11:37difference an AI agent that drifts and
  300. 11:40one that executes. And you don't have to
  301. 11:42build them from scratch for every
  302. 11:44project. I've put together a free blank
  303. 11:47template of all six files with
  304. 11:49step-by-step instructions on how I
  305. 11:51generate them using AI for whichever
  306. 11:54project I'm working on. And it's not
  307. 11:56specific to Ghost AI. It works for any
  308. 11:58application. Click the link down in the
  309. 12:00description to get it so you can apply
  310. 12:02this methodology to your own project
  311. 12:04starting today.
  312. 12:06We'll open up each one of these and I'll
  313. 12:08walk you through what's actually inside
  314. 12:10in the next lesson when we set up the
  315. 12:12project architecture for real. But yeah,
  316. 12:14once these six files exist, the build
  317. 12:17runs in units. We're going to break down
  318. 12:19the project into specific scoped pieces
  319. 12:22before we start. Not vague phases like
  320. 12:25build a dashboard, but concrete units
  321. 12:28small enough to build in a single focus
  322. 12:31session with clear conditions for what
  323. 12:33done looks like. That means that
  324. 12:35together for Ghost AI, we'll map out the
  325. 12:38entire build. Each lesson will have its
  326. 12:41own spec file. The spec defines the
  327. 12:44goal, the design decisions, the
  328. 12:46implementation details, dependencies,
  329. 12:48and a checklist of what has to be true
  330. 12:51before the unit is complete.
  331. 12:53You write the spec in the same way you
  332. 12:55write the context file through a
  333. 12:57conversation with the planning AI.
  334. 12:59Then you give the spec to your coding
  335. 13:01agent in one prompt. Make sure to read
  336. 13:04that spec. Mark that unit as in progress
  337. 13:07in the progress tracker. Implement it
  338. 13:09exactly as specified without going
  339. 13:12beyond scope. The agent will read your
  340. 13:14spec, read your context file, and build
  341. 13:17against a defined system instead of
  342. 13:20guessing.
  343. 13:21You review it against the checklist and
  344. 13:24if it passes, you close the unit, push
  345. 13:26the code, and move to the next spec. If
  346. 13:29something's off, you write a focused
  347. 13:32corrective prompt, exactly what's wrong,
  348. 13:35exactly what you expect, fix that
  349. 13:36specific thing, and move on.
  350. 13:39That's the entire workflow, the same one
  351. 13:41I used to build Ghost AI, and the same
  352. 13:44one you're about to use to build it with
  353. 13:47me. Oh, and last thing before we begin.
  354. 13:49These files take time to write. The
  355. 13:52conversation, the architectural
  356. 13:54decisions, the unit planning, all of it
  357. 13:57is real upfront work. And a lot of
  358. 13:59developers skip it because they want to
  359. 14:01feel productive immediately. I mean,
  360. 14:04I've done that as well. So, you open up
  361. 14:06the agent, type a prompt, and start
  362. 14:09watching code appear.
  363. 14:10But, that's the trap. The time you save
  364. 14:14by skipping this is the time you lose in
  365. 14:17week three debugging AI output that's
  366. 14:20drifted away from anything coherent. So,
  367. 14:23do this work once, and you'll do it
  368. 14:25faster every project after. And finally,
  369. 14:28it's time to build.
  370. 14:32Okay, enough talk, and let's build.
  371. 14:36Open up your desktop and create a new
  372. 14:38folder. Call it something like Ghost AI,
  373. 14:42and then simply drag and drop it into
  374. 14:44your favorite code editor. For this
  375. 14:46video, I'll be using VS Code as we have
  376. 14:49the file explorer on the left side, we
  377. 14:51have the code in the middle, and then we
  378. 14:53have the chat window which you can open
  379. 14:55up by pressing command shift P, and then
  380. 14:58just search for chat. Or, I think it's
  381. 15:00just command shift I to open it as well.
  382. 15:03No matter which agent you're using, is
  383. 15:05it Copilot, Claude, Codex, or whatever,
  384. 15:07the interface is more or less the same.
  385. 15:10This is how it looks like on Codex, and
  386. 15:12this is just general chat.
  387. 15:15So, this video is completely agentic
  388. 15:17tool agnostic. The thinking and the
  389. 15:20specs are what matters. The tool is
  390. 15:23completely your call. I'll personally be
  391. 15:25using Claude code as that's what most
  392. 15:27people are using and what's we're using
  393. 15:29internally within JSM. If you want the
  394. 15:31budget option, you can go with Codex.
  395. 15:34There's the Go plan, which is super
  396. 15:35cheap, the plus plan, which is also
  397. 15:37cheap, and I think they're also offering
  398. 15:39a month for free. And if you're already
  399. 15:41paying for something like Cursor, Win
  400. 15:43serve, or any other AI agent, just use
  401. 15:46that. I'll make sure you don't spend a
  402. 15:48lot of tokens, no matter what you're
  403. 15:49using, and that you learn a ton. Okay,
  404. 15:52so let's get started.
  405. 15:54We'll start with a fresh Next.js
  406. 15:56project. I'll do this manually with no
  407. 15:58prompts and agents.
  408. 16:00It's just a single command and it takes
  409. 16:02a couple of seconds and that'll give us
  410. 16:04a clean and predictable foundation to
  411. 16:06build everything else in top of. So,
  412. 16:08simply open up your integrated terminal
  413. 16:11and run MPX create next app at latest
  414. 16:15dot, which is going to create it in the
  415. 16:16current repository. It'll ask you
  416. 16:18whether you want to install the Next.js
  417. 16:20installer, so you can just say Y, yes,
  418. 16:22and proceed.
  419. 16:23And I also want you to know that you
  420. 16:25don't necessarily have to follow along
  421. 16:27by using Next.js.
  422. 16:29Of course, the majority of the context
  423. 16:31for AI agents we'll be working with is
  424. 16:33going to be featured around Next.js, but
  425. 16:36if you want to build this in TanStack,
  426. 16:38Angular, Vue, or anything else, the
  427. 16:40concepts will still be as valuable.
  428. 16:43So, let's just say Y for now. It's going
  429. 16:45to ask you whether you would like to use
  430. 16:46the defaults, so just press enter,
  431. 16:49which is going to install React,
  432. 16:51TypeScript, ESLint, Tailwind CSS, and
  433. 16:54the app router. Let's give it a moment
  434. 16:56until it finishes. Once the installation
  435. 16:58finishes, we need to clear out the
  436. 17:00default boilerplate.
  437. 17:01That's going to be within app and then
  438. 17:04page. Next.js ships with a lot of
  439. 17:06placeholder content that, honestly, we
  440. 17:08don't really need. Now, you could go
  441. 17:11ahead and clean it up manually by
  442. 17:13opening up your globals.css
  443. 17:15and cleaning everything besides the
  444. 17:17Tailwind CSS directives, deleting some
  445. 17:20SVGs and other stuff within the public
  446. 17:22folder, and replacing the page.tsx with
  447. 17:25a minimal component.
  448. 17:27Or we can use this as our first
  449. 17:29interaction with the coding agent.
  450. 17:33So, go ahead and open up your agent of
  451. 17:35choice. I'll just press command shift I
  452. 17:38to open up my chat sessions. And what I
  453. 17:40love about VS Code is that it's not
  454. 17:43shying away from the agnostic approach
  455. 17:45to agents.
  456. 17:46You can use their agents right here,
  457. 17:48such as Copilot CLI,
  458. 17:51or if you head over to extensions and
  459. 17:54then install an extension like Claude
  460. 17:56Code,
  461. 17:58which has like 12 million downloads, or
  462. 18:01something like CodeX, which has 8
  463. 18:03million downloads,
  464. 18:05and I installed both, you can actually
  465. 18:07just navigate over to them by selecting
  466. 18:10additional views,
  467. 18:11and then choosing the extension you
  468. 18:13want. Of course, alternatively, you can
  469. 18:15also just run all of these agents within
  470. 18:17the CLI by typing Claude, and you're in.
  471. 18:21For the longest time, I've been using
  472. 18:23Claude CLI, but the Claude VS Code
  473. 18:26extension recently got so much better,
  474. 18:28and honestly, it's working the same way
  475. 18:30as the CLI does, but with a bit of a
  476. 18:32nicer UI and a graphical interface that
  477. 18:35allows us to use it in an easier way.
  478. 18:37So, that's what I'll be proceeding with.
  479. 18:39I'll expand it so we have more space to
  480. 18:41work with, and you can notice that
  481. 18:43there's a little microphone button right
  482. 18:44here. So, you can either tap it or hold
  483. 18:47the command D key to speak into it. With
  484. 18:50CodeX and other agents, you can either
  485. 18:52type it manually,
  486. 18:53or what you can do is use a tool like
  487. 18:57Whisper Flow, not sponsored by the way,
  488. 18:59which is what I use to write prompts
  489. 19:02when I speak with agents. Speaking is
  490. 19:04just much faster. If you install it, you
  491. 19:06can just press the command key
  492. 19:09and start speaking into it. Like, clean
  493. 19:12up this Next.js boilerplate. Strip
  494. 19:15globals.css down to just the Tailwind
  495. 19:17directives. Delete all SVGs in the
  496. 19:20public folder, but keep the favicon.
  497. 19:23Remove page.module.css.
  498. 19:26Replace page.tsx with a minimal
  499. 19:28component that just renders a centered
  500. 19:31div saying Ghost AI.
  501. 19:34And I can stop it right here, and you
  502. 19:36can immediately see the output. Cool
  503. 19:38stuff, right? Go ahead and write
  504. 19:40something like this, and let's see how
  505. 19:42well Agent handles it.
  506. 19:43Also, just so we don't have to give it
  507. 19:46permissions every single time whenever
  508. 19:47we're doing something, for now I will
  509. 19:49say edit manually. Oh, and of course, we
  510. 19:52have to talk about the actual models
  511. 19:54we'll be using. In this case, we're
  512. 19:56using the default model, which is Opus 4
  513. 19:587 with a million token context, which is
  514. 20:00amazing, but you're going to hit the
  515. 20:02limits very soon. Instead, you'll be
  516. 20:04able to follow along this entire build
  517. 20:06with using Sonnet 4 6. It's fast, it's
  518. 20:10inexpensive, and it sometimes get lost
  519. 20:13unless you have the context files, which
  520. 20:16I'll teach you how to build so you guide
  521. 20:17it in a bit of a better way, and make it
  522. 20:20work much more like Opus does. So,
  523. 20:23that's what I'm going to select. If
  524. 20:24you're working with Codex, you can also
  525. 20:26go ahead and choose any model you'd
  526. 20:27like, like 5 4, 5 3, or anything else.
  527. 20:31Okay, let's give it a shot. It's going
  528. 20:33to think for a couple of seconds, read
  529. 20:35all the necessary files, and apply all
  530. 20:38four changes.
  531. 20:39Globals, just the import. Page, minimal
  532. 20:42centered Ghost AI component. Deleted
  533. 20:44five SVGs, but kept the favicon. And
  534. 20:47this file that I tried to trick it with
  535. 20:48doesn't really exist, so there's nothing
  536. 20:50to delete.
  537. 20:51You can see all the changes in the diff
  538. 20:53right here, and you can also see which
  539. 20:55files have been modified on the left
  540. 20:56side.
  541. 20:58There we go, just simple Ghost AI, and
  542. 21:01just the import for Tailwind. Which
  543. 21:03means that these classes right here
  544. 21:04should work to center the div. Before we
  545. 21:06run it, let's actually head over to
  546. 21:08package.json.
  547. 21:10Make sure that the project name is set
  548. 21:12to Ghost AI, and let's run it by running
  549. 21:15npm run dev.
  550. 21:18It'll run it on localhost:3000. So, if
  551. 21:21you open it up, you should be able to
  552. 21:23see something that looks like this.
  553. 21:25This means that our project is
  554. 21:26initialized, it's cleaned up, and now we
  555. 21:29are ready to move to the part that
  556. 21:31actually determines just how well
  557. 21:33everything goes. Setting up our context
  558. 21:36files and planning the build before the
  559. 21:38agent writes a single feature. So, let's
  560. 21:42do that next.
  561. 21:45Not that long ago, I talked about how
  562. 21:47senior engineers spend weeks designing
  563. 21:50systems before anyone writes a line of
  564. 21:53code.
  565. 21:54They write design docs, they define
  566. 21:56boundaries, and they make decisions
  567. 21:59early on so that everything else becomes
  568. 22:01predictable.
  569. 22:02So, let me show you how we are going to
  570. 22:04approach that.
  571. 22:06We're going to create a new folder right
  572. 22:08here in the root of our application,
  573. 22:10which we're going to call context.
  574. 22:12Everything inside of it is what your
  575. 22:15coding agent will read before it does
  576. 22:17anything. This is how it knows your
  577. 22:19project, and this is how it stays
  578. 22:21consistent across every session, commit,
  579. 22:24or unit of the build.
  580. 22:26So, you can switch multiple agents and
  581. 22:28share the context file with another
  582. 22:30developer so he can continue working
  583. 22:32with his agent from there. That's the
  584. 22:34catch. We're going to have a couple of
  585. 22:36different files within the context
  586. 22:37folder. Now, I don't want you to do a
  587. 22:40lot of copy-pasting, so I'll provide you
  588. 22:42with the final zipped context folder so
  589. 22:44we can easily review everything
  590. 22:46together. So, delete the context folder
  591. 22:48you just created. In the video kit link
  592. 22:51down in the description, get the zipped
  593. 22:53version of the folder, unzip it, and
  594. 22:55then just drag and drop it in.
  595. 22:57And here, you'll see six, well, seven
  596. 23:00different files with this agents.md.
  597. 23:02Might seem scary at first, but don't
  598. 23:05worry as I walk you through every single
  599. 23:07one of these files and show you how you
  600. 23:09can create them for yourself in the
  601. 23:10future. Let's start with the project
  602. 23:13overview. And let me walk you through
  603. 23:16why it's structured the way it is
  604. 23:18because understanding this is more
  605. 23:20valuable than just copying the file.
  606. 23:23Currently, we're looking at the markdown
  607. 23:25version of the file, but in VS Code, I
  608. 23:28believe this is done by default, you can
  609. 23:30also open the preview to the side by
  610. 23:32pressing command K and then V or just
  611. 23:34pressing this icon at the top and then
  612. 23:36you can close the actual MD and just see
  613. 23:38the formatted version. I think it's a
  614. 23:40bit easier to read this way. I typically
  615. 23:42open up these project overview documents
  616. 23:45with a one paragraph summary and then a
  617. 23:48numbered list of goals. This gives the
  618. 23:51agent the big picture immediately. So,
  619. 23:54when a requirement gets ambiguous 3
  620. 23:56weeks into the build and it will, this
  621. 23:59is where you resolve it. The agent uses
  622. 24:02this constantly to understand intent
  623. 24:05when a spec isn't specific enough.
  624. 24:08Notice the goals are concrete and
  625. 24:10measurable, not build a good canvas.
  626. 24:13Instead, let authenticated users create
  627. 24:16and manage architecture projects or let
  628. 24:19AI generate an initial architecture from
  629. 24:21a natural language prompt. The agent
  630. 24:24knows exactly what success looks like.
  631. 24:27And yeah, this is useful for us while we
  632. 24:29are going through the process of
  633. 24:30building the app. Just so you know what
  634. 24:32we are building. Just so everybody in
  635. 24:34the team, in this case me teaching you
  636. 24:36and you following along and you building
  637. 24:38it with me, are all on the same page. Go
  638. 24:42stay eye is a real-time collaborative
  639. 24:44system design workspace. Users describe
  640. 24:47a system in plain English and then AI
  641. 24:49agent maps that system onto a shared
  642. 24:51canvas. Collaborators refine the
  643. 24:54architecture and the app generates a
  644. 24:56technical specification document from
  645. 24:58the resulting graph.
  646. 25:00Okay, great. We have the overview, we
  647. 25:03have the goals, and then we have the
  648. 25:05core user flow. So, let me zoom this in
  649. 25:08and let's go through this together
  650. 25:10because this sequence matters. The agent
  651. 25:13can sometimes lose track of how features
  652. 25:16connect to each other.
  653. 25:17By defining a full flow from sign in to
  654. 25:21the spec generation, we make the logical
  655. 25:23sequence explicit. So, the agent won't
  656. 25:26try to build the spec generation feature
  657. 25:28on the login page because it knows the
  658. 25:30user has to create a project and the
  659. 25:32design architecture first. In the
  660. 25:34features, we get specific about
  661. 25:37technologies. And I want to take a
  662. 25:39second on this because the tools I chose
  663. 25:41for Ghost AI weren't random. I took a
  664. 25:44lot of time to choose what actually
  665. 25:46makes sense. Starting with
  666. 25:47authentication. For user sign in, route
  667. 25:50protection, project creation, ownership,
  668. 25:53and collaborator access, we're using
  669. 25:55Clerk. Could you have gone and created
  670. 25:57the full auth from scratch? I mean,
  671. 25:59sure, but it would take you a couple of
  672. 26:01days up to a couple of weeks to do it
  673. 26:03properly, even with AI.
  674. 26:06And when you do it, it's never going to
  675. 26:07be as secure as something like Clerk.
  676. 26:10And nowadays, the speed of shipping
  677. 26:12matters more than anything. If you have
  678. 26:15a specific product you want to push, you
  679. 26:17want to get it in front of potential
  680. 26:18users as soon as possible. And that's
  681. 26:20why for many of these agentic builds,
  682. 26:22it's just a no-brainer to plug and play
  683. 26:25Clerk into it. Especially considering
  684. 26:27just how well Clerk works with your
  685. 26:30agents. You can either just copy the
  686. 26:32prompt or use Clerk skills with
  687. 26:36whichever agent you're using.
  688. 26:38That way, it'll immediately become a
  689. 26:40professional developer at using Clerk
  690. 26:42and it'll be able to implement it within
  691. 26:45any project. And there's also the MCP,
  692. 26:48which is a server that allows AI agents
  693. 26:51like Claude,
  694. 26:52or others
  695. 26:54to access Clerk as the case snippets and
  696. 26:56implementation patterns, and basically
  697. 26:58implement everything for you. Oh, and
  698. 27:00not to mention that Clerk CLI is also
  699. 27:03being worked on. You'll just be able to
  700. 27:06ask your agent to use the Clerk CLI to
  701. 27:08add auth to your app, allowing you to
  702. 27:10not even have to leave your terminal or
  703. 27:12copy and paste any API keys. Clerk right
  704. 27:14now really is the leader in agentic
  705. 27:17development. And with a completely free
  706. 27:19pricing of up to 50,000 monthly
  707. 27:23recurring users, it's a no-brainer for
  708. 27:25me to build all of my applications with
  709. 27:27it. So, while we're here, I'll leave the
  710. 27:30link down in the description. You can
  711. 27:31click it, and then sign up so that we
  712. 27:33can very soon more easily get started
  713. 27:35with building. Okay, on top of auth, the
  714. 27:38most important part of our application
  715. 27:40is the collaborative canvas.
  716. 27:42And in this case, I wanted to make it
  717. 27:45real-time. So, for any kind of canvas,
  718. 27:47it makes sense to use React Flow. And if
  719. 27:50you want to make any part of your
  720. 27:51application live with cursors, so you
  721. 27:54can see what other people are doing,
  722. 27:55presence indicators, and node or edge
  723. 27:58editing, I mean, it just makes sense to
  724. 28:00use Liveblocks. Liveblocks is the leader
  725. 28:03for anything multiplayer, but not only
  726. 28:05apps, agents as well. Let me show you
  727. 28:08what I mean.
  728. 28:09I mean, this is the app without
  729. 28:11Liveblocks, and then if you add it, you
  730. 28:13immediately get live avatars. You can
  731. 28:16get the AI chat to generate something,
  732. 28:19and you can also leave comments and
  733. 28:21track what people are doing within your
  734. 28:22app, which is super useful for the
  735. 28:24collaborative canvas we're building.
  736. 28:26But, what's even cooler is interacting
  737. 28:29directly with AI assistants to do
  738. 28:32something within our application. I
  739. 28:33mean, if you try to build all of this
  740. 28:35from scratch, it would definitely take
  741. 28:37some time. But, with their AI assistants
  742. 28:39feature, you can just watch an AI do it
  743. 28:42for you. Oh, and this whole React Flow
  744. 28:44thing you're seeing, that got released
  745. 28:46recently, which means that in this
  746. 28:48video, we're building the latest stuff
  747. 28:49out there. Oh, and like Clerk and the
  748. 28:52many other amazing dev tools that are
  749. 28:54adapting to agentic development,
  750. 28:56Liveblocks also offers the agent skills,
  751. 28:59which you just have to install, and your
  752. 29:01agent will immediately know what it has
  753. 29:02to do to make the Liveblocks integration
  754. 29:05work. I'll teach you about all of that
  755. 29:07as we continue with the build. After the
  756. 29:09canvas, we have the starter system
  757. 29:11design, which I decided to have because
  758. 29:13it's very difficult for people to start
  759. 29:16with a blank canvas. So, I want to have
  760. 29:18some kind of a curated library of
  761. 29:20pre-built system design templates, where
  762. 29:23users can import a starter template into
  763. 29:25the canvas at any point during editing.
  764. 29:27But also, if the template doesn't do
  765. 29:29what you want it to do, we're going to
  766. 29:31allow our users to generate a system
  767. 29:33design from a prompt with AI. Then, that
  768. 29:37output will be structured as canvas
  769. 29:39nodes, and then we'll write it onto the
  770. 29:41canvas. And finally, we'll take a look
  771. 29:43at everything that is on the canvas, and
  772. 29:45we'll convert it into a technical
  773. 29:47specification in a markdown format. And
  774. 29:49then users will be able to view and
  775. 29:51download the generated specs. Oh, and an
  776. 29:54additional thing that I want to teach
  777. 29:55you is while we're generating stuff with
  778. 29:58AI, that'll obviously take time. As the
  779. 30:00user will likely provide a long idea of
  780. 30:03how they want to architect their app,
  781. 30:05and then the AI output is going to take
  782. 30:07potentially a minute or two. And running
  783. 30:10a more than 60-second AI generation call
  784. 30:13inside a Next.js API route will just
  785. 30:16time out in production. So, that's why
  786. 30:18I'll also teach you how to use
  787. 30:19Trigger.dev. It'll allow us to run
  788. 30:21background tasks that can run as long as
  789. 30:24they need to, with the retry logic and
  790. 30:26status tracking built-in. The way in
  791. 30:28which we'll combine Liveblocks and
  792. 30:30Trigger.dev is pretty amazing. So, we'll
  793. 30:33have to be very clear in letting our AI
  794. 30:35agent understand that it doesn't have to
  795. 30:37invent a custom web socket
  796. 30:39implementation when Liveblocks is
  797. 30:41already in stack, Or it won't try to run
  798. 30:44AI generation inside a request handler
  799. 30:47when trigger dev is defined as the layer
  800. 30:49for that work. Naming the tools we're
  801. 30:51going to use for the project in advance
  802. 30:53is crucial. Oh, and trigger allows you
  803. 30:55to do so much more. Recently, they've
  804. 30:57been diving deeper into allowing you to
  805. 30:59build and deploy AI agents, which is
  806. 31:01something we can explore in an
  807. 31:02additional video. But in this one, we'll
  808. 31:05also focus on many of its features,
  809. 31:07specifically running background tasks
  810. 31:09and reporting back to the front end. So
  811. 31:11while a long task is happening, we can
  812. 31:13keep the user updated on what's
  813. 31:15happening behind the scenes and allow
  814. 31:17the user to continue doing whatever
  815. 31:19they're doing on the application because
  816. 31:20we're no longer blocking the front end
  817. 31:22side while handling a specific task. So
  818. 31:24I'll leave a special link pointing to
  819. 31:26trigger as well as live blocks down in
  820. 31:29the description so you can create your
  821. 31:31accounts and then we'll be able to
  822. 31:32immediately dive into the development.
  823. 31:34Then we have the scope part which
  824. 31:36contains the in scope and out of scope
  825. 31:38features. And it's maybe the most
  826. 31:41important section for keeping your build
  827. 31:43focused. The out of scope section is
  828. 31:45doing serious work right here.
  829. 31:48Billing and subscription systems,
  830. 31:50enterprise permissions, version
  831. 31:51specification history and so on. This is
  832. 31:54telling the agent, don't even think
  833. 31:56about them. But we can add them later on
  834. 31:59after we build the base of our
  835. 32:00application. This is great because it
  836. 32:02keeps every session focused on what we
  837. 32:04are actually building.
  838. 32:06And finally, there's success criteria.
  839. 32:09Here, we define what actually matters.
  840. 32:12These are the benchmarks that your agent
  841. 32:14and you can verify against after each
  842. 32:17major feature lands. Not, does it look
  843. 32:19right? But, can a signed in user create
  844. 32:22and open up a project? Can multiple
  845. 32:24users collaborate? Can the graph be
  846. 32:26converted into a persisted markdown
  847. 32:28specification?
  848. 32:30Very simple, yet concrete.
  849. 32:33So that's our project overview. Written
  850. 32:35in a way that makes sense to agents, but
  851. 32:38also other team members working on the
  852. 32:40project. Next, let's take a look at the
  853. 32:42AI workflow rules. This file is
  854. 32:45different from others in a way that it's
  855. 32:48not about what we're building. It's
  856. 32:50about how the agent behaves when
  857. 32:52building it. And the most important rule
  858. 32:54right here is to work on one feature
  859. 32:57unit or subsystem at a time. We don't
  860. 33:00want to combine unrelated system
  861. 33:01boundaries in a single implementation
  862. 33:03step. And that single rule prevents most
  863. 33:06failures that the agents cause.
  864. 33:08Basically, all of these rules right here
  865. 33:10tell the agent, "Stay in your lane.
  866. 33:13Focus on one part of what you're doing,
  867. 33:15and then move on to the next one." After
  868. 33:17that, we have the code standards. So,
  869. 33:20you can open up that, and let's quickly
  870. 33:23take a look. This file is what keeps the
  871. 33:25code base consistent from our first all
  872. 33:28the way to the last chapter. Without it,
  873. 33:31the agent would drift away. Like,
  874. 33:33specific patterns that it uses for API
  875. 33:35routes when implementing feature five
  876. 33:37might look different from feature 16. Or
  877. 33:40maybe it's going to change some things
  878. 33:41regarding the TypeScript types, or how
  879. 33:43it uses Next.js, how it styles things.
  880. 33:46But here, we add that consistency. Like,
  881. 33:49we tell it, "Make sure to have strict
  882. 33:52mode enabled, and avoid using any." Or
  883. 33:54we're telling it to add use client only
  884. 33:57when the component needs browser
  885. 33:59interactivity. Or for styling, we're
  886. 34:01telling it, "No raw Tailwind color
  887. 34:03classes. Reference the tokens through
  888. 34:06the Tailwind utility names." I think you
  889. 34:08get the point. We want to stay
  890. 34:09consistent. Then, we have the UI
  891. 34:12context, which, as you can guess, dives
  892. 34:14a bit deeper into theming. Like, when I
  893. 34:17was initially coming up with a design
  894. 34:18for this application, I wanted to have
  895. 34:20something that is simple, yet functional
  896. 34:23and modern. And I spoke with AI a bit to
  897. 34:26generate this theme. Dark mode, no light
  898. 34:29mode, Uh, all colors are already
  899. 34:31defined, and we're telling the AI to use
  900. 34:34these colors.
  901. 34:35And again, if you're wondering how
  902. 34:37exactly I created all six of these
  903. 34:40documents by speaking with different AI
  904. 34:42agents, that's something that I'll cover
  905. 34:45in much more detail within the
  906. 34:47spec-driven agentic development course.
  907. 34:49So, you can join the waitlist in the
  908. 34:51description. But, I think you get the
  909. 34:52idea that I didn't just sit down and
  910. 34:54handpick every color in the file. I
  911. 34:56described the aesthetic that I wanted to
  912. 34:58AI, dark, technical, precise, something
  913. 35:01that feels like an engineering tool, and
  914. 35:04then I went back and forth on the
  915. 35:06palette, um, the token names, and this
  916. 35:08is what it came up with. Also, some
  917. 35:10font, border radiuses, and so on. That's
  918. 35:13exactly how you should approach your own
  919. 35:15UI. You don't need to be a designer, but
  920. 35:18you need to know the feel you're going
  921. 35:20for, and then AI can help you get there.
  922. 35:22Oh, and while the project overview gave
  923. 35:25some information about the project, the
  924. 35:28architecture context will give you the
  925. 35:30blueprint on how to build it. Here, I
  926. 35:32specified the tech stack,
  927. 35:35like every technology that we want to
  928. 35:36use, alongside the role that it has
  929. 35:38within the application. For auth, we're
  930. 35:40using Clerk for user identity and route
  931. 35:42protection. For databases, it's going to
  932. 35:44be Prisma and Postgres. For canvas, it's
  933. 35:47going to be Liveblocks and React Flow
  934. 35:50for real-time collaborative canvas.
  935. 35:52For background tasks, it's going to be
  936. 35:54Trigger.dev, and for storage, we're
  937. 35:55going to use Vercel Blobs. We also
  938. 35:57defined some system boundaries, like
  939. 35:59where we're going to put the request
  940. 36:01handlers. Trigger is what we're going to
  941. 36:03use for the long-running background
  942. 36:05jobs, and some other folders that we're
  943. 36:07going to use.
  944. 36:08Then, we defined the storage model,
  945. 36:10where and how we're going to save
  946. 36:12something. And specifically here, I
  947. 36:14decided to use a hybrid storage model,
  948. 36:16which is another senior-level decision.
  949. 36:18We aren't going to be stuffing massive
  950. 36:21JSON blobs or three-page markdown files
  951. 36:23into our database. Instead, we're going
  952. 36:25to use Postgres only for metadata and
  953. 36:28Vercel blob for the actual files. And
  954. 36:31this keeps our database lean. And this
  955. 36:33is important. We also need to tell it
  956. 36:35how different tools are working
  957. 36:37together.
  958. 36:38Since we're using Clerk with Liveblocks,
  959. 36:40we need to set a strict rule that
  960. 36:42project memberships must be verified
  961. 36:45before a Liveblocks token is ever
  962. 36:47issued. This ensures that our Ghost AI
  963. 36:50isn't just collaborative, but secure.
  964. 36:52And finally, invariants are the rules
  965. 36:55that the system must never violate. For
  966. 36:57example, request handlers do not run
  967. 37:00long-lived AI works. That belongs in
  968. 37:02background tasks through trigger.dev.
  969. 37:05Metadata and large artifacts are stored
  970. 37:07in separate layers. Auth and ownership
  971. 37:10are enforced at every mutation boundary.
  972. 37:12Client components only used when needed.
  973. 37:15And the canvas schema must remain
  974. 37:17consistent. Of course, we'll dive much
  975. 37:19deeper into this when we actually dive
  976. 37:21into building the application. But I
  977. 37:23wanted you to have a good idea of what
  978. 37:24it is that we're building. And finally,
  979. 37:26there's the progress tracker. This is
  980. 37:29the only file in the context folder that
  981. 37:31will look completely different by the
  982. 37:33end of this video.
  983. 37:35Right now, it is completely empty.
  984. 37:37Intentionally, because it reflects the
  985. 37:40actual state of the project. And right
  986. 37:42now, nothing has been built yet. So, as
  987. 37:45we complete each lesson, we're going to
  988. 37:47update this file. The current phase,
  989. 37:49what's in progress, what's complete, and
  990. 37:51what's coming next. And remember what I
  991. 37:53said in the beginning about agents
  992. 37:55having no memory between sessions.
  993. 37:57This file is the solution to that
  994. 37:59problem.
  995. 38:00At the start of every new session,
  996. 38:02whether that's tomorrow, next week, or 6
  997. 38:04months from now, one prompt is all it
  998. 38:06takes to restore full context. Our agent
  999. 38:10will read the progress tracker,
  1000. 38:11understand exactly where the project
  1001. 38:13stands, and pick up exactly where you
  1002. 38:15left off. So, you don't have to
  1003. 38:17re-explain yourself. Even though it's
  1004. 38:19going to be a small file, it does more
  1005. 38:21work than any other file in the project.
  1006. 38:23Oh, and finally, there's the agents.md
  1007. 38:26file. Within it, we're going to wire
  1008. 38:29everything together. When you installed
  1009. 38:30Next.js,
  1010. 38:32that file was already created for you
  1011. 38:34automatically at the root. This is the
  1012. 38:36entry point file, and every major coding
  1013. 38:38agent has one. They just name it
  1014. 38:40differently.
  1015. 38:41Claude calls it claude.md, Cursor, Win
  1016. 38:44Surf, and others use different names,
  1017. 38:46but the idea is always the same. It's
  1018. 38:48the first thing that the agent reads at
  1019. 38:50the start of every session.
  1020. 38:52So, Next.js has already added the first
  1021. 38:54section for you, and it tells the agent
  1022. 38:56that this is a recent version, and its
  1023. 38:58training data might be outdated, so read
  1024. 39:00the install documentation before writing
  1025. 39:02any code. Good default, and we can leave
  1026. 39:04it, but now we can add our own part
  1027. 39:06below it.
  1028. 39:08So, copy your agents.md, delete it from
  1029. 39:10the context, and instead move it right
  1030. 39:13here. It's not long, so let's see what
  1031. 39:16do we have within it. We're basically
  1032. 39:17instructing the agent to read all six
  1033. 39:20context files in order before
  1034. 39:22implementing anything, and then to
  1035. 39:25update the progress tracker after each
  1036. 39:27change. And you might think, "Isn't this
  1037. 39:29going to waste context and tokens?"
  1038. 39:32Well, I mean, sure, it has to read
  1039. 39:33through the files, but that's not even
  1040. 39:351/10 of how many tokens you're going to
  1041. 39:37save because there's going to be less
  1042. 39:39back and forth, and less mistakes and
  1043. 39:41bug fixing and correcting while you're
  1044. 39:44implementing the features in the first
  1045. 39:45place. So, that's the system. And now
  1046. 39:48that you understand it, let's start
  1047. 39:50building with it.
  1048. 39:53Now that the context files are ready,
  1049. 39:55before we build a single feature,
  1050. 39:57there's one more thing we need to set
  1051. 39:59up, and skipping this one is the most
  1052. 40:01common mistake I see in AI-assisted
  1053. 40:04projects.
  1054. 40:05And that is the globals.css
  1055. 40:08file.
  1056. 40:09This one right here. We've defined all
  1057. 40:11of our color tokens within our UI
  1058. 40:13context right here. But, if we don't
  1059. 40:16translate those tokens into actual CSS
  1060. 40:18custom properties within the globals.css
  1061. 40:21file, well, it'll just write the inline
  1062. 40:23colors. So, instead of maybe saying
  1063. 40:25something like text faint, it'll just
  1064. 40:28write #505060.
  1065. 40:31And the moment you want to change it,
  1066. 40:32you have to change it across all places.
  1067. 40:35So, let's set it up correctly. And this
  1068. 40:36is also the first real demonstration of
  1069. 40:39the spec-driven workflow in action. So,
  1070. 40:42let's do it properly. Create a new
  1071. 40:44folder inside side of the context folder
  1072. 40:47and call it feature specs, like this.
  1073. 40:51And then inside of it, create the first
  1074. 40:53spec file.
  1075. 40:5501
  1076. 40:56design system.
  1077. 40:59md. And then within it, we want to tell
  1078. 41:01it something like read the agents file
  1079. 41:04before starting.
  1080. 41:06Then, we need to tell it what we're
  1081. 41:07doing here, like adding the design
  1082. 41:09system and the UI components.
  1083. 41:12Then, we're telling it to install and
  1084. 41:15configure shadcn-ui.
  1085. 41:17And then we want it to add the following
  1086. 41:20components.
  1087. 41:21I figured we're going to use these
  1088. 41:23across the rest of the application.
  1089. 41:24Whenever we wanted to modify these files
  1090. 41:27after the installation, so we can
  1091. 41:29specify that.
  1092. 41:30We can also ask it to install
  1093. 41:32lucid-react for icons
  1094. 41:35and create a lib-utils.ts
  1095. 41:38with a reusable class names helper for
  1096. 41:40merging tailwind class names. Although,
  1097. 41:42I think it would do this by default,
  1098. 41:44it's good to mention it.
  1099. 41:46Finally, we want to ensure that all of
  1100. 41:49the components match the existing dark
  1101. 41:51theme within globals.css.
  1102. 41:54And then, we want to apply some checks
  1103. 41:56when it is done.
  1104. 41:58For example, we want to make sure that
  1105. 42:00all components import without errors,
  1106. 42:02that the cn works properly, and that no
  1107. 42:05default light styling appears. This is
  1108. 42:08what we call a feature specification or
  1109. 42:10a feature spec.
  1110. 42:12Every unit we build from here on has
  1111. 42:14one.
  1112. 42:15The spec tells the agent exactly what to
  1113. 42:18do, exactly what not to touch, and how
  1114. 42:21to verify when it's done. No guessing.
  1115. 42:24So, let's open up our agent by pressing
  1116. 42:26command shift I. As I said, you can use
  1117. 42:29anyone. I'll use Claude code.
  1118. 42:31I'll start a new chat, and you can even
  1119. 42:34open up that file, which will
  1120. 42:35automatically put it within its context.
  1121. 42:37And then, you can tell it something like
  1122. 42:39read
  1123. 42:41add 01 design system update
  1124. 42:45the progress tracker MD file to mark
  1125. 42:49this as in progress.
  1126. 42:51And then, implement exactly as
  1127. 42:55specified. This is the same template
  1128. 42:57we'll use often, but the only thing
  1129. 42:58that's going to change is going to be
  1130. 43:00the spec of the feature we're
  1131. 43:01developing. So, let's go ahead and run
  1132. 43:04it, and notice what will happen before
  1133. 43:06the agent writes a single line of code.
  1134. 43:08It'll read the specification, and then
  1135. 43:11update the progress tracker. You can see
  1136. 43:14how it's going through all the files we
  1137. 43:16prepared for it, and only once it has
  1138. 43:18enough context, it'll write and save the
  1139. 43:20plan, and then execute it. And only when
  1140. 43:23it has a full plan, it will update the
  1141. 43:25progress tracker.md, and then start
  1142. 43:27doing it. So, we can already take a look
  1143. 43:30at the progress tracker,
  1144. 43:32and I'll open it up so we can see what
  1145. 43:34it is doing. And you can see that the
  1146. 43:35current phase is feature 01 system
  1147. 43:38design, the current goal to install and
  1148. 43:40configure shadcn with dark theme, and
  1149. 43:43that is currently in progress with the
  1150. 43:45feature 02 to be done. And it's also
  1151. 43:48adding the architectural decisions
  1152. 43:50needed for every step, as well as the
  1153. 43:52session notes. It's going to ask us
  1154. 43:54whether we want to run this command to
  1155. 43:55install shadcn, so I'll say yes, go
  1156. 43:58ahead. And after it installs everything,
  1157. 44:00it'll verify it with TypeScript. It
  1158. 44:03looks like it completed with zero
  1159. 44:04errors, and finally, it needs to update
  1160. 44:06the progress tracker to complete it.
  1161. 44:09So, we can already open it up right here
  1162. 44:12under progress tracker, and it should
  1163. 44:14move it from current phase over to
  1164. 44:16completed.
  1165. 44:18So, now at any point in our application,
  1166. 44:20if we come back 2 months later, it'll
  1167. 44:23know that it's using shadcn, Tailwind V4
  1168. 44:26with the following components, only
  1169. 44:27using dark theme,
  1170. 44:29and all the additional helpers,
  1171. 44:31as well as the architectural decisions.
  1172. 44:33So, once it finishes, the agent will
  1173. 44:35have configured shadcn, installed the
  1174. 44:38components, and verified that it all
  1175. 44:39works. So, what do you say that we test
  1176. 44:41it out?
  1177. 44:42Back on localhost 3000, the first good
  1178. 44:45sign should be that we're now officially
  1179. 44:47in dark mode. And if you head over to
  1180. 44:49the home page, that's going to be within
  1181. 44:51app page, we can try to use a shadcn
  1182. 44:54button component coming from components
  1183. 44:57UI button, and we can try to make it say
  1184. 44:59something like click me. You can see
  1185. 45:01it's coming from there,
  1186. 45:03and it follows our UI theme. That's it.
  1187. 45:06Our first feature, being the theming and
  1188. 45:09shadcn setup, is done. And that's the
  1189. 45:11spectrum workflow I was telling you
  1190. 45:13about. We define the specifications, we
  1191. 45:16run the prompt, we verify the output,
  1192. 45:19and then we move on. But just before we
  1193. 45:21move on to our second feature, I want to
  1194. 45:24add just one little extra step to this
  1195. 45:26whole workflow that's going to make our
  1196. 45:28codebase even more scalable,
  1197. 45:30predictable, and less error-prone. And
  1198. 45:33that is whenever we implement a specific
  1199. 45:35feature, let's also review it with Code
  1200. 45:37Rabbit. There's been a report that says
  1201. 45:40that AI code creates 1.7 times more
  1202. 45:42problems, which means that even though
  1203. 45:44we're faster, we're producing more
  1204. 45:46issues per PR. Also, the code becomes
  1205. 45:50less readable, naturally, and the error
  1206. 45:52handling isn't being done properly.
  1207. 45:54Security also suffers. So, let's add
  1208. 45:57that one additional line of defense.
  1209. 45:59Let's review every single feature that
  1210. 46:01we add to our project in the same way
  1211. 46:03that biggest teams, such as the
  1212. 46:04developers over at Nvidia, are doing it.
  1213. 46:07I'll leave the link down in the
  1214. 46:08description, so you can create your free
  1215. 46:10account and follow along.
  1216. 46:12You can log in with GitHub, and once
  1217. 46:14you're in, you'll be able to see that I
  1218. 46:15already gave it access to many of my
  1219. 46:17repos. But first, we got to push our
  1220. 46:19project over to GitHub. So, head over to
  1221. 46:22github.com/new
  1222. 46:24and create a new repo. You can call it
  1223. 46:26Ghost AI.
  1224. 46:30And just create it. Next, you can copy
  1225. 46:32these commands one by one, or you can
  1226. 46:35just copy all of them together,
  1227. 46:37open up your agent, and paste it. Then,
  1228. 46:39press enter. It's going to ask us
  1229. 46:41whether we're going to allow it to stage
  1230. 46:43all the changes. So, I'll say, "Yeah, go
  1231. 46:45ahead." And it'll also allow all future
  1232. 46:47commits, as that's going to help us
  1233. 46:49speed up the workflow, as well as adding
  1234. 46:51a remote, and finally push. You can see
  1235. 46:54that the changes have been pushed
  1236. 46:55successfully. So, if you come back and
  1237. 46:57reload,
  1238. 46:59you'll be able to see the current list
  1239. 47:00of changes over on the repo. It's always
  1240. 47:03good to make your project descriptive,
  1241. 47:05so you can remove the releases,
  1242. 47:07deployments, and packages, and add a
  1243. 47:09short description,
  1244. 47:10such as Ghost AI
  1245. 47:13is an interactive systems
  1246. 47:16architecture
  1247. 47:19builder.
  1248. 47:20We can route to the deployed website.
  1249. 47:21For now, I'll just route it to
  1250. 47:23jsmastery.com, and here we can put the
  1251. 47:25different topics, such as Next.js,
  1252. 47:28React, My Blocks, Clerk, Trigger.dev,
  1253. 47:33and even Code Rabbit, which we'll be
  1254. 47:34using for reviewing your code. And I
  1255. 47:37like how AI always adds nice commit
  1256. 47:39messages and not random gibberish that
  1257. 47:41I'm used to. But yeah, now back within
  1258. 47:44Code Rabbit, you can head over to add
  1259. 47:46repositories,
  1260. 47:47sign in, and give it access to all your
  1261. 47:49repos. And then, when you're back, you
  1262. 47:52can just find your project right here.
  1263. 47:58Which means that it's automatically
  1264. 47:59being tracked. So, as soon as we start
  1265. 48:01adding the real features to the app,
  1266. 48:03we'll be able to open up a PR for every
  1267. 48:05new feature as we're developing within a
  1268. 48:07large organization and then get it
  1269. 48:09reviewed and only when Code Rabbit gives
  1270. 48:11it a green light,
  1271. 48:12merge it over to main.
  1272. 48:16Now that our colors are in and the
  1273. 48:18initial Shards and components are in as
  1274. 48:20well, we are ready to start building the
  1275. 48:22actual application. And the first thing
  1276. 48:24that we need is the editor, including
  1277. 48:27the top navbar and the left sidebar
  1278. 48:29because they're the foundation of every
  1279. 48:30feature we're going to build from here
  1280. 48:32on. We're not yet touching off and we're
  1281. 48:35not building this project creation. We
  1282. 48:37just need to establish the layout so
  1283. 48:39when these features come, they have
  1284. 48:41somewhere to go. So, inside of feature
  1285. 48:43specs folder, create a new file called
  1286. 48:4602 editor.md.
  1287. 48:49And within it, we're going to follow a
  1288. 48:50similar structure we followed before. We
  1289. 48:53want to start with explaining what we
  1290. 48:55need,
  1291. 48:56such as the base chrome components that
  1292. 48:58frame every editor screen, the top
  1293. 49:00navbar and the left sidebar shell. These
  1294. 49:04will be reused and extended in every
  1295. 49:06chapter that follows. Then, we need to
  1296. 49:08focus on what are we actually creating?
  1297. 49:11That's going to be the editor navbar.
  1298. 49:14So, we wanted to create a new component
  1299. 49:16within the editor editor navbar file
  1300. 49:19and then we want to specify some
  1301. 49:20requirements that follow. We want this
  1302. 49:23navbar to be of a fixed height at the
  1303. 49:25top. We want it to have both left,
  1304. 49:28center, and right sections, which you
  1305. 49:30can see right here. On the left, we open
  1306. 49:32up the sidebar. In the middle, we have
  1307. 49:34the name and on the right side, we have
  1308. 49:36additional actions. That's exactly what
  1309. 49:38we explained right here.
  1310. 49:41And of course, it's going to be of a
  1311. 49:42dark background with a subtle bottom
  1312. 49:44border. Next, we want to explain what we
  1313. 49:47want to do with the project sidebar. So,
  1314. 49:49right below, we can say create a project
  1315. 49:52sidebar component.
  1316. 49:54It should float above the editor canvas.
  1317. 49:57Opening it should not push the page
  1318. 49:59content. So, you can see it remains
  1319. 50:01where it is.
  1320. 50:03And slides in from the left. It has the
  1321. 50:05header that says projects and title and
  1322. 50:08a close button right here. It can use
  1323. 50:10the Shazian tabs component. And both
  1324. 50:13tabs show empty placeholder state, full
  1325. 50:16width new project button at the bottom
  1326. 50:18with the plus icon. So, something like
  1327. 50:20this. Oh, and finally, when we click
  1328. 50:23create new project, we need this kind of
  1329. 50:25a dialogue. A new pop-up that shows.
  1330. 50:29So, for that, we can say something along
  1331. 50:31the lines of
  1332. 50:33dialogue pattern. Use the existing color
  1333. 50:36tokens from globals for dialogue
  1334. 50:37styling. It supports title, description,
  1335. 50:40and footer action, but don't build any
  1336. 50:42dialogues yet.
  1337. 50:44We just want to create the component for
  1338. 50:46it. Finally, to check whether it is
  1339. 50:48done, we can check whether new
  1340. 50:50components compile without TypeScript
  1341. 50:52errors, no lint errors, and diagram
  1342. 50:54pattern is ready for future use. So,
  1343. 50:57hopefully, you were typing this out with
  1344. 50:59me, or maybe you paused the screen and
  1345. 51:01typed it with your own words. But, this
  1346. 51:03course isn't at all about typing. It is
  1347. 51:06about understanding what we're doing
  1348. 51:08right here. So, if you don't really feel
  1349. 51:10like typing, nor you should, in the
  1350. 51:12video kit link down in the description,
  1351. 51:14I'll provide you with all the prompts
  1352. 51:17that we're going to use throughout the
  1353. 51:18rest of this course. So, if at any point
  1354. 51:20I'm going too fast when explaining them,
  1355. 51:23and you just want to have it on your end
  1356. 51:25and listen along, you can totally do
  1357. 51:27that. But, yeah, let me quickly walk you
  1358. 51:29through the structure because this is
  1359. 51:31the template that every spec file in
  1360. 51:33this project will follow. We start with
  1361. 51:35a goal. One or two sentences, what does
  1362. 51:38this unit produce when it is done? Then,
  1363. 51:41we go over some specific design
  1364. 51:42decisions. Is it visual or structural or
  1365. 51:46something specific to the component like
  1366. 51:48layout behavior, responsiveness, and
  1367. 51:51this is where we can refer to that UI
  1368. 51:53context file so that the agent isn't
  1369. 51:55guessing the colors.
  1370. 51:56Then we go over into implementation, and
  1371. 51:59in this case, I decided to separate it
  1372. 52:01into sections. So, we have the editor
  1373. 52:03navbar, the project sidebar, and the
  1374. 52:06dialog pattern, and finally the
  1375. 52:08verification checklist. So, let's open
  1376. 52:10up our agent. Whenever you're building a
  1377. 52:12new feature, always open up a new chat
  1378. 52:15and don't use one of the older chats.
  1379. 52:17That's because we don't want some stale
  1380. 52:19context lingering around. Only remain
  1381. 52:21within the same chat when what you're
  1382. 52:23about to do next is related to what
  1383. 52:25you've done before, such as when you
  1384. 52:27want to fix specific issues. You can see
  1385. 52:29that it already has access to the editor
  1386. 52:31file.
  1387. 52:33So, I'll say, "Read this file and update
  1388. 52:37the tasks on the progress
  1389. 52:40tracker and then
  1390. 52:43implement it
  1391. 52:45exactly as specified."
  1392. 52:48And press enter. And in about a minute,
  1393. 52:51it's all done.
  1394. 52:52It developed the editor navbar, the
  1395. 52:54sidebar, and also the dialog pattern.
  1396. 52:58TypeScript and ESLint both pass clean.
  1397. 53:00Progress tracker also got updated. So,
  1398. 53:03let's check the progress tracker first.
  1399. 53:05It'll be right here within the progress
  1400. 53:07tracker.
  1401. 53:08So, if you check feature two completed,
  1402. 53:12editor navbar and project sidebar both
  1403. 53:15implemented. You can see them right here
  1404. 53:17under editor, editor navbar, and project
  1405. 53:20sidebar.
  1406. 53:21We just created them so far, but they're
  1407. 53:23not yet being used within the layout.
  1408. 53:25And even though this wasn't part of the
  1409. 53:27checks,
  1410. 53:28I want to actually be able to see them.
  1411. 53:30I want to tell it to use the navbar and
  1412. 53:33the sidebar right now within the
  1413. 53:34project. So, I'll open up the chat in
  1414. 53:37the same context window and tell it to
  1415. 53:39use these two components within a
  1416. 53:41layout. And within a minute it put it to
  1417. 53:44use. It even created a placeholder page
  1418. 53:46so we can navigate over to the editor
  1419. 53:49and check it out. So, head over to
  1420. 53:50localhost:3000/editor,
  1421. 53:53and you can see a canvas coming soon,
  1422. 53:55but there is a top bar and a left
  1423. 53:58sidebar, which opens up the projects.
  1424. 54:01So, you can see that what we requested
  1425. 54:03indeed got implemented. Since we're not
  1426. 54:05yet at the point where we need that
  1427. 54:06because we don't even yet have the
  1428. 54:08editor, I actually want to show you how
  1429. 54:10you can undo the changes, at least right
  1430. 54:12here in Claude code. The only thing you
  1431. 54:14have to do is press this back arrow on
  1432. 54:16the message that you used to create
  1433. 54:18these components, and then say rewind
  1434. 54:20code to here. Which is going to bring us
  1435. 54:22back and only give us what the
  1436. 54:24specification wanted, and that is the
  1437. 54:27components that we can then use and that
  1438. 54:29compile, but we're not using them quite
  1439. 54:32yet. Perfect. So, now that we have the
  1440. 54:33navbar and a togglable sidebar, let's
  1441. 54:36quickly check them out. The editor
  1442. 54:38navbar is pretty straightforward, and
  1443. 54:40the sidebar accepts some props such as
  1444. 54:42is open and on close, and uses the
  1445. 54:44Shadsy and tabs to modify what's being
  1446. 54:47shown. But, when you're writing code
  1447. 54:48yourself, you have a natural
  1448. 54:50understanding of every decision you
  1449. 54:52made. Heck, you wrote it.
  1450. 54:54You know why a function is structured in
  1451. 54:57a specific way or why you used specific
  1452. 54:59props.
  1453. 55:01But, AI-generated code doesn't come with
  1454. 55:04that context.
  1455. 55:05The agent made decisions that that were
  1456. 55:08reasonable most of the time, but you
  1457. 55:11didn't make them. And that means that
  1458. 55:13reviewing AI output isn't optional. It's
  1459. 55:16the step that keeps you in control of
  1460. 55:17your own codebase. So, that's the
  1461. 55:19perfect use case to test out the Code
  1462. 55:21Rabbit edition that we added in the last
  1463. 55:23lesson. I'll open up the chat and tell
  1464. 55:25it to push all the current changes to a
  1465. 55:29new branch called development.
  1466. 55:31Typically, in real production databases,
  1467. 55:33you often have multiple branches such as
  1468. 55:36dev, staging, and only then main.
  1469. 55:40So, for now, we want to push this over
  1470. 55:41to the development branch, get it
  1471. 55:43reviewed, and only if it's good, merge
  1472. 55:45it over to main. So, by giving it this
  1473. 55:47quick message, it'll run a couple of Git
  1474. 55:50commands,
  1475. 55:51figure out that we're currently on main,
  1476. 55:53that we need to switch over and push to
  1477. 55:55that new branch. And that's a little pro
  1478. 55:57tip. Uh-huh, I mean, sure you could run
  1479. 56:00these commands through the terminal, but
  1480. 56:02I find it super easy to just stay in
  1481. 56:04flow and tell the agent to push the code
  1482. 56:07for me, which you can see it just did.
  1483. 56:09So, if you head back over to your repo,
  1484. 56:11you'll see that the development branch
  1485. 56:13had recent pushes 3 seconds ago.
  1486. 56:15So, let's go ahead and compare them and
  1487. 56:17open up the pull request. We have 333
  1488. 56:20new lines of code across five different
  1489. 56:23files. So, Code Rabbit immediately
  1490. 56:25hooked itself onto the PR, and we'll see
  1491. 56:28whether it'll be able to pull out some
  1492. 56:29bugs out of the hat.
  1493. 56:31Let's give it a minute, and then I'll be
  1494. 56:33right back. And we got back the
  1495. 56:35walk-through, where it says exactly what
  1496. 56:38we introduced in this project, such as
  1497. 56:40two new React components for an editor
  1498. 56:42UI Chrome, an editor navbar, and a
  1499. 56:45project sidebar. These are super simple,
  1500. 56:47as this was a simple review. Later on,
  1501. 56:50these are going to get much more
  1502. 56:51detailed, but yeah, let's check whether
  1503. 56:54we have some potential issues even on a
  1504. 56:56simple PR, such as this one. There's one
  1505. 56:58major issue that says, "Hide the
  1506. 57:01off-screen sidebar from focus order and
  1507. 57:03assistive tech when closed." So,
  1508. 57:05specifically, this is an accessibility
  1509. 57:07fix, which is definitely a good
  1510. 57:09implementation.
  1511. 57:10Since we haven't yet utilized this
  1512. 57:12component in our app, I'll leave this so
  1513. 57:13we can add it later. There's also a
  1514. 57:15minor issue, where the spec lists only
  1515. 57:18the is open for the sidebar, but the
  1516. 57:21implementation also requires on close.
  1517. 57:23So, actually, it's suggesting to change
  1518. 57:25the specification. This is interesting,
  1519. 57:27because sometimes you're going to miss
  1520. 57:29some stuff from the spec, and it's okay
  1521. 57:31if AI tries to fix it or add some stuff,
  1522. 57:35but it's equally as important for Code
  1523. 57:37Rabbit to flag it. Because the whole
  1524. 57:39reason why we're writing specs in the
  1525. 57:41first place is so we can have predictive
  1526. 57:43output. So basically, you can just copy
  1527. 57:45this part right here, go back to your
  1528. 57:47code base where we're saying accepts
  1529. 57:50and then it's going to be is open prop.
  1530. 57:52But we're going to say accepts both is
  1531. 57:55open and on close props. Little change,
  1532. 57:59I know, but now our code base is
  1533. 58:01consistent with the spec. And that's it
  1534. 58:03for this simple PR. As we continue
  1535. 58:05developing more components, the reviews
  1536. 58:07are going to get significantly more
  1537. 58:09detailed. So for now, I'm going to go
  1538. 58:11ahead and merge it, which means that we
  1539. 58:13are ready to continue developing the
  1540. 58:15next component.
  1541. 58:18For this type of application, we don't
  1542. 58:21really need a traditional homepage.
  1543. 58:23Most tools like this drop you straight
  1544. 58:26into the editor.
  1545. 58:27You sign in from a simple sign in page
  1546. 58:30and you manage everything from the
  1547. 58:32canvas. And that's exactly what we'll do
  1548. 58:34within our app.
  1549. 58:36But we need auth, sign in, sign up, and
  1550. 58:39other similar pages where you explain
  1551. 58:41how your application works
  1552. 58:43and then allow users to sign back in. So
  1553. 58:46to get that set up, click the Clerk link
  1554. 58:48down in the description and sign in. You
  1555. 58:50can sign in with Google or GitHub. And
  1556. 58:53once you're in, you can head over to
  1557. 58:54applications and create a new app on the
  1558. 58:57dashboard. You can give it a name such
  1559. 58:59as Ghost AI and choose the sign in
  1560. 59:02options
  1561. 59:03such as email, Google, and since this is
  1562. 59:06a development website, we can also do
  1563. 59:08GitHub. Then click create application.
  1564. 59:11We're building on Next.js, so what you
  1565. 59:13can do is just install @clerk/nextjs
  1566. 59:17by copying this command and paste it
  1567. 59:20straight into the terminal.
  1568. 59:22And while that is being installed, you
  1569. 59:24can also set up your Clerk API keys by
  1570. 59:27copying them from here
  1571. 59:29and creating a new file called
  1572. 59:31.env.local
  1573. 59:34and then paste them right here.
  1574. 59:35Now, before we hand anything over to the
  1575. 59:38agent, there are two things you need to
  1576. 59:40know about Clerk and Next.js 16
  1577. 59:42specifically, because if you skip this,
  1578. 59:45the agent will get it wrong. And it says
  1579. 59:47it right here. If you're using Next.js
  1580. 59:4915 or lower, name your file
  1581. 59:52middleware.ts instead of proxy.ts.
  1582. 59:56The code itself remains the same, only
  1583. 59:58the file name changes. But, because most
  1584. 1:00:00agents were trained on Next.js 14 and 15
  1585. 1:00:03code bases, it'll almost certainly
  1586. 1:00:06create a middleware.ts file by default.
  1587. 1:00:09So, we'll have to specify proxy.ts
  1588. 1:00:11explicitly in our spec so it doesn't
  1589. 1:00:13have to guess. Oh, and another important
  1590. 1:00:15thing is that just by adding middleware,
  1591. 1:00:18it doesn't automatically protect all
  1592. 1:00:20routes. As you can see right here, by
  1593. 1:00:22default, it leaves all the routes
  1594. 1:00:24public. And this catches a lot of
  1595. 1:00:26developers. You have to explicitly
  1596. 1:00:28define which routes are protected and
  1597. 1:00:31which are public, which means that we
  1598. 1:00:32have to configure everything
  1599. 1:00:34intentionally. And this is exactly why
  1600. 1:00:36reading the updated documentation before
  1601. 1:00:38building with AI matters. The agent
  1602. 1:00:41knows Clerk, not necessarily the version
  1603. 1:00:43of Clerk you just installed or the
  1604. 1:00:45version of Next.js you're running on.
  1605. 1:00:46The spec bridges that gap. Oh, but we
  1606. 1:00:49can also use agent skills.
  1607. 1:00:52As I told you at the start, most major
  1608. 1:00:54frameworks and libraries now publish
  1609. 1:00:56official skill packages specifically for
  1610. 1:00:58this problem. It gives your agent
  1611. 1:01:00up-to-date knowledge, current APIs, and
  1612. 1:01:03patterns, and the best practices of the
  1613. 1:01:05library you're using. So, if you search
  1614. 1:01:07on Google or within the docs, Clerk
  1615. 1:01:09agent skills, you'll be redirected to
  1616. 1:01:11this page. Then, simply copy the
  1617. 1:01:14installation command,
  1618. 1:01:15head back over to your code base and
  1619. 1:01:17paste it in your terminal. npx skills
  1620. 1:01:20add clerk skills. Press enter.
  1621. 1:01:24You might need to install the skills
  1622. 1:01:25package by saying Y and then enter. And
  1623. 1:01:28then, by pressing the arrow up and down
  1624. 1:01:30keys and the space key, you can select
  1625. 1:01:33specific packages, such as core clerk.
  1626. 1:01:36You can either select some additional
  1627. 1:01:38clerk features or some additional clerk
  1628. 1:01:40frameworks. Like in this case, I'm going
  1629. 1:01:42to go with clerk next js patterns. And
  1630. 1:01:46press enter.
  1631. 1:01:48Then, you can select additional agents
  1632. 1:01:50that you want to add it to. By default,
  1633. 1:01:52it's going to work on codex, cursor, and
  1634. 1:01:54anti-gravity. But, if you want to add
  1635. 1:01:56Claude code, you have to select it here
  1636. 1:01:58and press enter.
  1637. 1:02:00And we can install it in project scope
  1638. 1:02:02via symlink. That's the recommended way.
  1639. 1:02:05So, just proceed with installation.
  1640. 1:02:07Perfect. Our skill is installed and
  1641. 1:02:09we'll be able to invoke it later on once
  1642. 1:02:12we focus on implementing the auth
  1643. 1:02:13functionality.
  1644. 1:02:15So, now we are ready to write the spec.
  1645. 1:02:19Open up your context feature specs and
  1646. 1:02:21create a new file called 03 auth.md.
  1647. 1:02:25And once again, the full feature specs
  1648. 1:02:28files are linked in the description in
  1649. 1:02:30case you want to just copy them and then
  1650. 1:02:31follow along. Or, you can slowly type it
  1651. 1:02:34out with me.
  1652. 1:02:35Let's start by telling it that clerk is
  1653. 1:02:38already installed and connected. So, we
  1654. 1:02:40just need to wire it into the next js
  1655. 1:02:42app, provider, auth pages, redirects,
  1656. 1:02:46route protections, and the user menu.
  1657. 1:02:49When it comes to the design, we just
  1658. 1:02:52want to use the clerk's dark theme from
  1659. 1:02:54the @clerk/ui themes as the base, and
  1660. 1:02:57then we want to override the clerk
  1661. 1:03:00appearance variables using the app's
  1662. 1:03:02existing CSS variables.
  1663. 1:03:05With no hardcoded colors. For the sign
  1664. 1:03:08up and sign in pages, this is what we
  1665. 1:03:11want to develop. On large screens, we
  1666. 1:03:14just want to have a simple two-panel
  1667. 1:03:16layout. On the left side, a logo, a
  1668. 1:03:19tagline, and text-only features. On the
  1669. 1:03:22right side, a centered Clerk form, and
  1670. 1:03:25on small screens, forms only.
  1671. 1:03:27We don't want to have any kind of
  1672. 1:03:29gradients, as that's going to seem
  1673. 1:03:30AI-ish. No oversized hero sections,
  1674. 1:03:33cards, or scroll-heavy layouts. Keep the
  1675. 1:03:36layout minimal and professional.
  1676. 1:03:38And then we can dive into a bit more
  1677. 1:03:40details on the full implementation.
  1678. 1:03:43So, we can say
  1679. 1:03:46wrap the root layout with a Clerk
  1680. 1:03:48provider using the Clerk's dark theme.
  1681. 1:03:52Create sign-in and sign-up pages using
  1682. 1:03:54Clerk components. And as I told you
  1683. 1:03:56before, we have to be specific in
  1684. 1:03:58telling it that it should use the
  1685. 1:04:00proxy.ts file name at the project root
  1686. 1:04:03instead of the middleware.ts.
  1687. 1:04:06And then, we have to define public
  1688. 1:04:07routes using the existing sign-in and
  1689. 1:04:10sign-up environment variables. Protect
  1690. 1:04:12everything else by default. Which means
  1691. 1:04:15that we have to update our home page so
  1692. 1:04:18that when authenticated users visit it,
  1693. 1:04:21we redirect them to the editor. Or when
  1694. 1:04:24unauthenticated users visit it, we
  1695. 1:04:26redirect them to the sign-in page.
  1696. 1:04:29We also want to implement Clerk's
  1697. 1:04:32built-in user button to the editor
  1698. 1:04:35navbar right section for profile
  1699. 1:04:37settings and log out. We want to keep
  1700. 1:04:39Clerk's default user menu and profile
  1701. 1:04:41flows intact and not rebuild heavily
  1702. 1:04:44custom- ized Clerk internals, and want
  1703. 1:04:46to use existing Clerk environment
  1704. 1:04:48variables without renaming or inventing
  1705. 1:04:51new ones. Finally, we can specify
  1706. 1:04:54additional dependencies, such as Clerk
  1707. 1:04:56UI, if we need to install it. And then,
  1708. 1:04:59when it's done, we want to check that
  1709. 1:05:00proxy file is there, that all routes are
  1710. 1:05:03protected except public auth routes,
  1711. 1:05:06auth pages use CSS variables with no
  1712. 1:05:09hardcoded colors, Clerk provider wraps
  1713. 1:05:12the layout and the build passes. This is
  1714. 1:05:15our complete authentication
  1715. 1:05:17implementation. Now, you know the drill.
  1716. 1:05:20Go ahead and open up your agent,
  1717. 1:05:22give it access to this file, and tell it
  1718. 1:05:25to read this file and update the
  1719. 1:05:28progress tracker.md file accordingly.
  1720. 1:05:31Then, implement the auth feature exactly
  1721. 1:05:34as specified in the auth.md file. Okay?
  1722. 1:05:38You can see that the built-in microphone
  1723. 1:05:40feature right here still isn't perfect.
  1724. 1:05:42Let me try to do the same thing with
  1725. 1:05:43Whisper flow specified in auth.md file.
  1726. 1:05:50There we go. That's a bit better, and
  1727. 1:05:52specifically it's 03.auth.md.
  1728. 1:05:55Perfect. Let's go ahead and run it.
  1729. 1:05:58First, it's asking me to run some bash
  1730. 1:06:00commands to check whether Clerk has been
  1731. 1:06:02properly installed, and we'll say,
  1732. 1:06:04"Yeah, go ahead, you can run it." It
  1733. 1:06:06took him about 2 minutes or so to go
  1734. 1:06:09through all the context we shared, and
  1735. 1:06:11only then it'll start to implement
  1736. 1:06:13everything in parallel.
  1737. 1:06:15And this is much better than if it
  1738. 1:06:17started right away and then just ended
  1739. 1:06:20up with a bunch of mistakes. So, the
  1740. 1:06:21list of updates that it put right here
  1741. 1:06:23is to update the .env.local with Clerk
  1742. 1:06:26sign-in and sign-up URL vars, create a
  1743. 1:06:29proxy with Clerk middleware route
  1744. 1:06:31protection, update the app layout with a
  1745. 1:06:33Clerk provider and dark theme, create
  1746. 1:06:36sign-in and sign-up pages with a
  1747. 1:06:38two-panel layout,
  1748. 1:06:39update the app page to redirect based on
  1749. 1:06:42the auth state, add the user button to
  1750. 1:06:44editor navbar,
  1751. 1:06:46and create editor page, and then update
  1752. 1:06:48the progress tracker, and run npm run
  1753. 1:06:50build to verify. It's going to ask me
  1754. 1:06:53whether it has the ability to create
  1755. 1:06:55some directories, and I'll tell it,
  1756. 1:06:57"Yeah, go ahead."
  1757. 1:06:58And in the future we can give it some
  1758. 1:07:00more permissions so it can do things a
  1759. 1:07:02bit more freely. And after it came up
  1760. 1:07:04with the initial plan, it actually built
  1761. 1:07:07out everything pretty quickly. Maybe
  1762. 1:07:09even in less time than it used to think
  1763. 1:07:12how to approach it in the first place,
  1764. 1:07:13which shows you just how important the
  1765. 1:07:16initial context and a proper task are.
  1766. 1:07:19And there we go. The build passes, and
  1767. 1:07:21here's the summary of everything that
  1768. 1:07:23was implemented. I think all of these
  1769. 1:07:25things right here shouldn't come as a
  1770. 1:07:27surprise because we initially specified
  1771. 1:07:30them in the spec. Then it updated the
  1772. 1:07:33to-do's, and now it just did it. And
  1773. 1:07:36yeah, it's pretty interesting that it
  1774. 1:07:37even notes right here that it would have
  1775. 1:07:39gotten confused about this middleware
  1776. 1:07:41proxy thing if we didn't specify it
  1777. 1:07:43properly. But thankfully, it did it in
  1778. 1:07:46the right way thanks to the research
  1779. 1:07:47that we've done at the start.
  1780. 1:07:49So, what do you say that we take it for
  1781. 1:07:51a spin? The application is running on
  1782. 1:07:53localhost 3000, but whenever I make some
  1783. 1:07:55bigger changes, I like to rerun it. But
  1784. 1:07:58initially, if you head over to
  1785. 1:07:59localhost, you might get redirected to
  1786. 1:08:02this clerk handshake part, which is
  1787. 1:08:04going to lead to a broken page. But
  1788. 1:08:06after you reload, it should properly
  1789. 1:08:09redirect you back to the homepage. And
  1790. 1:08:11after that, it should just work.
  1791. 1:08:14This is something that we can polish and
  1792. 1:08:16fix up later on.
  1793. 1:08:18But yeah, this is looking interesting.
  1794. 1:08:20Definitely not quite as nice as the
  1795. 1:08:23original application that I've showed
  1796. 1:08:25you that's deployed.
  1797. 1:08:26So, what are some of the things that we
  1798. 1:08:28can do to make it look more similar to
  1799. 1:08:31that one? Well, step one is to search
  1800. 1:08:34some kind of design websites online like
  1801. 1:08:36Dribbble or award-winning websites, and
  1802. 1:08:39then just take a screenshot and try to
  1803. 1:08:41get it to match to that closer. Or in
  1804. 1:08:43this case, you can head over to the
  1805. 1:08:45deployed version of this application,
  1806. 1:08:48take a screenshot of this whole UI that
  1807. 1:08:51you can see right here,
  1808. 1:08:52and then we can feed it over into our
  1809. 1:08:55chat. So, go ahead and open up the chat.
  1810. 1:08:57Keep in mind that we can still stay
  1811. 1:08:59within the authentication window that we
  1812. 1:09:01worked on
  1813. 1:09:02because now we're fixing some parts
  1814. 1:09:04about that specific implementation. So,
  1815. 1:09:06what you can do is just click this plus
  1816. 1:09:08right here and upload from computer or
  1817. 1:09:10just drag and drop the screenshot. Then,
  1818. 1:09:13select it and then we can further point
  1819. 1:09:15out to some things that could be
  1820. 1:09:17improved, not just the layout. It seems
  1821. 1:09:19like it didn't properly read the fonts,
  1822. 1:09:22that the right side of the screen is
  1823. 1:09:24taking a larger portion, so maybe we can
  1824. 1:09:26split them 50/50, same as it is right
  1825. 1:09:28here, and make the font size a bit
  1826. 1:09:31larger. So, it's not just the layout. We
  1827. 1:09:33needed to review the screenshot and
  1828. 1:09:35update the UI of our current application
  1829. 1:09:38to look more like the one on the
  1830. 1:09:39screenshot. Means 50/50 left and right
  1831. 1:09:43side layout with some kind of a color on
  1832. 1:09:45the left side to differentiate it from a
  1833. 1:09:47dark background,
  1834. 1:09:49as well as we need to fix the fonts so
  1835. 1:09:51that it uses the ones outlined in our UI
  1836. 1:09:55guidelines. I think for now this is
  1837. 1:09:56going to be enough for it to get closer
  1838. 1:09:59to the design we want to get. So, press
  1839. 1:10:01enter and let's see how it handles it.
  1840. 1:10:03And there we go, the build passes, it
  1841. 1:10:06updated the globals from circular font
  1842. 1:10:08reference to the one that should be
  1843. 1:10:10correct right now. The body was pointing
  1844. 1:10:12at itself, so this font was never
  1845. 1:10:15actually applied to anything. Same fix
  1846. 1:10:17for the heading and it also implemented
  1847. 1:10:19some other fixes. Let's check it out.
  1848. 1:10:21The design now looks much closer to the
  1849. 1:10:23finished product. The fonts are being
  1850. 1:10:26properly applied and that makes a big
  1851. 1:10:28difference. So does the increase in font
  1852. 1:10:30size and this shift between the two
  1853. 1:10:33different background colors. Of course,
  1854. 1:10:35later on we can come up with a unique
  1855. 1:10:37logo that we can put right here, but for
  1856. 1:10:39now this is looking great.
  1857. 1:10:41And believe it or not, we have a fully
  1858. 1:10:44functional authentication system built
  1859. 1:10:46in right here. So, what do you say that
  1860. 1:10:48we go ahead and test it out? You can
  1861. 1:10:50head over to sign up to see whether that
  1862. 1:10:52works and it does. Later on, if you want
  1863. 1:10:55to, you can modify the contents on the
  1864. 1:10:57left side depending on whether you're in
  1865. 1:10:59sign-in or sign-up page. And then let's
  1866. 1:11:01use something like GitHub to sign in.
  1867. 1:11:04I'll authorize it and the redirect
  1868. 1:11:06redirects us to a page that currently
  1869. 1:11:09breaks. So, I'll try to head back over
  1870. 1:11:12to localhost:3000 one more time. And now
  1871. 1:11:15when we get back, it actually redirects
  1872. 1:11:17to the editor properly. You can see that
  1873. 1:11:20we have the sidebar, we have a space for
  1874. 1:11:23the canvas that's about to come in the
  1875. 1:11:25future. And then on top right, we see
  1876. 1:11:27all the information about our currently
  1877. 1:11:29logged-in account, which is beautiful. I
  1878. 1:11:31mean, we get complete user management
  1879. 1:11:34within a single prompt that we've done.
  1880. 1:11:36Let's also try to sign out for now, and
  1881. 1:11:38we do get one issue when we click that
  1882. 1:11:40button saying there's an unexpected
  1883. 1:11:43response received from the server. So,
  1884. 1:11:45if we head back over here and open up
  1885. 1:11:47the terminal, we can see an unhandled
  1886. 1:11:49rejection. Unexpected response was
  1887. 1:11:51received from the server. And then in
  1888. 1:11:53the terminal, we see something like
  1889. 1:11:55this, which doesn't really tell us much.
  1890. 1:11:58Now, what we could do is just copy this,
  1891. 1:12:00open up the chat window one more time by
  1892. 1:12:03heading over here, and then just pasting
  1893. 1:12:06this error and telling it to fix it.
  1894. 1:12:08But, I'm actually glad that this error
  1895. 1:12:10happened because I can teach you a bit
  1896. 1:12:12better and more precise way to handle
  1897. 1:12:14these issues and so that when you try to
  1898. 1:12:16fix them, you don't cause new ones.
  1899. 1:12:19So, instead of pasting this right into
  1900. 1:12:21the chat, we're actually going to open
  1901. 1:12:22up a new file right here within context
  1902. 1:12:26and call it current issues.md.
  1903. 1:12:31You can even do it within feature specs.
  1904. 1:12:33Either way works. Then, you can paste
  1905. 1:12:35any kind of errors that you have and
  1906. 1:12:37explain what's happening. So, I'll
  1907. 1:12:39explain that when I click the logout
  1908. 1:12:43button,
  1909. 1:12:46the following error appears. And now I
  1910. 1:12:49can paste this error message. And we can
  1911. 1:12:51also specify that sometimes when we log
  1912. 1:12:54in, we get redirected to this weird long
  1913. 1:12:57URL, which doesn't show anything on the
  1914. 1:12:59page.
  1915. 1:13:00And then we can just paste this URL
  1916. 1:13:03right here. Again, the errors on your
  1917. 1:13:05end might be a bit different from what
  1918. 1:13:08I'm seeing right here. Whatever they
  1919. 1:13:10are, I don't want to teach you how to
  1920. 1:13:12copy and paste. I want to teach you how
  1921. 1:13:14to solve the problems for yourself.
  1922. 1:13:16Explore the current issues file and
  1923. 1:13:19deeply analyze the problem.
  1924. 1:13:22Only when you have the analysis, give it
  1925. 1:13:24back to me with the idea of how you're
  1926. 1:13:26planning to solve it, and then wait for
  1927. 1:13:28me to give it the green light to execute
  1928. 1:13:31it. So yeah, writing something like this
  1929. 1:13:33makes sense because that way it doesn't
  1930. 1:13:35go into the spiral of trying to fix its
  1931. 1:13:37own bugs while breaking 10 other things.
  1932. 1:13:39You provided the error, it's going to
  1933. 1:13:41come back with the analysis. You're the
  1934. 1:13:43one deciding whether that analysis makes
  1935. 1:13:45sense and whether it can actually
  1936. 1:13:47execute it. So, let's run it and see
  1937. 1:13:50what it comes back with. And after some
  1938. 1:13:52thinking, it's back with the analysis.
  1939. 1:13:55And this is so much better and so much
  1940. 1:13:58more detailed than if we just told it to
  1941. 1:14:00fix it immediately. Now, it actually
  1942. 1:14:03tried it out and has a deep idea of
  1943. 1:14:05what's happening. The server log is the
  1944. 1:14:07key clue. Proxy took 373 milliseconds
  1945. 1:14:11out of a half a second total request.
  1946. 1:14:13Almost all time is spent in the proxy.
  1947. 1:14:16So, that already points it in the right
  1948. 1:14:18direction.
  1949. 1:14:19As a human person, I would never figure
  1950. 1:14:22this out on my own. At least not from
  1951. 1:14:24such a vague error message. But yeah,
  1952. 1:14:27here it figures out that this button
  1953. 1:14:29needs an after sign out URL. So, it's
  1954. 1:14:32just going to add it.
  1955. 1:14:33And a similar thing is happening with
  1956. 1:14:35the handshake URL. It basically needs to
  1957. 1:14:38configure that after sign up URL, and
  1958. 1:14:41that way it's going to route it
  1959. 1:14:42properly. So, it provided a two fix
  1960. 1:14:44plan. So, this looks plausible to me,
  1961. 1:14:47looks good. So, let's just tell it to
  1962. 1:14:50execute the plan and fix the issues.
  1963. 1:14:52There we go. So, the fix now seems very
  1964. 1:14:55apparent. We just needed this after sign
  1965. 1:14:57out URL. And if you want to learn more
  1966. 1:14:59tips and tricks just like this one about
  1967. 1:15:02actually analyzing and fixing the errors
  1968. 1:15:04and how I approach building these
  1969. 1:15:06production level applications,
  1970. 1:15:08definitely check out the spec driven
  1971. 1:15:10agentic development course. It's not out
  1972. 1:15:12yet as it's going to be super detailed
  1973. 1:15:14and it's going to follow the best
  1974. 1:15:15practices from the strongest developer
  1975. 1:15:17teams out there. But yeah, it'll be out
  1976. 1:15:19soon, but I'm still super glad that
  1977. 1:15:21while I'm developing that, you can still
  1978. 1:15:24learn how I develop these applications
  1979. 1:15:26with the agentic ways with this new
  1980. 1:15:28video that you're watching right now.
  1981. 1:15:30And you can let me know down in the
  1982. 1:15:32comments how you like this new type of
  1983. 1:15:34video. I get that it's completely
  1984. 1:15:36different from manual coding, but I
  1985. 1:15:38still think there's so much to learn and
  1986. 1:15:41we can have a predictable development
  1987. 1:15:44workflow even with AI doing the writing
  1988. 1:15:47for us. So, let's see whether this
  1989. 1:15:49actually fixes it. And the build passes.
  1990. 1:15:51The after sign out URL prop was removed
  1991. 1:15:54from the user button as it belongs in
  1992. 1:15:56clerk options and is set via environment
  1993. 1:15:58variables. So, we'll soon be able to
  1994. 1:16:00verify whether that actually fixes it.
  1995. 1:16:03But before, I want to open up my
  1996. 1:16:05terminal,
  1997. 1:16:06stop it from running and then rerun it
  1998. 1:16:08again on localhost 3000 because we
  1999. 1:16:10changed the ENVs, so we want to make
  2000. 1:16:12sure that they're read by the browser.
  2001. 1:16:14So now, heading back over to localhost
  2002. 1:16:163000, maybe you're signed in already,
  2003. 1:16:18which is fine. You can simply sign out
  2004. 1:16:20now and that brings us to another error,
  2005. 1:16:23which is the same one we've had before.
  2006. 1:16:25And another thing you can do is head
  2007. 1:16:27over to inspect element, switch over to
  2008. 1:16:29the application tab, and then clear all
  2009. 1:16:32the cookies. So, find the cookies for
  2010. 1:16:34localhost 3000, clear them, and then
  2011. 1:16:36reload the page.
  2012. 1:16:38You'll be redirected back to the home
  2013. 1:16:40page and now we can retry with a clean
  2014. 1:16:42slate.
  2015. 1:16:43So, I'll sign in using GitHub the same
  2016. 1:16:46way I did before. That works. I
  2017. 1:16:48automatically get redirected over to the
  2018. 1:16:50editor, which is great. And now, I'll
  2019. 1:16:52sign out, and that worked. So, now head
  2020. 1:16:55back over within your terminal,
  2021. 1:16:57run git add dot, git commit {dash} m,
  2022. 1:17:01implement auth, and then git push. This
  2023. 1:17:04is going to push all the changes to
  2024. 1:17:06origin development, allowing us to open
  2025. 1:17:08up a pull request over to the main
  2026. 1:17:10branch. Then, you can open up a PR, and
  2027. 1:17:14let's wait for CodeRabbit to review it.
  2028. 1:17:16This time, we had many changes, but not
  2029. 1:17:19many of them are directly related to
  2030. 1:17:21what we did in the code. We just added
  2031. 1:17:23these agent skills so that everybody
  2032. 1:17:25else's agents working on this code base
  2033. 1:17:28also, well, become smart in the
  2034. 1:17:30technologies that we're using for the
  2035. 1:17:32project. And then, yeah, of course, we
  2036. 1:17:34implemented a couple of different files
  2037. 1:17:36that CodeRabbit will verify. But,
  2038. 1:17:38primarily, what we've done is right here
  2039. 1:17:41within app, sign in and sign up pages,
  2040. 1:17:45we have added some features that would
  2041. 1:17:46display on the left side. And then, the
  2042. 1:17:48sign-in page, where on the right side,
  2043. 1:17:51we just render the sign-in component
  2044. 1:17:54coming from Clerk.
  2045. 1:17:56Similar thing happens over to the
  2046. 1:17:58sign-up page. So, right here, we're just
  2047. 1:18:01rendering the sign-up UI.
  2048. 1:18:03Then,
  2049. 1:18:04over in the layout, we are wrapping
  2050. 1:18:07everything with a Clerk provider,
  2051. 1:18:09setting the theme to dark, and setting
  2052. 1:18:11some custom variables. That's it.
  2053. 1:18:14Everything else remains the same. And
  2054. 1:18:15then, within the editor page, we are
  2055. 1:18:18simply showing the nav bar and the
  2056. 1:18:20sidebar, as well as the rest of the
  2057. 1:18:22content.
  2058. 1:18:23In the nav bar, we display the Clerk
  2059. 1:18:26user button, allowing us to see more
  2060. 1:18:27info about the user, and allowing us to
  2061. 1:18:30log us out. Pretty straightforward so
  2062. 1:18:32far. As our components and features get
  2063. 1:18:34more detailed, we're going to do deeper
  2064. 1:18:36dives into the code base, but so far so
  2065. 1:18:39good. Let's wait for the review. And
  2066. 1:18:41quickly we're back with a full
  2067. 1:18:43walk-through. This pull request
  2068. 1:18:45integrates Clerk auth into a Next.js
  2069. 1:18:47application and establishes
  2070. 1:18:49comprehensive agent skills for Clerk
  2071. 1:18:52integration across multiple frameworks.
  2072. 1:18:54It also adds auth middleware, sign-in
  2073. 1:18:57and sign-up pages, Clerk provider setup,
  2074. 1:18:59and introduces five new skill
  2075. 1:19:01definitions for supporting scripts,
  2076. 1:19:03documentation, and so on. So, obviously
  2077. 1:19:06a lot of the checks right here from
  2078. 1:19:08CodeRabbit are going to be about the
  2079. 1:19:09skills that we set up, but we can skip
  2080. 1:19:12those for now and focus on the ones
  2081. 1:19:14about the actual files we implemented.
  2082. 1:19:17In this case, it looks like there's one
  2083. 1:19:19critical issue, and that is within the
  2084. 1:19:21context current issues.md.
  2085. 1:19:24Well, you never want to publish current
  2086. 1:19:26issues to GitHub anyways, because you
  2087. 1:19:28want people to see your code and not
  2088. 1:19:30your mistakes. Um what we're doing here
  2089. 1:19:33is even worse. We're exposing the
  2090. 1:19:36handshake or the JWT token from the
  2091. 1:19:38track docs. So, this is a real security
  2092. 1:19:42issue. So, what we need to do is delete
  2093. 1:19:44this file. Obviously, this won't delete
  2094. 1:19:46it from the Git history, but that's fine
  2095. 1:19:49for us because this JWT is no longer in
  2096. 1:19:51use.
  2097. 1:19:53So, right here over to getignore, I'm
  2098. 1:19:54going to add our {forward-slash} context
  2099. 1:19:58{forward-slash}, and that's going to be
  2100. 1:20:00the current issues
  2101. 1:20:03.md file.
  2102. 1:20:05And I'll also remove everything that is
  2103. 1:20:07within it.
  2104. 1:20:09Not that it matters right now, because
  2105. 1:20:10we're adding it to getignore anyway. So,
  2106. 1:20:13let's go ahead and push those changes by
  2107. 1:20:14saying get add {dot} get commit update
  2108. 1:20:18{dot} getignore.
  2109. 1:20:20And get push. Immediately the changes
  2110. 1:20:23will be recognized, which means that we
  2111. 1:20:24can merge this over to the main branch.
  2112. 1:20:27And while we're here, we can also head
  2113. 1:20:29over into context on the main branch and
  2114. 1:20:32remove the current issues file right
  2115. 1:20:34here from GitHub by simply deleting the
  2116. 1:20:36file.
  2117. 1:20:38And committing the changes.
  2118. 1:20:40We can also do the same thing on the
  2119. 1:20:41development branch by heading over to
  2120. 1:20:43context
  2121. 1:20:45and heading over to current issues, and
  2122. 1:20:48just removing the file
  2123. 1:20:50so that it's no longer here, and it's
  2124. 1:20:51not going to be pushed to GitHub any
  2125. 1:20:53longer because we added it to get
  2126. 1:20:55ignore.
  2127. 1:20:56Perfect. With that in mind, we've
  2128. 1:20:58successfully implemented the full UI and
  2129. 1:21:01functionality for the authentication
  2130. 1:21:03within our application.
  2131. 1:21:07Now that our authentication is done, and
  2132. 1:21:09we can actually sign into our
  2133. 1:21:11application, let's make the sidebar
  2134. 1:21:14actually do something. As right now, it
  2135. 1:21:16is just static. Before we hook up any
  2136. 1:21:19real data, we need the UI in place.
  2137. 1:21:22The create, rename, and delete
  2138. 1:21:25dialogues, plus the editor home state.
  2139. 1:21:27So, we're keeping this prompt focused on
  2140. 1:21:29UI only with no API calls yet. Head over
  2141. 1:21:33into context, feature specs, and add a
  2142. 1:21:36new file called 04 project dialogues.
  2143. 1:21:40Within it, we can specify that the goal
  2144. 1:21:43is to build the editor home screen and
  2145. 1:21:45add the project dialogues and sidebar
  2146. 1:21:47actions with no API calls yet. So, what
  2147. 1:21:51does this specifically mean?
  2148. 1:21:52Well, it means that on the home page, we
  2149. 1:21:54want to reuse the existing editor layout
  2150. 1:21:58without modifying the navbar or sidebar
  2151. 1:22:00behavior, but in the center of the page,
  2152. 1:22:02we want to add a heading, create a
  2153. 1:22:04project, or open up an existing one, and
  2154. 1:22:07a description. Start a new architecture
  2155. 1:22:09workspace or choose a project from the
  2156. 1:22:11sidebar, and a new project button with a
  2157. 1:22:14plus icon. Keeping the layout minimal
  2158. 1:22:16without wrapping this content in cards.
  2159. 1:22:19And then clicking new project should
  2160. 1:22:21open up the create project dialogue.
  2161. 1:22:23Let me actually show you what I mean by
  2162. 1:22:26all of this by heading over to the
  2163. 1:22:27finished version of the application, and
  2164. 1:22:30quickly signing in. Notice how right
  2165. 1:22:32here in the middle we have some text to
  2166. 1:22:34greeting us, even though the canvas is
  2167. 1:22:36empty, allowing us to create a new
  2168. 1:22:38project, which then opens up this
  2169. 1:22:39dialogue. That's exactly what we want to
  2170. 1:22:42achieve.
  2171. 1:22:43So, we'll have a dialogue for creating a
  2172. 1:22:45new project, as well as for editing one,
  2173. 1:22:48and deleting it. So, let's specify these
  2174. 1:22:51three dialogues below.
  2175. 1:22:53We're going to have one for creating a
  2176. 1:22:54project that takes in the project name
  2177. 1:22:57input, the live slug preview based on
  2178. 1:23:00the name, and preview updates as the
  2179. 1:23:02user types. Then, the one for the rename
  2180. 1:23:05with pre-filled project name input, and
  2181. 1:23:08the one for delete. Finally, on the
  2182. 1:23:10sidebar, we want to add the following
  2183. 1:23:13project item actions, rename and delete,
  2184. 1:23:16show actions only for the projects that
  2185. 1:23:18we own, and hide actions for the shared
  2186. 1:23:21or projects belonging to collaborators,
  2187. 1:23:23and on mobile, tapping outside the
  2188. 1:23:25sidebar closes it, and want to add some
  2189. 1:23:27kind of a backdrop scrim. Finally, let's
  2190. 1:23:29specify the implementation right here by
  2191. 1:23:32telling it to create a dedicated hook to
  2192. 1:23:35manage the dialogue state, the form
  2193. 1:23:37state, and the loading state, that way
  2194. 1:23:39we can reuse the functionality.
  2195. 1:23:41And then we want to wire the editor home
  2196. 1:23:44new project to create dialogue, the
  2197. 1:23:47sidebar create button to create dialogue
  2198. 1:23:49as well, sidebar rename to rename
  2199. 1:23:52dialogue, and sidebar delete to delete
  2200. 1:23:54dialogue. For now, we only want to use
  2201. 1:23:56mock project data with no API calls.
  2202. 1:24:00And to check when it is done, we need to
  2203. 1:24:03check that sidebar actions are wired,
  2204. 1:24:05that slug preview works, that no
  2205. 1:24:07TypeScript errors exist, and there's
  2206. 1:24:09also no linting errors.
  2207. 1:24:11So, let's open up Claude Code or your AI
  2208. 1:24:14agent of choice,
  2209. 1:24:16and then we can tell it to read this
  2210. 1:24:19file, update the progress-tracker.md
  2211. 1:24:22to mark this as in progress and then
  2212. 1:24:24implement it exactly as specified. And
  2213. 1:24:28let's run it.
  2214. 1:24:29And in about a minute or so, feature
  2215. 1:24:31four is done.
  2216. 1:24:33Here's what's built. New file hooks use
  2217. 1:24:36project dialogues, which centralizes the
  2218. 1:24:38dialogue type, form, including the name
  2219. 1:24:41and the slug, the loading state and mock
  2220. 1:24:44data, which exposes these different
  2221. 1:24:46functions to deal with the dialogues.
  2222. 1:24:48Then there's the dialogue component, as
  2223. 1:24:50well as within the project sidebar, we
  2224. 1:24:53also call the dialogues when needed.
  2225. 1:24:56So, let's quickly check this hooks file
  2226. 1:24:58that it implemented. You can see that it
  2227. 1:25:00is strictly typed right here with the
  2228. 1:25:02project interface, the dialogue type, to
  2229. 1:25:05slug, which takes in the name and turns
  2230. 1:25:07it into a human readable ID,
  2231. 1:25:09and it even created some mock three
  2232. 1:25:11projects that we can verify.
  2233. 1:25:13It came up with a lot of different use
  2234. 1:25:15states, keeping track of all the
  2235. 1:25:17projects, the dialogue type, the
  2236. 1:25:20selected project, the name, slug, and
  2237. 1:25:22loading.
  2238. 1:25:23And all of these are going to be used
  2239. 1:25:25within the dialogues themselves. Then it
  2240. 1:25:27returns the data, so we can actually use
  2241. 1:25:29them. Let's check where the dialogue is
  2242. 1:25:31being used. Most often, it is right here
  2243. 1:25:33within project dialogues,
  2244. 1:25:35where we have the actual code for how
  2245. 1:25:37the dialogue looks like. If the dialogue
  2246. 1:25:40is of a type create, then we show this
  2247. 1:25:42one. If it's of a type rename, we show
  2248. 1:25:44this one. And if it's delete, we show
  2249. 1:25:47the one below. Before we test it out,
  2250. 1:25:49let's check out the progress tracker
  2251. 1:25:51that says that the current phase is the
  2252. 1:25:53feature four dialogues.
  2253. 1:25:55It has the goal to do it. And it has
  2254. 1:25:58actually completed the project dialogues
  2255. 1:26:00with all of these different components.
  2256. 1:26:02So, now if you come back to the editor,
  2257. 1:26:04this is going to look much better. It's
  2258. 1:26:06no longer just a blank screen, but
  2259. 1:26:08rather in the middle, it says create a
  2260. 1:26:10project or open up an existing one,
  2261. 1:26:12start a new architectural workspace, or
  2262. 1:26:14choose is project from the sidebar. And
  2263. 1:26:16if you click create project, it actually
  2264. 1:26:19opens up a new project dialogue where
  2265. 1:26:22you can type something like my project.
  2266. 1:26:26It automatically creates a slug at the
  2267. 1:26:28bottom as well. And if you click create,
  2268. 1:26:30you saw that creating loading.
  2269. 1:26:33And of course, the data is currently
  2270. 1:26:35static, but you can see how it's going
  2271. 1:26:37to look once it actually picks the data
  2272. 1:26:39from the database.
  2273. 1:26:41So, we have Ghost AI Core, which you can
  2274. 1:26:44select
  2275. 1:26:45to edit its name
  2276. 1:26:47as well as to delete it. This means that
  2277. 1:26:50the UI for all of the dialogue
  2278. 1:26:52functionalities has now been implemented
  2279. 1:26:54alongside this centerpiece of the
  2280. 1:26:56application, which means that now that
  2281. 1:26:58the majority of the UI is done, in the
  2282. 1:27:00next lesson, we can start focusing on
  2283. 1:27:03implementing real data with a real
  2284. 1:27:05database to make our app come to life.
  2285. 1:27:08But before we dive into the database,
  2286. 1:27:10let's make sure that our current code is
  2287. 1:27:12good. And I want to show you another
  2288. 1:27:14Code Rabbit feature allowing you to
  2289. 1:27:16review your code directly within your VS
  2290. 1:27:18Code, which means that you don't even
  2291. 1:27:20have to create a PR and you can be that
  2292. 1:27:22much faster. You can install the Code
  2293. 1:27:24Rabbit extension, authenticate to your
  2294. 1:27:26account.
  2295. 1:27:28It'll notice the changes that you have
  2296. 1:27:29right now, so you can just click review
  2297. 1:27:32all changes. And the review will start
  2298. 1:27:34directly within your editor.
  2299. 1:27:37So, let's give it a minute. We'll check
  2300. 1:27:39the changes and if they're good, push
  2301. 1:27:41them. If not, we're going to fix them.
  2302. 1:27:43And within a minute, the review is in
  2303. 1:27:45and Code Rabbit left the comments
  2304. 1:27:47directly on our code base. So, you can
  2305. 1:27:49expand all the files and click on them
  2306. 1:27:52to see exactly what's happening.
  2307. 1:27:55For example, right here, specific
  2308. 1:27:57confirmation message and project name
  2309. 1:27:58display, the delete project dialogue
  2310. 1:28:01lacks key detail. What text should be
  2311. 1:28:03shown to the user? Should the dialogue
  2312. 1:28:05show which project is being deleted? And
  2313. 1:28:08should we show the cancel button as
  2314. 1:28:09well? These are some important
  2315. 1:28:11questions. And it's good because in this
  2316. 1:28:13case Code Rabbit is telling us that we
  2317. 1:28:15can be even more precise with our
  2318. 1:28:17feature specifications. But, let's see
  2319. 1:28:19if it has any comments within our code
  2320. 1:28:21base. It says right here that the
  2321. 1:28:22project item that is this one right here
  2322. 1:28:25appears clickable, but it lacks
  2323. 1:28:27interaction handling. It has a cursor
  2324. 1:28:29pointer, that is this one right here in
  2325. 1:28:31the sidebar, but when I click on it, it
  2326. 1:28:34doesn't do anything. That's fine for now
  2327. 1:28:36because later on we're going to make it
  2328. 1:28:37open the actual canvas of that project.
  2329. 1:28:40Since that is not implemented yet,
  2330. 1:28:42that's totally fine. Then, another
  2331. 1:28:44inconsistency, feature four is being
  2332. 1:28:46marked as both in the current phase as
  2333. 1:28:49well as finished right here at the
  2334. 1:28:50bottom. So, we need to modify the
  2335. 1:28:52progress tracker to say that the feature
  2336. 1:28:54five is to be done. And then, and then
  2337. 1:28:57modify the current goal to be determined
  2338. 1:29:00for feature five. Next up, feature five.
  2339. 1:29:03This is good. And finally, in the use
  2340. 1:29:05project dialog hooks, we have a couple
  2341. 1:29:08of comments as well.
  2342. 1:29:09First, we have missing validation for
  2343. 1:29:12empty slug edge case.
  2344. 1:29:14If the user enters a name containing
  2345. 1:29:16only special characters, it passes the
  2346. 1:29:18truthy check, but returns an empty
  2347. 1:29:20string, resulting in a project with an
  2348. 1:29:22empty slug. So, if I head back right
  2349. 1:29:25here and try to create something, take a
  2350. 1:29:27look. It's true.
  2351. 1:29:29I can actually create a new project, but
  2352. 1:29:31nothing gets added to the slug because
  2353. 1:29:33these are not valid slug characters. So,
  2354. 1:29:36we definitely have to fix this.
  2355. 1:29:37Thankfully, what we need to do is add
  2356. 1:29:40slug validation.
  2357. 1:29:42So, I'll just press accept right here
  2358. 1:29:45and it'll update the code for me. That's
  2359. 1:29:47another perk of using Code Rabbit within
  2360. 1:29:49VS Code. And I think there is one other
  2361. 1:29:51comment right here in this dialog, which
  2362. 1:29:54is the same issue right here.
  2363. 1:29:56Same as before, the rename operation has
  2364. 1:29:58the edge case where the slug could end
  2365. 1:30:00up empty. So, we definitely want to fix
  2366. 1:30:02the validation there as well.
  2367. 1:30:05Now, we can push the changes by saying
  2368. 1:30:07get add dot, get commit {dash} m
  2369. 1:30:11implement dialogues
  2370. 1:30:14and then get pull to pull the latest
  2371. 1:30:16changes and then run get push {dash}
  2372. 1:30:19{dash} force to push the latest changes.
  2373. 1:30:22Because remember, we deleted that file
  2374. 1:30:24directly on GitHub, but still we want to
  2375. 1:30:25push the local changes as well. So now
  2376. 1:30:28if you want to, you can manually open up
  2377. 1:30:30a PR by heading over to new pull request
  2378. 1:30:33from the development branch
  2379. 1:30:34over to the main branch
  2380. 1:30:37and we can immediately merge it because
  2381. 1:30:39we've already reviewed all the changes
  2382. 1:30:41with Code Rabbit with their VS Code
  2383. 1:30:43extension. So back within the
  2384. 1:30:45application, you can run get pull
  2385. 1:30:48and you can also check out to main and
  2386. 1:30:50run get pull there as well
  2387. 1:30:53to be up to date. But make sure to
  2388. 1:30:55switch back to the development branch
  2389. 1:30:56because that is where we're actively
  2390. 1:30:58developing new features.
  2391. 1:31:02Now that our project management UI is
  2392. 1:31:04wired up, we need the actual database
  2393. 1:31:06behind it. And for that, we're going to
  2394. 1:31:08use Prisma with Postgres.
  2395. 1:31:11If you prefer a different database, the
  2396. 1:31:13process is the same. Just swap the
  2397. 1:31:15provider in the schema.
  2398. 1:31:17Prisma supports Postgres, MySQL, SQLite,
  2399. 1:31:20and more. So let's start with a manual
  2400. 1:31:23installation right here within the
  2401. 1:31:24terminal. Stop the app from running and
  2402. 1:31:27then run npm install Prisma tsx {at}
  2403. 1:31:31types {forward-slash} pg {dash} {dash}
  2404. 1:31:33save {dash} dev. These are the dev
  2405. 1:31:35dependencies so that we have a nice
  2406. 1:31:37development workflow. After that is
  2407. 1:31:39done, you can install all the necessary
  2408. 1:31:41packages needed for us to set up our
  2409. 1:31:43database such as {at} Prisma
  2410. 1:31:45{forward-slash} client, Prisma adapter
  2411. 1:31:48pg, {dot} env, and pg itself. And press
  2412. 1:31:52enter. After that is done, initialize
  2413. 1:31:54Prisma with the correct output path for
  2414. 1:31:57the Next.js router.
  2415. 1:31:59You can do that by running npx Prisma
  2416. 1:32:01init dash dash output, data slash app
  2417. 1:32:04generated Prisma. This creates a new
  2418. 1:32:07Prisma folder with the schema.prisma
  2419. 1:32:10file and an ENV file at the root. So,
  2420. 1:32:13head over to the Prisma dashboard. I'll
  2421. 1:32:15leave the link down in the description
  2422. 1:32:17and create a new account. You can sign
  2423. 1:32:19in with GitHub or Google. And once
  2424. 1:32:22you're in, you can create a new project.
  2425. 1:32:25I'll call it Ghost AI and they'll give
  2426. 1:32:28you a one command setup, but in this
  2427. 1:32:30case we can proceed with the connection
  2428. 1:32:32string.
  2429. 1:32:33So, you can just copy it and then head
  2430. 1:32:35over into your .env and override the
  2431. 1:32:38current database URL with the new one
  2432. 1:32:40that you just got from the dashboard. As
  2433. 1:32:42a matter of fact, we can take this
  2434. 1:32:43database URL and put it within the
  2435. 1:32:45.env.local as that's what we're using
  2436. 1:32:47for our environment variables. Then,
  2437. 1:32:49open up your prisma.config.ts
  2438. 1:32:53and update the path to the schema. It's
  2439. 1:32:55just going to be prisma forward slash.
  2440. 1:32:57We want to remove this schema.prisma
  2441. 1:33:00because we'll make a separate Prisma
  2442. 1:33:02model.
  2443. 1:33:03So, just use prisma forward slash. Now,
  2444. 1:33:06before we run our spec, let's also
  2445. 1:33:08install Prisma Agent Skill. We did the
  2446. 1:33:11same thing with Clerk, so the same idea
  2447. 1:33:13applies. Just for a different library.
  2448. 1:33:16Open up your terminal and run MPX skills
  2449. 1:33:19add Prisma skills.
  2450. 1:33:22It'll ask you which ones you
  2451. 1:33:24specifically want to install and in this
  2452. 1:33:26case you can select all of them. CLI,
  2453. 1:33:28client API, database setup, Postgres,
  2454. 1:33:31Postgres setup, and upgrade V7 and press
  2455. 1:33:33enter.
  2456. 1:33:35You can install them for cloud code
  2457. 1:33:37within this project with simlink.
  2458. 1:33:40And we can proceed with the
  2459. 1:33:41installation. And now we are ready to
  2460. 1:33:43generate our schemas. So, let's create a
  2461. 1:33:46new file right here within our context
  2462. 1:33:49feature specs
  2463. 1:33:5105-prisma.md.
  2464. 1:33:54And one sentence update is that Prisma
  2465. 1:33:56is already installed, but we needed to
  2466. 1:33:59add the project data models, Prisma
  2467. 1:34:01client singleton, and the first
  2468. 1:34:03migration. So, then we have to start
  2469. 1:34:05specifying the models that we want to
  2470. 1:34:07install.
  2471. 1:34:09That we want to set up.
  2472. 1:34:11First, we're going to have the project
  2473. 1:34:13model.
  2474. 1:34:14So, we'll ask it to add project that has
  2475. 1:34:19to have an owner ID mapped to the Clerk
  2476. 1:34:21user, a name, an optional description, a
  2477. 1:34:25status enum, either draft or archived, a
  2478. 1:34:28canvas JSON path for future canvas blob
  2479. 1:34:31storage, timestamps, and indexes on
  2480. 1:34:34owner ID and creation date. So, we can
  2481. 1:34:36actually search through them. The second
  2482. 1:34:38model we want to have is going to be the
  2483. 1:34:40project collaborator, which is a project
  2484. 1:34:43relation with cascading delete. It
  2485. 1:34:46includes collaborator email, timestamp,
  2486. 1:34:49and some constraints on the project and
  2487. 1:34:51email, and indexes, so we can actually
  2488. 1:34:54map over it. Do not add any extra fields
  2489. 1:34:56unless required by Prisma. Finally, to
  2490. 1:34:59be able to use these models, we have to
  2491. 1:35:01set up Prisma client.
  2492. 1:35:03So, create a lib prisma.ts file as a
  2493. 1:35:07cached singleton,
  2494. 1:35:08branch by database URL. If it starts
  2495. 1:35:11with Prisma plus Postgres, then use
  2496. 1:35:13accelerate, else direct to add Prisma
  2497. 1:35:16adapter PG. In our case, it's going to
  2498. 1:35:19start with Postgres forward slash, which
  2499. 1:35:22means that it is actually hosted
  2500. 1:35:24somewhere. Finally, we want to ask it to
  2501. 1:35:27run the migrations and to generate that
  2502. 1:35:29Prisma client, and want to verify
  2503. 1:35:31whether it has installed all the
  2504. 1:35:32dependencies,
  2505. 1:35:34such as Prisma, Prisma client, Prisma
  2506. 1:35:36adapter PG, and PG itself, and some
  2507. 1:35:39checks are whether schema has both
  2508. 1:35:41models with correct relations and
  2509. 1:35:43indexes, the lib Prisma file exports one
  2510. 1:35:46cached Prisma instance,
  2511. 1:35:48the migration runs successfully, and the
  2512. 1:35:50NPM run build passes. So, let's open up
  2513. 1:35:54Claude Code, give it this file, and tell
  2514. 1:35:56it to read this file, update the
  2515. 1:35:59progress tracker, and implement it
  2516. 1:36:01exactly as specified. I think you get
  2517. 1:36:04the idea with these prompts.
  2518. 1:36:06The actual spec file is doing the heavy
  2519. 1:36:08lifting.
  2520. 1:36:09So, let's see how it approaches it.
  2521. 1:36:11It'll first read the Prisma spec,
  2522. 1:36:14the progress tracker, the architecture
  2523. 1:36:16context, and only then will it start
  2524. 1:36:18implementing it.
  2525. 1:36:20It'll first verify we have all the
  2526. 1:36:22necessary packages, and it might even
  2527. 1:36:24consult the Prisma skill. So, the agent
  2528. 1:36:27does a better way implementing the best
  2529. 1:36:29practices. So, let's give it some time,
  2530. 1:36:31and I'll be right back. Now, it's in the
  2531. 1:36:33process of creating the Prisma models
  2532. 1:36:36for the project and the project
  2533. 1:36:37collaborator.
  2534. 1:36:39Then, creating the Prisma singleton, so
  2535. 1:36:41we can actually have the client and run
  2536. 1:36:43it. It's asking us whether we can
  2537. 1:36:45actually run Prisma migrate. So, I'll
  2538. 1:36:47allow it to run it.
  2539. 1:36:50And then, it'll verify everything is
  2540. 1:36:51done, and we'll be able to check it all
  2541. 1:36:53out.
  2542. 1:36:54You can see that we have many files
  2543. 1:36:56changed, but once again, the majority of
  2544. 1:36:58these are coming from the agents that we
  2545. 1:37:00installed or the agent skills. The
  2546. 1:37:02actual generated files that we care
  2547. 1:37:04about are going to be within just a
  2548. 1:37:06couple of files, such as this Prisma
  2549. 1:37:08model right here,
  2550. 1:37:10and this Prisma client. That's it. But
  2551. 1:37:13okay, let's let it do its thing, and the
  2552. 1:37:15feature five is done. Here's what's
  2553. 1:37:18created, just two files that we need to
  2554. 1:37:20take a look at.
  2555. 1:37:21The first one is the project model, and
  2556. 1:37:24the second one is the Prisma client. So,
  2557. 1:37:27let's go ahead and check them out. I'll
  2558. 1:37:28first open up the model that is going to
  2559. 1:37:31be within models, project.prisma, and it
  2560. 1:37:34looks like I'm missing the Prisma syntax
  2561. 1:37:37highlighting. So, I'll head over into
  2562. 1:37:39extensions and install Prisma, which
  2563. 1:37:42would add the syntax highlighting,
  2564. 1:37:43formatting, auto completion, and more.
  2565. 1:37:46There we go. This now looks better. But
  2566. 1:37:48yeah, essentially we have created a new
  2567. 1:37:50model for the project with the ID, owner
  2568. 1:37:53ID, name, description, status, the
  2569. 1:37:56canvas, which is going to be attached to
  2570. 1:37:57a project very soon, and a potential
  2571. 1:38:00list of collaborators. And we also made
  2572. 1:38:02it indexable so we can search for these
  2573. 1:38:04projects.
  2574. 1:38:05Same thing happens with the project
  2575. 1:38:07collaborator. That's going to be a clerk
  2576. 1:38:09ID connected to it. And it's going to
  2577. 1:38:12have access to one or more projects.
  2578. 1:38:15Then, if we take a look at the actual
  2579. 1:38:17Prisma client, that's going to be within
  2580. 1:38:20lib Prisma,
  2581. 1:38:22we're just using the Prisma PG adapter
  2582. 1:38:24to create a new Prisma client and
  2583. 1:38:27connect it to it.
  2584. 1:38:29Then, we export this global Prisma
  2585. 1:38:31instance that we can use to make any
  2586. 1:38:33kind of database calls. We can't really
  2587. 1:38:36test a lot of stuff right here because
  2588. 1:38:38we've just built a database.
  2589. 1:38:39But in the next lesson, we can build a
  2590. 1:38:41couple of API routes that'll bring us
  2591. 1:38:43one step closer to actually making use
  2592. 1:38:45of this data.
  2593. 1:38:47So, for time being, let's just run git
  2594. 1:38:49add dot, git commit {dash} m, implement
  2595. 1:38:54Prisma,
  2596. 1:38:55and then git push.
  2597. 1:38:59Now that our schema is ready, we're
  2598. 1:39:02ready to build the API routes that sit
  2599. 1:39:05on top of it.
  2600. 1:39:06This is back end only.
  2601. 1:39:08We're not yet wiring the UI. That'll
  2602. 1:39:11come next. But right now, we need to
  2603. 1:39:13focus on one single thing.
  2604. 1:39:15A clean, secure set of routes for
  2605. 1:39:18creating, listing, renaming, and
  2606. 1:39:21deleting projects.
  2607. 1:39:23So, create a new spec right here under
  2608. 1:39:26context feature specs 06
  2609. 1:39:30project APIs.md.
  2610. 1:39:33And within it, we want to tell it that
  2611. 1:39:35the database schema is ready. So, we
  2612. 1:39:38need to build the back end project API
  2613. 1:39:41routes. The routes are as follows: the
  2614. 1:39:44REST endpoints for get API project,
  2615. 1:39:46which is going to list the current
  2616. 1:39:48user's projects, the post for API
  2617. 1:39:51projects, which creates a project, we
  2618. 1:39:54have the patch for renaming, and delete
  2619. 1:39:57for, obviously, deleting.
  2620. 1:39:59We can also give it a couple of rules,
  2621. 1:40:02such as use the authenticated clerk user
  2622. 1:40:05ID as an owner ID.
  2623. 1:40:07And when creating, default missing
  2624. 1:40:10project to untitled project and use the
  2625. 1:40:12schema's existing ID strategy without
  2626. 1:40:15adding sequential IDs. We also want to
  2627. 1:40:18tighten up the security a bit by telling
  2628. 1:40:20it that the unauthenticated requests
  2629. 1:40:22return 401, and only the project owner
  2630. 1:40:26can rename or delete. Non-owners
  2631. 1:40:28mutations return 403. Which means that
  2632. 1:40:31we're making our app secure not only on
  2633. 1:40:33the client side, but the server-side API
  2634. 1:40:36calls are also going to return invalid
  2635. 1:40:38responses if somebody tries to break
  2636. 1:40:41them. And again, we're not yet wiring
  2637. 1:40:43any UI.
  2638. 1:40:44And finally, to verify, we need to check
  2639. 1:40:46whether the routes exist, whether the
  2640. 1:40:49owner's checks are enforced, whether 401
  2641. 1:40:52and 403 responses are handled correctly,
  2642. 1:40:54and that the npm run dev build passes.
  2643. 1:40:57You know the drill. Open up Claude code,
  2644. 1:40:59tell it to read the file, and execute.
  2645. 1:41:03Read this file, update the progress
  2646. 1:41:05tracker, and implement it exactly as
  2647. 1:41:07specified. Let's see how it does.
  2648. 1:41:10The process of actually creating four
  2649. 1:41:13REST API routes would take us some time,
  2650. 1:41:16and you most likely already know how to
  2651. 1:41:17do that. But our agent is just going to
  2652. 1:41:19do it much more quickly for us. And then
  2653. 1:41:22when you take a look at it, you can
  2654. 1:41:23fully understand the structure, and
  2655. 1:41:25you'll be able to add any other
  2656. 1:41:26additional routes very easily, because
  2657. 1:41:28it's mostly boilerplate. So, let's give
  2658. 1:41:30it some time, and I'll be right back.
  2659. 1:41:32There we go. That was quick. Four routes
  2660. 1:41:35have been created, and the build is
  2661. 1:41:37clean.
  2662. 1:41:38All of them are right here within
  2663. 1:41:40project routes or project project ID
  2664. 1:41:43route. So, these are the general ones
  2665. 1:41:46and these are the ones for update and
  2666. 1:41:48delete.
  2667. 1:41:49Let's go ahead and check them out. They
  2668. 1:41:51are right here under app API route.ts
  2669. 1:41:56for general project routes where we have
  2670. 1:41:59a asynchronous get function where we
  2671. 1:42:01first get the user ID from auth
  2672. 1:42:03belonging to clerk.
  2673. 1:42:06We check whether the user ID doesn't
  2674. 1:42:07exist. In that case, we return a 401.
  2675. 1:42:10But, if it does exist, we try to find
  2676. 1:42:13all the projects that match with that
  2677. 1:42:15user and then we return them.
  2678. 1:42:17Similarly, if the user is trying to
  2679. 1:42:19create a post, we get all the data from
  2680. 1:42:23request.json. We take the name and
  2681. 1:42:26finally create it. Then, if we want to
  2682. 1:42:28update or delete them, you can head over
  2683. 1:42:30to the project ID route where we can
  2684. 1:42:33patch it based on the project ID. So, we
  2685. 1:42:36first check whether the user has access.
  2686. 1:42:39If they do, we take a look at the
  2687. 1:42:40context params,
  2688. 1:42:42find the project, parse the data,
  2689. 1:42:45update the project data, and then return
  2690. 1:42:47it.
  2691. 1:42:48And the same thing goes with the delete.
  2692. 1:42:50It's going to be even simpler. We find
  2693. 1:42:52it, we delete it, and we call it a day.
  2694. 1:42:55It's even returning a proper 204 status,
  2695. 1:42:58which means deleted. But now, in the
  2696. 1:43:00same lesson, I want to actually create
  2697. 1:43:02an additional feature spec, which is
  2698. 1:43:04going to be 07
  2699. 1:43:06wireeditorhome.md.
  2700. 1:43:10Where we want to wire the editor home
  2701. 1:43:13sidebar and dialogues to the real
  2702. 1:43:16project APIs we just created.
  2703. 1:43:19So, first, we got to deal with data
  2704. 1:43:21fetching because the editor home page is
  2705. 1:43:24a server component. So, we need to fetch
  2706. 1:43:27owned and shared projects server-side
  2707. 1:43:30using the existing project data helper
  2708. 1:43:33and pass both lists to the sidebar. And
  2709. 1:43:35I don't want to see any client-side
  2710. 1:43:37fetching for the initial load. Now, we
  2711. 1:43:39can do that by using the project
  2712. 1:43:42actions. So, I want to create a new hook
  2713. 1:43:45in the hooks folder that manages dialog
  2714. 1:43:48state and project mutation.
  2715. 1:43:51That's going to look something like
  2716. 1:43:52this.
  2717. 1:43:53Create manage create dialog state,
  2718. 1:43:56manage project name input, generate a
  2719. 1:43:59short unique suffix, slugify the name,
  2720. 1:44:02call the post API projects, and then
  2721. 1:44:05navigate over to the new workspace.
  2722. 1:44:07The project ID and Liveblocks room ID
  2723. 1:44:09should stay aligned, and we can do a
  2724. 1:44:12similar thing for rename and delete. The
  2725. 1:44:15rename simply has to store the target
  2726. 1:44:17project ID plus current name, and then
  2727. 1:44:20patch the name, and delete has to store
  2728. 1:44:22the target project ID, and then patch
  2729. 1:44:24it. Finally, we are ready to wire it all
  2730. 1:44:27together by connecting the hook to the
  2731. 1:44:30sidebar and dialogs. Create dialog will
  2732. 1:44:32show a room ID preview.
  2733. 1:44:35Rename dialog will prefill the current
  2734. 1:44:37name, and delete dialog will show the
  2735. 1:44:39project name. As usual, we want to run
  2736. 1:44:42some checks when we are done, and that
  2737. 1:44:43is to see whether the sidebar uses real
  2738. 1:44:46project data, not the fake dummy data it
  2739. 1:44:48uses right now, whether the create
  2740. 1:44:50actually navigates to the workspace,
  2741. 1:44:52whether the rename updates correctly,
  2742. 1:44:55and whether delete refreshes or
  2743. 1:44:57redirects correctly.
  2744. 1:44:58Finally, the build has to pass. So, this
  2745. 1:45:01is the moment that our sidebar goes from
  2746. 1:45:03mock data to real data.
  2747. 1:45:06So, let's open up our agent,
  2748. 1:45:09tell it to read the file,
  2749. 1:45:12update the progress tracker, and
  2750. 1:45:14implement it exactly as specified. So,
  2751. 1:45:16let's let it do its thing, and once it's
  2752. 1:45:19done, we can test it out in the browser.
  2753. 1:45:21And after some time, we are back. The
  2754. 1:45:23build passes clean, and it created a
  2755. 1:45:26couple of new files. The lib projects is
  2756. 1:45:29used for fetching the own projects and
  2757. 1:45:31shared projects. We can quickly check
  2758. 1:45:33that out right here under lib projects.
  2759. 1:45:38And you can see that this file simply
  2760. 1:45:40exports one function called get projects
  2761. 1:45:43for user, which calls all the projects
  2762. 1:45:45where the owner ID is the user ID that
  2763. 1:45:48is currently signed in, and then it
  2764. 1:45:50returns all the owned and shared
  2765. 1:45:52projects. It also created a hook that
  2766. 1:45:54deals with all the project actions.
  2767. 1:45:57And it modified some additional files
  2768. 1:45:59such as the editor, the projects route,
  2769. 1:46:02and some more types and props updates
  2770. 1:46:04over the sidebar and the dialogues. So,
  2771. 1:46:06don't forget to rerun your application
  2772. 1:46:08by running npm run dev. And then back on
  2773. 1:46:11localhost:3000, we are ready to test it
  2774. 1:46:14out by creating a new project. I'll give
  2775. 1:46:17it a name such as my system design.
  2776. 1:46:22And you can see that it's going to give
  2777. 1:46:24it an additional slug right here, and we
  2778. 1:46:26can click create project.
  2779. 1:46:29It's creating it, and we get redirected
  2780. 1:46:31to editor my system design. So, the
  2781. 1:46:34redirect is actually working, but
  2782. 1:46:36there's no route under that page. But,
  2783. 1:46:39that's to be expected because so far, we
  2784. 1:46:41just wanted to test whether we can wire
  2785. 1:46:43the database functions with the API
  2786. 1:46:45routes. So, if I head back over to the
  2787. 1:46:47editor and then open up the sidebar,
  2788. 1:46:49you'll see that there's a new my system
  2789. 1:46:51design project. And you can also rename
  2790. 1:46:55it to something like Ghost AI system
  2791. 1:46:59architecture, and you can see that it
  2792. 1:47:01updated it in real time. Or, you can
  2793. 1:47:03also just delete it. Let's test it out.
  2794. 1:47:06Yep, that works and it updates in real
  2795. 1:47:08time. So, this means that we have not
  2796. 1:47:10only implemented the dialogues to create
  2797. 1:47:13all of this, but also implemented the
  2798. 1:47:16API routes that handle the
  2799. 1:47:17functionality.
  2800. 1:47:19And if you're wondering why we didn't do
  2801. 1:47:20all of this in a single prompt? Well,
  2802. 1:47:23the API routes touch the back-end layer
  2803. 1:47:26and the UI wiring touches the front-end
  2804. 1:47:28and server components.
  2805. 1:47:30Combining them gives the agent too much
  2806. 1:47:32surface area to make assumptions across.
  2807. 1:47:35Instead, we had two focused prompts,
  2808. 1:47:38which means that we got back two clean
  2809. 1:47:40results without messing up stuff on
  2810. 1:47:42front-end and the back-end. So, before
  2811. 1:47:44we go ahead and review these changes,
  2812. 1:47:46head over to GitHub and merge the
  2813. 1:47:48previous PR, which contained
  2814. 1:47:50implementing Prisma and even more
  2815. 1:47:52importantly adding all of those
  2816. 1:47:54additional files for agent skills. So,
  2817. 1:47:57I'll just go ahead and merge it. So, now
  2818. 1:48:00when we push this over to GitHub, we'll
  2819. 1:48:01be able to review just those changes.
  2820. 1:48:04So, run git add dot,
  2821. 1:48:06git commit {dash} m, wire up Prisma
  2822. 1:48:11UI and REST APIs,
  2823. 1:48:14and run git push. You can head over to
  2824. 1:48:16your repo, open up a new pull request,
  2825. 1:48:19and do it specifically from the
  2826. 1:48:20development branch. This one will be
  2827. 1:48:22fairly quick as there's only 11 files
  2828. 1:48:24changed. So, let's give the Dr. Code
  2829. 1:48:27Rabbit some time to review it. In this
  2830. 1:48:29PR, we've finally introduced the REST
  2831. 1:48:32APIs and CRUD functionalities, making
  2832. 1:48:35our app, well, full stack. We've done
  2833. 1:48:37that across all the different files and
  2834. 1:48:39I always like when Code Rabbit thinks
  2835. 1:48:42the functionality is so detailed that it
  2836. 1:48:44actually gives us a diagram that we can
  2837. 1:48:46review. So, as the user clicks the new
  2838. 1:48:49project, the action that open create
  2839. 1:48:51dialog runs.
  2840. 1:48:53Then we initialize the dialog and
  2841. 1:48:55generate the room ID with a suffix.
  2842. 1:48:58We ask the user to enter the project
  2843. 1:49:00name and submit. After they submit, we
  2844. 1:49:03set the loading and we then make a post
  2845. 1:49:05request to our API projects, which is
  2846. 1:49:08our CRUD REST API route, which then
  2847. 1:49:11calls Prisma project create.
  2848. 1:49:13As soon as the project is created in the
  2849. 1:49:15database, we return the project data,
  2850. 1:49:18set the loading to false, and bring it
  2851. 1:49:20back and then navigate over to the new
  2852. 1:49:22project. It looks like we have one issue
  2853. 1:49:25where we need to import the use project
  2854. 1:49:27actions as a value and not as a type.
  2855. 1:49:30So, return type of requires the hook in
  2856. 1:49:32a value space, but import type is a type
  2857. 1:49:35only import that TypeScript erases from
  2858. 1:49:38the value namespace. So, what we can do
  2859. 1:49:40is just copy this import right here,
  2860. 1:49:43find where we're already importing a
  2861. 1:49:45type, specifically the use project
  2862. 1:49:48actions. That's going to be right here.
  2863. 1:49:50And instead of it, we can just import
  2864. 1:49:52the use project actions without the type
  2865. 1:49:55at the start.
  2866. 1:49:57That way, when it's referred right here,
  2867. 1:49:59we can say type of use project actions,
  2868. 1:50:02which is a function that TypeScript can
  2869. 1:50:04now actually understand. This is a
  2870. 1:50:05pretty nice save. And there's another
  2871. 1:50:07issue in the use project actions where
  2872. 1:50:10we need to handle the failed mutations
  2873. 1:50:12before closing or redirecting. So,
  2874. 1:50:15rename and delete always close the
  2875. 1:50:17dialogue and refresh push even if the
  2876. 1:50:20API calls fail. So, a server or off
  2877. 1:50:23error can look like a success. We need
  2878. 1:50:25to gate those transitions on res.ok and
  2879. 1:50:28keep the dialogue open on failure.
  2880. 1:50:30Thankfully, there's a quick fix right
  2881. 1:50:31here or we can copy just this part,
  2882. 1:50:33which is going to be the submit
  2883. 1:50:35function. So, copy the submit,
  2884. 1:50:37head over into the project actions or
  2885. 1:50:41use project actions.
  2886. 1:50:44And again, the these changes might be
  2887. 1:50:46different for you as they are for me.
  2888. 1:50:48So, if you have some other issues to
  2889. 1:50:49fix, you can definitely do that.
  2890. 1:50:52I'll remove the submit,
  2891. 1:50:55bring in the correct one, push the
  2892. 1:50:57changes by running git add dot, git
  2893. 1:50:59commit {dash} m, implement
  2894. 1:51:03CodeRabbit suggested
  2895. 1:51:06fixes
  2896. 1:51:07and run git push.
  2897. 1:51:10The changes will automatically be
  2898. 1:51:12recognized right here. So, we can go
  2899. 1:51:14ahead and merge it and we are ready to
  2900. 1:51:16continue.
  2901. 1:51:19Before we build the canvas, let me
  2902. 1:51:21quickly explain how Liveblocks works.
  2903. 1:51:24Because once you understand it, the
  2904. 1:51:26build order will make complete sense.
  2905. 1:51:29Liveblocks gives every project a shared
  2906. 1:51:32real-time room.
  2907. 1:51:33Think of it like a live session.
  2908. 1:51:36Everyone who opens the same project
  2909. 1:51:38connects to that room over web sockets.
  2910. 1:51:41And any change one person makes
  2911. 1:51:43instantly appears on everyone else's.
  2912. 1:51:46That canvas state, multiple users'
  2913. 1:51:48cursors, the AI drawing nodes, all of it
  2914. 1:51:52lives in that shared room and syncs in
  2915. 1:51:54real time. Liveblocks rooms are open by
  2916. 1:51:57default. So, technically, anyone could
  2917. 1:51:59connect if we let them.
  2918. 1:52:01But since Ghost AI is a project-based
  2919. 1:52:04app where only owners and collaborators
  2920. 1:52:06should have access, we need to control
  2921. 1:52:09who gets in with a sharing mechanism.
  2922. 1:52:12So, before Liveblocks connects a user to
  2923. 1:52:14a room, it has to call authentication
  2924. 1:52:16endpoints first.
  2925. 1:52:18And when we check whether that user
  2926. 1:52:20belongs to a specific project, only if
  2927. 1:52:22they do, we issue a token to let them
  2928. 1:52:25in.
  2929. 1:52:26That token endpoint is what we're
  2930. 1:52:28building in this chapter. And for it to
  2931. 1:52:30work, the access control and the
  2932. 1:52:32collaborator model have to exist. So,
  2933. 1:52:34we're doing it in this order. Workspace
  2934. 1:52:37access first, so each project has a
  2935. 1:52:39secure route only authorized users can
  2936. 1:52:42enter. And then we'll focus on the
  2937. 1:52:44collaborator model second, so the system
  2938. 1:52:46knows exactly who those authorized users
  2939. 1:52:49are.
  2940. 1:52:50Then Liveblocks and then the canvas.
  2941. 1:52:53So, head over into context, feature
  2942. 1:52:55specs, and create a new file called 08
  2943. 1:52:59editor-workspace-shell.md.
  2944. 1:53:03And within it, we'll explain exactly
  2945. 1:53:05what has to happen next. So, let's go
  2946. 1:53:07through it together. The goal of this
  2947. 1:53:09prompt is to build the editor room ID
  2948. 1:53:12workspace.
  2949. 1:53:13Remember, that's that page that we got
  2950. 1:53:15redirected to and we saw a 404. So, if I
  2951. 1:53:19create a new spec right here and we
  2952. 1:53:22navigate over to it, we get a 404. So,
  2953. 1:53:25this is the page we're building. Before
  2954. 1:53:27rendering, the unauthenticated users
  2955. 1:53:29will be redirected to sign in. The users
  2956. 1:53:32without project access will see the
  2957. 1:53:34access denied and non-existent projects
  2958. 1:53:37will also show access denied.
  2959. 1:53:40Then, we need to create that access
  2960. 1:53:42denied component with a centered layout,
  2961. 1:53:44lock icon, short message, and a link
  2962. 1:53:47back to the editor.
  2963. 1:53:48And we can also create some helpers that
  2964. 1:53:50are going to make it simpler for us to
  2965. 1:53:52reuse the access functionality
  2966. 1:53:54such as getting access to Clerk's
  2967. 1:53:56identity and checking whether they can
  2968. 1:53:58access a specific project.
  2969. 1:54:01When it comes to the layout, we want to
  2970. 1:54:02build a full viewport workspace layout
  2971. 1:54:05with a top bar showing the project name,
  2972. 1:54:07navbar actions at the top right, the
  2973. 1:54:10existing projects hyper on the left, the
  2974. 1:54:13current room highlighted in the sidebar,
  2975. 1:54:16central canvas placeholder with a dark
  2976. 1:54:18background and a centered message, and
  2977. 1:54:19the right sidebar placeholder for future
  2978. 1:54:21AI chat. This is exactly how the final
  2979. 1:54:24version of the application looks like.
  2980. 1:54:26We have the left sidebar with the
  2981. 1:54:27currently open project highlighted, the
  2982. 1:54:30top bar with the icons on the right, and
  2983. 1:54:32then we have the AI chat, which is going
  2984. 1:54:34to be coming soon. The canvas area, of
  2985. 1:54:36course, should fill the remaining space.
  2986. 1:54:39And in this case, we want to tell it to
  2987. 1:54:41not add any real canvas logic, live
  2988. 1:54:44blocks, AI chat, or sharing behavior
  2989. 1:54:47yet. That's the keyword right here.
  2990. 1:54:50When it's done, it should perform the
  2991. 1:54:51following checks. So, let's open it up
  2992. 1:54:54within our agent
  2993. 1:54:55and tell it to read the current file,
  2994. 1:54:58update the progress, and execute it
  2995. 1:55:01exactly as specified. Of course, make
  2996. 1:55:03sure that it knows what file you're
  2997. 1:55:05talking about. Let's run it and give it
  2998. 1:55:07some time to process it. And after a
  2999. 1:55:10couple of minutes, it is done. I
  3000. 1:55:12actually took Codex for a spin to see
  3001. 1:55:14how well it can handle it. And yeah, it
  3002. 1:55:16said that it implemented feature eight
  3003. 1:55:18as specified. The guarded workspace
  3004. 1:55:20route now lives under this page, stays
  3005. 1:55:23server-side, and the redirects
  3006. 1:55:25unauthenticated users to sign in. The
  3007. 1:55:27workspace shell component is right here,
  3008. 1:55:30and it includes a project aware top
  3009. 1:55:32navbar with buttons to share. Okay, so
  3010. 1:55:35let's go ahead and test it. Oh, this is
  3011. 1:55:38looking nice. It is a bit different from
  3012. 1:55:39the final design, but I actually love
  3013. 1:55:42it. You can see how the sidebar
  3014. 1:55:44collapses and then the central part
  3015. 1:55:46actually expands. Later on, we can play
  3016. 1:55:48a bit more with the design, but so far,
  3017. 1:55:50I love it. So, right now we are looking
  3018. 1:55:52the details of the new spec project
  3019. 1:55:55because you can see that we're on that
  3020. 1:55:56specific URL. And if you just head over
  3021. 1:55:58to the editor, you'll be able to see
  3022. 1:56:00something like this. You can expand the
  3023. 1:56:02sidebar and then navigate over to the
  3024. 1:56:04details page.
  3025. 1:56:06If the redirect isn't working for
  3026. 1:56:07whatever reason, send a small corrective
  3027. 1:56:10prompt describing exactly what's
  3028. 1:56:12happening, and it'll fix it. Now, let's
  3029. 1:56:15test access control.
  3030. 1:56:17Open up an incognito tab and then head
  3031. 1:56:19over to the same URL. You'll
  3032. 1:56:21automatically be redirected back to sign
  3033. 1:56:23in, which is the first good sign. Go
  3034. 1:56:25ahead and create a new account. I'll try
  3035. 1:56:28to use the email and password this time.
  3036. 1:56:31Let's go with contact js mastery pro and
  3037. 1:56:34a password. And it's good to see that
  3038. 1:56:36Clerk is trying to keep us safe, so it's
  3039. 1:56:38suggesting a stronger password. So, let
  3040. 1:56:40me do that. There we go. And for the
  3041. 1:56:44email, I'll use a secondary email that I
  3042. 1:56:47have because the first one is already
  3043. 1:56:49tied with GitHub. There we go. And we're
  3044. 1:56:51going to even have the email
  3045. 1:56:53verification. So, you're going to get an
  3046. 1:56:55email that looks something like this. Go
  3047. 1:56:56ahead and copy the verification code.
  3048. 1:56:59Then, paste it right here and you'll be
  3049. 1:57:01logged in and redirected to the editor.
  3050. 1:57:04So, if once again, you try to go to that
  3051. 1:57:06same project URL,
  3052. 1:57:09you should hit the access denied screen.
  3053. 1:57:11You don't have access to this workspace.
  3054. 1:57:13Hit back to your editor home to open up
  3055. 1:57:15a project you actually can access.
  3056. 1:57:17That's great. So, now, let's allow this
  3057. 1:57:19user to actually invite that
  3058. 1:57:21collaborator. To do that, I'll head over
  3059. 1:57:24within our context, feature specs, and
  3060. 1:57:27create a new file called 09 share
  3061. 1:57:31dialog.md.
  3062. 1:57:33Let's go through it together. In this
  3063. 1:57:34case, we're basically working on the
  3064. 1:57:36share button.
  3065. 1:57:37It's going to be within the editor
  3066. 1:57:39navbar and it's going to open up the
  3067. 1:57:41share dialog, allowing owners to invite
  3068. 1:57:44collaborators by email, view current
  3069. 1:57:47collaborators, remove collaborators, and
  3070. 1:57:49copy the project link with the temporary
  3071. 1:57:52copy feedback.
  3072. 1:57:53Collaborators can view the collaborator
  3073. 1:57:55list only and not invite, remove, or
  3074. 1:57:59manage access. It's also important that
  3075. 1:58:01we're going to use Clerk data for the
  3076. 1:58:03collaborator sharing system. So, they're
  3077. 1:58:05going to be stored by email in the
  3078. 1:58:07database and we'll use Clerk's backend
  3079. 1:58:09API to enrich the collaborator email
  3080. 1:58:12with display name and avatar image.
  3081. 1:58:16And if a Clerk user is not found for an
  3082. 1:58:18email, then we can fall back to showing
  3083. 1:58:20the email only. We want to add the
  3084. 1:58:22required API logic for listing,
  3085. 1:58:24inviting, and removing collaborators,
  3086. 1:58:27and we want to enforce ownership
  3087. 1:58:28server-side, not client-side, for
  3088. 1:58:31inviting and removing actions. Finally,
  3089. 1:58:34we have a couple of checks to see
  3090. 1:58:35whether everything's been done properly.
  3091. 1:58:37So, once again, let's open up Codex or
  3092. 1:58:40whichever agent you're using and tell it
  3093. 1:58:42to read the 09 share dialog,
  3094. 1:58:47update the progress tracker,
  3095. 1:58:49and implement it exactly as specified.
  3096. 1:58:52We can do it within the same chat
  3097. 1:58:55because this is somewhat related to the
  3098. 1:58:56functionality we just worked on. Let's
  3099. 1:58:58give it some time and I'll be right
  3100. 1:59:00back. And in about 5 minutes, feature
  3101. 1:59:02number nine got implemented exactly
  3102. 1:59:05within the specs scope. The workspace
  3103. 1:59:08navbar share button now opens a new
  3104. 1:59:10dialogue.
  3105. 1:59:12So, what do you say that we actually
  3106. 1:59:13test it out? Back within the browser,
  3107. 1:59:15but not the anonymous one, which doesn't
  3108. 1:59:17have the access. We have to go to the
  3109. 1:59:19one that is the owner of this workspace.
  3110. 1:59:22We can now click this share button,
  3111. 1:59:24which allows us to copy the workspace
  3112. 1:59:25link or invite them via email. And I
  3113. 1:59:28love this share interface. So, I'll
  3114. 1:59:30enter the email of my second account
  3115. 1:59:34and click invite. You can see that the
  3116. 1:59:36user has been invited as the
  3117. 1:59:37collaborator, and since we signed up via
  3118. 1:59:40email, this user doesn't have a profile
  3119. 1:59:42photo. So, now if you head back and
  3120. 1:59:44reload,
  3121. 1:59:46check this out.
  3122. 1:59:48The user now has access. And for this
  3123. 1:59:50user, it's not under my projects, but
  3124. 1:59:52under shared projects. And this user
  3125. 1:59:55doesn't have the permissions to update,
  3126. 1:59:57rename, or delete. Whereas for this
  3127. 2:00:00user, you can see that it's under my
  3128. 2:00:01projects and we have full permissions.
  3129. 2:00:04That's the full collaborator flow
  3130. 2:00:06working end-to-end.
  3131. 2:00:08Owner invites, collaborator receives the
  3132. 2:00:10invites, and nobody else can access it.
  3133. 2:00:13And before we push the changes, let's
  3134. 2:00:15review them with Code Rabbit. This time,
  3135. 2:00:17I'll do it directly within VS Code
  3136. 2:00:19through the Code Rabbit extension. And
  3137. 2:00:21as soon as the comments are in, we can
  3138. 2:00:23go ahead and check them out. Within the
  3139. 2:00:25use project share.ts file, that is the
  3140. 2:00:28hook that the share button borrows the
  3141. 2:00:31functionality from.
  3142. 2:00:32And right here, where we have the copy
  3143. 2:00:35link button, this does nothing else than
  3144. 2:00:37basically copy the URL to clipboard.
  3145. 2:00:40But currently, the copy link doesn't
  3146. 2:00:42handle the clipboard API failures, and
  3147. 2:00:44the timer lacks cleanup. So, if the
  3148. 2:00:46clipboard fails due to permissions or
  3149. 2:00:48something else, the set timeout will
  3150. 2:00:51still fire letting the user know that it
  3151. 2:00:53has been copied, whereas that's not
  3152. 2:00:55really true.
  3153. 2:00:56So, we have to set the error in case
  3154. 2:00:58something goes wrong. We can very easily
  3155. 2:01:00do that. I'll just copy this part right
  3156. 2:01:04here with a try and catch block, and we
  3157. 2:01:06have to replace everything from await
  3158. 2:01:09navigator. So, right here, await
  3159. 2:01:11navigator,
  3160. 2:01:12replace it with this part right here.
  3161. 2:01:15And we have to remove these plus signs
  3162. 2:01:17right here at the start. Okay, great.
  3163. 2:01:20So, this one has been fixed, and I
  3164. 2:01:22believe there's another one right here
  3165. 2:01:24where we have the reload functionality.
  3166. 2:01:26Reload silently swallows errors, which
  3167. 2:01:29may cause stale UI state. If the reload
  3168. 2:01:32function fails due to a network error,
  3169. 2:01:34the error is not captured, and the UI
  3170. 2:01:36may show outdated collaborator data
  3171. 2:01:39after a successful invite or remove,
  3172. 2:01:41which means that here we also have to
  3173. 2:01:43check for errors and display them if
  3174. 2:01:45there are any. So, once again, I'll copy
  3175. 2:01:48this part and replace the old one.
  3176. 2:01:51And don't forget to remove the plus
  3177. 2:01:53signs just to make sure it works.
  3178. 2:01:55Wonderful. So, two comments in this file
  3179. 2:01:57resolved. We have one more in the
  3180. 2:01:59project share dialogue. This is the
  3181. 2:02:02actual dialogue where we have a key
  3182. 2:02:04collision when collaborators share the
  3183. 2:02:06same email or display name. Well, that's
  3184. 2:02:09not really going to happen, right?
  3185. 2:02:11Because each one of the collaborators is
  3186. 2:02:12unique. So, this isn't unlikely, but
  3187. 2:02:15it's impossible. So, yeah, this one is
  3188. 2:02:17good. And finally, there is one more
  3189. 2:02:19under project collaborators where it
  3190. 2:02:22says batch emails in chunks of 500 to
  3191. 2:02:25respect Clerk's API limit. Well, yeah,
  3192. 2:02:28here where we're getting the users, uh
  3193. 2:02:30we definitely don't want to fetch more
  3194. 2:02:31than 500 users. This is great regardless
  3195. 2:02:34of Clerk's limit, but I'm glad that it
  3196. 2:02:36caught it because you never want to
  3197. 2:02:38fetch so many emails at the same time.
  3198. 2:02:41So, in this case, it's not just a copy
  3199. 2:02:43and paste that couple of lines of code.
  3200. 2:02:45What we can do here is use our agent to
  3201. 2:02:48fix it. So, if you click that button,
  3202. 2:02:50it's going to copy a little prompt and
  3203. 2:02:53put it into the chat that's going to
  3204. 2:02:54know exactly which part it has to fix.
  3205. 2:02:56So, let's give it a second to read it
  3206. 2:02:58and fix it. And it's done. The get clerk
  3207. 2:03:01email now batches emails into chunks of
  3208. 2:03:03500 so that it doesn't go over the
  3209. 2:03:05limit. But, instead of doing that, what
  3210. 2:03:08I actually want to do is never fetch
  3211. 2:03:10more than 500. I mean, that's too much.
  3212. 2:03:13So, I'll tell it
  3213. 2:03:14instead of chunking the emails, maybe we
  3214. 2:03:17just don't have to fetch so many. We can
  3215. 2:03:19just fetch fewer emails. So, let's see
  3216. 2:03:21how it handles a bit more vague
  3217. 2:03:23response. I mean, so far it has been
  3218. 2:03:25implementing everything so perfectly
  3219. 2:03:28because our prompts, or our specs,
  3220. 2:03:31should I say, were so precise. So, it
  3221. 2:03:33never had any issues.
  3222. 2:03:35But, yeah, in this case, it simplified
  3223. 2:03:37it. It's going to call fewer emails.
  3224. 2:03:39Good. So, we're going to keep this. And
  3225. 2:03:41now that all the issues have been fixed,
  3226. 2:03:43we actually fixed these two manually, we
  3227. 2:03:45can just go ahead and push all of these
  3228. 2:03:47changes by opening up our terminal and
  3229. 2:03:50running get add dot get commit {dash} m
  3230. 2:03:54implement share functionality.
  3231. 2:03:58And get push.
  3232. 2:04:00Perfect. Great job.
  3233. 2:04:03Now that the access control is done and
  3234. 2:04:06collaborators and sharing is enabled,
  3235. 2:04:10we are ready to finally build the
  3236. 2:04:12canvas. First, click the link down in
  3237. 2:04:14the description and head over to
  3238. 2:04:16Liveblocks.
  3239. 2:04:18If you haven't already, create a new
  3240. 2:04:20account, create a new project, call it
  3241. 2:04:23Ghost AI, and choose a region that is
  3242. 2:04:25closest to you. And the environment can
  3243. 2:04:27be set to development for now. Once the
  3244. 2:04:29project is created, select personalized
  3245. 2:04:32setup
  3246. 2:04:33and multiplayer. Then, select canvases
  3247. 2:04:36as we want to focus on workflow
  3248. 2:04:38diagrams, whiteboards, design tools, or
  3249. 2:04:40in this case, code architecture. And
  3250. 2:04:43then for the guide, you can select React
  3251. 2:04:45Flow with Next.js. That's exactly what
  3252. 2:04:48we're using. Then, copy the first
  3253. 2:04:49command that you can see right here, and
  3254. 2:04:51paste it within your terminal. You can
  3255. 2:04:53press enter, and here we're installing a
  3256. 2:04:55couple of things.
  3257. 2:04:56The Liveblocks client is the core client
  3258. 2:04:59that manages the WebSocket connection to
  3259. 2:05:02Liveblocks.
  3260. 2:05:03Then, there's the Liveblocks React,
  3261. 2:05:05which contains the React hooks for
  3262. 2:05:07accessing shared room state, presence,
  3263. 2:05:10and storage.
  3264. 2:05:11There's also the Liveblocks React UI,
  3265. 2:05:13containing the pre-built UI components.
  3266. 2:05:16There's also Liveblocks React Flow,
  3267. 2:05:19which is the bridge between Liveblocks
  3268. 2:05:21and React Flow, so canvases are synced
  3269. 2:05:24in real time across all the connected
  3270. 2:05:26users.
  3271. 2:05:27And finally, the XY Flow is the React
  3272. 2:05:30Flow itself, which handles the canvas,
  3273. 2:05:32nodes, edges, and interaction. Once that
  3274. 2:05:35is done, we can initialize the
  3275. 2:05:37Liveblocks config file. So, go ahead and
  3276. 2:05:39copy this command, and paste it into the
  3277. 2:05:42terminal,
  3278. 2:05:43and press enter.
  3279. 2:05:45This will generate a Liveblocks
  3280. 2:05:47config.ts file at the root of our
  3281. 2:05:49directory.
  3282. 2:05:50This is where we define the TypeScript
  3283. 2:05:52types for the shared room, what the
  3284. 2:05:54presence will look like, what user data
  3285. 2:05:56we want to attach to each connected
  3286. 2:05:58session. You can think of it as the
  3287. 2:06:00contract that describes everything
  3288. 2:06:02shared between users in real time.
  3289. 2:06:05And we'll configure it with AI. But
  3290. 2:06:07before we do, let's install Liveblocks
  3291. 2:06:10agent skills. Same pattern as with Clerk
  3292. 2:06:13and Prisma. We want to allow our agent
  3293. 2:06:15to be fluent in how Liveblocks works.
  3294. 2:06:19So, go ahead and copy this command, or
  3295. 2:06:21follow along with me,
  3296. 2:06:23and just run
  3297. 2:06:26npx skills add Liveblocks skills.
  3298. 2:06:30Say Y to update it, and then select
  3299. 2:06:33Liveblocks best practices, and we don't
  3300. 2:06:35need the second part. Press enter.
  3301. 2:06:38Select Claude or whichever agent you're
  3302. 2:06:40using,
  3303. 2:06:41and install it for the project and using
  3304. 2:06:43Simulink.
  3305. 2:06:45Perfect. This was quick. Now, I want to
  3306. 2:06:47split this specific feature
  3307. 2:06:49implementation into three separate spec
  3308. 2:06:52files. So, let's take it step by step,
  3309. 2:06:55and I'll walk you through everything.
  3310. 2:06:56First, let's dive into feature number
  3311. 2:06:5810, Liveblocks setup. Here, we want to
  3312. 2:07:01tell it to set up the real-time
  3313. 2:07:03collaboration infrastructure using
  3314. 2:07:06Liveblocks. This file will wire up the
  3315. 2:07:09entire collaboration infrastructure. The
  3316. 2:07:11config file will get the presence and
  3317. 2:07:13user metadata types, and then we'll
  3318. 2:07:15create a Liveblocks client. Finally,
  3319. 2:07:18we'll build the off endpoints like API
  3320. 2:07:21Liveblocks off, so we can verify that
  3321. 2:07:23people can actually access the room. So,
  3322. 2:07:25go ahead and open it with either Codex
  3323. 2:07:28or Claude Code. Tell it to read this
  3324. 2:07:31file,
  3325. 2:07:32update the progress,
  3326. 2:07:34and execute everything as specified, and
  3327. 2:07:37press enter. Let's give it some time to
  3328. 2:07:39do all the hard work for us while we
  3329. 2:07:42remain the architect and monitor exactly
  3330. 2:07:45what it is doing. And very soon, feature
  3331. 2:07:4710 is complete. It implemented just
  3332. 2:07:50three separate files. The Liveblocks
  3333. 2:07:52config, now with types for the presence
  3334. 2:07:55and user metadata, the lib Liveblocks
  3335. 2:07:58file, which allows us to fetch the
  3336. 2:08:00cached Liveblocks node client, so we can
  3337. 2:08:03use its instance, and we also have the
  3338. 2:08:06function that maps out a specific user
  3339. 2:08:08color. Most importantly, we have the
  3340. 2:08:10post endpoint that verifies whether the
  3341. 2:08:12user has been authenticated and whether
  3342. 2:08:15it has access to the project. If it
  3343. 2:08:17does, it returns all the data, and we're
  3344. 2:08:20one step closer to testing it out. But,
  3345. 2:08:22all of these were just some
  3346. 2:08:23functionalities that we need to use
  3347. 2:08:25within our code, but we're not using
  3348. 2:08:27them yet. So, instead of testing at this
  3349. 2:08:29point, what I want to do is head over to
  3350. 2:08:32feature number 11.
  3351. 2:08:34That's going to be the base canvas.md.
  3352. 2:08:38So, right here in lesson 11, we want to
  3353. 2:08:41replace the canvas placeholder with a
  3354. 2:08:44real LiveBlocks backed ReactFlow canvas.
  3355. 2:08:48Allowing multiple users to connect to a
  3356. 2:08:51LiveBlocks room and share the same
  3357. 2:08:53canvas state. That means that the nodes
  3358. 2:08:56and edges will sync in real time. And
  3359. 2:08:59after that, we can basically say that we
  3360. 2:09:01have a full collaborative canvas
  3361. 2:09:03application.
  3362. 2:09:04Not yet polished, but real. We don't
  3363. 2:09:08want to add any controls yet or custom
  3364. 2:09:10nodes or edges. We just want to create
  3365. 2:09:12that canvas.
  3366. 2:09:14So, let's open this up in a new chat. As
  3367. 2:09:17usual, I'll tell it to read the file,
  3368. 2:09:21update the progress,
  3369. 2:09:23and execute as specified. And I've just
  3370. 2:09:27went to grab a coffee, and feature 11 is
  3371. 2:09:30done. So, let's review it. It built out
  3372. 2:09:32the canvas types, so that our
  3373. 2:09:34application remains heavily typed.
  3374. 2:09:37Then, it added the storage part over to
  3375. 2:09:40the LiveBlocks config.
  3376. 2:09:41This matters right here because it knows
  3377. 2:09:43that we're going to be keeping track of
  3378. 2:09:45the presence of the cursors and whether
  3379. 2:09:47they're thinking,
  3380. 2:09:48but also the storage of different nodes
  3381. 2:09:50and edges and users on the screens.
  3382. 2:09:52Later on, we're going to fill up these
  3383. 2:09:54two.
  3384. 2:09:55using LiveBlocks provider and the room
  3385. 2:09:57provider, it created the canvas room.
  3386. 2:10:00And most importantly, the canvas
  3387. 2:10:02placeholder got replaced with that room.
  3388. 2:10:05So, what do you say that we go ahead and
  3389. 2:10:07test it out?
  3390. 2:10:08Back on localhost:3000, we got
  3391. 2:10:10connecting to a room, but there's one
  3392. 2:10:13issue. It says LiveBlocks authentication
  3393. 2:10:16failed, reason not provided. Maybe
  3394. 2:10:18because this project was created before
  3395. 2:10:20our whole LiveBlocks setup. So, what
  3396. 2:10:22I'll do is delete it, reload the page,
  3397. 2:10:25and create a new project.
  3398. 2:10:27I'll call it live blocks live room and
  3399. 2:10:31create. Unfortunately, we still get the
  3400. 2:10:34same issue. Thankfully, the error in the
  3401. 2:10:36terminal gives us a bit more info. It
  3402. 2:10:39looks like we're missing the live blocks
  3403. 2:10:40keys. So, if you head over to your
  3404. 2:10:42project under API keys,
  3405. 2:10:44you'll be able to see your public key
  3406. 2:10:46and the secret key. So, go ahead and
  3407. 2:10:48copy them and add them to your
  3408. 2:10:50.env.local
  3409. 2:10:52where we can first specify the live
  3410. 2:10:54blocks public key as well as the live
  3411. 2:10:58blocks secret key.
  3412. 2:11:00With these two keys in place, head back
  3413. 2:11:02over to your application and reload. And
  3414. 2:11:05after connecting to room, you'll be able
  3415. 2:11:07to see the actual canvas. This is the
  3416. 2:11:10React Flow canvas underneath that you
  3417. 2:11:12can move through. And there's even a
  3418. 2:11:14little window that you'll be able to
  3419. 2:11:16scroll through to very quickly access
  3420. 2:11:18specific parts of the workspace. This is
  3421. 2:11:20looking absolutely amazing. We can even
  3422. 2:11:23expand it by collapsing the left
  3423. 2:11:24sidebar. Oh, and the right sidebar is
  3424. 2:11:27collapsible, too. So, now we have a real
  3425. 2:11:30fully functional React Flow canvas. But,
  3426. 2:11:34of course, what is the canvas for if we
  3427. 2:11:36can't add any elements on top of it? So,
  3428. 2:11:38let's create a little bottom navigation
  3429. 2:11:41that allows us to add some shapes that
  3430. 2:11:43are going to act as specific parts of
  3431. 2:11:45the diagrams within our application.
  3432. 2:11:47We'll do that by creating a new feature
  3433. 2:11:50spec called 12 shape panel.md.
  3434. 2:11:55You can add it right here. This one will
  3435. 2:11:56be simple.
  3436. 2:11:58And what this does is it adds a floating
  3437. 2:12:01toolbar at the bottom of the canvas
  3438. 2:12:03where users can drag shapes onto the
  3439. 2:12:06canvas to create notes. Rectangle,
  3440. 2:12:09diamond shapes, circles, pills,
  3441. 2:12:11cylinders, and hexagons for databases.
  3442. 2:12:14And after this, users will actually be
  3443. 2:12:17able to start creating the architectural
  3444. 2:12:20diagrams. We want to allow the users to
  3445. 2:12:22drag a shape, including the shape name
  3446. 2:12:24and the default size. Then, they can
  3447. 2:12:27also drag and drop it.
  3448. 2:12:29And on drop, we need to read the dragged
  3449. 2:12:31shape payload, convert it to the screen
  3450. 2:12:34position, create a new node at that
  3451. 2:12:36position, use an empty label, and the
  3452. 2:12:39default color. We then want to give each
  3453. 2:12:41one of these shapes a node ID with their
  3454. 2:12:44shape name, timestamp, and a counter.
  3455. 2:12:47And we want to render it.
  3456. 2:12:49So, this is an exciting one. So, let's
  3457. 2:12:51get it built. Read the file, update the
  3458. 2:12:54progress, and execute it exactly as
  3459. 2:12:56specified. I'm sure there's an easier
  3460. 2:12:58way for me to just to read the file and
  3461. 2:13:01not have to repeat this sentence every
  3462. 2:13:03now and then. I mean, I could have put
  3463. 2:13:05it at the top of the file and just share
  3464. 2:13:06the file itself. That would have worked.
  3465. 2:13:09Uh but yeah, I don't mind it. It's the
  3466. 2:13:11actual work that you put before that
  3467. 2:13:14saves you so much time later down the
  3468. 2:13:16line. This one took a bit longer, but
  3469. 2:13:18feature 12 is done. It created the
  3470. 2:13:21canvas node renderer and a floating pill
  3471. 2:13:23toolbar at the bottom with six draggable
  3472. 2:13:26shapes. So, if you head back over to
  3473. 2:13:28your room,
  3474. 2:13:30take a look at the bottom.
  3475. 2:13:31You have the rectangle, which you can
  3476. 2:13:33drag and drop. Hopefully, nope. As I
  3477. 2:13:37dropped it, it didn't appear on the
  3478. 2:13:39screen.
  3479. 2:13:40Let's try with a second one.
  3480. 2:13:42It looks like I can drag and drop them,
  3481. 2:13:44but they're not actually showing up on
  3482. 2:13:46the screen, which makes it a great
  3483. 2:13:47opportunity to debug it the proper way
  3484. 2:13:50by specifying in detail the current
  3485. 2:13:52issue that we're experiencing. So, I
  3486. 2:13:55took a second to write all of the issues
  3487. 2:13:57that I believe we currently have with
  3488. 2:13:59the application. At least that I have on
  3489. 2:14:01my version of the app. Your agent might
  3490. 2:14:04have done something different. So, let's
  3491. 2:14:05go through everything together first,
  3492. 2:14:07and then you'll be able to tell your
  3493. 2:14:09agent to fix some issues that you see on
  3494. 2:14:11your end as well. Let's think of this as
  3495. 2:14:13a little corrective prompt.
  3496. 2:14:15So, review the editor canvas
  3497. 2:14:16implementation and fix the visual
  3498. 2:14:18issues. The canvas currently looks like
  3499. 2:14:21it's floating above the background
  3500. 2:14:23inside a border box. Instead of feeling
  3501. 2:14:25like a real design canvas. And I want to
  3502. 2:14:28teach you how we can also add images to
  3503. 2:14:29the context. So, right here within the
  3504. 2:14:32context, you can create a new folder
  3505. 2:14:34called screenshots.
  3506. 2:14:36And then you can screenshot the entire
  3507. 2:14:37design and simply drag and drop it in.
  3508. 2:14:42Of course, I'll rename it to image as I
  3509. 2:14:44specified right here within the
  3510. 2:14:46document. That way you can also give
  3511. 2:14:48your agent some visual feedback.
  3512. 2:14:51Also, read the current canvas component
  3513. 2:14:53code in the components editor. And here
  3514. 2:14:55are a couple of issues to look for.
  3515. 2:14:57Obviously and first of all, the drag and
  3516. 2:15:00drop issues, right? The canvas nodes
  3517. 2:15:02from the node panel cannot be dragged
  3518. 2:15:05and dropped onto the canvas. We need to
  3519. 2:15:06investigate the full drag and drop
  3520. 2:15:09pipeline. We need to confirm that the
  3521. 2:15:11draggable nodes in the node panel have
  3522. 2:15:13the correct draggable attribute, that
  3523. 2:15:15the canvas has the on drag over handler
  3524. 2:15:19and on drop allowing us to drop them.
  3525. 2:15:21That the drop handler reads the node
  3526. 2:15:23type from data transfer, calculates the
  3527. 2:15:26coordinates, and then actually creates a
  3528. 2:15:28new node at the drop position.
  3529. 2:15:30And while we're fixing the drag and drop
  3530. 2:15:32issues, I also thought we can fix some
  3531. 2:15:34visual inconsistencies such as the way
  3532. 2:15:37that the canvas and the left and the
  3533. 2:15:39right sidebar are positioned. So, the
  3534. 2:15:41left and the right sidebar should float
  3535. 2:15:42over the canvas, not push or shrink it.
  3536. 2:15:45Sidebars must use the fixed position or
  3537. 2:15:48absolute with a higher Z index and so
  3538. 2:15:50on. So, after documenting all issues, we
  3539. 2:15:53want to fix all of the above so that it
  3540. 2:15:55basically corrects what we specified.
  3541. 2:15:58So, let's actually open this up right
  3542. 2:16:00here. We can tell it to read this file
  3543. 2:16:03and fix all of the listed issues and
  3544. 2:16:06then run it.
  3545. 2:16:08So, we've done three things. First, we
  3546. 2:16:11gave Claude code some file references up
  3547. 2:16:14front and the screenshots right here.
  3548. 2:16:16This stops it from wandering around the
  3549. 2:16:18entire project trying to figure out
  3550. 2:16:20where things live.
  3551. 2:16:21We're pointing it exactly where to look.
  3552. 2:16:23We're listing every issue one by one and
  3553. 2:16:26mixing some technical hints alongside
  3554. 2:16:28them.
  3555. 2:16:29These technical details act as
  3556. 2:16:31shortcuts. They give the AI the stronger
  3557. 2:16:34starting point so it can find and fix
  3558. 2:16:36the root cause faster instead of
  3559. 2:16:38guessing. And third, at the bottom, we
  3560. 2:16:40describe exactly what success looks
  3561. 2:16:42like. The AI now knows not just what's
  3562. 2:16:45broken, but what done looks like. So,
  3563. 2:16:48let's see if we can manage to correct
  3564. 2:16:50itself and fix it. Quickly after reading
  3565. 2:16:52through some of these files, it has a
  3566. 2:16:54full picture of all the issues, so it's
  3567. 2:16:57going to use the to-do right to track
  3568. 2:16:59the fixes and then implement them. Fix
  3569. 2:17:02the canvas layout was the first thing,
  3570. 2:17:04removing the card styling and making it
  3571. 2:17:06a fill full viewport, fixing the left
  3572. 2:17:09sidebar not fully hiding when closed,
  3573. 2:17:11fixing the dotted canvas background
  3574. 2:17:13visibility, and finally and most
  3575. 2:17:14importantly, verifying the drag-and-drop
  3576. 2:17:17pipeline. And see how well we did. Uh
  3577. 2:17:20it's even thanking us,
  3578. 2:17:21uh specifying that the core issue is
  3579. 2:17:23clear from the screenshot of the code.
  3580. 2:17:26The canvas is boxed inside a padded main
  3581. 2:17:29with card styling and the layout shrinks
  3582. 2:17:32the canvas to accommodate sidebars
  3583. 2:17:34instead of floating over them. So, it's
  3584. 2:17:36going to fix it very easily.
  3585. 2:17:38Perfect. Hopefully, this video is
  3586. 2:17:40teaching you how you can approach
  3587. 2:17:42developing apps with AI. You are the
  3588. 2:17:45architect and agent is just a coder. And
  3589. 2:17:49there we go. All four files have been
  3590. 2:17:51updated, so let's test it out.
  3591. 2:17:54Back into the browser, I will reload.
  3592. 2:17:57You can see that now the canvas spans
  3593. 2:17:59across left and right and the left and
  3594. 2:18:02right sidebar appear to be floating on
  3595. 2:18:04top of it. So, if you want to hide it,
  3596. 2:18:06it just gets completely hidden away,
  3597. 2:18:08which is great. And the right sidebar
  3598. 2:18:11also gets completely hidden away, so we
  3599. 2:18:14have a complete canvas. This is a big
  3600. 2:18:16difference from what we had before,
  3601. 2:18:18because now if you hide the sidebars,
  3602. 2:18:20you have so much more space to work
  3603. 2:18:22with. And what happens if we try to drag
  3604. 2:18:24and drop an element?
  3605. 2:18:26It looks like that functionality is
  3606. 2:18:28still not working properly. And I think
  3607. 2:18:30that's because Claude focused mostly on
  3608. 2:18:32cosmetic changes and the layout. I don't
  3609. 2:18:35see too many mentions of the drag and
  3610. 2:18:38drop functionality being fixed. So, what
  3611. 2:18:40we can do now is head over into the
  3612. 2:18:42current issues and specify that we want
  3613. 2:18:45to fix the drag and drop functionality.
  3614. 2:18:50So, we're going to remove everything
  3615. 2:18:52else besides the drag and drop and keep
  3616. 2:18:55the last part saying nodes can be
  3617. 2:18:57dragged from the node panel and dropped
  3618. 2:18:59onto the canvas as correctly. So, now we
  3619. 2:19:01can say read the current issues file
  3620. 2:19:04again and fix the remaining issue and
  3621. 2:19:07press enter.
  3622. 2:19:09This time, it's all about the drag and
  3623. 2:19:11drop. And after some thinking, it looks
  3624. 2:19:14like it found the root cause. The React
  3625. 2:19:17Flow viewport has pointer events none,
  3626. 2:19:20and React Flow internally uses D3 zoom
  3627. 2:19:23or native pointer listeners that call
  3628. 2:19:25prevent default on pointer down. So,
  3629. 2:19:27when the shape panel is rendered inside
  3630. 2:19:30of the React Flow as a panel, those
  3631. 2:19:32pointer handlers interfere with the
  3632. 2:19:34browser's drag gesture recognition
  3633. 2:19:36before Dragster can fire. The standard
  3634. 2:19:39React Flow drag and drop pattern puts
  3635. 2:19:41drag sources outside of the React Flow
  3636. 2:19:44and puts on drop or on drag over on a
  3637. 2:19:46wrapper div, not on the React Flow
  3638. 2:19:48component. So, it's going to fix this
  3639. 2:19:50issue for both the canvas editor and the
  3640. 2:19:52shape panel. That's it. Note that there
  3641. 2:19:55is the fix is clean. We specified what
  3642. 2:19:57was wrong, and the fix was to move the
  3643. 2:20:00on drag over and on drop from the React
  3644. 2:20:03Flow component to the outer wrapper. And
  3645. 2:20:05also to replace the panel position from
  3646. 2:20:07bottom center, which is React internal
  3647. 2:20:09panel, with a plain absolutely
  3648. 2:20:11positioned div.
  3649. 2:20:12So, let's test it out. Back on localhost
  3650. 2:20:153000 within a specific project, I'll
  3651. 2:20:17drag and drop this rectangle, and it
  3652. 2:20:20still doesn't do it. So, what I'm
  3653. 2:20:22thinking is maybe we can make use of
  3654. 2:20:25that Liveblocks agent skills that we
  3655. 2:20:27installed earlier.
  3656. 2:20:28I mean, this is the exact situation
  3657. 2:20:30they're built for. So, in the same
  3658. 2:20:31context window, let's simply tell the
  3659. 2:20:34agent to check the Liveblocks best
  3660. 2:20:37practices and fix the drag and drop
  3661. 2:20:39flow. Dragging shapes from the shape
  3662. 2:20:41panel should create new nodes on the
  3663. 2:20:43canvas. But, it's still not working.
  3664. 2:20:46Nodes should be draggable from the panel
  3665. 2:20:49and dropped onto the canvas correctly.
  3666. 2:20:51So, by telling it to check the
  3667. 2:20:52Liveblocks best practices, I'm hoping
  3668. 2:20:54that it's going to consult the
  3669. 2:20:56Liveblocks agent skill. So, let's give
  3670. 2:20:58it a shot, and you can see that that is
  3671. 2:20:59the first thing that it did. Liveblocks
  3672. 2:21:01best practices. After analyzing it, it
  3673. 2:21:04came back with the complete picture with
  3674. 2:21:06three things that are wrong.
  3675. 2:21:08The storage type declares top-level
  3676. 2:21:10nodes and edges, but use Liveblocks flow
  3677. 2:21:13actually stores everything under a
  3678. 2:21:15nested flow key. Within the canvas room,
  3679. 2:21:17the initial storage creates top-level
  3680. 2:21:19nodes and edges, once again, wrong
  3681. 2:21:21schema. And then the canvas editor add
  3682. 2:21:23node mutation calls storage. get nodes,
  3683. 2:21:27which writes to the wrong storage path.
  3684. 2:21:30Instead, it should use on nodes change
  3685. 2:21:32with a type of add and then the item
  3686. 2:21:34we're adding.
  3687. 2:21:35So, let's wait until it fixes all three,
  3688. 2:21:38and it says clean. So, let's actually
  3689. 2:21:40test it out. Back within the browser,
  3690. 2:21:42I'll reload the page, and I'll try drag
  3691. 2:21:45and dropping a node once again.
  3692. 2:21:47And you can see that this time we
  3693. 2:21:49actually get a a
  3694. 2:21:50Now, if you try drag and dropping
  3695. 2:21:52another shape, you'll see that it'll
  3696. 2:21:54just give you another rectangle. And yet
  3697. 2:21:56another rectangle of a different size.
  3698. 2:21:59You're only getting rectangles, and
  3699. 2:22:01that's okay for now. Because in the next
  3700. 2:22:04lessons, we're going to turn these
  3701. 2:22:05rectangles into different shapes. We'll
  3702. 2:22:08basically make it like a real
  3703. 2:22:09architecture canvas where you can
  3704. 2:22:11connect different nodes and give them
  3705. 2:22:13titles and make them make sense. But
  3706. 2:22:16thankfully, we fixed this shape drag and
  3707. 2:22:18dropping feature, which is one of the
  3708. 2:22:19bigger features in the app. And while
  3709. 2:22:21fixing it, I wanted to keep the full
  3710. 2:22:23process of me doing that. So, you're not
  3711. 2:22:25just watching me copy and paste from the
  3712. 2:22:27other screen.
  3713. 2:22:28We're actually debugging this together.
  3714. 2:22:31And in this case, the solution was to
  3715. 2:22:33invoke an agent skill. So, whenever
  3716. 2:22:35you're working with specific tools,
  3717. 2:22:37always verify that they also have their
  3718. 2:22:39agent skills, install them, and ask your
  3719. 2:22:42agent to use them.
  3720. 2:22:44Okay, great. So, let's actually get
  3721. 2:22:46these changes pushed by saying get add
  3722. 2:22:48dot, get commit {dash} m,
  3723. 2:22:50implement drag and drop canvas
  3724. 2:22:54functionality,
  3725. 2:22:55and then run get push. And I'll actually
  3726. 2:22:57open up a PR for this and get it merged
  3727. 2:23:00so that in the next lesson, we can focus
  3728. 2:23:02on adding more canvas features. For
  3729. 2:23:05these, we already reviewed most of the
  3730. 2:23:07changes before.
  3731. 2:23:08So, I won't be reviewing them again. And
  3732. 2:23:11we have to resolve the conflicts right
  3733. 2:23:13here within our current issues. And
  3734. 2:23:15there's a fix with Copilot thing right
  3735. 2:23:16here, resolve the merge conflicts in
  3736. 2:23:18this pull request by clearing the
  3737. 2:23:22current issues.md file.
  3738. 2:23:25We basically want to make it empty as we
  3739. 2:23:27said. We don't need to push whatever is
  3740. 2:23:29in the current issues file. This is also
  3741. 2:23:31a new feature by GitHub where the
  3742. 2:23:33Copilot can automatically fix it on our
  3743. 2:23:35behalf.
  3744. 2:23:37And once it does, we'll be able to merge
  3745. 2:23:39it back to the main branch and continue
  3746. 2:23:41developing. And there we go. It
  3747. 2:23:42basically cleared out the file, and
  3748. 2:23:44we're good to merge it. So now, back
  3749. 2:23:46within the editor, you can just run git
  3750. 2:23:48pull to pull the latest changes and
  3751. 2:23:50we're ready to continue with the next
  3752. 2:23:52feature.
  3753. 2:23:55In this lesson, the goal is to make the
  3754. 2:23:57canvas feel like a real product. So,
  3755. 2:24:01open up your feature specs and go ahead
  3756. 2:24:04and create another one that's going to
  3757. 2:24:06be 13 node shape.md.
  3758. 2:24:09In this lesson, we're going to actually
  3759. 2:24:11polish and add six features. Each one
  3760. 2:24:14will have a distinct layer of
  3761. 2:24:16interaction. So, that by the end, the
  3762. 2:24:18canvas will have proper shape rendering,
  3763. 2:24:21node colors, edge behavior, and keyboard
  3764. 2:24:23shortcuts. Everything that makes a
  3765. 2:24:25difference between a working prototype
  3766. 2:24:27and something that genuinely feels
  3767. 2:24:29polished to use. So, starting with the
  3768. 2:24:32first one, it's going to be the node
  3769. 2:24:34shape. It's a fairly simple one where we
  3770. 2:24:36just want to replace the placeholder
  3771. 2:24:38node renderer with proper shape
  3772. 2:24:40rendering and a drag preview.
  3773. 2:24:43So, instead of a placeholder node shape,
  3774. 2:24:45which is just a rectangle, we want to
  3775. 2:24:47render all of these different types of
  3776. 2:24:48shapes through SVGs.
  3777. 2:24:51They should scale with the node size and
  3778. 2:24:53we want to keep the border subtle. We
  3779. 2:24:54also want to add a shape drag preview
  3780. 2:24:57while we're dragging.
  3781. 2:24:59We want to keep the node rendering
  3782. 2:25:00connected to the existing collaborative
  3783. 2:25:02canvas state.
  3784. 2:25:03We don't want to rebuild anything.
  3785. 2:25:06And when we're done, we want to check
  3786. 2:25:08that the node renderer renders the
  3787. 2:25:10correct shape variant for each type.
  3788. 2:25:13So, you know the drill. Open up your
  3789. 2:25:15agent and let's ask it to read this
  3790. 2:25:18file, update the progress, and implement
  3791. 2:25:20it as specified. Let's give it some time
  3792. 2:25:23and I'll be right back. And a couple of
  3793. 2:25:25minutes after, feature 13 is done. It
  3794. 2:25:28replaced the single style placeholder
  3795. 2:25:30with a shape aware rendering and also
  3796. 2:25:33added the cursor tracking ghost preview.
  3797. 2:25:35I'll show you what that means quickly.
  3798. 2:25:38But, basically now, you can see that our
  3799. 2:25:40array of rectangles that we created
  3800. 2:25:42before is now a bunch of different
  3801. 2:25:45shapes. And we can actually move across
  3802. 2:25:47the canvas and drag and drop different
  3803. 2:25:49shapes. There's a mini map at the bottom
  3804. 2:25:50as well, which we can later on remove as
  3805. 2:25:53we don't need it as we'll be mostly
  3806. 2:25:54working within a single centralized
  3807. 2:25:56place. But yeah, we now have the shapes
  3808. 2:25:59and you can actually connect the shapes
  3809. 2:26:01together. But we still can't change the
  3810. 2:26:03size of the nodes, right?
  3811. 2:26:05They are always of the same size and we
  3812. 2:26:07can't edit their labels. Like currently
  3813. 2:26:09these are just shapes. They don't have
  3814. 2:26:11any data associated with them.
  3815. 2:26:14So what we can do is create another file
  3816. 2:26:17right here, another feature
  3817. 2:26:1914 node editing.md.
  3818. 2:26:23And within it, we essentially want to
  3819. 2:26:25add resizing and inline label editing to
  3820. 2:26:28the canvas. So that when we select a
  3821. 2:26:30specific node, we can resize it and
  3822. 2:26:32scale them however we need to. And if we
  3823. 2:26:34double click it, we'll be able to edit
  3824. 2:26:37its label. So this is the next feature
  3825. 2:26:39that we're going to develop. I'll tell
  3826. 2:26:40it to read the file, update the
  3827. 2:26:43progress,
  3828. 2:26:45and implement it exactly as specified.
  3829. 2:26:49And you know what? I will actually copy
  3830. 2:26:51this part right here. So in the future I
  3831. 2:26:53can just paste it into the prompt.
  3832. 2:26:56Okay, and after some wearing and
  3833. 2:26:59cogitating and thinking, let's see what
  3834. 2:27:02it'll actually come up with. And as it's
  3835. 2:27:04close to being done after running a
  3836. 2:27:06couple of minutes, um near the end, uh
  3837. 2:27:09when it tries to build and check for
  3838. 2:27:11errors, it almost always finds some type
  3839. 2:27:15issues. Like right here, it was
  3840. 2:27:17complaining about the canvas node. So it
  3841. 2:27:20expanded the types and made it a bit
  3842. 2:27:22more type safe. And only once that is
  3843. 2:27:24done, it actually updates the progress
  3844. 2:27:26tracker and then finishes with the
  3845. 2:27:28feature. So it's always great to ask it
  3846. 2:27:30to test the application and test the
  3847. 2:27:32output.
  3848. 2:27:33Okay, great. So the The
  3849. 2:27:35from XY flow now renders when a node is
  3850. 2:27:38selected and we can resize dimension
  3851. 2:27:40changes through live boxes on node
  3852. 2:27:42change automatically. Also,
  3853. 2:27:44double-clicking any node opens up a text
  3854. 2:27:47area.
  3855. 2:27:48So, let's go ahead and test it out. We
  3856. 2:27:50now have these labels, which is perfect.
  3857. 2:27:53But first, let's test the resizing. If I
  3858. 2:27:56now pull it at any of the borders
  3859. 2:27:59or even at any of the edges, you can see
  3860. 2:28:02that this is very precise and would take
  3861. 2:28:05us some time to implement properly. You
  3862. 2:28:06can now resize it both horizontally and
  3863. 2:28:09vertically or if you want to keep the
  3864. 2:28:11aspect ratio, you can resize it by the
  3865. 2:28:13edges. This is absolutely amazing.
  3866. 2:28:17And let's also test changing the label
  3867. 2:28:19by double-clicking right here and typing
  3868. 2:28:21something like start
  3869. 2:28:23of the app
  3870. 2:28:25and leaving it and you can see that it
  3871. 2:28:27looks good. It quickly brings the text
  3872. 2:28:29up in case you want to type more stuff
  3873. 2:28:31into it.
  3874. 2:28:32But
  3875. 2:28:33but we can fix that later on because the
  3876. 2:28:35text will mostly always stay centered.
  3877. 2:28:38So, if we pull some kind of a label, we
  3878. 2:28:40can now mark this as a post grass DB,
  3879. 2:28:43for example, and it's going to fall down
  3880. 2:28:46right here and we can now connect the
  3881. 2:28:48application that way. Perfect. Let's
  3882. 2:28:50just quickly tell it that even though
  3883. 2:28:52while we're typing into the field, we
  3884. 2:28:54want the text to stay in the middle.
  3885. 2:28:56Right now, it jumps to the start. So,
  3886. 2:28:59I'll take a quick screenshot while I am
  3887. 2:29:01typing
  3888. 2:29:03and drag and drop it into the chat and
  3889. 2:29:05tell it while the label editing is
  3890. 2:29:07focused, the text appears at the top of
  3891. 2:29:10the element instead of in the middle
  3892. 2:29:12where it falls back to when not focused
  3893. 2:29:15any longer.
  3894. 2:29:16Make it so that when we're typing, we're
  3895. 2:29:18also typing within the middle of the
  3896. 2:29:20element. Hopefully, this should be clear
  3897. 2:29:22enough for a little quick corrective fix
  3898. 2:29:25and very quickly, the build passes. It
  3899. 2:29:27just swapped the text area for the
  3900. 2:29:29content editable div. So, now if we head
  3901. 2:29:32back right here and start typing, you
  3902. 2:29:34can see that it remains in the middle
  3903. 2:29:36and you can say start, here we can say
  3904. 2:29:40label and as soon as we start typing, it
  3905. 2:29:43basically centers itself right in the
  3906. 2:29:46middle.
  3907. 2:29:47Wonderful. So, now that we can actually
  3908. 2:29:49type within these inputs, what do you
  3909. 2:29:51say that we implement the functionality
  3910. 2:29:53to also be able to differentiate them by
  3911. 2:29:56color? So, create a new feature spec
  3912. 2:29:58called 15 nodes color toolbar.md
  3913. 2:30:03and here we want to add a floating color
  3914. 2:30:05toolbar that appears when a node is
  3915. 2:30:08selected. We then want to allow the user
  3916. 2:30:10to pick a color and both the node
  3917. 2:30:13background and text color will update
  3918. 2:30:15instantly synced across all
  3919. 2:30:17collaborators in real-time. So, it'll
  3920. 2:30:20check our UI context for the node color
  3921. 2:30:22palette, include a background color as
  3922. 2:30:25well as a matching text color so that
  3923. 2:30:27the contrast is nice
  3924. 2:30:28and we want to reuse existing colors if
  3925. 2:30:31they exist in globals, otherwise it can
  3926. 2:30:33keep the palette in the canvas types.
  3927. 2:30:35Then we want to add a toolbar
  3928. 2:30:38above the selected node that'll only
  3929. 2:30:40show when the node is selected.
  3930. 2:30:43And when a color is selected, we want to
  3931. 2:30:45update the node background color and
  3932. 2:30:47text color. I think this is pretty
  3933. 2:30:49understandable.
  3934. 2:30:51So, let's actually build it by telling
  3935. 2:30:53it our usual secret sentence which is
  3936. 2:30:56super simple, but again, the spec file
  3937. 2:30:58does the heavy lifting. This one for
  3938. 2:31:00some reason was super quick. It added
  3939. 2:31:03the text color, and the ability to
  3940. 2:31:05choose between a predefined set of
  3941. 2:31:07colors and also the color background.
  3942. 2:31:10So, if we head back over here and select
  3943. 2:31:12an element, would you look at that? I
  3944. 2:31:14mean, this is really starting to come
  3945. 2:31:15into life and I'm not sure how much time
  3946. 2:31:18this would take me to manually code it
  3947. 2:31:20out. But this way, we just have to think
  3948. 2:31:23of an idea, write a fairly simple yet
  3949. 2:31:26descriptive uh spec file, and then it
  3950. 2:31:29does it instantly. And
  3951. 2:31:32take a look.
  3952. 2:31:33You can actually select the colors of
  3953. 2:31:35each one of the nodes
  3954. 2:31:38separately.
  3955. 2:31:39So, if I make this one purple, the
  3956. 2:31:41database, for example, can be green.
  3957. 2:31:44Uh yep, for example, this one can be
  3958. 2:31:46MongoDB in its classic green color.
  3959. 2:31:49Then, we can have some kind of an
  3960. 2:31:50algorithm right here going on, which can
  3961. 2:31:53be orange. And yeah, it is all working
  3962. 2:31:56wonderfully. So, on top of the colors,
  3963. 2:31:59what else is there to implement?
  3964. 2:32:00Currently, there's these custom edges
  3965. 2:32:02from all four sides. But no matter which
  3966. 2:32:05you select, it's always going to start
  3967. 2:32:06making a connection from the bottom, as
  3968. 2:32:08you can see right here.
  3969. 2:32:09And it'll connect it to the bottom or
  3970. 2:32:11the top as well. So, we want to fix that
  3971. 2:32:13edge behavior.
  3972. 2:32:15So, I'll create a new spec just for
  3973. 2:32:17that, and you can see how I'm being very
  3974. 2:32:19specific with the specs, only focusing
  3975. 2:32:22on the smallest thing possible. So, 16
  3976. 2:32:26edge behavior
  3977. 2:32:28.md. And the goal of this spec is to
  3978. 2:32:31just replace the default canvas edges
  3979. 2:32:33with custom edges that feel easier to
  3980. 2:32:36follow, easier to click, and support
  3981. 2:32:39inline labels. So, we want to add
  3982. 2:32:41connection handles to every node at the
  3983. 2:32:43top, right, bottom, and left sides, and
  3984. 2:32:45user should be able to connect from any
  3985. 2:32:47handle to any other handle. Oh, and
  3986. 2:32:50another thing you can notice is that
  3987. 2:32:52we're opening up a new chat for every
  3988. 2:32:55single one of these specs. This helps us
  3989. 2:32:57with lowering the overall context window
  3990. 2:33:00and the amount of tokens that we're
  3991. 2:33:02spending for each transaction, and it
  3992. 2:33:04also makes the agent that much more
  3993. 2:33:06focused on the task at hand. And all
  3994. 2:33:09these little things together, like the
  3995. 2:33:11separate feature spec.md files instead
  3996. 2:33:13of just regular messages,
  3997. 2:33:15or the current issues file, where we can
  3998. 2:33:17specify what's wrong, and these six
  3999. 2:33:20files that altogether make the system
  4000. 2:33:22work, just makes it a breeze to work
  4001. 2:33:24with an AI, which is typically not the
  4002. 2:33:26case because it starts imagining things
  4003. 2:33:29and creating stuff that we don't want or
  4004. 2:33:30breaking other things. But this way, it
  4005. 2:33:33is super predictable. And if you take a
  4006. 2:33:35look at the progress tracker, which we
  4007. 2:33:38haven't looked at in a long time now,
  4008. 2:33:40you'll see that everything we've done so
  4009. 2:33:42far is written right here. But what I
  4010. 2:33:45care more about is that it even kept
  4011. 2:33:48some additional architectural decision
  4012. 2:33:50so that it knows what we're doing. And
  4013. 2:33:52the session notes for specifically what
  4014. 2:33:54it thought is very important. Like the
  4015. 2:33:56specific versions of different tools
  4016. 2:33:58that we're using, the fact that the
  4017. 2:33:59Prisma config uses Prisma forward slash
  4018. 2:34:02and not some other path, and that it
  4019. 2:34:04reads the database URL from the .env.
  4020. 2:34:07It kept everything it needs and
  4021. 2:34:09everything that future sessions with AI
  4022. 2:34:11or other developers continuing to
  4023. 2:34:13develop this project need to do it in a
  4024. 2:34:16sane and happy way. And another build
  4025. 2:34:19passes.
  4026. 2:34:20It implemented the canvas edge data
  4027. 2:34:22pieces, allowing us to connect the
  4028. 2:34:24source and the end.
  4029. 2:34:27So if you head back over here, you would
  4030. 2:34:29see that we have plenty of different
  4031. 2:34:30lines happening. But now, if you select
  4032. 2:34:32it from the left side, you can see how
  4033. 2:34:34it creates a bit of a different kind of
  4034. 2:34:36connection, and you can now connect it
  4035. 2:34:38to another element. This line looks a
  4036. 2:34:40bit different from other more
  4037. 2:34:42organic-looking lines. Oh, and right
  4038. 2:34:44now, we cannot even delete the elements.
  4039. 2:34:46So we have plenty of elements on the
  4040. 2:34:48screen.
  4041. 2:34:49But I'll create a new one right here and
  4042. 2:34:51another database on the right.
  4043. 2:34:54Drag [snorts] the canvas so we can see
  4044. 2:34:56them right here. Now the mini map starts
  4045. 2:34:58making a bit more sense, as you can see.
  4046. 2:35:00But if you try to connect it, you can
  4047. 2:35:02now do that in a bit of a more
  4048. 2:35:04consistent and better way.
  4049. 2:35:06Now that the canvas is looking so good,
  4050. 2:35:08I guess we can focus on little
  4051. 2:35:10quality-of-life fixes.
  4052. 2:35:12Like under feature specs, we're going to
  4053. 2:35:14do 17 canvas ergonomics.md.
  4054. 2:35:18And within it we can focus on adding a
  4055. 2:35:20little floating control bar for zooming
  4056. 2:35:23in and out and undoing or redoing and
  4057. 2:35:26then wiring those actions to keyboard as
  4058. 2:35:28well. So if you press plus or equal it's
  4059. 2:35:30going to zoom in minus to zoom out
  4060. 2:35:33command or control Z or Y to undo and
  4061. 2:35:36redo and I also don't like that mini map
  4062. 2:35:39at the bottom right. I don't think our
  4063. 2:35:41app will need it. So simply say remove
  4064. 2:35:44the mini map at the bottom right.
  4065. 2:35:47It's just a personal preference. But
  4066. 2:35:49yeah, this is that finishing layer that
  4067. 2:35:51makes the canvas feel like a tool that
  4068. 2:35:53somebody would actually use every day.
  4069. 2:35:54So let's implement this one as well and
  4070. 2:35:57very quickly feature 17 is done as well.
  4071. 2:36:00We now have a new pill shaped floating
  4072. 2:36:02bar at the bottom left for zooming in
  4073. 2:36:05and out or fitting within the view. So
  4074. 2:36:07if we collapse the sidebars, you'll be
  4075. 2:36:09able to see it right here at the bottom.
  4076. 2:36:11Ooh, it it actually looks very nice and
  4077. 2:36:14if I move some things around, you can
  4078. 2:36:16see that the left arrow or the undo
  4079. 2:36:19actually starts shining and you can undo
  4080. 2:36:22previous actions or redo them. You can
  4081. 2:36:25also use command or control Z or Y to
  4082. 2:36:28actually go back and forth, which is
  4083. 2:36:30absolutely amazing. There's this fit in
  4084. 2:36:32view, which is going to fit all the
  4085. 2:36:34elements within the view. So if you're
  4086. 2:36:36working on something that is a bit
  4087. 2:36:37closer together, it's going to actually
  4088. 2:36:39increase the view, which is always nice.
  4089. 2:36:41And you can zoom in or you can zoom out,
  4090. 2:36:43but that's hidden by the next JS logo,
  4091. 2:36:46but that's only in development.
  4092. 2:36:48So these little things really do make a
  4093. 2:36:50big difference. And finally, I had an
  4094. 2:36:52idea that isn't even necessary, but I
  4095. 2:36:55want to make it work.
  4096. 2:36:57So let's create a new feature spec 18
  4097. 2:37:00starter template.md.
  4098. 2:37:03The goal of this one is to create a
  4099. 2:37:05template library that lets users start
  4100. 2:37:08from a pre-built diagram instead of
  4101. 2:37:11blank canvases. So we can start with
  4102. 2:37:13some ideas, like let's say microservices
  4103. 2:37:17or a CICD pipeline or an event-driven
  4104. 2:37:19system. Each one will load directly into
  4105. 2:37:22the shared canvas. That's going to make
  4106. 2:37:24it easier for users to figure out how to
  4107. 2:37:26actually use the app and what are the
  4108. 2:37:28different use cases. Because maybe
  4109. 2:37:30somebody's not going to even get the
  4110. 2:37:31idea of what they can use this app for.
  4111. 2:37:34So, the templates should give them a
  4112. 2:37:35pretty good idea. This one took a bit
  4113. 2:37:37longer, but feature 18 is done. We now
  4114. 2:37:40have the starter templates file.
  4115. 2:37:43So, if you head over here and collapse
  4116. 2:37:46everything, maybe we should start with a
  4117. 2:37:48blank canvas, but we can keep doing it
  4118. 2:37:51within our mess right here. Uh at the
  4119. 2:37:53top right, there's the templates button.
  4120. 2:37:56And if you click it, you'll see a couple
  4121. 2:37:58of different starter templates, which
  4122. 2:38:00aren't looking that good right now. They
  4123. 2:38:02look a bit too vertical, but yeah, as
  4124. 2:38:05soon as you click import, it'll actually
  4125. 2:38:07import a lot of stuff pre-labeled. Uh
  4126. 2:38:10but it may be better to do that within a
  4127. 2:38:12new project, so we can see it a bit
  4128. 2:38:13better. So, I'll call it CICD
  4129. 2:38:16and create a new project.
  4130. 2:38:19And then we'll start from a template by
  4131. 2:38:21going with maybe the CICD pipeline or
  4132. 2:38:24let's go with microservices.
  4133. 2:38:27And you can take a look that that
  4134. 2:38:29immediately tells you a bit about how we
  4135. 2:38:31can start structuring the application
  4136. 2:38:33infrastructure. But yeah, this right now
  4137. 2:38:35is looking a bit too vertical. The
  4138. 2:38:38design is not actually being displayed.
  4139. 2:38:40So, we want to take this screenshot and
  4140. 2:38:42we want to feed it into the chat by
  4141. 2:38:44holding the shift key and then drag and
  4142. 2:38:46dropping. And then we want to compare
  4143. 2:38:47that with how it looks like on the
  4144. 2:38:49finished product.
  4145. 2:38:50Where we can clearly see the full
  4146. 2:38:53template before we drag and drop it. So,
  4147. 2:38:55I'll also put that here.
  4148. 2:38:57And I'll say
  4149. 2:38:59I'll pass in the screenshot of how the
  4150. 2:39:02templates look right now. They look a
  4151. 2:39:04bit too vertical and the actual elements
  4152. 2:39:07are not clearly visible. Whereas, on
  4153. 2:39:10another screenshot, which is the
  4154. 2:39:11finished product, you can see how each
  4155. 2:39:13card gets its own space, and they show
  4156. 2:39:16the entire diagram or the entire
  4157. 2:39:18template that's going to be entered in
  4158. 2:39:20once clicked. Make it look more similar
  4159. 2:39:22to that. So, once again, this is a
  4160. 2:39:24little corrective prompt with two
  4161. 2:39:26different screenshots, one before and
  4162. 2:39:28one after. Let's see how well it does.
  4163. 2:39:31So, currently, it looks like this. So,
  4164. 2:39:33I'm going to snap my fingers, and we
  4165. 2:39:35come down to something that looks like
  4166. 2:39:37this.
  4167. 2:39:38Definitely not good.
  4168. 2:39:40Even though now it's a bit better, as
  4169. 2:39:42it's showing the full template that's
  4170. 2:39:43going to be inserted in, but I'm not
  4171. 2:39:46quite sure why it cannot get the widths
  4172. 2:39:49right. So, we could be a bit more
  4173. 2:39:50specific and tell it to increase the
  4174. 2:39:52width of the whole import template card,
  4175. 2:39:54and then to increase the width of the
  4176. 2:39:56cards within it, so that they are the
  4177. 2:39:58same as this.
  4178. 2:40:00And that's what I'll tell it for the
  4179. 2:40:01second time
  4180. 2:40:03by saying, "Increase the width of the
  4181. 2:40:05entire import template overlay, and then
  4182. 2:40:08increase the width of the card within it
  4183. 2:40:10as well, so it looks the same as on the
  4184. 2:40:12final screenshot." And I'm purposefully
  4185. 2:40:15being not as descriptive right here as
  4186. 2:40:17we are within our spec files, because I
  4187. 2:40:19want to show you how
  4188. 2:40:21it can cost you a lot by not being
  4189. 2:40:23specific from the start. A lot of
  4190. 2:40:25back-and-forth messages, conversations,
  4191. 2:40:27and corrective fixes. And very soon, the
  4192. 2:40:30fix is in, and now it actually looks
  4193. 2:40:32amazing. It increased the width, and
  4194. 2:40:34it's much clearer what it's actually
  4195. 2:40:36going to insert in. So, that means that
  4196. 2:40:37we now also officially have the
  4197. 2:40:40templates. So, we implemented a lot of
  4198. 2:40:43stuff across these five separate feature
  4199. 2:40:45specs, 18 files changed in total, which
  4200. 2:40:48means a lot of stuff to review. This
  4201. 2:40:49actually deserves its own pull request.
  4202. 2:40:51So, let's go ahead and push the changes
  4203. 2:40:53either via terminal or via the source
  4204. 2:40:55control right here. It's going to
  4205. 2:40:57auto-craft a nice message, such as
  4206. 2:40:59improve node shape, added resizing and
  4207. 2:41:01inline labels, and adding color
  4208. 2:41:04toolbars.
  4209. 2:41:05Then, once you commit and sync, back on
  4210. 2:41:08GitHub, you'll see that the development
  4211. 2:41:09branch had recent pushes 7 seconds ago.
  4212. 2:41:13So, let's just open up a new pull
  4213. 2:41:15request, and let's wait Code Rabbit to
  4214. 2:41:17provide us with a review. I think this
  4215. 2:41:19walkthrough will be particularly useful,
  4216. 2:41:21as we've covered many different
  4217. 2:41:22features.
  4218. 2:41:24So, this PR implements a comprehensive
  4219. 2:41:26canvas editing feature set, including
  4220. 2:41:28custom edge rendering with inline
  4221. 2:41:30labels, node resizing with color
  4222. 2:41:33toolbars, keyboard shortcuts for zooming
  4223. 2:41:35and undoing and redoing, a canvas
  4224. 2:41:37control bar, and a starter template
  4225. 2:41:40system with a modal dialogue and
  4226. 2:41:42SVG-based previews. We've made changes
  4227. 2:41:45across 19 different files, and here is
  4228. 2:41:48the sequence diagram. The user clicks
  4229. 2:41:50the templates button. It opens the
  4230. 2:41:52editor navbar, and then we open up the
  4231. 2:41:54templates. We display the templates with
  4232. 2:41:57card previews. The user imports them,
  4233. 2:42:00and then once they do, we pass the
  4234. 2:42:02pending template prop. Then, we forward
  4235. 2:42:05that pending template to the canvas
  4236. 2:42:07editor. Live Blocks clears the existing
  4237. 2:42:09nodes or edges, adds the templates,
  4238. 2:42:12syncs this new graph to the canvas,
  4239. 2:42:14triggers the fit view automatically, and
  4240. 2:42:17then once it's imported, we bring it
  4241. 2:42:19back to the user.
  4242. 2:42:20This is a nice diagram on the starter
  4243. 2:42:22templates feature. This was a complex
  4244. 2:42:24PR, so I'm assuming there's going to be
  4245. 2:42:27a lot of different things we can fix.
  4246. 2:42:29The first one points out to exposing an
  4247. 2:42:31accessible name on these icon-only
  4248. 2:42:34buttons.
  4249. 2:42:35Because title is not a dependable
  4250. 2:42:37accessible label. It's telling us to add
  4251. 2:42:40the area label title for the zoom, fit,
  4252. 2:42:43undo, redo buttons for people who are
  4253. 2:42:46using some assistive technologies. So,
  4254. 2:42:47if I head back over here and hover over
  4255. 2:42:50them, it will tell me that this is an
  4256. 2:42:52undo. But, for people with screen
  4257. 2:42:54readers, this is not going to do it, and
  4258. 2:42:56they will have no idea what these
  4259. 2:42:58buttons are all about. I mean, it's rare
  4260. 2:43:01that these types of people would be
  4261. 2:43:02using this kind of an application
  4262. 2:43:04anyway, but it's always great to
  4263. 2:43:06implement anything you're doing with
  4264. 2:43:08best practices in mind. So, in this
  4265. 2:43:09case, CodeRabbit provided me with a
  4266. 2:43:11prompt for AI agents to use, so we can
  4267. 2:43:14add those area labels. After that,
  4268. 2:43:15there's a major potential issue on
  4269. 2:43:17avoiding double committing the edge
  4270. 2:43:20label on enter or escape. So, when
  4271. 2:43:22pressing enter or escape, it'll call the
  4272. 2:43:25commit edit immediately, then the
  4273. 2:43:27input's on blur handler will call it
  4274. 2:43:29again when the element loses focus. This
  4275. 2:43:31sends two mutations through live blocks,
  4276. 2:43:33creating duplicate undo retries for a
  4277. 2:43:36single edit. That's interesting. So, the
  4278. 2:43:38fix is simply to call the prevent
  4279. 2:43:40default and prevent blur instead of
  4280. 2:43:43commit edit. So, let's find that. I'll
  4281. 2:43:45find where this commit edit is getting
  4282. 2:43:47called.
  4283. 2:43:48It is right here in canvas edge
  4284. 2:43:50component. Specifically, we're looking
  4285. 2:43:52at it on the enter key or the escape
  4286. 2:43:55key. So, right here, and instead of
  4287. 2:43:58that, we want to apply those two lines,
  4288. 2:44:01prevent blur and
  4289. 2:44:03prevent default.
  4290. 2:44:05And we also want to remove the commit
  4291. 2:44:07edit from the dependency array. After
  4292. 2:44:09that, there's a minor issue to move ref
  4293. 2:44:12updates into a sync effect to comply
  4294. 2:44:14with React 19 ref values. So, basically,
  4295. 2:44:17it's telling us to put it within a use
  4296. 2:44:19effect. That's super simple. Let's just
  4297. 2:44:21find where in the code this is.
  4298. 2:44:23And after that, you can see that even
  4299. 2:44:25it's complaining right here about the
  4300. 2:44:26code, but we didn't take a look at it
  4301. 2:44:28because we weren't looking at the actual
  4302. 2:44:30code.
  4303. 2:44:31It's always good to use the best
  4304. 2:44:33practices. So, we just need a use effect
  4305. 2:44:36right here below that's going to put all
  4306. 2:44:38of these node refs into edges and nodes
  4307. 2:44:41like this.
  4308. 2:44:42And everybody's happy. After that, we're
  4309. 2:44:45missing the enter key for handling the
  4310. 2:44:46label commit. So, if it says save the
  4311. 2:44:49label on blur, enter, or escape, but on
  4312. 2:44:53handle key down, we only add escape. So,
  4313. 2:44:55right here, we also have to add the
  4314. 2:44:58enter key. I think we searched for this
  4315. 2:45:00across the code base just before. That
  4316. 2:45:02was right here in the canvas edge.
  4317. 2:45:05But, not this instance, the instance
  4318. 2:45:07where we just had the escape. So, I'll
  4319. 2:45:09search for escape.
  4320. 2:45:11And it's right here. We have to replace
  4321. 2:45:13it with if key is escape or if is key is
  4322. 2:45:16enter. And once again, for you, these
  4323. 2:45:19suggestions might be completely
  4324. 2:45:20different from mine. And that's normal
  4325. 2:45:22because agentic development is not
  4326. 2:45:24predictable. So, for me, it's adding
  4327. 2:45:26some accessibility names or guarding
  4328. 2:45:28some colors. For you, it's going to be
  4329. 2:45:30something else. But, I always love
  4330. 2:45:32learning about everything that Code
  4331. 2:45:34Rabbit throws at me because the next
  4332. 2:45:35time, I can immediately do it better. Or
  4333. 2:45:37in this case, we can make our feature
  4334. 2:45:39specs more specific so that our agents
  4335. 2:45:42don't make these mistakes in the first
  4336. 2:45:44place. Oh, and this one is interesting.
  4337. 2:45:46When trying to undo or redo, it's
  4338. 2:45:48currently looking only at a lower letter
  4339. 2:45:50Z, but in case somebody has caps lock
  4340. 2:45:52turned on, we also want it to take a
  4341. 2:45:54look at the upper case Z.
  4342. 2:45:56This is interesting. So, let's go ahead
  4343. 2:45:58and push those Code Rabbit suggested
  4344. 2:46:00fixes.
  4345. 2:46:02All of them were within the canvas.
  4346. 2:46:06And then, once they're up, we can simply
  4347. 2:46:09go ahead and merge this PR.
  4348. 2:46:12Amazing job on adding all of these
  4349. 2:46:14little improvements that make our canvas
  4350. 2:46:17that much more interactive.
  4351. 2:46:21In this chapter, we'll add the
  4352. 2:46:23collaborators avatar. So, when somebody
  4353. 2:46:25else is moving something on the screen,
  4354. 2:46:27you can see who is messing with you.
  4355. 2:46:29We'll also complete the chat sidebar UI
  4356. 2:46:32and implement a canvas auto save, which
  4357. 2:46:35will save our canvas data to a Vercel
  4358. 2:46:37blob. So, when you create something, you
  4359. 2:46:40don't lose it. And I'll break down all
  4360. 2:46:42of these within three separate feature
  4361. 2:46:45spec files. Each one is independent, but
  4362. 2:46:47together they complete the collaborative
  4363. 2:46:50experience before AI generation enters
  4364. 2:46:53the picture. So, back within our
  4365. 2:46:54application, create a new 19 presence
  4366. 2:46:59avatars cursors.md
  4367. 2:47:02chat. The goal of this spec is to
  4368. 2:47:04implement presence avatars and cursors.
  4369. 2:47:08Because right now, multiple users can
  4370. 2:47:10edit the same canvas, but they can't see
  4371. 2:47:13each other.
  4372. 2:47:14And after this, every connected
  4373. 2:47:16collaborator will appear as a live
  4374. 2:47:19cursor directly on the canvas with their
  4375. 2:47:22name and color. So, we want to render
  4376. 2:47:25those collaborator avatars and add those
  4377. 2:47:27cursors to the canvas. And also, on the
  4378. 2:47:30top right, we can show a stacked group
  4379. 2:47:33of avatars where we can see everyone in
  4380. 2:47:35the room at one place. So, you know the
  4381. 2:47:38drill. Let's get it implemented. And the
  4382. 2:47:40presence feature has now been
  4383. 2:47:42implemented. There's a new component
  4384. 2:47:44rendered inside of the canvas wrapper
  4385. 2:47:46called the presence cursor as well as
  4386. 2:47:49the collaborators avatars. So, if you
  4387. 2:47:51head back over to a specific project, we
  4388. 2:47:53can stay within the CICD, open up this
  4389. 2:47:56project within a second tab. And check
  4390. 2:47:58this out. Right here on top, you should
  4391. 2:48:00see that Adrian is also within this
  4392. 2:48:02canvas. But in this case, both of us are
  4393. 2:48:04Adrians. So, you can see another
  4394. 2:48:06person's cursor. And if I put these tabs
  4395. 2:48:09side by side, take a look at this.
  4396. 2:48:12Using LiveBlocks, while one user is
  4397. 2:48:15doing something, all the other users in
  4398. 2:48:17the room can see exactly what they're
  4399. 2:48:19doing. So, this is a great first step
  4400. 2:48:22toward interactivity, but we can do
  4401. 2:48:24more.
  4402. 2:48:25Head over and create a new feature spec,
  4403. 2:48:28or just get it from the zip, called 20
  4404. 2:48:30AI sidebar.md.
  4405. 2:48:34The goal of this one is to create a
  4406. 2:48:37sidebar placeholder that'll later on get
  4407. 2:48:39replaced with a proper UI.
  4408. 2:48:42Two tabs, the AI architect and the
  4409. 2:48:45specs. The AI architect tab will have a
  4410. 2:48:48scrollable chat area, starter prompt
  4411. 2:48:50chips, message bubbles, and a composer
  4412. 2:48:53input. While the specs tab will have a
  4413. 2:48:56generate button and a placeholder spec
  4414. 2:48:58card.
  4415. 2:49:00No back-end logic yet, just the UI that
  4416. 2:49:02everything else will connect to.
  4417. 2:49:04So, let's run it and let's see how it
  4418. 2:49:07does. And after a couple of minutes, it
  4419. 2:49:09is done. In this case, it touched only
  4420. 2:49:12the AI sidebar, which is a new
  4421. 2:49:14standalone component, as well as the
  4422. 2:49:16editor workspace client, where it
  4423. 2:49:18replaced the old aside with this new AI
  4424. 2:49:21sidebar. So, now we got a new sidebar
  4425. 2:49:24that looks something like this. You can
  4426. 2:49:26see it on the right side. There's the AI
  4427. 2:49:29architect, which soon enough will allow
  4428. 2:49:31you to design full workflows and systems
  4429. 2:49:34within the canvas, which looks like a
  4430. 2:49:36chat because you're speaking with an
  4431. 2:49:38agent. And then there's a specs tab,
  4432. 2:49:41which allows you to generate a specific
  4433. 2:49:43specification and then later on download
  4434. 2:49:45it. This is just the UI for now, but
  4435. 2:49:47soon enough this will become real. You
  4436. 2:49:49can also type multiple messages by
  4437. 2:49:51pressing shift and then enter, which is
  4438. 2:49:54useful for those longer prompt. Oh, and
  4439. 2:49:56before we run the next spec, which is
  4440. 2:49:58all about auto-saving what we're
  4441. 2:50:00currently working on,
  4442. 2:50:01we need to set up Vercel blob storage.
  4443. 2:50:04Vercel blob is basically an object
  4444. 2:50:06storage service. Think of it like a
  4445. 2:50:09cloud drive for your app. So, instead of
  4446. 2:50:11storing large files directly in your
  4447. 2:50:13database, you upload them to the blob
  4448. 2:50:16and store only the URL reference in
  4449. 2:50:18Prisma.
  4450. 2:50:19We're using it for two different things
  4451. 2:50:21in Ghost AI.
  4452. 2:50:22Canvas snapshots as saved JSON and
  4453. 2:50:25generated specs that will be available
  4454. 2:50:27for download later on through markdown.
  4455. 2:50:30It's completely free to get started
  4456. 2:50:32with. You can just head over to
  4457. 2:50:33vercel.com. Then on the left side, click
  4458. 2:50:36storage and create a new database.
  4459. 2:50:38Choose blob for store name, enter
  4460. 2:50:41something like ghost AI, and we'll set
  4461. 2:50:43it to private because private storage
  4462. 2:50:45means that your blob URLs require a
  4463. 2:50:48token to access.
  4464. 2:50:49Without this, anyone who gets a hold of
  4465. 2:50:52your blob URL can read the file
  4466. 2:50:53directly, which means the canvas data
  4467. 2:50:56and generated specs would be publicly
  4468. 2:50:58readable. But private storage keeps
  4469. 2:51:00everything scoped to your application
  4470. 2:51:02only.
  4471. 2:51:04So, create it. And once it is created,
  4472. 2:51:07click on it, and then right here you'll
  4473. 2:51:09be able to find your .env.local, where
  4474. 2:51:11you can just copy the snippet. Then
  4475. 2:51:13within your .env.local,
  4476. 2:51:15you can simply add this new .env, blob
  4477. 2:51:18read write token, and we are ready to
  4478. 2:51:21execute our next feature spec
  4479. 2:51:23by adding a file called
  4480. 2:51:2521_canvas_autosave.md.
  4481. 2:51:30Before we add that AI generation, canvas
  4482. 2:51:33state needs to persist.
  4483. 2:51:35So, after this, every change to the
  4484. 2:51:37canvas is automatically saved to Vercel
  4485. 2:51:39blob, which we just set up. And then
  4486. 2:51:41we'll save the blob URL, store it in
  4487. 2:51:43Prisma, and our canvas data will be
  4488. 2:51:46saved securely. So, this spec is all
  4489. 2:51:48about saving the current canvas state.
  4490. 2:51:51It should be pretty simple for our agent
  4491. 2:51:53to implement, given that we gave it all
  4492. 2:51:55the information about the Vercel blob
  4493. 2:51:57and about the environment variable that
  4494. 2:51:59it can use to save data. And after a
  4495. 2:52:01couple of minutes, it is done. A Vercel
  4496. 2:52:04blob is installed, and blob read write
  4497. 2:52:07token is already present in the
  4498. 2:52:09.env.local.
  4499. 2:52:10But if we get back to the editor, at
  4500. 2:52:12least on my end, there seems to be a
  4501. 2:52:14bug. So, let me show you how I would
  4502. 2:52:16approach fixing it. To fix this issue,
  4503. 2:52:19you can just copy it, head back over to
  4504. 2:52:21our application,
  4505. 2:52:23specifically into the current issues.md,
  4506. 2:52:27and specify that this is the current
  4507. 2:52:31error that I'm seeing on the screen. And
  4508. 2:52:35you can paste it right here. It's going
  4509. 2:52:36to give it all the necessary
  4510. 2:52:37information, and you can say
  4511. 2:52:40fix it.
  4512. 2:52:42So, make sure that it has access to the
  4513. 2:52:44current issues, and say
  4514. 2:52:46fix it. Or you could have just pasted
  4515. 2:52:48that into the chat itself.
  4516. 2:52:50For just a singular issue like this, it
  4517. 2:52:52should be totally okay. And as it's
  4518. 2:52:54working through it, I can already see
  4519. 2:52:55what was the issue. Even though we ran
  4520. 2:52:57MPX Prisma generate and migrate, the
  4521. 2:53:00generated client is correct, but there's
  4522. 2:53:03a stale .next cache bundling the old
  4523. 2:53:06schema. So, it's going to clear the old
  4524. 2:53:08cache and then delete it, which forces
  4525. 2:53:10Turbopack to recompile from a freshly
  4526. 2:53:13generated Prisma client, which already
  4527. 2:53:15has the canvas blob URL. Then, we just
  4528. 2:53:17have to restart our server, and the
  4529. 2:53:19error will be gone. So, open up your
  4530. 2:53:21terminal and just to rerun it by saying
  4531. 2:53:23npm run dev. And then back on
  4532. 2:53:25localhost:3000, if you reload, the error
  4533. 2:53:28will be gone. So, now we are ready to
  4534. 2:53:30test that final feature we implemented.
  4535. 2:53:33Head over to one of the active projects,
  4536. 2:53:35add a couple of nodes right here,
  4537. 2:53:37refresh the page, and make sure it
  4538. 2:53:39remains at the exact space where you
  4539. 2:53:40left it at.
  4540. 2:53:41So, I'll try to change its name and move
  4541. 2:53:44it below the auth service, and just make
  4542. 2:53:46sure that it actually remains there,
  4543. 2:53:47which would mean that the auto save is
  4544. 2:53:49working.
  4545. 2:53:51Perfect. But even though it saved it, it
  4546. 2:53:53wasn't saved through a blob, because if
  4547. 2:53:55you head over to the Ghost AI blob
  4548. 2:53:57storage, you'll see that there is
  4549. 2:53:59absolutely nothing there. So, let's fix
  4550. 2:54:01this issue and uh couple others.
  4551. 2:54:04I went through the application, tested
  4552. 2:54:06it deeply, and came up with a couple of
  4553. 2:54:08different issues that I added in the
  4554. 2:54:10current issues.md file. You should
  4555. 2:54:13already have a file like this in your
  4556. 2:54:15zip, which you can just refer to. But
  4557. 2:54:17again, it's possible that for you,
  4558. 2:54:19you'll have to go through the app
  4559. 2:54:20yourself, try to find some specific
  4560. 2:54:22issues within your app, and then write
  4561. 2:54:24the prompt to fix them.
  4562. 2:54:26But yeah, in this case, let's go over
  4563. 2:54:28the most important one, which is the
  4564. 2:54:30saving button in the workspace navbar.
  4565. 2:54:33Uh the workspace navbar is missing a
  4566. 2:54:35save button. The auto save hook exists,
  4567. 2:54:38but we need to wire the button to it. It
  4568. 2:54:41should default to save. While saving, it
  4569. 2:54:43should switch over to saving. After
  4570. 2:54:45successful save, it should switch over
  4571. 2:54:47to save. And that's it. The most
  4572. 2:54:50important thing that I noticed right
  4573. 2:54:51here is in this canvas route.ts
  4574. 2:54:55file. If you take a look at the blob
  4575. 2:54:58storage, the access is set to public.
  4576. 2:55:01And remember what I said before, it has
  4577. 2:55:03to be set to private because we don't
  4578. 2:55:05want other people to be able to view the
  4579. 2:55:07changes we make within the canvas. So,
  4580. 2:55:09we need to set it to private. And we're
  4581. 2:55:11not asking it to change anything else
  4582. 2:55:13for now. For now, I just want to focus
  4583. 2:55:15on issue one and then later on go
  4584. 2:55:17through all of the other issues. So,
  4585. 2:55:19yeah, let's ask it to fix the save
  4586. 2:55:21button first. I'll open up a new chat
  4587. 2:55:24and tell it to read the current issue.md
  4588. 2:55:27file, check the issue one and fix it.
  4589. 2:55:29After fixing it, mark it as pending to
  4590. 2:55:31test. Let's run it and see how well it
  4591. 2:55:34does. And very quickly, issue one is
  4592. 2:55:36fully implemented and marked as pending
  4593. 2:55:39for tests. So, let's go ahead and test
  4594. 2:55:41it out. You can see the save button
  4595. 2:55:43right here. And as you move something on
  4596. 2:55:45the screen and change its color and
  4597. 2:55:47click save, you can see that the saving
  4598. 2:55:50indicator is not really changing. So,
  4599. 2:55:52you can quickly head over to the code
  4600. 2:55:53base, see there's no errors in the
  4601. 2:55:55terminal, but it's still not doing its
  4602. 2:55:57thing. So, let's send it one quick
  4603. 2:55:59corrective prompt by telling it that
  4604. 2:56:02issue one still hasn't been fully fixed.
  4605. 2:56:05The saving status indicator is not being
  4606. 2:56:07changed, and when I click the save
  4607. 2:56:09button, nothing is changing either.
  4608. 2:56:11Analyze the issue further and fix it.
  4609. 2:56:14And we can send it out. And it was doing
  4610. 2:56:16a bit of thinking, but it came back with
  4611. 2:56:18the response that the root cause was
  4612. 2:56:20React strict mode, Enabled by default in
  4613. 2:56:23next js app router. It double invokes
  4614. 2:56:26effects in development. So on initial
  4615. 2:56:28mount, the cleanup is intentionally
  4616. 2:56:30fired by the strict mode before remount,
  4617. 2:56:33and then remount effect only registers
  4618. 2:56:35the cleanup again, but it never resets.
  4619. 2:56:38So that means that the is mounted is
  4620. 2:56:40permanently set to false in development.
  4621. 2:56:42So the save exited every time. This fix
  4622. 2:56:45removes the is mounted ref entirely. Uh
  4623. 2:56:48because react 18 made this guard
  4624. 2:56:50unnecessary. Perfect. So if we head back
  4625. 2:56:52right here and reload, and if you move
  4626. 2:56:55something around, and then press save at
  4627. 2:56:58the top right,
  4628. 2:57:00you can see that it says saving, and
  4629. 2:57:02then we get an error. Save failed.
  4630. 2:57:05If I move it again a couple of times and
  4631. 2:57:07click save again,
  4632. 2:57:08it says save failed.
  4633. 2:57:11It's funny because when I tested it
  4634. 2:57:12initially, it actually said saving and
  4635. 2:57:15then saved. So back in the blob storage,
  4636. 2:57:18you can see that I have this new canvas,
  4637. 2:57:20and it actually stored the JSON data.
  4638. 2:57:22But then when I tried doing it again, it
  4639. 2:57:25failed. So if you open up the terminal,
  4640. 2:57:27you'll see that we have an error with
  4641. 2:57:29the vercel blob saying that the blob
  4642. 2:57:31already exists, so we should add allow
  4643. 2:57:34override is set to true if we want to
  4644. 2:57:37override it. So what we can do is simply
  4645. 2:57:39find this file. That's the canvas root.
  4646. 2:57:42So you can go over to canvas root, and
  4647. 2:57:46just add an additional prop of allow
  4648. 2:57:49override is set to true. This single
  4649. 2:57:51line should immediately allow us to save
  4650. 2:57:55every other time,
  4651. 2:57:57not just the first time. You can see it
  4652. 2:58:00says saved, and back when I did the
  4653. 2:58:01blob, you can see that it got modified
  4654. 2:58:04less than a minute ago, which means that
  4655. 2:58:06it is consistently saving data. And
  4656. 2:58:08right now the size of this JSON file is
  4657. 2:58:116.11 kilobytes, but if we head back and
  4658. 2:58:13add a couple more labels and models and
  4659. 2:58:17shapes and some pieces of text within
  4660. 2:58:19them and then save again and then head
  4661. 2:58:22to the blob. You can see that now the
  4662. 2:58:24size increased, which means that it is
  4663. 2:58:26properly saving all the data. So, now
  4664. 2:58:29that our issue one has been fixed right
  4665. 2:58:31here,
  4666. 2:58:32uh we can ask it to continue fixing the
  4667. 2:58:34other issues.
  4668. 2:58:35Uh specifically, some issues that are
  4669. 2:58:37found are about deleting nodes and
  4670. 2:58:40edges. Uh so, right now we don't have a
  4671. 2:58:43way to delete anything. So, if I try
  4672. 2:58:46pressing backspace or the delete keys or
  4673. 2:58:48anything, I can't do it. So, the
  4674. 2:58:51solution is simple. We just need to add
  4675. 2:58:53a key down event listener to the canvas
  4676. 2:58:56that listens for the delete and
  4677. 2:58:57backspace keys, doesn't fire when the
  4678. 2:59:00event target is an input or text area,
  4679. 2:59:02but just gets fired when we're selecting
  4680. 2:59:05specific nodes, and then it deletes
  4681. 2:59:07them.
  4682. 2:59:08As the third issue, uh currently, we can
  4683. 2:59:10also just connect from top to the top of
  4684. 2:59:15the handle. You can see, even if I drag
  4685. 2:59:17from the right handle, it connects from
  4686. 2:59:19top to top. We want to be able to drag
  4687. 2:59:22and drop from any side of the element to
  4688. 2:59:25any other side. That will allow us to
  4689. 2:59:27make these graphics so much more
  4690. 2:59:29customizable.
  4691. 2:59:30So, we just want to allow it to be
  4692. 2:59:32connected from top, right, bottom, and
  4693. 2:59:35left.
  4694. 2:59:36Then, as the fourth issue, I noticed
  4695. 2:59:38that when I drag and drop specific
  4696. 2:59:40elements, they drop a bit lower than
  4697. 2:59:43where they're supposed to. So, I just
  4698. 2:59:45wanted to fix that offset.
  4699. 2:59:48And notice when I dragged and dropped
  4700. 2:59:50it, it actually said saving at the
  4701. 2:59:52bottom left right here and then saved,
  4702. 2:59:54which means that the auto save
  4703. 2:59:55functionality is working. And then, the
  4704. 2:59:58fifth issue is the auto zoom on first
  4705. 3:00:01node. We want to read the Liveblocks
  4706. 3:00:03agent skills before implementing it, and
  4707. 3:00:05then as soon as we drop it, we want to
  4708. 3:00:06zoom it in. And for six and seven, we
  4709. 3:00:09want to check the clerk skills, um and
  4710. 3:00:11we have some issues with the
  4711. 3:00:12collaborator avatar images. If the image
  4712. 3:00:15is coming from Clerk, we want to add it
  4713. 3:00:17to next config, so it gets properly
  4714. 3:00:19shown. And also, currently, we have two
  4715. 3:00:23different Clerk buttons. We just want to
  4716. 3:00:25keep the one and remove the other one.
  4717. 3:00:27So, let's ask it to fix the errors from
  4718. 3:00:30two all the way to seven. Okay, now that
  4719. 3:00:33the issue one in the current issues.md
  4720. 3:00:36file has been fixed, uh analyze and fix
  4721. 3:00:39issues from two to seven. Press enter.
  4722. 3:00:43And let's see how well it does. Okay, it
  4723. 3:00:45looks like all the remaining issues have
  4724. 3:00:48been implemented, and uh it marked them
  4725. 3:00:51for pending test, uh which is a good
  4726. 3:00:53thing for us to test right now. We have
  4727. 3:00:55to test deleting the nodes and edges,
  4728. 3:00:58um handling uh the positions or the
  4729. 3:01:01lines in between the elements, drop
  4730. 3:01:04position offset, auto zooming, and then
  4731. 3:01:06Clerk images.
  4732. 3:01:08So, if I head back right here and reload
  4733. 3:01:11the page, let's first test the drag and
  4734. 3:01:13drop. So, if I try to drag and drop it
  4735. 3:01:15here, you can see that it gets placed at
  4736. 3:01:17the exact position. This is pretty
  4737. 3:01:19crazy.
  4738. 3:01:21Take a look at once again. I'll try to
  4739. 3:01:22place it right here,
  4740. 3:01:24and it worked. Of course, it's going to
  4741. 3:01:26depend on the zoom position. I think if
  4742. 3:01:28we're at a normal regular zoom, and you
  4743. 3:01:30once again drag and drop it to a
  4744. 3:01:32specific position, that's exactly where
  4745. 3:01:34it places it. So, that has been fixed.
  4746. 3:01:37Also, now there's just one Clerk icon
  4747. 3:01:39right here, where you can see your
  4748. 3:01:40account.
  4749. 3:01:42Uh what else did we fix? The edges
  4750. 3:01:45connections. So, for example, let's try
  4751. 3:01:47to drag and drop the bottom of this edge
  4752. 3:01:49right here to the left side of the test
  4753. 3:01:52suite, and take a look at how well it
  4754. 3:01:55connects. It even places the arrow from
  4755. 3:01:57here to here. Or maybe when I go into
  4756. 3:01:59the package, that works as well, and the
  4757. 3:02:02arrows move. This makes our application
  4758. 3:02:04so much more usable, because now, for
  4759. 3:02:06example, we can connect the auth service
  4760. 3:02:09horizontally with the database
  4761. 3:02:12and then take the database output and do
  4762. 3:02:14something with it.
  4763. 3:02:16Again, this canvas is becoming a mess
  4764. 3:02:18right now because there's so much stuff
  4765. 3:02:20happening. So, it would make sense to
  4766. 3:02:22test out the delete. Select a couple of
  4767. 3:02:24elements and try to press the backspace
  4768. 3:02:27or the delete key and see whether it's
  4769. 3:02:30going to remove them. Because for me, it
  4770. 3:02:33doesn't. So, it looks like that's the
  4771. 3:02:35last issue that's still pending. So,
  4772. 3:02:37let's just tell it that issue two
  4773. 3:02:40remains unfixed. When I select an
  4774. 3:02:42element and press the backspace or the
  4775. 3:02:44delete key, the element is still there
  4776. 3:02:47and isn't being deleted from the canvas.
  4777. 3:02:49Analyze it and fix it. So, let's see if
  4778. 3:02:52we can just narrow it down to one issue,
  4779. 3:02:54whether it can finish that last one. And
  4780. 3:02:57again, this just shows you that whenever
  4781. 3:02:58you give it more stuff to fix,
  4782. 3:03:01it's easy for some of these to fall
  4783. 3:03:04through because it maybe didn't analyze
  4784. 3:03:06them as deeply in isolation.
  4785. 3:03:09So, you can see why these feature specs
  4786. 3:03:11worked so well so far because they were
  4787. 3:03:14super detailed and well-documented. But
  4788. 3:03:17as soon as you go deeper into the
  4789. 3:03:18conversation, the agent can easily get
  4790. 3:03:20lost.
  4791. 3:03:22So, this is its last chance. Let's see
  4792. 3:03:24how well it does.
  4793. 3:03:27It looks like it was able to find a root
  4794. 3:03:29cause in about 30 seconds. In apply no
  4795. 3:03:32changes inside of the live blocks react
  4796. 3:03:35flow source, we had a case of remove
  4797. 3:03:38which was not doing anything.
  4798. 3:03:40So, it was silently ignoring the remove
  4799. 3:03:43type changes, whereas live blocks
  4800. 3:03:46exposes a dedicated on delete function
  4801. 3:03:49that correctly deletes from the live
  4802. 3:03:51map. So, it fixed it and let's see how
  4803. 3:03:54well it does right now.
  4804. 3:03:55I'll reload the page and then I'll
  4805. 3:03:58select a couple of elements and press
  4806. 3:04:00the backspace key and now it deletes
  4807. 3:04:02them properly. Now, if you don't want to
  4808. 3:04:04delete them one by one, you can also
  4809. 3:04:06hold the shift key, and then drag and
  4810. 3:04:09drop over multiple, and remove them that
  4811. 3:04:11way.
  4812. 3:04:12Also, another thing that I didn't tell
  4813. 3:04:13you so far is that you can also add uh
  4814. 3:04:16text to the lines connecting different
  4815. 3:04:19elements. Like, we want to build and
  4816. 3:04:23then
  4817. 3:04:24run
  4818. 3:04:25the test suite. So, this way kind of it
  4819. 3:04:28makes more sense with the connection.
  4820. 3:04:30But, you can also use the text on the
  4821. 3:04:31lines for significantly more detailed
  4822. 3:04:34instructions when it comes to connecting
  4823. 3:04:36different elements. But, yeah, now that
  4824. 3:04:38all of these issues are fixed, we can go
  4825. 3:04:40ahead and push them. So, say get add
  4826. 3:04:43dot, get commit {dash} m, and this
  4827. 3:04:45lesson was all about canvas interaction.
  4828. 3:04:48So, say implement improved canvas
  4829. 3:04:51interaction.
  4830. 3:04:53And then run get push. Now, in the next
  4831. 3:04:55lesson, we'll focus on the AI
  4832. 3:04:58collaborative side of the application.
  4833. 3:05:02And now that we have the full canvas
  4834. 3:05:05right here, where we can drag and drop
  4835. 3:05:07elements, move things around, and create
  4836. 3:05:10our own architectural systems,
  4837. 3:05:13we're ready to help our users a bit by
  4838. 3:05:16implementing the AI workspace, where we
  4839. 3:05:19can allow our users to collaborate with
  4840. 3:05:22our AI agent within the application,
  4841. 3:05:25that I'll teach you how to implement
  4842. 3:05:26right now.
  4843. 3:05:28But, I want you to think about it a bit.
  4844. 3:05:30Like, before we start building the AI
  4845. 3:05:32generation features,
  4846. 3:05:34um you need to understand why these
  4847. 3:05:36can't run inside a normal API route.
  4848. 3:05:40See, when a user sends a prompt to Ghost
  4849. 3:05:42AI, something like this, to design an
  4850. 3:05:45e-commerce back end, the agent doesn't
  4851. 3:05:48just make one call. It analyzes the
  4852. 3:05:50request, runs multiple AI steps,
  4853. 3:05:53generates nodes and edges, and syncs
  4854. 3:05:56everything back to the canvas all
  4855. 3:05:58keeping the user updated. And that can
  4856. 3:06:00easily take 30 to 60 seconds, maybe even
  4857. 3:06:04a couple of minutes. And I mean, you've
  4858. 3:06:05already seen this pattern. When you
  4859. 3:06:07generate an image with ChatGPT or
  4860. 3:06:09Gemini, it doesn't happen instantly. The
  4861. 3:06:12work runs in the background, and you
  4862. 3:06:14keep receiving the updates until the
  4863. 3:06:16response is ready. And the API routes
  4864. 3:06:18within our application are not designed
  4865. 3:06:20for that. They have execution limits,
  4866. 3:06:23which means that long-running requests
  4867. 3:06:24can time out. And even if they didn't,
  4868. 3:06:27keeping a request open for that long
  4869. 3:06:29isn't how production systems are built.
  4870. 3:06:31That's what I'll teach you how to
  4871. 3:06:33implement Trigger.dev to solve this
  4872. 3:06:35problem.
  4873. 3:06:36In the final version of the application,
  4874. 3:06:38if you give it a detailed prompt and
  4875. 3:06:40send it, you'll be able to see direct
  4876. 3:06:43updates as it is working on the thing.
  4877. 3:06:46It'll first start with analyzing your
  4878. 3:06:48architecture request, and all of these
  4879. 3:06:51functions will run as durable background
  4880. 3:06:54tasks outside of the request life cycle,
  4881. 3:06:57which means that the work is running in
  4882. 3:06:59the background, and you'll be updated on
  4883. 3:07:02the process. So, the work of the API
  4884. 3:07:04route is to just trigger the task and
  4885. 3:07:06then return, while the heavy work
  4886. 3:07:08continues in the background. And that's
  4887. 3:07:10why both the AI design generation and
  4888. 3:07:13the spec generation in Ghost AI run
  4889. 3:07:16through Trigger.dev instead of directly
  4890. 3:07:18in API routes. And even before we used
  4891. 3:07:20Trigger on Ghost AI, I was already using
  4892. 3:07:24it within jsmastey.com platform, where
  4893. 3:07:27every time that users go through
  4894. 3:07:28different lessons, check out the
  4895. 3:07:30overviews, contents, or transcripts, we
  4896. 3:07:32can perform some actions on the back end
  4897. 3:07:35without slowing down or freezing what
  4898. 3:07:37the user can see on the front end, which
  4899. 3:07:39is super helpful for quizzes or sharing
  4900. 3:07:41the status of the AI interviewer that we
  4901. 3:07:44worked on. So, yeah, let me show you how
  4902. 3:07:46we can set up Trigger.dev in your
  4903. 3:07:48project.
  4904. 3:07:49First, click the link down in the
  4905. 3:07:51description to be able to follow along
  4906. 3:07:53and see exactly what I'm seeing.
  4907. 3:07:55And then create a new account. Once
  4908. 3:07:58you're in, you should be able to see
  4909. 3:07:59your dashboard that looks something like
  4910. 3:08:01this.
  4911. 3:08:02So, go ahead and create a new project.
  4912. 3:08:04I'll call it Ghost AI.
  4913. 3:08:08We are working on an AI agent, and under
  4914. 3:08:11technologies, I thought that Gemini
  4915. 3:08:13works the best. So, you can proceed with
  4916. 3:08:15Google Gemini. And what we're trying to
  4917. 3:08:17do with Trigger? Well, we're still
  4918. 3:08:19learning how Trigger works, as well as
  4919. 3:08:21potentially shipping a production
  4920. 3:08:23workflow. So, let's create it. Then,
  4921. 3:08:25once it is created, you can run this CLI
  4922. 3:08:28command to initialize it in the existing
  4923. 3:08:31project. So, just copy it.
  4924. 3:08:33Head back. Open up the terminal.
  4925. 3:08:36You can do it under a new tab.
  4926. 3:08:39And
  4927. 3:08:40just run NPX trigger.dev@latest
  4928. 3:08:43in it, and then pass your specific
  4929. 3:08:45project ID.
  4930. 3:08:46Say yes to install the Trigger.dev CLI.
  4931. 3:08:49And this will now install the
  4932. 3:08:51Trigger.dev SDK and initialize the
  4933. 3:08:54config file. But, it'll first ask you a
  4934. 3:08:56couple of questions, such as choose how
  4935. 3:08:59you want to initialize your project. In
  4936. 3:09:01this case, we'll proceed with the
  4937. 3:09:02Trigger.dev MCP, which allows you to
  4938. 3:09:05vibe your way to a new project. Well, in
  4939. 3:09:08this case, write detailed project
  4940. 3:09:10specifications to come up with a new
  4941. 3:09:12scalable project. It's going to ask you
  4942. 3:09:14whether you want to restrict the MCP
  4943. 3:09:16server to the dev environment only. I'll
  4944. 3:09:18say no.
  4945. 3:09:19And then, you'll be able to choose one
  4946. 3:09:21or more clients to install the MCP
  4947. 3:09:23server into. You can choose all the ones
  4948. 3:09:26that you're using, such as Claude Code,
  4949. 3:09:28VS Code, OpenAI Codex, or really
  4950. 3:09:31anything else that you want.
  4951. 3:09:33And then, press enter.
  4952. 3:09:35Where should the MCP server for Claude
  4953. 3:09:37Code be installed? I'll go over with the
  4954. 3:09:40project.
  4955. 3:09:41Same thing for all the other ones.
  4956. 3:09:45And that's it. We don't need to
  4957. 3:09:47our MCP clients. In your client, look
  4958. 3:09:50for a server named trigger, and then get
  4959. 3:09:52started with trigger dev by asking it to
  4960. 3:09:55add trigger to our project. So, let's do
  4961. 3:09:58just that. I'll open up our Claude code,
  4962. 3:10:01and that's going to be on a new chat
  4963. 3:10:03window, and I'll simply tell it to add
  4964. 3:10:05trigger dev to my project. And we can
  4965. 3:10:07now run it, but just before I do, I want
  4966. 3:10:10to share another thing with you, and
  4967. 3:10:11that is that trigger also supports agent
  4968. 3:10:15skills to teach any AI coding assistant
  4969. 3:10:17best practices for writing tasks,
  4970. 3:10:20agents, and workflows. So, we can
  4971. 3:10:22install it as we did for all the other
  4972. 3:10:24dev tools by opening up the terminal and
  4973. 3:10:27running MPX skills add trigger.dev
  4974. 3:10:31skills.
  4975. 3:10:32We can choose uh trigger agents, config,
  4976. 3:10:36and maybe setup. I think that's going to
  4977. 3:10:38be all we need for now, but you can just
  4978. 3:10:40go ahead and add all of them as well.
  4979. 3:10:43Choose your specific agents you want to
  4980. 3:10:45add it for.
  4981. 3:10:47Do it within the projects through
  4982. 3:10:49symlink, and then quickly install it.
  4983. 3:10:52Now, let's go ahead and ask it to add
  4984. 3:10:54trigger dev to my project. Then, let's
  4985. 3:10:57run it. It's going to explore the
  4986. 3:10:58project structure,
  4987. 3:11:00find all the relevant files, and the
  4988. 3:11:02architecture context, which matters a
  4989. 3:11:03lot, it's going to get the full picture,
  4990. 3:11:06and it'll start with configuring the
  4991. 3:11:08trigger config.ts,
  4992. 3:11:10creating a trigger directory with
  4993. 3:11:12example tasks, adding the trigger.dev
  4994. 3:11:15route handler, and finally updating the
  4995. 3:11:17progress tracker. And there we go, after
  4996. 3:11:19a couple of minutes, the trigger dev is
  4997. 3:11:21now set up. So, it first added the
  4998. 3:11:24trigger config.js.
  4999. 3:11:27So, let's quickly go over into it.
  5000. 3:11:30That's going to be within our
  5001. 3:11:33trigger.config.ts
  5002. 3:11:34in the root of the application,
  5003. 3:11:36and it looks something like this.
  5004. 3:11:39It is coming from trigger dev SDK.
  5005. 3:11:41We define a specific configuration, and
  5006. 3:11:44then we need to connect it to a project
  5007. 3:11:46reference.
  5008. 3:11:48This is coming from our environment
  5009. 3:11:49variables. So, very soon we'll have to
  5010. 3:11:51find it in our Trigger Dev dashboard,
  5011. 3:11:53and then add it to our .env's. Then,
  5012. 3:11:56below the project, we can add a runtime
  5013. 3:11:59and set the environment to node. When it
  5014. 3:12:02comes to directories, ./trigger is going
  5015. 3:12:05to be fine, or in this case, I think we
  5016. 3:12:07can just leave it to trigger. Now, max
  5017. 3:12:09duration stands for the max compute
  5018. 3:12:12seconds a task is allowed to run.
  5019. 3:12:15If the tasks exceed this duration, it'll
  5020. 3:12:17be stopped. And by default, we can set
  5021. 3:12:20it to something like 3600,
  5022. 3:12:23so that any task can run up to an hour
  5023. 3:12:25before it's stopped.
  5024. 3:12:27But again, that's not needed because
  5025. 3:12:28most of our AI tasks will be done in a
  5026. 3:12:30couple of minutes.
  5027. 3:12:32And then for the retries, if something
  5028. 3:12:34fails, Trigger Dev will retry it up to
  5029. 3:12:37three times with increasing delays
  5030. 3:12:39between each attempt. So, having that
  5031. 3:12:41built right in to make sure that if
  5032. 3:12:43something does go wrong, which it often
  5033. 3:12:44does with AI generation,
  5034. 3:12:47it retries it. So, when your user comes
  5035. 3:12:49back to your app, whatever they were
  5036. 3:12:50waiting for from an AI agent is waiting
  5037. 3:12:52for them there. Okay, so let's get those
  5038. 3:12:54keys.
  5039. 3:12:55I'll head back over to Trigger Dev,
  5040. 3:12:57specifically scroll down to API keys,
  5041. 3:13:01and right here you'll be able to find
  5042. 3:13:02your secret key. So, simply copy it.
  5043. 3:13:05Then, head over into your .env.local,
  5044. 3:13:09and here we can add, as it specifies,
  5045. 3:13:13the Trigger project ref,
  5046. 3:13:16as well as the Trigger secret key. So,
  5047. 3:13:19the secret key is the one we just
  5048. 3:13:20copied, and the project key you can find
  5049. 3:13:22right here by going over to the tasks
  5050. 3:13:25and copying it right here from the end
  5051. 3:13:28part of the CLI init command.
  5052. 3:13:31And then just paste it over here. And
  5053. 3:13:33the next part is to start your local dev
  5054. 3:13:36workflow. And I think this is the exact
  5055. 3:13:39second step from our 3-minute setup. NPX
  5056. 3:13:42trigger dev at latest dev. So, you can
  5057. 3:13:45open up your terminal, make sure that
  5058. 3:13:47it's not the one running your
  5059. 3:13:48application.
  5060. 3:13:49And before we run this, let me actually
  5061. 3:13:51explain what it does.
  5062. 3:13:53This is specific to local development.
  5063. 3:13:55Trigger dev background tasks don't run
  5064. 3:13:58on your machine automatically. They need
  5065. 3:14:00a local worker process running alongside
  5066. 3:14:03your Next.js dev server.
  5067. 3:14:05So, just to run this command, would you
  5068. 3:14:07like to install the Trigger dev code
  5069. 3:14:09agent rules? Well, yeah, go ahead.
  5070. 3:14:11We can select it for Claude code or
  5071. 3:14:14whichever other agent you're using.
  5072. 3:14:16And choose the rules you want to
  5073. 3:14:17install. Let's go with basic, advanced.
  5074. 3:14:21You know what? Let me go with all of
  5075. 3:14:22them.
  5076. 3:14:24Now, it's going to wait for you to log
  5077. 3:14:26in to your Trigger dev account, which
  5078. 3:14:28you can do by simply heading over to
  5079. 3:14:30this URL and then authenticating your
  5080. 3:14:32account. Once you're successfully
  5081. 3:14:34authenticated, you can head back and
  5082. 3:14:36you'll be able to see a screen that
  5083. 3:14:38looks something like this.
  5084. 3:14:40Logged in successfully, Trigger dev is
  5085. 3:14:42running, and the local worker is ready.
  5086. 3:14:46So, keep this running whenever you're
  5087. 3:14:47developing locally, because without it,
  5088. 3:14:49any task you trigger will queue, but
  5089. 3:14:52never execute.
  5090. 3:14:53And in production on Vercel, this isn't
  5091. 3:14:55needed because Trigger dev will handle
  5092. 3:14:58the worker infrastructure for you. So,
  5093. 3:15:00if you now head back over to your
  5094. 3:15:01dashboard, you'll be able to see two
  5095. 3:15:03different tasks generate design and
  5096. 3:15:05generate spec, which is absolutely
  5097. 3:15:07amazing. This was going to be one of my
  5098. 3:15:10upcoming project specifications to add,
  5099. 3:15:12but it looks like the MCP already
  5100. 3:15:14figured out exactly what we want, and it
  5101. 3:15:17created those tasks right here. So, soon
  5102. 3:15:19enough, you'll be able to see how those
  5103. 3:15:21tasks actually run and then see more
  5104. 3:15:24information about it. So, that was it
  5105. 3:15:26for the setup. And then in the next
  5106. 3:15:28lesson, let's build the AI generation
  5107. 3:15:30logic.
  5108. 3:15:33Okay, Trigger.dev and the agent together
  5109. 3:15:36already created for us the task
  5110. 3:15:38skeletons. But in this lesson, we'll
  5111. 3:15:41build the full AI generation flow. Now,
  5112. 3:15:44before we make our system design agent
  5113. 3:15:46logic, we'll have to install a couple
  5114. 3:15:48more packages. So, open up your
  5115. 3:15:50terminal. We'll have to go with the
  5116. 3:15:52third one right here.
  5117. 3:15:54And run npm install
  5118. 3:15:56@trigger.dev/react-hooks,
  5119. 3:16:00which lets the front-end subscribe to a
  5120. 3:16:02live Trigger.dev background run without
  5121. 3:16:05manually polling. So, think of it like
  5122. 3:16:07instead of asking is the job done yet
  5123. 3:16:10every few seconds, the hook will stream
  5124. 3:16:12in real-time status updates directly to
  5125. 3:16:15the UI as the task progresses.
  5126. 3:16:18Then, there's the @ai-sdk/google,
  5127. 3:16:21which is the Google provider for the
  5128. 3:16:22Vercel AI SDK. And in this case, we'll
  5129. 3:16:25be using Gemini for both design
  5130. 3:16:27generation and spec generation. But of
  5131. 3:16:29course, feel free to use any other agent
  5132. 3:16:31you prefer. And finally, AI is the core
  5133. 3:16:34Vercel AI SDK, which is going to give us
  5134. 3:16:37utilities for generating text or
  5135. 3:16:39generating different objects by working
  5136. 3:16:41consistently with any kind of AI
  5137. 3:16:43provider. So, go ahead and install these
  5138. 3:16:46three. And while they're getting
  5139. 3:16:47installed, head over to AI
  5140. 3:16:49Studio.google.com,
  5141. 3:16:51which we're going to connect with
  5142. 3:16:53Trigger.dev to infuse it with all sorts
  5143. 3:16:55of different functionalities. So, click
  5144. 3:16:57get started. Make sure to authenticate
  5145. 3:16:59with your account.
  5146. 3:17:01And Google AI Studio will give you free
  5147. 3:17:03credits in most regions, which is going
  5148. 3:17:05to be enough to test out the generation
  5149. 3:17:07flow throughout this build.
  5150. 3:17:09So, click get API key, then create a new
  5151. 3:17:13API key. You can call it something like
  5152. 3:17:15Ghost AI.
  5153. 3:17:18And then, you'll be given all your API
  5154. 3:17:20key details. So, first, copy the actual
  5155. 3:17:22API key
  5156. 3:17:24and paste it into your .env.local.
  5157. 3:17:28Specifically, that's going to be under
  5158. 3:17:31google_ai_api_key,
  5159. 3:17:35and it's going to be set to this key you
  5160. 3:17:37just copied. Or, if you want to get a
  5161. 3:17:40completely free alternative to Google
  5162. 3:17:43Gemini, OpenRouter has a pretty good
  5163. 3:17:45selection of free models. I recommend
  5164. 3:17:47this Nvidia Neumotron 3 Nano Omni.
  5165. 3:17:51That's a mouthful. Which is a free model
  5166. 3:17:54that has a 256,000 context window, and
  5167. 3:17:58it handles the architecture generation
  5168. 3:18:00pretty well. Just keep in mind that the
  5169. 3:18:01free tier models always have usage
  5170. 3:18:03limits. So, if you go that route, simply
  5171. 3:18:06swap that AI SDK Google thing for the
  5172. 3:18:09OpenRouter SDK in the generation task.
  5173. 3:18:12For this video, I'll personally use
  5174. 3:18:13Google AI Studio, but again, as with the
  5175. 3:18:16AI agents, follow along with whichever
  5176. 3:18:18one works for you. So, now with the
  5177. 3:18:20setup ready, we are ready to start
  5178. 3:18:22adding the Trigger.dev task spec files.
  5179. 3:18:26So, head over into our context feature
  5180. 3:18:29specs,
  5181. 3:18:30and find or create a new one called
  5182. 3:18:3322_design_agent_api.md.
  5183. 3:18:38The goal of this feature is to set up
  5184. 3:18:40the back-end flow for design generation
  5185. 3:18:43using Trigger.dev.
  5186. 3:18:44And keep in mind that when we're
  5187. 3:18:45referring to design here, we're
  5188. 3:18:47referring to the systems or architecture
  5189. 3:18:49design of our applications. So, we're
  5190. 3:18:52setting up this design agent API for the
  5191. 3:18:54back-end wiring. Starting with the
  5192. 3:18:57trigger route, where we need to create a
  5193. 3:18:59specific post route that should accept
  5194. 3:19:01the design prompt and some context, and
  5195. 3:19:04then trigger the design task through
  5196. 3:19:06Trigger.dev. Because, as I said, these
  5197. 3:19:09tasks and these AI prompts can take some
  5198. 3:19:11time to process. Then, we'll add task
  5199. 3:19:14tracking. This is going to be a special
  5200. 3:19:16model in Prisma to track Trigger.dev
  5201. 3:19:19runs and verify ownership.
  5202. 3:19:21Who created the run, when, and what is
  5203. 3:19:24it all about?
  5204. 3:19:25We should add the token route to verify
  5205. 3:19:27ownership, and then finally create the
  5206. 3:19:30actual design task. We want to check the
  5207. 3:19:33existing Trigger.dev setup and installed
  5208. 3:19:35agent features, reuse the existing
  5209. 3:19:37setup, export a minimal design task, and
  5210. 3:19:40for now not add any design logic yet.
  5211. 3:19:44Just the infrastructure that makes the
  5212. 3:19:45next spec possible.
  5213. 3:19:47You learned that already. Spec by spec,
  5214. 3:19:50we're getting closer to the final
  5215. 3:19:51solution.
  5216. 3:19:53So, let's go ahead and run it. As usual,
  5217. 3:19:56you can just tell it to read the current
  5218. 3:19:58file, update the context progress
  5219. 3:20:00tracker, and implement it exactly as
  5220. 3:20:03specified. And after some work, feature
  5221. 3:20:0622, the design agent API, has now been
  5222. 3:20:09completed. It created a new Prisma model
  5223. 3:20:13called task run with run ID, project ID,
  5224. 3:20:16user ID, so we know which projects are
  5225. 3:20:18being run over on Trigger.dev. Then,
  5226. 3:20:20there's the design agent itself, which
  5227. 3:20:23is a minimal task accepting a prompt and
  5228. 3:20:25a room ID, which logs and echoes the
  5229. 3:20:28inputs.
  5230. 3:20:29So, if you open it up, you'll see that
  5231. 3:20:31it looks like this. Currently, there's
  5232. 3:20:34no logic and functionality, but we'll
  5233. 3:20:36add it very soon.
  5234. 3:20:38Then, there's the post API AI design,
  5235. 3:20:41which requires authentication. And what
  5236. 3:20:43this one does is it basically figures
  5237. 3:20:45out whether the user is authenticated,
  5238. 3:20:47takes in the body, and finally creates a
  5239. 3:20:50new task run in the database.
  5240. 3:20:53But of course, before it hands it over
  5241. 3:20:55to Trigger.dev. But now, the actual task
  5242. 3:20:58is pretty empty. It's just console
  5243. 3:21:00logging design agent triggered, and it's
  5244. 3:21:02not doing anything else.
  5245. 3:21:04So, our next task is to implement the
  5246. 3:21:07full AI design agent logic, so a user
  5247. 3:21:10prompt results in real-time updates on
  5248. 3:21:13the canvas. To do that, head over into
  5249. 3:21:15our feature specs, and let's focus on
  5250. 3:21:18adding the 23rd spec, which is design
  5251. 3:21:21agent
  5252. 3:21:23logic.md.
  5253. 3:21:25And as I said, the goal here is to
  5254. 3:21:27implement the full AI design agent
  5255. 3:21:29logic.
  5256. 3:21:31So, first we need to update the file
  5257. 3:21:32which was just created.
  5258. 3:21:34Before, when I check the product
  5259. 3:21:36behavior of the system, check the live
  5260. 3:21:38blocks and trigger agent skills. This is
  5261. 3:21:40very important. Sometimes you have to
  5262. 3:21:41explicitly tell it to check the skills.
  5263. 3:21:44Follow the trigger dev setup and agent
  5264. 3:21:46patterns already set up. Reuse the
  5265. 3:21:48existing live blocks flow and presence
  5266. 3:21:50patterns instead of creating new ones,
  5267. 3:21:52and then implement use Gemini logic to
  5268. 3:21:56interpret the user prompt, update the
  5269. 3:21:59canvas using the collaborative flow
  5270. 3:22:01utilities, supporting actions like
  5271. 3:22:03adding nodes, moving them, resizing
  5272. 3:22:05them, updating them, deleting them.
  5273. 3:22:07Basically, everything that our
  5274. 3:22:09application is already doing.
  5275. 3:22:11Then, want to publish that AI activity
  5276. 3:22:13to the shared status feed, so all users
  5277. 3:22:15can see the progress.
  5278. 3:22:17Update the AI presence through cursors
  5279. 3:22:19and thinking state, and push clear
  5280. 3:22:21status messages at key steps. If you
  5281. 3:22:24think about it, this is a very important
  5282. 3:22:28and big feature spec. Maybe the biggest
  5283. 3:22:31one in our application so far, because
  5284. 3:22:33now we're essentially telling our AI
  5285. 3:22:35agent and trigger
  5286. 3:22:37to figure out the entirety of our
  5287. 3:22:40application
  5288. 3:22:42and to replicate its functionality on
  5289. 3:22:44its own while following the user prompt.
  5290. 3:22:47Like, the user is telling it to create
  5291. 3:22:50something on the canvas, and it should
  5292. 3:22:52create it.
  5293. 3:22:53So, let's go ahead and see how well it
  5294. 3:22:55does by opening up a new Claude code
  5295. 3:22:57window, giving it access to the file,
  5296. 3:22:59and asking it to read the spec file,
  5297. 3:23:04update the progress document, and
  5298. 3:23:07implement it exactly as specified. This
  5299. 3:23:09is a big one, so I'm super excited to
  5300. 3:23:12see how well it actually does it. And
  5301. 3:23:14feature 23 is now complete. This one
  5302. 3:23:17took a bit longer because it's a it's a
  5303. 3:23:19huge one. And we now have a full AI
  5304. 3:23:23agent built within our application
  5305. 3:23:25powered by trigger.dev.
  5306. 3:23:27It uses Gemini 2.0 flash via create
  5307. 3:23:31Google generative AI plus generate text
  5308. 3:23:34with output object to produce a typed
  5309. 3:23:37list of canvas actions for adding,
  5310. 3:23:40moving, resizing, updating, and deleting
  5311. 3:23:42nodes and edges. It sets the AI presence
  5312. 3:23:46by thinking is set to true. So, all
  5313. 3:23:48collaborators can see the AI cursor. It
  5314. 3:23:51broadcasts three different statuses:
  5315. 3:23:53start, thinking, and complete. And it
  5316. 3:23:56applies all mutations atomically in a
  5317. 3:23:59single mutate storage call.
  5318. 3:24:01Perfect. This is exactly what we wanted.
  5319. 3:24:03So, while we can't see it on the screen
  5320. 3:24:06just yet,
  5321. 3:24:07what we can do is head over to our
  5322. 3:24:09trigger.dev dashboard under tasks.
  5323. 3:24:12Currently, we have three separate tasks.
  5324. 3:24:14That's because our initial setup task
  5325. 3:24:17created the skeletons for generate
  5326. 3:24:19design and generate spec, but the new
  5327. 3:24:21one is right here under design agent.
  5328. 3:24:23So, what we can do is maybe we can clean
  5329. 3:24:26up the other two just so they're not
  5330. 3:24:28confusing us. So, under trigger, we can
  5331. 3:24:30remove the generate design and generate
  5332. 3:24:32spec, which are just empty placeholders.
  5333. 3:24:36And instead, we can just leave the
  5334. 3:24:37design agent right here. So, that's the
  5335. 3:24:39only one that remains.
  5336. 3:24:41Now, open it up
  5337. 3:24:43and perform a test run.
  5338. 3:24:46It's going to ask you to pass the data
  5339. 3:24:48as a regular user would through the
  5340. 3:24:49application.
  5341. 3:24:50And we can write something like room ID,
  5342. 3:24:53and you'll have to get this room ID
  5343. 3:24:55directly from one of your canvases.
  5344. 3:24:57So, head over here and create a new
  5345. 3:24:59project. Let's call it something like um
  5346. 3:25:03system design.
  5347. 3:25:06Created. And you can copy the project ID
  5348. 3:25:08directly from the URL right here at the
  5349. 3:25:11top.
  5350. 3:25:13Then, if you head back, you can update
  5351. 3:25:15it over here. And we can ask it to
  5352. 3:25:17architect a real-time chat application.
  5353. 3:25:20I need a web socket server for live
  5354. 3:25:23messaging, a presence service to track
  5355. 3:25:25online users, and a relational database
  5356. 3:25:27for message history. Connect the
  5357. 3:25:29services using a pub sub system like
  5358. 3:25:31Redis, so it can scale horizontally, and
  5359. 3:25:33include an S3 bucket for media
  5360. 3:25:36attachments.
  5361. 3:25:37I'll give you a prompt like this in the
  5362. 3:25:39video kit link down in the description,
  5363. 3:25:41so you can copy it and paste it.
  5364. 3:25:43But make sure to update the room ID. And
  5365. 3:25:46now, let's go ahead and run the test.
  5366. 3:25:48Oh, but before, make sure that your dev
  5367. 3:25:51server is connected right here. If it's
  5368. 3:25:53not, connect it, and then we'll be able
  5369. 3:25:55to run the test.
  5370. 3:25:57As you run it, you'll be able to see all
  5371. 3:26:00the information about this specific task
  5372. 3:26:02run. When it was triggered, when it was
  5373. 3:26:05queued, and when it has started. Now,
  5374. 3:26:07immediately, it'll fail after three
  5375. 3:26:10attempts, saying that we exceeded our
  5376. 3:26:12current quota, and we need to check our
  5377. 3:26:14Google billing plan. So, it's super
  5378. 3:26:16convenient to be able to test the runs
  5379. 3:26:18directly within the Trigger dashboard.
  5380. 3:26:20So, once you top it up or change your
  5381. 3:26:22providers, uh you can just reload your
  5382. 3:26:24Trigger dev server, and then replay the
  5383. 3:26:26run.
  5384. 3:26:28Hopefully, this time, it continues
  5385. 3:26:30running after just a couple of seconds.
  5386. 3:26:32And we get another little API error,
  5387. 3:26:35saying that models Gemini 2.0 Flash is
  5388. 3:26:37no longer available.
  5389. 3:26:39Um I wish they made those backwards
  5390. 3:26:41compatible, but it is what it is. We got
  5391. 3:26:44to find one that actually is compatible.
  5392. 3:26:46So, instead of using 2.0 Flash, I'll
  5393. 3:26:49head over into this design agent file,
  5394. 3:26:52that's going to be right here,
  5395. 3:26:54and I'll switch it over to 2.5
  5396. 3:26:58Flash. I believe that is the latest
  5397. 3:27:00running model. Then, when you change it,
  5398. 3:27:03don't forget to rerun your server.
  5399. 3:27:06Again, the Trigger.dev server by running
  5400. 3:27:08MPX Trigger.dev at latest dev. Then,
  5401. 3:27:11after it creates the local worker, go
  5402. 3:27:13ahead and replay the run. Third times
  5403. 3:27:15the charm. Or, apparently not, because
  5404. 3:27:18after about 20 seconds, we got a little
  5405. 3:27:20error saying, "No object generated.
  5406. 3:27:23Response did not match the schema."
  5407. 3:27:27So, open up a new chat, and let's tell
  5408. 3:27:30it something like this.
  5409. 3:27:32While implementing
  5410. 3:27:35at 23, that's going to be the 23rd
  5411. 3:27:39design spec
  5412. 3:27:41that we tried to do, the agent logic. Or
  5413. 3:27:44rather, we can say after implementing, I
  5414. 3:27:46tried to run a test. And then, I give it
  5415. 3:27:49some more information that we used for
  5416. 3:27:51the test itself, and then pasted the
  5417. 3:27:53error that we got, which you can get
  5418. 3:27:54from the web.
  5419. 3:27:56Finally, we can tell it something like
  5420. 3:27:57analyze trigger.dev and Liveblocks best
  5421. 3:28:00practices. Analyze this doc, and I
  5422. 3:28:03shared it a link to the doc of the
  5423. 3:28:06generating structured data part, because
  5424. 3:28:08so far, it generated it just as text.
  5425. 3:28:11But, what we need to do instead is have
  5426. 3:28:14some kind of a schema that we can
  5427. 3:28:16validate against. So, currently, it is
  5428. 3:28:18using this output, but what we can do is
  5429. 3:28:21use a so-called tool calling approach
  5430. 3:28:24with generate text with a tools object.
  5431. 3:28:28So, I'll tell it analyze this docs page
  5432. 3:28:31and the error, and then, I'll pass some
  5433. 3:28:33additional info which I think is the
  5434. 3:28:35reason for why it's failing.
  5435. 3:28:37So, that design agent is failing because
  5436. 3:28:39generate text is being used with output
  5437. 3:28:42object for structured output. That
  5438. 3:28:45experimental API is causing the runtime
  5439. 3:28:47error.
  5440. 3:28:48So, instead, replace it with a tool
  5441. 3:28:50calling approach using generate text
  5442. 3:28:52with a tools object. Each canvas action
  5443. 3:28:55should be its own tool. So, we have the
  5444. 3:28:57add node, move node, and so on. And this
  5445. 3:29:00way it's going to follow the schema
  5446. 3:29:02precisely. So, have a message that looks
  5447. 3:29:04like this and send it out.
  5448. 3:29:08This is also a useful approach to share
  5449. 3:29:10it a link to a specific documentation
  5450. 3:29:13page so that it can do a web fetch and
  5451. 3:29:16figure out how it works. Or
  5452. 3:29:17alternatively, there's also this context
  5453. 3:29:20seven, which is a library of the latest
  5454. 3:29:22documentations that you can directly
  5455. 3:29:24fuse with cursor, Claude, or other LLMs.
  5456. 3:29:28For example, it has the latest docs for
  5457. 3:29:29Next.js updated 9 hours ago. Same thing
  5458. 3:29:32for React and most likely for AI agents
  5459. 3:29:36as well. There we go. AI SDK. This is
  5460. 3:29:39what we're using. So, if we hook this up
  5461. 3:29:41with our agent, and you can do that very
  5462. 3:29:43easily just by copy and pasting this
  5463. 3:29:45thing right here, it would have all the
  5464. 3:29:47latest docs. But let's see what it can
  5465. 3:29:49do with just the URL. And very quickly,
  5466. 3:29:51the build passes. Here's what changed.
  5467. 3:29:54The output object in generate text
  5468. 3:29:56relies on the model emitting a single
  5469. 3:29:59structured JSON blob. But Gemini 2.5
  5470. 3:30:02Flash returned a response that didn't
  5471. 3:30:04match the schema, triggering the AI no
  5472. 3:30:06object generated. So, in this case,
  5473. 3:30:08we're replacing the output with a tool
  5474. 3:30:11approach where each canvas action is its
  5475. 3:30:13own named tool, like add node, move
  5476. 3:30:16node, and so on. So, after generation,
  5477. 3:30:18all tool calls are collected and then we
  5478. 3:30:20get the final canvas.
  5479. 3:30:22Okay, so let's go ahead and test it out.
  5480. 3:30:25Back on Trigger.dev, we can just replay
  5481. 3:30:27the run. And in about 15 seconds, it
  5482. 3:30:30finished. We got a successful output
  5483. 3:30:32with 11 actions applied and a summary of
  5484. 3:30:36what happened. Now, let's make it even
  5485. 3:30:38better by adding another feature spec
  5486. 3:30:42right here. That's going to be 24 AI
  5487. 3:30:45presence state.md.
  5488. 3:30:48And the goal of this one is to add a
  5489. 3:30:51shared activity indicator so that when
  5490. 3:30:54AI is generating, everyone in the room
  5491. 3:30:56will see it. A status indicator in the
  5492. 3:30:59sidebar, as well as a thinking spinner
  5493. 3:31:02cursor, and the input will be disabled
  5494. 3:31:04while generation is active. So, let's go
  5495. 3:31:06ahead and run it with the usual message.
  5496. 3:31:11And let's give it a minute. And I sped
  5497. 3:31:13up the process for you, but this one
  5498. 3:31:15definitely took some time, but
  5499. 3:31:17thankfully the build passes cleanly.
  5500. 3:31:20We added some new types for the
  5501. 3:31:23tasks.ts,
  5502. 3:31:24modified the liveblocks.config, and
  5503. 3:31:27added the presence cursors. But before
  5504. 3:31:29we actually go ahead and test this out,
  5505. 3:31:31I want to finish the implementation of
  5506. 3:31:33the sidebar so we can test everything
  5507. 3:31:35we've been working on together.
  5508. 3:31:37So, go ahead and open up a 25 sidebar
  5509. 3:31:42chat feed.md
  5510. 3:31:44file.
  5511. 3:31:45And within this one, the goal is to wire
  5512. 3:31:49up the AI chat liveblocks feed into the
  5513. 3:31:52sidebar.
  5514. 3:31:53See, liveblocks feeds are real-time
  5515. 3:31:56message channels. Think of them like a
  5516. 3:31:59group chat that is tied to a specific
  5517. 3:32:01project room. Anyone in that room can
  5518. 3:32:04send a message, and everyone else can
  5519. 3:32:06instantly see it. In this case, we're
  5520. 3:32:08using two separate feeds, the AI chat
  5521. 3:32:11feed and the AI status feed. The AI
  5522. 3:32:14status feed is simply for some kind of
  5523. 3:32:17progress signals, and AI chat is for the
  5524. 3:32:20actual conversation. This spec handles
  5525. 3:32:22the chat side where users can send
  5526. 3:32:25messages and make them appear across
  5527. 3:32:27every connected client. So, let's go
  5528. 3:32:29ahead and run it, and I'll speed it up
  5529. 3:32:32for you. And feature 25 is done. Here's
  5530. 3:32:35what was changed across three files.
  5531. 3:32:37First, added some additional types.
  5532. 3:32:40Then, in the config, we extended the
  5533. 3:32:42feed message data with optional chat
  5534. 3:32:45fields. So, now it also supports the
  5535. 3:32:47sender, role, content, and timestamp
  5536. 3:32:50alongside the existing AI status fields,
  5537. 3:32:53so they both coexist under the same
  5538. 3:32:55type. The key addition right here was
  5539. 3:32:57the chat feed ID constant. So, now we
  5540. 3:33:01support the chat alongside these status
  5541. 3:33:03updates as well. And finally, just one
  5542. 3:33:06more thing before we test it, we have to
  5543. 3:33:09wire everything together. So far, this
  5544. 3:33:11is just the UI. In the last couple of
  5545. 3:33:13prompts, we implemented the UI side of
  5546. 3:33:15things and Liveblocks side of
  5547. 3:33:17functionality. Just before that, we
  5548. 3:33:19implemented background tasks through
  5549. 3:33:22trigger.dev, but now we have to wire it
  5550. 3:33:25all together.
  5551. 3:33:26So, go ahead and open up 26
  5552. 3:33:30design agent
  5553. 3:33:33the goal here
  5554. 3:33:36is really to connect everything
  5555. 3:33:38together.
  5556. 3:33:39We are submitting a prompt from the AI
  5557. 3:33:42sidebar, then we're tracking the status
  5558. 3:33:45live through the use real-time run
  5559. 3:33:48function. We're also showing a status
  5560. 3:33:51strip while the task runs,
  5561. 3:33:54and we're letting Liveblocks handle the
  5562. 3:33:56updates of the canvas automatically.
  5563. 3:33:59So, let's go ahead and run it. And as
  5564. 3:34:01soon as it is finished, we're going to
  5565. 3:34:03test everything together.
  5566. 3:34:05And in a couple of minutes, definitely
  5567. 3:34:07much faster than it would take me to do
  5568. 3:34:09all of this, feature 26 is done. Again,
  5569. 3:34:13just modify some of the types,
  5570. 3:34:16modify the config to widen it just a
  5571. 3:34:18bit, and then most importantly, the
  5572. 3:34:20major rework happened within the AI
  5573. 3:34:22sidebar, where the handle send now
  5574. 3:34:25actually pushes the user message to AI
  5575. 3:34:28chat, calls our API endpoint to get the
  5576. 3:34:32run ID, and then the token as well to
  5577. 3:34:34get the public token, and then stores
  5578. 3:34:36both in state.
  5579. 3:34:39Finally, trigger.dev hooks run. We track
  5580. 3:34:42the run and once it reaches a final
  5581. 3:34:44status, it pushes the final AI message
  5582. 3:34:46to the AI chat, resetting the loading
  5583. 3:34:48state and clearing the presence. So,
  5584. 3:34:51what do you say that we head back over
  5585. 3:34:53to localhost:3000,
  5586. 3:34:54reload the page, and you'll see a
  5587. 3:34:56missing access token in trigger context
  5588. 3:34:59auth or use API client options. We can
  5589. 3:35:02quickly head back over to just a
  5590. 3:35:04localhost:3000 and editor. It is
  5591. 3:35:07possible that that's because of this
  5592. 3:35:08specific project. So, I'll create a new
  5593. 3:35:11project now.
  5594. 3:35:12I'll call it
  5595. 3:35:14testing
  5596. 3:35:15AI designs
  5597. 3:35:18and create it.
  5598. 3:35:20And once again, we immediately get the
  5599. 3:35:22missing access token in trigger auth
  5600. 3:35:25context or use API client options.
  5601. 3:35:28So, there's this handy little copy error
  5602. 3:35:31info click that you can copy, and then
  5603. 3:35:33you can directly paste the full error
  5604. 3:35:35right here. When I try to open a
  5605. 3:35:37specific canvas, this is the error that
  5606. 3:35:40I get. And then we can just display that
  5607. 3:35:42error.
  5608. 3:35:43Tell it to analyze it by following the
  5609. 3:35:47best practices from both Liveblocks and
  5610. 3:35:50Trigger.dev, and provide me your
  5611. 3:35:53reasoning and idea of what is wrong and
  5612. 3:35:56how to fix it. So, something like this
  5613. 3:35:58does. I noticed when you don't ask it to
  5614. 3:36:00fix it immediately, but rather you first
  5615. 3:36:03ask it to analyze it and give you the
  5616. 3:36:05idea of what it would do, that's not
  5617. 3:36:07cluttering the context as much, and it
  5618. 3:36:10gives you the ability to say whether you
  5619. 3:36:13would like it to execute what it
  5620. 3:36:15suggests or not. So, let's see what it
  5621. 3:36:17comes up with, and then we can
  5622. 3:36:18potentially execute it. And very
  5623. 3:36:20quickly, it was able to figure out the
  5624. 3:36:22reasoning, and I believe it actually
  5625. 3:36:24applied it because it was just a couple
  5626. 3:36:26of lines of code. The root cause was
  5627. 3:36:28that the use real-time run performs an
  5628. 3:36:30eager validation check for access token
  5629. 3:36:33on every render, and it doesn't wait for
  5630. 3:36:36a connection attempt. So, if we pass
  5631. 3:36:38empty string, it's the same as if we
  5632. 3:36:40don't pass it at all, so it immediately
  5633. 3:36:42throws the error on the first render.
  5634. 3:36:44But rather, we need to wait, and only
  5635. 3:36:47when there's an active run, then we need
  5636. 3:36:49to check for the token. So, now if we
  5637. 3:36:50head back, you can see that we can open
  5638. 3:36:53up a design, the new one as well as the
  5639. 3:36:57old one. So, now let's go within the new
  5640. 3:36:59project we created,
  5641. 3:37:01and we are ready to describe a new
  5642. 3:37:03system to AI.
  5643. 3:37:06In this case, you can really go ahead
  5644. 3:37:07and type anything. I'll write something
  5645. 3:37:09like this. You can also pause your
  5646. 3:37:11screen and write it with me. But the
  5647. 3:37:13goal here is to design a high-scale
  5648. 3:37:16e-commerce back-end architecture,
  5649. 3:37:18including an API gateway, a user service
  5650. 3:37:21with auth, a product catalog service
  5651. 3:37:24using a no SQL database,
  5652. 3:37:26and an order processing system that
  5653. 3:37:28communicates via a message queue. Also,
  5654. 3:37:31don't forget to add a Redis cache for
  5655. 3:37:33the catalog to handle high traffic.
  5656. 3:37:36And now, we can go ahead and click send.
  5657. 3:37:39You can see that Ghost AI is analyzing
  5658. 3:37:42your request in real time right now.
  5659. 3:37:46I'm going to zoom it in. So, this is the
  5660. 3:37:48first status that we're seeing. It says
  5661. 3:37:50working right here.
  5662. 3:37:51And then immediately after, we were able
  5663. 3:37:54to see a completed product. So, in this
  5664. 3:37:57case, we get the API gateway,
  5665. 3:38:00the user accessing it, browsing
  5666. 3:38:03different products, placing an order
  5667. 3:38:05through the product catalog service, and
  5668. 3:38:07that goes into the message queue, and
  5669. 3:38:09then the order is actually processed.
  5670. 3:38:11So, this is a great and pretty detailed
  5671. 3:38:14system architecture diagram, and we were
  5672. 3:38:16able to generate it using AI very
  5673. 3:38:19quickly. Because we already had the
  5674. 3:38:21underlying system for creating different
  5675. 3:38:23nodes and adding labels within the
  5676. 3:38:25elements and the edges.
  5677. 3:38:28And then we just created a system that
  5678. 3:38:30works in the background through
  5679. 3:38:31trigger.dev that makes use of all of
  5680. 3:38:34those functionalities within the app,
  5681. 3:38:37generates that JSON, and then we just
  5682. 3:38:39slap it onto the canvas. So, now that
  5683. 3:38:41everything is working so well, the last
  5684. 3:38:43missing piece of the puzzle is to
  5685. 3:38:46generate the specs. We need to take
  5686. 3:38:49everything that is on the canvas and
  5687. 3:38:51generate a markdown document that we can
  5688. 3:38:53then actually feed into a thinking or
  5689. 3:38:57planning AI agent, which is going to
  5690. 3:38:58make it the strongest possible starting
  5691. 3:39:00point for starting to develop any kind
  5692. 3:39:03of an application for real. But, the
  5693. 3:39:06first step is now done. It's all about
  5694. 3:39:08approaching the architecture from a
  5695. 3:39:10planning and very detailed way, like you
  5696. 3:39:13are an architect really, designing a
  5697. 3:39:15specification document. So, in the next
  5698. 3:39:17lesson, let's focus on generating that
  5699. 3:39:20spec.
  5700. 3:39:22The flow for generating the spec is
  5701. 3:39:25almost the same pattern as for
  5702. 3:39:27generating the design. A trigger route,
  5703. 3:39:30a background task, and a token route for
  5704. 3:39:33ownership tracking. Then, persistence to
  5705. 3:39:36Vercel blob, and finally, a piece of UI
  5706. 3:39:39to then view and download the result.
  5707. 3:39:42Because we've already built this pattern
  5708. 3:39:44once, these specs will move faster. So,
  5709. 3:39:48let's go ahead and build it one by one
  5710. 3:39:50by creating a feature spec number 27
  5711. 3:39:53called spec generation flow.md.
  5712. 3:39:58And yeah, as I told you, the goal of
  5713. 3:40:01this one is to build the full backend,
  5714. 3:40:04the trigger route, and the trigger.dev
  5715. 3:40:06task that calls Gemini and then
  5716. 3:40:09generates a markdown spec, but most
  5717. 3:40:11importantly, it generates it from the
  5718. 3:40:14canvas state and the chat history. You
  5719. 3:40:18can see that right here, spec generation
  5720. 3:40:20based on the project ID, room ID, chat
  5721. 3:40:24history, nodes, and edges. No backend
  5722. 3:40:27yet, We just wanted to execute that
  5723. 3:40:29task. So, let's go ahead and run it. 27
  5724. 3:40:32spec already. I'm not sure how to feel
  5725. 3:40:35about it. Is it too high or too low of a
  5726. 3:40:37number? I mean, considering what we've
  5727. 3:40:39implemented and what we've done so far,
  5728. 3:40:42like a full stack, full canvas
  5729. 3:40:45AI-powered application with templates
  5730. 3:40:48and everything else we've done. I mean,
  5731. 3:40:50I think this would take us months to
  5732. 3:40:53develop manually. And yeah, now that I
  5733. 3:40:56think about it, I'm sure. 27 spec files
  5734. 3:41:00is definitely not a lot for this
  5735. 3:41:02production-ready application we've
  5736. 3:41:04developed so far. We're very close, so I
  5737. 3:41:07believe we'll be able to get it done in
  5738. 3:41:08under 30. Let's make it run.
  5739. 3:41:11In this case, it looks like it's
  5740. 3:41:13actually running all three files in
  5741. 3:41:15parallel. This one was actually pretty
  5742. 3:41:17quick. Feature 27 is complete, and the
  5743. 3:41:20only thing we need to check from this
  5744. 3:41:21one is the trigger task called generate
  5745. 3:41:24spec. So, let's head over into that
  5746. 3:41:26file, and you'll notice that it's quite
  5747. 3:41:29similar to design agent. It takes all
  5748. 3:41:31the schemas, it builds the context,
  5749. 3:41:34returns it all, and here's a system
  5750. 3:41:36prompt saying that we are a ghost AI
  5751. 3:41:39senior technical architect whose job is
  5752. 3:41:42to generate a comprehensive markdown
  5753. 3:41:44technical specification document based
  5754. 3:41:46on the provider architecture canvas and
  5755. 3:41:49the conversation context. And we then
  5756. 3:41:51give it some information on how to
  5757. 3:41:52structure the spec. Finally, we call the
  5758. 3:41:55schema task coming from trigger, give it
  5759. 3:41:58an ID, the schema of what it needs to
  5760. 3:42:01do, the ability to retry it after
  5761. 3:42:03specific options, and then what is it
  5762. 3:42:06actually running? In this case, we're
  5763. 3:42:07calling the Google generative AI and
  5764. 3:42:10asking it to generate the spec, build
  5765. 3:42:13the context, generate it in text. Again,
  5766. 3:42:16we have to use 2.5 flash. 2.0 is no
  5767. 3:42:20longer there. And then finally, it gets
  5768. 3:42:22the spec and returns it. Before we go
  5769. 3:42:25ahead and test it, we have to first
  5770. 3:42:27implement a couple of functionalities
  5771. 3:42:29and then wire it to the sidebar. So, go
  5772. 3:42:32ahead and open feature specs and create
  5773. 3:42:35a unit 28 spec persistence
  5774. 3:42:39download.md.
  5775. 3:42:41The goal of this one is to save the
  5776. 3:42:44generated spec file to Vercel blob,
  5777. 3:42:47store the URL in project spec Prisma
  5778. 3:42:49model, and then add a secure download
  5779. 3:42:52route. Basically, same Prisma metadata
  5780. 3:42:55plus the blob content pattern that we
  5781. 3:42:57use for the canvas auto save. That's how
  5782. 3:42:59we want to save it.
  5783. 3:43:00And then finally, we want to ensure that
  5784. 3:43:02it's downloadable through this specific
  5785. 3:43:05API route. It should authenticate the
  5786. 3:43:08user, verify the access, verify the spec
  5787. 3:43:11belongs to that project, and then fetch
  5788. 3:43:13the file and return it as a downloadable
  5789. 3:43:16markdown file.
  5790. 3:43:18Go ahead and open this with your AI
  5791. 3:43:20agent. As usual, we'll tell it to read
  5792. 3:43:23the file, update our progress tracker,
  5793. 3:43:25and then implement it exactly as
  5794. 3:43:27specified.
  5795. 3:43:29And while it's doing its job, let's
  5796. 3:43:31quickly check how the progress tracker
  5797. 3:43:33is coming along. I mean, we've
  5798. 3:43:34implemented so many features so far, and
  5799. 3:43:37all of it is here for future developers
  5800. 3:43:40within your team or future agents
  5801. 3:43:42working on the project to check out and
  5802. 3:43:44then continue developing new features on
  5803. 3:43:47top of. All the architecture decisions,
  5804. 3:43:49session notes, and more.
  5805. 3:43:52So, yeah. Let's see how it approaches
  5806. 3:43:54this one. And feature 28 is done. A
  5807. 3:43:57summary right here is that it added a
  5808. 3:43:59project spec Prisma model with the ID,
  5809. 3:44:03project ID, file path, and created at.
  5810. 3:44:05And it's attached to a project. So, if
  5811. 3:44:08we delete it, it's going to be deleted
  5812. 3:44:09as well. Migrations have already been
  5813. 3:44:11applied for us. I love agents for doing
  5814. 3:44:14that automatically, so we don't have to
  5815. 3:44:16run Prisma generate and migrate on our
  5816. 3:44:18own. And finally, it updated the
  5817. 3:44:20generate spec so that after the markdown
  5818. 3:44:23is generated, it uploads it to a Vercel
  5819. 3:44:25blob so that we can download it later
  5820. 3:44:28on. And this route is responsible for
  5821. 3:44:30that. So now, just before we tested we
  5822. 3:44:34need to wire everything together. You
  5823. 3:44:36know how I like to make sure that these
  5824. 3:44:38spec files are really only handling one
  5825. 3:44:40thing at a time. So in 27, we handled
  5826. 3:44:43the spec generation flow. Then we made
  5827. 3:44:46it persist by storing it into Vercel
  5828. 3:44:48blob and creating a download route. And
  5829. 3:44:51now finally, in 29, spec UI
  5830. 3:44:55integration.md,
  5831. 3:44:57we are going to wire everything together
  5832. 3:44:59into the specs tab in the AI sidebar
  5833. 3:45:03through a list of generated specs. We
  5834. 3:45:05could have multiple, a preview model
  5835. 3:45:07that renders the markdown in case you
  5836. 3:45:09want to preview it in the browser, and
  5837. 3:45:11finally a download action to download it
  5838. 3:45:14on your device. So, go ahead and run it.
  5839. 3:45:17And let's give it some time to implement
  5840. 3:45:18it. And let's let it do its thing.
  5841. 3:45:21And now that feature 29 is fully
  5842. 3:45:23implemented and the build passes, which
  5843. 3:45:25is important, we'll soon be ready to
  5844. 3:45:27test it out. So, there's two new backend
  5845. 3:45:30routes. The first one gets access to all
  5846. 3:45:33the project specifications for a
  5847. 3:45:34specific project, and then the second
  5848. 3:45:37one actually creates a downloadable
  5849. 3:45:39markdown text. And the AI sidebar got
  5850. 3:45:42updated so we can test it all out. Back
  5851. 3:45:45within the browser, if you now head over
  5852. 3:45:47to specs and click generate spec, you'll
  5853. 3:45:50notice that, at least on my end,
  5854. 3:45:52nothing's happening.
  5855. 3:45:54On your end, it might be working. Maybe
  5856. 3:45:56your agent did a bit of a better job,
  5857. 3:45:58but at least here, it's not budging. But
  5858. 3:46:01thankfully, we are getting some errors
  5859. 3:46:03right here within the terminal.
  5860. 3:46:05So, I'll go ahead and copy these errors
  5861. 3:46:08and tell it when I click the generate
  5862. 3:46:11spec button, it doesn't do anything. And
  5863. 3:46:14this is what I see in the terminal. I
  5864. 3:46:15pasted it and then I'll say analyze it
  5865. 3:46:19and provide a solution.
  5866. 3:46:21Refer to trigger.dev and liveblocks
  5867. 3:46:25skills if needed and press enter.
  5868. 3:46:28I find it that sometimes it's great to
  5869. 3:46:30explicitly mention that it can refer to
  5870. 3:46:32specific skills if you think it's going
  5871. 3:46:34to be useful. Yeah, this definitely took
  5872. 3:46:36some time. But yeah, it says right here
  5873. 3:46:39just to restart your server. It did some
  5874. 3:46:43additional changes, but I think after
  5875. 3:46:45all the changes, it's necessary to just
  5876. 3:46:47reload it. So that's what I'm going to
  5877. 3:46:49do. Back on localhost 3000, it's going
  5878. 3:46:51to be active.
  5879. 3:46:53Make sure to reload the page and then
  5880. 3:46:55head over to specs.
  5881. 3:46:58Click generate spec
  5882. 3:47:00and it is generating. While it is
  5883. 3:47:02actually generating, you can head over
  5884. 3:47:05to trigger.dev under runs and you can
  5885. 3:47:08see generate spec is being executed as
  5886. 3:47:10we speak. So here you can see a bit more
  5887. 3:47:13information on exactly what is
  5888. 3:47:14happening. This is the payload that we
  5889. 3:47:16sent into it, all the different nodes,
  5890. 3:47:19all the information about the
  5891. 3:47:20architecture and more. And it looks like
  5892. 3:47:23it generated it and returned it. So now
  5893. 3:47:25if you head back, you'll be able to see
  5894. 3:47:27a new markdown file that when you click
  5895. 3:47:30on it, it'll be opened within a markdown
  5896. 3:47:32previewer right here in the browser.
  5897. 3:47:36There we go. It's a bit tiny. We can
  5898. 3:47:38definitely increase its width.
  5899. 3:47:40But yeah, I mean, take a look at this.
  5900. 3:47:42This architecture diagram, it was able
  5901. 3:47:45to generate a pretty hefty technical
  5902. 3:47:47specification document that outlines
  5903. 3:47:50this huge system that we can send over
  5904. 3:47:52to our planning agent and start
  5905. 3:47:54developing it. Let's test the download
  5906. 3:47:56functionality as well. I clicked the
  5907. 3:47:58button and it opened it up. It's a long
  5908. 3:48:01file, but if you've been following along
  5909. 3:48:04with this course, you know that
  5910. 3:48:05specifications have to be long,
  5911. 3:48:08especially if you're creating one spec
  5912. 3:48:10for the entire system. So, that's it.
  5913. 3:48:13That's the full Ghost AI feature set
  5914. 3:48:15working end to end. So, what do you say
  5915. 3:48:18that we test out the functionalities one
  5916. 3:48:20more time on two separate screens? At
  5917. 3:48:22least right now, I'm on two separate
  5918. 3:48:24tabs, so still logged in with the same
  5919. 3:48:26account, but that should be okay.
  5920. 3:48:28So, I'll say final test and create a new
  5921. 3:48:32project.
  5922. 3:48:34That project will immediately show up
  5923. 3:48:36right here as well after reloading the
  5924. 3:48:39page.
  5925. 3:48:40And now we are viewing it from both
  5926. 3:48:42sides.
  5927. 3:48:44Both of us are in the same room, and you
  5928. 3:48:45can see my name
  5929. 3:48:48and cursor pointing different locations.
  5930. 3:48:51Of course, if it were some other people
  5931. 3:48:53right here, you'll be able to see their
  5932. 3:48:55profiles as well.
  5933. 3:48:57And as soon as I drag and drop
  5934. 3:48:58something, you can see that it appears
  5935. 3:49:01immediately. It also auto zoomed in
  5936. 3:49:03right here, and we can continue creating
  5937. 3:49:06the diagram. You can see it happens in
  5938. 3:49:09real time. And that's the beauty of
  5939. 3:49:11Liveblocks. What we can do next is test
  5940. 3:49:14the AI functionalities. So, I'll open up
  5941. 3:49:17the AI window right here,
  5942. 3:49:20and let's go with something simple and
  5943. 3:49:22default like design an e-commerce
  5944. 3:49:24backend.
  5945. 3:49:26I'll first select all of these by
  5946. 3:49:27holding the shift key and then remove
  5947. 3:49:29them.
  5948. 3:49:31And design that e-commerce backend
  5949. 3:49:33by sending a new AI chat message. It'll
  5950. 3:49:37start working on it,
  5951. 3:49:39and very quickly it'll generate the full
  5952. 3:49:42UI right here. And that UI got generated
  5953. 3:49:46for the other user as well. Finally, we
  5954. 3:49:48can generate some specs out of it. And
  5955. 3:49:50of course, this is happening in the
  5956. 3:49:52background as a task that is being run
  5957. 3:49:55on the trigger.dev side of things. Or
  5958. 3:49:58specifically, we are running an agent,
  5959. 3:50:00in this case Gemini, to process
  5960. 3:50:02something. But, of course, you can run
  5961. 3:50:04all sorts of different AI agents, media
  5962. 3:50:06processing, media generation. Like,
  5963. 3:50:08there's tons of different use cases for
  5964. 3:50:10how Trigger can be used, and we can
  5965. 3:50:12definitely explore some more of it in
  5966. 3:50:14one of the upcoming videos.
  5967. 3:50:16But, yeah, the spec is here. We can
  5968. 3:50:18preview it, download it, and that's it.
  5969. 3:50:22That is the entire app. So, in the next
  5970. 3:50:25lesson, let's get it deployed.
  5971. 3:50:30Okay. Now that the app is complete,
  5972. 3:50:32before we deploy, we need to switch a
  5973. 3:50:35few services from development to
  5974. 3:50:37production.
  5975. 3:50:39Dev keys are rate-limited and aren't
  5976. 3:50:41meant for real traffic. So, we have to
  5977. 3:50:44update Liveblocks, Trigger.dev, and make
  5978. 3:50:46sure that every environment variable is
  5979. 3:50:49set correctly in Vercel. Let's start
  5980. 3:50:51with Liveblocks.
  5981. 3:50:52Create a new project and call it Ghost
  5982. 3:50:56AI production or something like that.
  5983. 3:50:59And set the environment to production.
  5984. 3:51:02Then, from the API key section, simply
  5985. 3:51:05copy the public key,
  5986. 3:51:07head over into your .env.local,
  5987. 3:51:10and paste it right here.
  5988. 3:51:12Liveblocks public key, you can override
  5989. 3:51:15the development one, or in case you want
  5990. 3:51:17to keep it, you can just comment it out.
  5991. 3:51:19But, again, make sure to add new
  5992. 3:51:22production ones right here. Or at least
  5993. 3:51:24when we're deploying the project on
  5994. 3:51:25Vercel, you'll have to put these new
  5995. 3:51:27updated ones.
  5996. 3:51:29So, yeah, let's go ahead and update it.
  5997. 3:51:32Uh the Liveblocks public key is going to
  5998. 3:51:34be this new prod key right here.
  5999. 3:51:37And also, let's generate a secret key,
  6000. 3:51:40which you can copy,
  6001. 3:51:42and then also override right here.
  6002. 3:51:45Step two is get the Trigger.dev
  6003. 3:51:47production API keys by heading over to
  6004. 3:51:50the dashboard, and then in the top
  6005. 3:51:52selector right here, where it says
  6006. 3:51:55environment, switch it over from
  6007. 3:51:57development to production. Then, from
  6008. 3:52:01the project settings right here under
  6009. 3:52:03API keys,
  6010. 3:52:04go ahead and copy the secret key and
  6011. 3:52:07replace the existing one right here
  6012. 3:52:09under ENV local.
  6013. 3:52:11Once again, I will comment out the
  6014. 3:52:12previous one and just update this one
  6015. 3:52:15that's going to have prod right here in
  6016. 3:52:17the middle. And below the API keys, you
  6017. 3:52:19can head over to general project
  6018. 3:52:21settings and copy the project ref, which
  6019. 3:52:24I believe should be the same. So, if you
  6020. 3:52:27duplicate it
  6021. 3:52:29and override it here, you'll see that
  6022. 3:52:31one is actually the same, so we can
  6023. 3:52:33leave it as it is. Now, go ahead and
  6024. 3:52:35copy all of your ENVs
  6025. 3:52:38and we have to push our changes.
  6026. 3:52:40So, run git add dot, git commit {dash}
  6027. 3:52:44m,
  6028. 3:52:45finalize the app and prepare it for
  6029. 3:52:48deployment, and then run git push.
  6030. 3:52:51Then, head over to Vercel, click add a
  6031. 3:52:54new project, and just import it from
  6032. 3:52:56git. Once pushed, it should have changes
  6033. 3:52:59a couple of seconds ago, not a couple of
  6034. 3:53:01hours ago. But, the reason it says 5
  6035. 3:53:03hours here is because we've pushed the
  6036. 3:53:05changes to our dev branch. So, for them
  6037. 3:53:09to show up on Vercel, we first have to
  6038. 3:53:10push them over to the main branch by
  6039. 3:53:13creating a new PR.
  6040. 3:53:16And in this case, there were so many
  6041. 3:53:17changes that we've done, most of which
  6042. 3:53:19are actually agent skills that we
  6043. 3:53:22installed. So, there's going to be 1.7
  6044. 3:53:24million lines of code to review. In this
  6045. 3:53:27case, what I'm going to do just to get
  6046. 3:53:29it deployed is I will first fix the
  6047. 3:53:32conflict we have with Copilot. I'll just
  6048. 3:53:35tell it to completely remove the current
  6049. 3:53:38issues.md file,
  6050. 3:53:41which should fix the conflict,
  6051. 3:53:42obviously.
  6052. 3:53:44That's because we're hoping not to have
  6053. 3:53:46any more issues. It's going to look into
  6054. 3:53:48it and start implementing it right away.
  6055. 3:53:51And as soon as it has been removed, we
  6056. 3:53:53are ready to merge the PR,
  6057. 3:53:55which means that the latest changes
  6058. 3:53:57under the Ghost AI project should be
  6059. 3:53:59reflected momentarily. And after a
  6060. 3:54:02reload, they say just now. So, we can go
  6061. 3:54:05ahead and import it.
  6062. 3:54:07And immediately add the environment
  6063. 3:54:10variables by pasting all of them into
  6064. 3:54:12this first key and value pair, and it'll
  6065. 3:54:14automatically populate all of them. So,
  6066. 3:54:17go ahead and scroll down and click
  6067. 3:54:19deploy.
  6068. 3:54:20Now, we've implemented so many
  6069. 3:54:22individual features within this
  6070. 3:54:24application,
  6071. 3:54:25integrated and wired up so many services
  6072. 3:54:28across front-end and back-end and Prisma
  6073. 3:54:30databases.
  6074. 3:54:32It would be a miracle if it worked first
  6075. 3:54:34try. So, just as I said that, in about 8
  6076. 3:54:37seconds, the initial build failed saying
  6077. 3:54:40that we can find a full log right here.
  6078. 3:54:43So, I'll go ahead and inspect the
  6079. 3:54:44deployment, and it looks like it just
  6080. 3:54:47failed on running npm install.
  6081. 3:54:50So, typically when we face an error this
  6082. 3:54:52early with the npm install, most likely
  6083. 3:54:55culprit is going to be the
  6084. 3:54:57package-lock.json.
  6085. 3:54:59So, what I like to do in this situation
  6086. 3:55:01is just make sure that we are on the
  6087. 3:55:04main branch, and we are, and want to
  6088. 3:55:07delete the package-lock.json entirely,
  6089. 3:55:10and then push to the main without it by
  6090. 3:55:12running git add dot, git commit {dash} m
  6091. 3:55:15remove package-lock.json,
  6092. 3:55:19and want to get push.
  6093. 3:55:21This is going to push it straight over
  6094. 3:55:22to main, which means that it should
  6095. 3:55:24automatically re-trigger another
  6096. 3:55:26deployment. And this time, it is
  6097. 3:55:28building past second eight, successfully
  6098. 3:55:32installing the dependencies. So, this
  6099. 3:55:33time we've gotten a bit further, but it
  6100. 3:55:36still breaks right here on Prisma.
  6101. 3:55:39Uh this is a typical procedure. Whenever
  6102. 3:55:41you're publishing a Next.js project on
  6103. 3:55:44Vercel with Prisma, you also have to add
  6104. 3:55:47an additional script to the
  6105. 3:55:49package.json.
  6106. 3:55:50That's going to be right here.
  6107. 3:55:52Right after lint, go ahead and add a
  6108. 3:55:55post
  6109. 3:55:56install script where you can run Prisma
  6110. 3:56:00generate. So, once again, you can make
  6111. 3:56:03that change
  6112. 3:56:04and push it over to the main branch.
  6113. 3:56:08As I told you, it's going to be unlikely
  6114. 3:56:10that the build is going to succeed from
  6115. 3:56:12the first try. As we've been developing
  6116. 3:56:14this project for so long locally and in
  6117. 3:56:17development version, and now we want to
  6118. 3:56:19run it in production.
  6119. 3:56:21But, don't worry, we're going to get
  6120. 3:56:22there. And third time's the charm
  6121. 3:56:25because the status is now ready and we
  6122. 3:56:27are live. So, go to the project overview
  6123. 3:56:31and visit your URL, which brings us back
  6124. 3:56:34to our auth and home page at the same
  6125. 3:56:36time, where after you sign in, you are
  6126. 3:56:39redirected to an empty project screen or
  6127. 3:56:42since we already logged in with the same
  6128. 3:56:44account, you can find all of your
  6129. 3:56:45previous projects. This means that
  6130. 3:56:48everything is working exactly as it's
  6131. 3:56:50supposed to, even on the deployed
  6132. 3:56:52version of the application. So,
  6133. 3:56:54congrats.
  6134. 3:56:55This was a long build and quite a
  6135. 3:56:58different one from the typical ones
  6136. 3:57:00where we manually code everything out.
  6137. 3:57:02So, I want to hear from you.
  6138. 3:57:04How did you like this new approach?
  6139. 3:57:06Would you like to dive even deeper
  6140. 3:57:08within the Agenty course that I'm
  6141. 3:57:10working on?
  6142. 3:57:11If so, you can join the waitlist. And if
  6143. 3:57:13you haven't already, also go ahead and
  6144. 3:57:15download that six-file contact system
  6145. 3:57:17for Agenty development that I prepared
  6146. 3:57:19for you alongside this video. That way,
  6147. 3:57:22you can use the same system we followed
  6148. 3:57:24along with this build and implement it
  6149. 3:57:27with your future builds. And yeah, huge
  6150. 3:57:29thanks to Trigger for amazing background
  6151. 3:57:32tasks and AI agent functionalities that
  6152. 3:57:35they allow you to add to your app. Also,
  6153. 3:57:37huge thanks to Liveblocks for allowing
  6154. 3:57:39us to make our applications interactive.
  6155. 3:57:42And finally, to Clerk for simplifying
  6156. 3:57:44authentication and user management.
  6157. 3:57:47Thank you not only for sponsoring this
  6158. 3:57:49video, but for developing such amazing
  6159. 3:57:51developer tools that I get to share with
  6160. 3:57:54you guys watching this video.
  6161. 3:57:56That was it for this one. I'll see you
  6162. 3:57:58within jsmastey.com
  6163. 3:58:00or if not there, within one of the
  6164. 3:58:03upcoming videos on the YouTube channel.
  6165. 3:58:05Once again, thank you for watching and
  6166. 3:58:08have a wonderful day.

About this transcript

This page contains the full transcript of How Senior Engineers Actually Build With AI in 2026 | Build a Full Stack Systems Architecture App by JavaScript Mastery, generated from the public captions YouTube serves with the video. The transcript has 40,317 words across 6,166 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.

What you can do with it

Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.

Free YouTube transcript tool

YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.