Leveraging AI for Web Development
Chapters24
Introduces a practical, PHP/Laravel-focused approach to AI tooling, highlighting JetBrains AI and Juny, and outlining how to explore a Laravel workshop codebase with guidance on using AI in chat and agent modes, plus setting up and understanding guidelines, MCPs, and workflows.
A practical, developer-focused guide to using JetBrains AI, Juny, Claude, and Laravel Boost to build and test Laravel apps with AI-assisted workflows.
Summary
Laracasts’ Leveraging AI for Web Development shows how to stay practical in a crowded AI tool landscape. The host demos JetBrains AI plus Juny and Claude, explaining when to use chat versus autonomous agents and how to keep costs in check. The walkthrough uses the Laravel workshop codebase and then layers in Laravel Boost’s MCP servers to give the AI deeper project context. You’ll see real-world steps like generating a guidelines.md, creating an inertia/Vue3 front-end, and leveraging Pest for tests. Simon, Jeremy, and the host highlight the contrast between “agent-driven” planning and “developer-driven” iteration, stressing explicit context and prompts. The session also covers handling increasingly complex tasks by iterating on prompts, updating guidelines, and using dedicated tools like Whisper Flow for speech-to-text. Throughout, the emphasis is on keeping control: define plans, verify with tests, and refine guidelines to prevent drift. The video also touches advanced topics like work trees for parallel AI work and how to use Context 7 for up-to-date documentation when AI lacks current package knowledge. It’s a practical playbook for PHP/Laravel developers who want AI to augment rather than replace their skillset.
Key Takeaways
- JetBrains AI (Juny) can create autonomous, step-by-step plans for code tasks and run commands like artisan boost MCP to bootstrap AI-enabled workflows.
- Use Laravel Boost to inject dynamic, project-specific guidelines (ND files) so agents follow your team’s conventions (e.g., inertia guidelines, Pest vs PHPUnit, strict types).
- Distinguish between chat and agents: chat is conversational review; agents execute plans with an explicit sequence, updating as needed.
- Enable MCP servers and use tools like read logs, browser logs, and be prepared to grant permissions for command execution; brave mode should be used with caution.
- Be explicit in prompts and iterate: when an output is too broad or off-base, refine the prompt and update your guidelines to improve future results.
- Architect AI-assisted workflows around tests: if AI writes code, ensure tests exist and pass to verify correctness (test-driven AI workflow).
- Leverage work trees to run multiple AI-driven features in parallel without collision, branching, or overwriting another agent’s changes.
Who Is This For?
Essential viewing for Laravel developers who want hands-on, repeatable AI-driven workflows without losing control over code quality. It’s especially valuable for teams adopting AI agents, context-driven prompts, and automated testing in a Laravel project.
Notable Quotes
"‘Even people who do this all the time aren't entirely sure which one they're supposed to pick.’"
—Explains model volatility and the need to choose between chat vs agent carefully.
"“Think more. This is kind of a fun one.”"
—Highlights the “Think more” option to improve AI output, with trade-offs in time and cost.
"“Context is exactly the way you would use that term in real life.”"
—Defines how to structure guiding context for AI agents.
"“This will give us three up-to-date guidelines that instruct AI on how to behave.”"
—Shows generating dynamic, project-specific guidelines with Laravel Boost.
"“You're developer-driven AI. We remain in control the entire process.”"
—Contrasts developer-driven AI with vibe coding and emphasizes control.
Questions This Video Answers
- how do I choose between chat and agent modes in JetBrains AI for Laravel projects
- what is Laravel Boost MCP and how do I enable it in PHPStorm?
- how can I run AI-assisted tests to ensure code changes actually work in Laravel?
- what are work trees in Git and how can they help AI-driven development?
- how can I implement AI-driven but test-verified features for Laravel apps?
JetBrains AIJunyClaudeClaude CodeClaude MDLaravel BoostMCP serverInertia.jsVue 3Pest PHP","PHPStorm","Whisper Flow","Context 7","Nutgram","Laravel 12"],
Full Transcript
All right, so before we get started, here is the game plan. So, as you already know, even at this point, there's no shortage of AI tooling and agents in the wild. And to be honest, it can sometimes be a little bit overwhelming. But that's okay. We're going to keep things super practical and super laser focused on the working PHP and Laravel developer. Let's get going. So with PHP and Laravel in mind, because tooling like PHP Storm is so widely adopted in our world, we're going to use Jet Brains AI. But don't worry, all of this knowledge is portable.
Uh or in other words, 95 96 97% of what we're going to talk about here can be applied anywhere. All right, so let's scroll down. Of course, you're going to have access to AI completions directly within your editor, but you also have access to super powerful agents, which we'll talk about more in the future, but you'll start with Jet Brains's own Juny agent. But you can also reach for Claude if you prefer. All right. And if I scroll down, here's an example of that interaction. Notice how the agent is creating a plan and sequentially working through that plan.
It's very cool. We can also do updates as you see here. Now, to get us going, we're going to use the Laravel workshop codebase that Simon, Jeremy, and I worked on together. So, this will give us some good material to figure out what AI is capable of. All right, let's get going. So, I'm going to start by visiting our settings, and let's come down to plugins, marketplace, and at the time of this recording, I'm going to look for AI assistant. Alternatively, you might search for Jet Brains AI just in case they rename it. All right, so let's install it.
And that's done. All right. So, very quickly though, you'll notice that it says purchased here. You don't have to buy it if you don't want to. Let's quickly talk about that. If I switch back to the landing page and scroll down to the plan section, yeah, you'll see there is a free plan that has unlimited code completion and local AI support, but it also includes a one-mon trial of their pro plan that gives you uh access to Juny and things like that. So, take a look, decide for yourself. It's not up for me to tell you which one to pick.
Anyhow, I will apply that. Okay. So now I can bring up AI chat by going to tools in this one here. Works great. Alternatively, if you prefer, you can do it through the menu bar as you see here. This icon. Next, if you prefer uh search anything, I could do it like that. Let's look for AI chat or I'm sorry, AI assistant. And then here we go. But generally, I'm sort of a keystroke guy. So this is what I would do. I'd once again bring up settings. I'd go to keymap. I'd look for AI chat or AI assistant.
And here you can see I've already added a keystroke of option C, but you can add whatever makes sense to you. So now anywhere in my codebase on my machine, I can press option C to pull up the chat tab. All right, let's get going. So right away we see a bunch of icons here. We see chat versus agent. Do we use Juny or Claude? What's the difference between an agent and and chat? Again, it can all be a little bit overwhelming. And then for chat, we see all of these different models and you're just expected to know which one you need to use.
Well, I'm going to tell you the truth. Even people who do this all the time aren't entirely sure which one they're supposed to pick. And that's because things are a little volatile right now and things keep changing and models improve and one surpasses the other, but two months later the other one comes back and surpasses the former. Uh, don't worry about it too much. So for now, here's what I want you to think about. You will see a distinction between chat and agents. Chat means exactly what you think it means. Chat with AI. Ask it questions.
In this case, it's not going to do any work. It's just going to talk to you. And in many situations when you are reviewing a codebase, it's helpful to just have someone to talk to. Hey, this code looks a little weird. Why do you think it was done that way? Or in our case, maybe this is our first introduction. and we might say, "Can you give me a quick review of what this application does?" This is a great example of using the chat. Now, for the model, you might just stick with auto and uh Jet Brains will do its best to choose a performant and cheap option.
In this case, it's recommending Gemini 3. But if you know a bit more and you prefer a version of Claude or Chat GPT, you could reach for those as well. Do pay attention to the little icons here because they will give you an indication in terms of cost. All right, in our case, let's stick with auto and give this a run. So now, literally what it's doing is it's collecting all the context it can. It's looking at your files. It's going to read the routes file. It's it's going to check if you have certain guidelines in place.
It'll review the controllers and what tooling is being used, stuff like that. All right, and that's done. Took about 20 seconds. So here's a quick review. It's a social media platform. Correct. Mimics Twitter or X. Correct. It's built with Laravel and view and inertia. Again, all correct. Providing a single page application feel. All right. Next key features. It has a timeline and posts and likes and follows. Users can have a profiles. We support authentication. Uh for the back ends, we're using Laravel 12. For the front end, Vue3 and Inertia. For testing, we're using Pest. Again, this is just a a great introduction to a codebase if you are interacting with it for the first time.
Now, in this case, again, I want you to notice that we're just chatting with AI, if not actually writing specific code. So, in those situations, you have to decide uh two things. First, do I want to be the agent or in other words, do I want to be fully in control every step of the way? I ask it to do a thing and it does the thing and then it comes back to me or am I okay with it functioning as an agent where it has a bit more autonomy. In these situations, I can tell it what I want and it'll start making a plan and it'll work through that plan sequentially implementing the code.
Are you okay with that or do you want to be in complete control every step of the way? The answer to that question will determine how often you reach for maybe the chat tab versus a dedicated agent. All right. So, here's another example. This time I will switch to one of the agents. We'll go to Juny in this case. And you'll see a handful of menu options here that can be a little confusing, but they're super important to know. So, first up, even in the context of an agent, you have the ability to simply ask it questions, right?
Or once again, it can be treated as a full autonomous agent that can get to work or Juny can figure out what you want in this case. Uh, so you do have that option. All right. Next, brave mode again is what you think it is. Is it okay if Juny is a little bit brave here? Is it allowed to write terminal commands without asking for permission? Uh, and you just have to decide for yourself. Are you okay with that? Or do you want to be in complete control where you have to manually approve every single command.
My recommendation is why don't you leave that one deselected unless you really know what you're doing. All right. And then finally, think more. Yeah, this is kind of a fun one. So, as it turns out, if you ask AI to take a little more time and think a little bit harder, it will do better. Isn't that interesting? Even in a a general web chat, if you say, "Think really hard about this," well, it's going to think a little bit harder about it and it's going to give you better output. Just keep in mind sometimes the this will take longer and there might be a cost associated with that.
So only select this for situations where it's vital that the AI takes its time to really prepare the best possible response. Okay. Now if we take a look here, it doesn't seem that AI is being referenced anywhere. And by that I mean it doesn't look like Laravel boost is installed and I don't see any agents.m MD or guideline files for AI. So that might be a good first step for us. Now, I could write this out here or you can pull in dedicated tools to convert your speech into text and just have a Google for that.
The one that I will be using here is called Whisper Flow. And again, you can try it out for free. So now I can hit a keystroke and you'll see it allows me to begin speaking. And when I let go of that keystroke, it will convert that into text. All right. So let's do this uh throughout this course. perform a thorough review of this codebase, including its structure and patterns, and then extract that into your own guidelines file for future reference. All right, so we'll give that a run and let's see what it comes up with.
All right, so almost immediately it wants to run a terminal command to scan our project for PHP view and JavaScript files. But again, it's a terminal command and it has to ask for permission because we don't have brave mode turned on. So I will say yeah go ahead. All right and that's done. So yeah in real life it took three or four minutes to complete and that mostly consisted of scanning our entire project reviewing it figuring things out. What are the patterns? What are the style guides we use? What are the conventions? So it created a comprehensive guidelines file documents the standards the patterns the testing the code quality.
You get the idea. Okay. So now you'll find a new guidelines.mmd file or potentially you could place this directly within the juni directory if you want this guideline to be unique and only accessible to juny. So take a look here. Uh we have a general um style guide so to speak for our project. Here's what the tool is. Here is the tooling that we can reach for. And keep in mind you can modify this to your heart's content. So if you see a section you disagree with change it. If you want to make something explicit, maybe the braces should always go on the same line as the method signature rather than its own line, you can be clear about uh the the rules that AI should follow when writing code on your behalf.
All right, so next it picked up on the fact that we always use strict types, which means again when AI creates a new class on our behalf, it's going to know, all right, I'm going to include that because that seems to be a convention in the codebase. Next, we can see type declarations, how rules might be declared, where we store our models, how we define relationships, you get the idea. If I bring up the uh outline here, notice it's quite comprehensive. What are the patterns for front ends? Let's take a look real quick. Well, we use view components, and this is where our pages are, and this is how we store layouts.
Think of this literally as a guide for AI to figure out how it should go about implementing the code we ask it to write. Here are the best practices that it picked up for our codebase. And once again, just to be crystal clear, you are in charge of this file. Make sure it reflects what you want. Okay. But yeah, I think you get the idea. So once again, we're calling this guidelines MD, but there's no hard rule at the time of this recording. You'll often see agents ND. This is a markdown file specifically for agents so that they can better gather context about how to proceed with what you want.
And again, it turns out context is sort of a keyword. Keep it simple. Context is exactly the way you would use that term in real life. It allows the model to gather additional information in order to proceed. Right? So in this case, the context is well when you work on my codebase, this is how you should structure it. This is the style guide you should use. this is how you should prepare tests. Uh here's another one. If you wanted to always include tests as part of any featured implements, you can be explicit here. On the other hand, if if you're a cowboy and you just want to skip that part, well, you could tell it to skip the test as well, although I would not recommend it.
And then further in terms of context, if I bring up our tab again, let's imagine you're working on the profile feature and there's something specific you want AI to do for you. Well, you can include the profile model in the context just so you're crystal clear that here's what we're working with, here's the migration file, and based on that context, here's what I want you to do. So, just as a general rule, the more information you give AI, the the more equipped it is to execute the task. Now, we're still not done with context. So, next up is Laravel Boost.
So, work along with me and visit github.com/laravelboost. All right. So, Laravel Boost, of course, is a Laravel specific package. It's an MCP server, but don't worry about that right now. Basically, it provides additional context and power and capabilities to your AI agent. So the best way to explain this is to dive right in and try it out. Let's do it now. So first up, we're going to install it. And we can do this directly from my editor. So I will paste that into the terminal. Give that just a second to complete. And now it's going to give us among other things three uh boost specific artisan commands.
So if I run PHP artisan boost, it'll show us well we have install, mcp, and update. So of course right now we want install. All right. PHP Artisan boost install and it's gonna ask us a series of questions. All right, first up, do we want to install the herd MCP alongside Boost MCP? We don't know what MCP is at this point. For now, just hit yes. And until we talk more, and we have a dedicated episode on what those are. Just think of it as a server that provides additional knowledge and capabilities to your AI agent.
All right, that's good enough for now. Next, what editors are you using? Select all that apply. At the moment, just PHP Storm. Next, what agent? Remember, there's lots of different agents. We're using Claude Code or Codeex from the Facebook team. Cursor, Gemini. Choose all of them that apply. In our case, we'll stick with Juny and maybe Claude Code if you use that. All right. So now notice as part of the installation, it's including guidelines, but these guidelines are dynamic, which means it's scanning our codebase and our packages to determine what we're using here. And then if it has associated guidelines, it pulls those in.
So in our case, we're using Laravel 12. And notice we have Laravel 12 guidelines. We're using inertia.js. So we have inertia guidelines. We are using pest PHP instead of PHP unit. So once again, we have pest specific guidelines. And again, those guidelines instruct AI for how it should go about writing that code. All right, best practices as provided by the creators of these uh tools. All right. So, next we have everything all set to go. So, if I run a get status, you'll see that we have a handful of files that we can interact with.
Okay. All right. So, let's take a look. If I open up the sidebar, I now have a Juny directory. And here's a guidelines file, but this time it was created specifically by Laravel Boost. And again, just to reiterate, it's dynamic based upon what we have installed. So here's the tooling that AI now knows about without having to manually scan uh our project. Next, you'll see all of the various guidelines here. So let's go down to how about inertia. We're using inertia here and boost wants it to know well this is where we place our pages.
This is how you should render an inertia page. We have code snippets and then look at this section right here. Use search docs for accurate guidelines on all things inertia. All right. So now you're thinking, well, what is search docs? Well, search docs is sort of like a skill that the MCP server provides, right? Remember I said MCP provides knowledge and capabilities? Well, those capabilities could be referred to as skills. And in this case, one of those skills is to search the documentation without having to scrape the web and pull up blog posts and things like that.
No, now it can use this skill to get the most upto-date documentation for the very version of the package that you're using. That's really cool. Next, let's keep going. It's going to let it know, hey, don't try to do any Inertia one code here. We have inertia 2. Here are the things it supports. And if you need to, for example, pull my server, don't wire up your own version here. We have this out of the box. And again, if you've ever run into this in the past where AI is using outdated methodologies to solve a problem, well, things like this really do help.
Now, we can instruct it that, hey, no, we're using inertia 2 and make sure you review the features. Here's the documentation if you need to learn more via that skill and this is how I want you to behave. Got it? Cool. So, anyways, let's come back. Here is the MCP servers. This is how we register these servers with your agent. In this case for Juny notice and and don't be overwhelmed here this is very simple we have an MCP server for Laravel boost and herd and notice it's just specifying well we're going to run PHP and then we're going to run artisan and then we're going to run boost MCP so this is effectively PHP artisan boost MCP and in fact you can run this directly from the command line to start up your MCP server but now this is a way to instruct the agent how to start it up on its own and then we also have one for her.
All right, so cool. I think we're all set to go here. All right, so now the final step is to simply enable these MCP servers. So, open up your settings, look for MCP, and yeah, down with Juny if we're using that. Let's make sure we enable these. I'll click apply. And if you're working along, make sure the status is green. If it's red, that means for some reason the server didn't start up properly. But sure enough, if I hover over this, we'll see, yep, these tools are now available. Okay, so let's try it out. Behind the scenes, I have uh created a route for the homepage that instantly throws an error.
And I've already triggered that error. So, if I go into my log file, sure enough, we can see beep beep alert alert failure. So, here's what I want. I want AI to inspect this log, determine the reason for that error, and then fix the bug automatically. Let's go. All right. So, let's open our chat. We're going to use the Juny agent and let's speak it out loud once again. The last time I loaded the homepage, an error was thrown. I'd like you to read the application logs and fix the bug. Thank you. All right. So, let's give it just a second and we're going to watch what happens here.
Ah, take a look at this. run mcp command. So yes, otherwise without boost what it would probably do is try to tail the laravel.log file and that would work. But again, just notice that we're providing better capabilities, more efficient uh capabilities to the agent. So it's saying, hey, I want to use this MCP server and I want to run the read log entries um tool. Yeah, go ahead. All right, it revealed a critical error. Yes, it was a critical error and it's going to fix the bug now. All right. So, now it's going into home controller.
It's kind of it's kind of a good learning opportunity as well to figure out how do I debug things if you're at the beginning of your career. So, it goes into home controller and it reads that action and it sees oh well it was throwing an error. So, it's going to change the file. I examined the controller and I found a deliberate throw statement that was causing the error. Removing it fixed the bug. It's always amazing when just removing the error fixes the bug. So notice we have our plan that it creates on its own and it fixed the error.
So if I were to close this out, sure enough, if I go into what was it? Home controller, you'll see, yep, it it removed the error and it fixed the bug. You get the idea. Here's some other things you can do. Uh let's create a new chat. And we're just going to have a conversation for now. So I will be explicit that we're only asking the agent. uh we'll say what routes are available um in my application. Right? So once again without boost it might try to scan your routes file. Um it might try to trigger an artisan command through the terminal but in this case uh it can instead defer to a list routes tool.
So we give that a run. It retrieves the routes and now it's preparing the response. All right here we go. So we have a big massive list of routes that we don't need to take a look at right now. All right, let's do one more together. So, we have this home controller and it loads the home inertia page. This is mostly just kind of generic um just a generic splash page. But why don't we do this? Why don't we say, well, when uh the component mounts, I'm going to do a console. And once again, we'll say beep beep browser um issue.
All right. So yeah, if I have Vit running behind the scenes and I run this in the browser, sure enough, if I bring up the inspector and I go into console, yep, we're going to see beat beep browser issue. Okay, so let's have AI fix this issue as well. When loading the homepage, I noticed in the console there was an error related to beep beep. I'm not sure why. Can you read the browser logs and fix the bug for me? All right, let's get going. All right. Once again, it's going to use the browser logs tool.
All right. It revealed a local error. It knows to check the homepage component. It found a console. In the mounted hook, it fixes it and now it understands that maybe you need to rebuild the project. Notice it knew what the command was. It might be able to figure that out on its own, but we have a guideline for it to let it know uh how to build our assets. All right. And now, yeah, once again, the bug is fixed. Back to the browser, give it a refresh, open the console, and we already know, ignore this, that's just related to an old GIF.
Uh, but the main error is now gone, which is great. Uh, so yeah, all of this factors into the context that we present to AI. And again, just to reiterate, context refers to all relevant data and information and knowledge that we provide to the AI. So this would include the chat itself of course the chat history, the project, the files that we explicitly reveal to AI and of course the MCP servers that we install. That provides essential guidelines and context for the AI to make the best possible decision. So, the next tip I have for you is to nip it in the bud.
And here's what I mean. If at any point AI generates some code or doesn't adhere to a convention that your team has, stop, take 30 seconds, and then update your guidelines file. I know it's kind of annoying, but just do it to ensure that this never happens again. I'll show you an example here. I'm in the Laravel workshop project. You can search for that on Larcast and at the end of the series, we added a readme with some potential suggestions if you want to take it further. Let's do the first one on the list. Implement the bookmarking feature.
When the user clicks a bookmark icon, the user ID and post ID field should be inserted into a new bookmarks table that we create. All right. Add the ability to bookmark a post effectively. So, here's what I'm going to do. I'm going to select this entire thing and we're going to have AI work on this, but I want to show you something. I want to work on a new bookmarking feature. Review this plan and I'll paste that in here. And then I just wanted to do plan mode. I want you to give me some examples for the eloquent model that you will create for this particular feature.
Don't write any code yet. Okay. So, let's uh let's let it run. And I want you to notice, by the way, that I am using the claude agent here. All right, let's have a look. Here's the full bookmark model I would create. So, bookmark extends model. We have the relationships. Sort of what you'd expect. But I want you to notice this section right here, the fillable fields. Now, maybe for your team, this is what you want. But for my team, we don't do this. We call model unguard across uh the entire project. In which case, this is not following my conventions.
So, of course, it takes two seconds to delete that, but I don't want it to ever do that again. So, here's what I'd do. I'd close this out. And if I'm using the Claude agent here, then I would open claude.md. Uh, if I was using if I were using a different agent like Juny, then I would open up the Juny configuration file. And that would be within the Juny guidelines file, and I would update it there. Anyhow, in this case, we're using the Claude agent. So yeah, you'll notice there's no reference here to fillable fields or guarding.
So I want to add my own rules. And I'm going to show you two ways to do that. First up, let's imagine I'm not using Laravel boost at all. In that case, maybe I might even have a blank claw. D file and I could say eloquent. And I'm just going to give it some brief uh instructions here. How about this? Never use fillable or guarded fields. We run model unguard applicationwide. All right. And in fact, if I go to app service provider, you can see right here it says model unguard. Okay, that's it. So now we've updated our guidelines to instruct AI or claude in this case to never use those properties.
Okay, so let's bring this back. Try one more time while reviewing claw.md guidelines. All right, here we go. Perfect. I see the important guidelines. Let me revise the bookmark model. So now I want you to notice it omits the fillable fields entirely. And this is what we want. So here's the deal. You're going to rinse and repeat. You're going to follow this exact step every single time you run into uh even the smallest of paper cuts. If something's not working, then you need to fix it. Okay. So, if you're starting with a blank uh claw.md configuration file or guideline file, this is fine.
However, if you are using something like Laravel boost, then this file will be generated dynamically. In that case, here's what you do. I want you to open up your sidebar and you're going to create a new directory called.ai. And within there, create a directory called guidelines. and then add a series of markdown files, each of which will effectively be appended to the top of this um cloud. MD file. So, I'll show you. Let's go right here and fix the typo and let's add a file. We'll call it laravel.md. And I'm just going to paste this in here.
Okay. So, now I've added custom guidelines. But of course, it's not magical. This doesn't get updated automatically. That will only happen when we run boost install. So let's do that now. PHP artisan boost install. All right. And we can see right up here that's working. So now if we scroll to the top of this file after it refreshes, you can now see that it is appended to the top of the file. All right. All right. So, yeah, just as a general rule of thumb, if you're using Laravel Boost, well, when you fix these paper cuts, always update your AAI directory instead of rewriting this file because, of course, it's going to be overwritten as soon as you run boost install a second time.
All right, next up is prompting essentials. That's what we're going to call this video. So, here's the deal. Uh, you can browse the web and find dozens and dozens and dozens and dozens of best practices, so to speak. Uh, but from my experiences, this whole thing is evolving as the models mature. And what was a best practice a year ago, you don't necessarily need to do anymore. So, I'm not sure how helpful it is if I tell you 48 best practices, but I will tell you three core patterns that you should get in the habit of.
The first technique is to be explicit. And this is precisely why voicetoext tooling can be so incredibly helpful when interacting with AI. It encourages you to be a little more verbose than you otherwise might. And this is a good thing. So for example, if I were not a programmer and I was working on this Laravel workshop uh application, remember it's basically uh Twitter or exclone. Uh maybe if I wanted to add a bookmarking feature, but I wasn't a software developer. Well, maybe I would go to AI and I would say add bookmarking. And you know what, the AI is decent, right?
The agent will review the context. It'll figure things out. wanted to look at the application information as you see here and it won't do the worst job in the world. But again, you're a programmer, right? Maybe the way you interact with AI should be just a little bit more mature than the way, for example, my daughter or my young son might interact with it. Okay, so with that in mind, why don't we abort this entirely and instead rewrite it? Now, here's a little tip. You may find that it's actually a little difficult to be explicit because you haven't yet fully thought through the feature.
And that's okay. No judgment. We've all been there. But in these situations, maybe take a moment and AI can still help us out. And here's how. I'm going to switch to the ask section. We're not writing code yet. We're brainstorming with the AI. And let's do it. Let's ask it to help us prepare a prompt. I'm thinking about adding a bookmarking feature to this application. and I would like some help preparing a detailed prompt. So, here's what I know so far. I know that I want a bookmarks link in the main sidebar. Next, every single post should offer a button that when clicked bookmarks that post for the current user.
Next, there should be a dedicated page to view all of my bookmarks. And that's what that bookmark link in the sidebar should direct me to. And then finally, I think we should make bookmarks private. I can view my own bookmarks, but I shouldn't have access to any other users bookmarks. Can you help me work on the prompt for this? All right. So, there we go. We're going to give that a run. And here's what I want you to notice. At this point, I'm not thinking what are the what are the best practices for prompting I need to include here.
No, I'm I'm just talking to it the way I would talk to a real human. It's going to evaluate this, help me. it might suggest some things and then at that point once I have figured this out a bit more then I can get started on the feature. All right. So it's going to take a look at our application details. Fine. It wants to take a look at our database schema. All right. And already that's getting to work. So while this wraps up I want you to notice how this works and the way an agent behaves.
It's not like it does everything in one go. Instead it's kind of recursive. it will take what you're asking and try to solve the first question. And then once it has solved that question, it moves on to the next thing. What's the next thing I should do? Okay, that's done. Now, what's the next thing I should do? And it keeps calling itself recursively. Uh, which is kind of cool and it's a good way to think of it. Anyways, that seems to be done. So, let's go full screen and see what it came up with. All right, so let's take a look.
We want to implement a bookmarking feature. Here are the requirements. And notice the requirements are quite extensive. It's a full document. And this is great. At this point, I could go over all of it. I can tweak it. Uh I can decide if I like the suggested API that they have here. What do I think about the routing URIs? Uh should there be certain relationships? Uh this is really excellent, I think. Okay. Okay. So now, of course, I'm not going to do this as part of a video, but I could copy this whole thing, tweak it, and then use that as part of my prompt for the actual feature.
Next up is technique number two. Think small, and show examples. All right, so in the first technique, we were rather broad, weren't we? We gave it the full feature request, and we worked on that prompt to make it as targeted and explicit as possible. However, what you might prefer to do is to break that feature into tiny little miniature features that AI helps you with. That way, you remain in control and and you remain the architect every step of the way. So, in this case, why don't we let's do this. Let's get started. I want to begin working on a new bookmarking feature.
Let's create a new git branch for this. And to start, I need a migration for a bookmarks table. I need a bookmark eloquent model and let's see the bookmarks table should consist of a user ID a post ID and timestamps. Yeah. So from this point of view I'm almost treating AI like my my workhorse my assistant here. So it creates a new branch. It's going to create the model for me. All right. And while that's doing its thing, it looks like it updated the migration. So let's just take a look at that right now. create bookmarks table.
And notice it has the user ID and the post ID and the timestamps. Great. Now it looks like it's trying to scan our models. Perhaps it's going to add some relationships for us. Yeah, keep that in mind. It's not always going to stick precisely to what you ask. Uh there are some prompting techniques to help with that, but even still, sometimes it's going to do its own thing. All right, and that's done. So we can see everything that's been done here. Created a handful of files. And by the way, if we ever want to undo everything, we can click this roll back button here, which is actually incredibly helpful if you want to if you want to take a a second stab at it.
Okay, so now at this point, I have a bookmark model. I of course have a create bookmarks migration. And then finally, we have a bookmark factory that contains all of the uh the relevant attributes here. So with that, let's move on to technique number three. My final technique for you is to offer the agent a way to verify completedness. And often a good way to get started is through a test of course. So let me show you. Let's create a new test using test. And we'll call it bookmark uh bookmarking test. All right. So I can open that up now.
All right. So this will mostly be a model test. A post can be bookmarked by a user. All right. And now, yeah, we're just going to write the API that we would love to have, right? So, I could say something like given I have a post and a If I call user bookmark post, then that should be reflected in the DB, right? Something along those lines. So, I'm going to interact with this code the way I want, but it's not actually going to work yet because we haven't written that logic. That's where the AI will take over and implement uh my requirements.
All right. So let's say we have a post. We'll create a factory for one. Next, let's create a user. All right. Next, if I call user bookmark. So notice in this case, I'm just going to interact with that method in that API even though it doesn't exist. Great. User bookmark post. And then what is my verification? And this is really important. This will determine whether or not the feature has been implemented uh the way I would uh expect. And now, yeah, of course, we could do a database check. So, I could say, well, I assert that the database has within the bookmarks table a record like this, right?
So, yeah, this is kind of the um I don't know the manual way we could do it, but it doesn't really verify the API itself. But yeah, we could keep that if we want if it would help uh the agent. I could also do something like well let's grab the user's bookmarks and I'm going to expect to for that to have a count of one right these are the things we can do so again none of this works but it will work in just a minute so let's open up our agent create a new chat I'm going to give it some additional context which is the current file and here we go so I'm still working on this bookmarking feature have a look at bookmarking test where I have created did a test to describe the API that I would like.
Your job is to implement it and you will know that you are successful when the test returns green. Just keep in mind that you should never hardcode values just for the sake of making the test pass. It should always work in a general way in addition to the test returning green. All right. So once again, maybe maybe a little jumbled in my speech there. I could clean it up, but I don't really have to. This should be clear enough. So let's go. All right, that's done. So, let's take a look. If I expand this, it updated looks like three or four files and it implemented the test.
So, let's have a look. Let's give it a run and it returns green. Kind of amazing, right? So, if we have a look at the relationship, sure enough, it knew to add this and then it creates one, sends through the post on the post, it adds the fillable fields if you like. And by the way, if you don't like that, then of course your guideline can be explicit that we are unguarding our attributes. But yeah, here's the key thing to be aware of with this approach. I think of it sort of like developerdriven AI. We remain in control the entire process.
It's almost the polar opposite to vibe coding, right? And it doesn't mean vibe coding is bad. Not by any stretch. It's just a different way of doing things. With vibe coding, you're hitting approve. Approve. Approve. Yep. It's good. I don't care what the code says. Yep. Yep. Yep. Keep going. Right. with this approach. No, we remain in control. We want to know what the API is. We want to define the interface and then the AI is simply our assistant who will implement it for us. Let me know what you think. Now, as a developer myself, when it comes to vibe coding, I don't necessarily want to use it for my real code and my real projects and things that actually make me real money.
I feel a little uncomfortable with that, at least right now. However, where I do very much enjoy it is for personal software. And when I say personal software, I'm referring to tools and tasks and software that is meant for one person. This guy right here. In these situations, I genuinely don't care what the code looks like. I will never distribute it. I will never ask you to sign up. I will never sell it to you. It is only for me and a particular need that I have. Yeah, in those cases, I think V coding is actually spectacular.
So with that in mind, I have a particular unique weird random need that I'm going to vibe code. Come along. I'm going to call it real. All right. So this is a this is a strange one. Come along. But it should actually be fairly easy to implement. So no starter kit pest if we have any tests. And I do want Laravel boost. If we have a database, which I don't think we will, SQLite would be fine. For my code editor, we're just going to stick with PHP Storm here. And usually I would stick with like Juny or Cloud Code.
Yes, install my dependencies. And let's CD in there and open this up in my editor. All right, here we go. So, let's bring up the terminal. And I will initialize Git. Um, just in case I need to roll anything back. Now, ideally, the point is I will mostly just approve just about everything as long as it works. Uh, but nonetheless, it might be useful. So, I'll say initial commit. All right. So, here's what we're building. It's a weird one. So, as it turns out, I'm a really big fan of this video game called Outer Wilds.
It's the only information-based video game I've ever played, which means there's no fighting. You're not killing anyone. And as it turns out, if you can gather all of the information you need, you could actually complete the game in 15 minutes from the very beginning. But the whole point of the game is to travel around and figure out what it is you're supposed to do and what happened um to these aliens um that caused them to disappear so long ago, right? It's so much fun. It's it's a spectacular game. Anyways, as part of the DLC, you travel to this new area, and I don't want to have any spoilers, but I do want you to play it if you're interested.
And uh you're trying to once again figure out what happened, and you watch these reels and slides that guide you to different locations. And then you go to the locations and you find a little more information, and that will guide you somewhere else. So, I'm going to do this very thing for a present for my son. And we're going to do it in the form of sort of like slideshows where he will visit a website and he will have a series of photos that guide him to a particular location where he can get more information.
So one of those websites we're going to build together. Let's go. Just come along. It's weird. Come along. All right. So let's get started. I'm going to bring up Jet Frames AI and I'm going to speak it out. And this might take a moment or so. And I might be a little sloppy, but that's okay. This is real life. I'd like you to build a one-page website that has the sole purpose of displaying a slideshow of photos. Now, this should be perfectly centered. It should be optimized for mobile and incredibly minimal. Don't reach for more UI than is necessary.
At any given time, we should only see one photo. And when we click a next and previous button below the photo, it will take us to the next photo in the in the array of photos that we have available. If we reach the end, it should cycle back to the beginning. Again, to reiterate, I only want a single photo on the page perfectly centered at a time. I want to cycle through the photos as I click those buttons. Now, in terms of tooling, I do want to use Vue3 and Inertia 2. And I'd like uh for any components you might need uh for us to reach for the Shad CN UI uh package.
Uh so get started, use a dark theme and ask me any questions you need to uh as you prepare your plan. All right. So again, notice like I I kind of jumbled my words a little bit. That's okay. In real life, I might go through here and tweak anything. For example, um I believe the website is shad cn- view. um package. It can track that down. Okay, let's go. I'm excited to see what it does here. All right. And fairly quickly, it has a handful of questions. Before I create the implementation plan, I have a few questions.
The photo source, of course, we have to reveal the photos. Where should they come from? Next, in terms of the setup, I notice Vue3 and Inertia are not yet installed. Should I install them? Okay, we will clarify that for the photo dimensions. Should we scale to fit? Yes. Should we have a maximum width? Yeah, this is very useful. And notice it's asking these questions because I was clear that I want it to ask me questions. Remember, sometimes you you have to be verbose in your instructions or sometimes it'll just figure it out for you. And often it'll do uh something that you don't necessarily want.
All right, so here's what we're going to do. First up, I'm going to copy over the assets. So, I have these stored within my home directory, and I think I call them, yeah, outer wild assets. And I'm going to move it into an assets directory within this project. Okay. So, if we take a look real quick, now I have assets, and we have some slides and some background music. So, actually, with that in mind, why don't we just take both of these and move them into my public directory. All right. Next, I'm going to answer these questions, but I'm not going to make you watch.
So, I will answer them and then review them with you and uh quickly submit it. All right, so I've answered these questions and yeah, very quickly, here's where the photos are stored. They're numbered. Uh because we're vi coding here, I don't care too much about manually installing things. Uh but just note for real life and for real projects that are not vibe coded, generally my approach is just to manually install whatever tools I want AI to reach for. But in this case, it just doesn't matter. And then finally, photos can be a maximum of 1200 pixels uh or 90% of the viewport width.
and that will handle mobile optimization. And then finally, nav. Uh the the navigation buttons can just be icons. So, I'm going to turn on brave mode so I don't have to approve everything. And again, I just don't care too much. And we'll give this a run. All right, it looks like it's done. So, I'm not going to lie, I'm a little bit excited. Uh it's always fun. You never know, are you going to get something incredibly impressive or not quite right? And yeah, don't forget in terms of the code itself, uh the entire philosophy is we don't necessarily care what the code looks like, but of course as programmers sometimes it's fun just to take a look.
So it has a slideshow here. It somewhat verbosely is reading those files and sending that through to a slideshow component. The slideshow component is using the composition API. Very good. It's getting that from the boost guidelines. It accepts some photos. It tracks what the current one is. It has buttons to to increment it basically. Uh it is using shad CN. So notice it's pulling in a button component that is again provided uh by shad CN as you see here. Not necessarily needed but just for fun. Um it looks good. So I'm going to take a look in the browser.
Okay. So if we load real.est immediately I can see an issue. The photo is simply too large. And maybe this is my fault because I think it did honor my requirement. Yeah. Notice the photo is 1200 pixels, but maybe I should have been clear that I still want to contain the entire photo within the viewport. So that's something we should fix right now. All right, back to the editor. I checked the website and the first thing I notice is that the photo is simply too large. So yes, you maintained a maximum width of 1200 pixels.
However, I want to display the entire photo within the viewport without the user needing to scroll. All right, let's see if it can fix the issue. All right, that's fixed. So, if I switch back. Perfect. Nice and easy. All right, so now you can see how this works. So, we have these like owl/mooselike creatures. And the way this works is I actually photographed my wife in real life and then we swap her out with um a version from the game. Okay. So, now I can cycle through here and you can see there's a blue lock box and we hand it to him and he goes up the stairs.
Okay. And he goes into the green room and then he opens something and then it repeats, right? So you get just a glimpse of there's a lock box here and where did it go? It looks like it got put into this secret compartment area and then he will find that but then he also needs a key and the key will be located somewhere else and he has to gather these clues. That's the way it works. Okay, so this is working but next I want some some creepy background music. So that's my next step. Great. Um, I'd like you to add background music now to add a bit of mood.
When the page loads, we should instantly start playing the background music. And you will find it within the public directory. I believe it's called bg-music.mpp3. All right, good enough for me. Let's see if it works. All right, and that's done as well. So, let's scroll up and we can see an audio element with autoplay and loop attributes was successfully added to the slideshow component. So, let's look for audio. And there we go. It's referencing that file. It loops and it automatically plays. So, let's try that one out now. So, we reload, but you know what?
It's not going to work. And I think this is because modern browsers will by default mute audio like this just for better, I don't know, security and user experience. It's a little annoying in this case, but you know, it's probably a good idea to mute it. So, let's see if we can fix this. Let's switch back and continue. I don't hear any audio when the page loads. And I assume and imagine this is related to browsers automatically muting it by default. So, can you find a way to trigger it perhaps with the press of the initial uh next button?
Maybe that triggers the audio. And again, noticing like I'm jumbling my words. It's okay. Uh, usually it will figure out what you want to do there. All right. So, hopefully that fixes the problem. Let's give it a shot. So, now when I refresh and hit the next button, that will start and keep the audio going. Let's go. and then it resets, right? Really fun, right? So, yeah, in this case, we have to have a user interaction to trigger the audio. By default, the browsers are going to mute it because otherwise, you know, websites will just get incredibly annoying.
All right. So, this is actually a really good example, by the way, of how having some existing programming knowledge is incredibly helpful even when you're vibe coding. Otherwise, if I have no experience, the best I can do is constantly lean on the AI. And all I can do is say, "Hey, didn't work. Sorry, I don't hear anything. Didn't work. Try again." But because I have some experience, I know how the browsers act and I can say, "Hey, I think this might be the reason why we're not hearing anything. So why don't we hook into a click event so that we have a user interaction to start the audio.
Right? It's incredibly helpful even when you're vi coding and you don't necessarily care about the code being written. All right. So now I just want to finish up with one more thing. I have a background forest image here and why don't we see how that looks as the backdrop for our slideshow. So let's go. This is looking very good. So finally I have a bg-forest.jpg file within my public directory. And let's see how that looks as the background for the entire web page. Now I'm thinking that image might be a little too prominent. So perhaps we should lower the background opacity to 25% or so.
Next for the background image, maybe uh contain it or or have it cover the entire page. I don't want any awkward borders where the image cuts off. All right, maybe a tiny bit verbose, but it's fine. It should work. All right, that's done. So, let's take a look. And yeah, I mean, we're not going to win any design awards, but this looks good to me. So, now we have our mood, we have our slideshow, we have our background music. I think this is complete. Okay, so now here's what I would do in real life. I'm going to push this up to a Forge uh server I have.
That's going to give me a free onforge.com URL and I will then share that with my son as part of one of his presents. Remember, there's there's multiple clues that he has to open. So, he opens a present and he sees a mysterious webpage URL and when he visits that on my phone, he has a slideshow that leads him to the next clue. Okay, so in the last episode we vibecoded a project from scratch. And again, that's incredible for things where you genuinely do not care about the code quality at all. It's irrelevant. But now in this episode, we're going to take a slightly different perspective.
I think of this more as developerdriven AI. Come along. So here I have a fresh installation of Laravel and yeah for this demo here's what I want to do. Let's set up a telegram bot so that we can interact with our application through a telegram chat. Let's get going. We'll start with Juny here. I'd like to set up a telegram bot for this application. And here's how I imagine it working. I start a chat with a bot that we create on Telegram. And when I send it a message, that message is posted to a web hook on my server.
The server receives the message and it parses it to determine which action to take. It performs that action and then it replies or returns a response to my telegram chat. So I want you to start working on a plan for this and then we'll get started. Okay. So this is fine for the initial plan, but I'll give you a little tip. Often when you're working on features, uh sometimes it can be cumbersome to go through the chat. So often what I will do is this. Once you have a plan, I want you to write the contents of that plan to a file called telegram.md within my project route.
Okay, so yeah, it's just going to make a plan and write it to a file so I can review it with a fine tooth comb. All right, that seems to be done. So it has a detailed Telegrambot implementation here and uh let's go over this together. All right, we'll do this side by side. Hi. Uh Telegrambot implementation plan. All right. Architecture user sends a message to the bot. Telegram sends a web hook. Good. Laravel recognizes validates the web hook. Application parses parses the message. Good. It executes the action. So it parses it, figures out what are we trying to do here?
Are we refunding an account? Are we sending a coupon? Are we updating a record or something? Uh, executes the action, sends the response, user receives the response. That's that's the flow we want. All right. So here are the implementation steps. And yeah, this is where it's different from vibe coding. By the way, with vibe coding to a certain extent, you just don't care. It's like whatever it makes is what it makes. If it works, it works. And if it doesn't work, then you update the chat and you say that didn't work. Right? This is a little different.
I want to be involved every step of the way. I I don't want the codebase to end up in a state where I do not understand any of it. I very much want to avoid that. So before it writes any big feature like this, I'm very much involved. I'm going over every step. If I'm reviewing what the controller name is, what the route is, how it goes about it, are we using caching? Uh which package did did we pull in? I want to be involved every step of the way. Okay. So anyways, uh implementation steps.
Create a new bot. This is correct. Save the bot token. Fine. Uh so it's like a token to interact with your Telegram bot uh or the API. Set up a web hook. Correct. Okay. Store web hook secret. All right. Okay. So now we're just setting up environment variables. Fine. Database schema. So they're actually storing this within a database. Yeah. So this is another good example. Like I didn't necessarily say that I want to store the chat within a database. Uh that might be useful for the future, but I didn't ask for that. It's just making assumptions, which is why we start with a plan before the AI gets to work.
All right. Because I don't necessarily want uh database here. All right. Next. API routes. That's fine. Um. Yep, that's what I would do. Uh, no CSRF protection. That's why you put it within your route API file. That's good. Here's your web hook controller. Fine. Um, middleware. So, it wants a middleware that basically validates that the request is coming specifically from Telegram. Fine. Um, next. Yeah. So, it's it's building up a command parser, a command handler. Yeah. I mean, these are terms that you often use. um when building a bot like this. But notice it's sending a little alarm bells for me.
I'm seeing a lot of programry jargon which I don't necessarily love. But command is fine. But yeah, like handler interface and like we're just building a simple bot chat here. We don't need to get too crazy. Anyways, let's keep going. This is why we do this. Uh the handler will have a handle method. Next, it's going to create an API client and it will use the Laravel HTTP client to communicate. Fine. It's going to have messages like send message and send photo. Yeah. So, what you can see here is it's basically building the entire functionality and interaction and client from scratch.
Maybe it should have considered that there are packages already available that will do this better and um more bug-free than we might um than we might do. All right. Next, it has a job to process Telegram message. It has form request to validate the incoming request. Uh service provider to register um maybe our middleware and the client. We got a bunch of artisan commands. Set web hook command. Get web hook delete. I I hope alarm bells are going up for you as we do this. And this is again the distinction between what we might call developerdriven AI versus vibe coding.
We have some exception handling. We have some tests. That's good. It's just Okay, here's the deal. We're at the end. I like I've already lost interest because I think we can hopefully all agree it's too much. We're we're building a simple little feature here and this is like a whole thing. This is a whole thing and I don't want it. So, this is why we need to very much be involved in the entire process. So, here's what I'm going to do. We're going to go right back to the AI and work on a new plan.
So, I've reviewed your plan and I've come to the conclusion that it is drastically too complex. There's way too much going on here. You didn't review uh or you didn't consider the possibility that there are dedicated composer packages that will wrap all of this functionality up so that we don't have to write it out by hand. For example, I'd like you to take a look at the nutgram composer package, which I believe offers a very nice and clean API to um interact with Telegram. And I believe they offer a feature where we can register dedicated commands um so that from the Telegram chat, we could just say slashreund email and then we can register a command to respond to that.
So again, I want you to note that your current plan is too complex and too verbose. Your job is to simplify this, make it more clear, and pull in a dedicated nutcram package through composer to simplify this drastically. Please work on a new plan and update telegram.md. All right. And it's going to give it another try. All right. So now yeah while while this is doing its thing yeah I just want you to consider that if we were vi coding this we would have just approved approved approved and look it would still work and maybe the future is just the quality of the code doesn't matter really at all but right now to me it does matter and if we took a v coding approach for this feature it would have been too complex and too verbose way more than is necessary and what about the next feature and the next feature very very quickly you can end up in a situation where every single feature is like five times more verbose than it needs to be.
This is why as developers our job at this point is to very much be involved uh in the process. All right, so now we have an updated Telegram file. Let's take a look and we're going to go through this very quickly. So now it's using Nutgram uh spelled awkwardly. It wants us to pull in. All right, so it figured out we're using Laravel and there is a nutgramarl package. It knows that we can create telegram commands. Next, you can see it's recommending in a service provider or a routes file to register the command and it's doing it all inline.
We definitely don't want to do this within a service provider. We can create a dedicated route/telegram file. So once again, uh we'll need to update that. Let's keep going. Um all right. So it is detecting that there are um dedicated nutcram specific commands for registering web hooks with the telegram API. much better than what we had before. Uh for complex commands, uh commands, create dedicated handler classes. So yeah, we register the command. And yeah, real quick, if you've never done this before, in Telegram, you can do things like this where you say slashreund, that's the name of our command.
You would send through an email and this would get parsed by nutgram. It would detect that we're running a refund command and it would trigger the handler and pass through the associated email. But yeah, even in this case, like this is too much as well. It's just parsing the message text to figure out the email. Um, we can use wild cards for that. And then for for some reason, it's not picking up on that. All right. Next, uh, we register it, how to handle it, testing. Yep. Okay. So, this is using the API. All right.
There's a few issues here, but this is 10 times better than the first plan it came up with. Okay. So, we'll make a slight tweak here, and then we're going to get started. But real quick, it's important for me to reiterate. Look, if we had run that um that initial chat multiple times, sometimes it might have pulled in nutgram immediately, right? Sometimes it might have written the claim out from scratch manually with no dependencies. Sometimes it might have found a different uh package or SDK or something like that to pull in. So that's why you want to be a little bit careful.
And sometimes it can be useful to try two or three different approaches and then work with AI to choose the best implementation and we can talk about that in the future. Okay, anyways, back to the chat. I think this is significantly better. Good job. Uh, one thing I did notice is that when it comes to the command uh, parameters, you're still parsing them and using explode. uh have a look at the nutgram documentation and you will find that we can accept wild cards to our nutcra commands in the same way that we can accept wild cards for Laravel routes.
So I'm going to link you to that. I want you to review it and then I want you to update the plan and then you can get started. Okay. So very quickly I'm visiting nutgram.dev. Let's go into the documentation down to um handlers perhaps and we're going to look for parameters. Yeah, here we go. Here's an example. So, we can register um listen for text or even a command. And notice that it can capture wild cards and those wild cards are then sent to um the the handler or the callback. So, I'm just going to copy this and include it with our chat.
Review this documentation. Okay. So, now it has updated this file and yeah, let's see how it's going to prepare this. Yeah, this is what we want. It accepts the email address as the wild card that is received within the handler. Uh it does some validation. That's fine. Next, it has a section on order. That's fine. It doesn't really know what we're working on. We can tweak that ourselves. But this looks uh fairly good. So now what I think I'm going to do is create a brand new chat just so we can truncate things. And I can say read telegram.md plan and implement.
It has everything it needs at that point. And by the way, just to show you that we can mix and match agents. Yeah, there's nothing keeping you from uh implementing this feature in both Juny and Claude. And then you can review uh the results. All right, it looks like that's done. Now we can see all the to-dos have been completed. Okay, so if we take a look at our project, we have a new Telegram folder. We have a help command, a refund command, and a start command. That's fine. You'll see if I scroll down, we have a test for telegram um command tests.
If I give this a run, they all return green. We should also have a routes/telegram file. And this is where we register our commands. Notice bot register command uh start command, help command, refund command, and then we have a fallback if we don't understand uh what you want. Perfect. Next, let's go into our environment file. And there should be yeah we have a telegrambot token that it is currently waiting on. Good. Uh what else? Let's go into our route. Did it not create one? No. So yeah, this is just such a great example. It did most of what it said it would do, but it didn't complete the job.
So it entirely forgot the portion of uh registering a endpoint to receive the web hook. So in these cases, what we would do, and this is why we call this developerdriven API, is we could create a new file manually, and we're just going to pair with it. We'll say route. We're going to listen for a post request to uh Telegram/webhook. And let's see if we have any controllers within here. Uh HTTP controllers. Nope. So let's create one now. Let's create a Laravel controller. We'll call it Telegram web hook controller. All right. So now let's accept the nutgram bot.
And yeah, here we could just say something like bot run. And why don't we make this uh an invocable controller. Yeah. And that's basically it. So now if we switch back to route API, yeah, we could we could defer to that. And of course, yeah, if you want, you can add whatever middleware is necessary. So for example, if you want to throttle it um as a protection uh if you want to limit it to a particular uh user or telegram user only, all of these things can be done. Okay, so now we have a route.
Let's register that and we can do that right here. Our API specific routes will live here. Again, these will not receive CSRF um protection or things like that. Okay, so now I don't want to leave you hanging. I at least want you to see something here. So, let's quickly register the bot on the Telegram end. The first step is to visit Telegram and search for bot father and start a chat. Okay. And one of the commands we can do is register a new bot. So, notice how we we use a command forward slash and then the name of the command.
For our project, we'll have forward slash and refund or forward slash and coupon, stuff like that. Okay, let's make a new bot. We'll call it demobot. Next, we need a username. It just needs to end with bot. Why don't we say LC for Lariccast demo_bot. All right. And now it's going to give us a unique uh Telegram token. So, we can copy this. Switch back to our project. Go intov and I will paste it here. So, yeah, generally what you might want to do is set up one bot specifically for your local testing and then a different bot uh for your production.
And that's one way that you can handle things like this. Okay. So now if we open up our terminal uh let's run php artisan and you will see that there are a bunch of nutgram specific commands we can run. So the ones I want you to focus on right now are nutcram listen. This starts the polling for local development and then also nutgram hook set which will set the bot uh web hook and it's basically our way of saying all right telegram here's the URL that I want you to ping whenever a new message comes in.
And again to reiterate that happens uh for production. Finally notice nutgram register commands. This is what tells telegram about all of the commands that we have registered within our routes/te telegram file. So in this case we would have three. Okay let's do it. PHP artisan nutgram register commands. Good. Next let's do php artisan nutgram listen. All right, it's running. So now let's try a chat. I can click here to chat with our bot. And welcome to the order manager. Yeah, it's just assuming we have orders here. And we could have been more specific. So I I might start by saying gibberish.
And this should hit the fallback unknown command. And that's happening because if I switch back right here, we have our fallback command. All right. So let's see what happens if we run help. I can say forward slashhelp. And notice by the way this will list all of the commands and these are available because we ran that register commands uh artisan command and yeah we can see three different commands we can run and yeah just to reiterate they are defined here. All right so here is our start command we register it here we add a description and then we add a handler.
Okay so I want to show you some other things in the next episode but here's what I want to leave you with. I want you to notice how if we had just vcoded this project, it would have used the first implementation which is like building everything from scratch and creating all of these command classes and handler classes and client classes and it's just not necessary. So we had to work with it to guide it in the direction that we care about. And that's our job as developers to review this plan and constantly tweak it and constantly let AI know when it's going too far out on a limb and when to rein it in.
All right. So, there's other stuff I want to show you that is somewhat related to this. So, let's keep watching in the next episode. All right. Here's one thing you will often run into. Sometimes an agent will be interacting with maybe a package you have installed and it just doesn't know that much about it. Sometimes it'll just guess or sometimes it'll scan the web and try to find some article that could potentially be wildly outdated. We've all run into this many times. So, one way to get around to this is to leverage a tool like Context 7.
Have a look. Yeah. So, Context 7 provides up-to-date documentation for LLMs. So yeah, you can see, of course, it has support for all of the most popular tools, but even smaller packages, maybe you're using like a a spoty library, and maybe you want to give it up-to-date information on how to generate images, then you could pull this in, which is really cool. So, I'll show you an example. Uh, I use a package for interacting with a Telegram bot. Uh, it's a composure package and it's called Nutgram. So the first time I interacted with my agent, it just didn't know that much about it and it made so many mistakes.
But I could enhance its skills by basically saying, "Hey, here's the documentation. Go learn it." And only at that point should you proceed. So let's see how we can make use of this. Let's open up NetCra. Or actually, let's go into the documentation. And if we scroll down, we can see a context summary of how to use it. This is all incredibly helpful. Okay, so we can sign up for a free plan. Once you do, you can go to the dashboard. You'll see I already have an API key here, but let's just generate one on the fly.
All right. And I'm going to copy that and then delete it at the end of the video. All right. Next, we need to connect it to PHP Storm and Juny if we're using that or Cloud Code. Just find the one you prefer. So, in our case, let's see if we have something for Jet Brains. Let's see. Here we go. I'm going to look for Jet Brain. There we go. So, all you have to do really is set up the MCP server. So, here it is. I'm just going to grab this and then we can use this with um with Juny or really it'll work uh anywhere.
Okay. All right. So, from PHP Storm, I will open up my settings and we're going to look for Juny. So, remember this is Juny specific MCP settings. If you're using claw, then you would need to add it um the way they suggest on the website. All right. So, we're going to add a new MCP server and we're just going to paste it in right here. All right. So, notice that we do need to provide an API key. So, I will update this with the one we just copied and generated like so. All right, there it is.
So, that should do it. And by the way, whenever you set up an MCP server, always make sure that you have it activated there. Okay, and that's it. Okay, so now all we have to do is ask Juny in this case to use it like this. I'd like you to review my Telegram bot code that leverages the nutgram uh library. use context 7 to confirm that I'm following best practices and let's say C app services folder. All right, that's it. So the key here is that we said use context 7. That's like the trigger. All right, let's go.
Okay, so it's read some files and here is the key prompt. Can it use the context 7 MCP server? Yes. So, it's going to figure out what the library ID is, and then it's going to query the up-to-date documentation as you see here. look together. All right, so it changed a handful of files. I've reviewed the Telegram bot implementation, applied several improvements following Nutcra and Laravel best practices. Great. So, yeah, uh I was using a standard Laravel middleware, but actually, uh Nutcra has its own concept of middleware built in. So it looks like it implemented that and it applied uh that global registration within our telegram routes file.
So real quick I'll show you. Let's go in there and yeah now it registered and authorized admin middleware as part of nutgram and it figured that out because of the documentation. Okay but anyways what else? Uh it updated our tests some of which were failing. It ran pint. It did an architectural review. It's reviewing my Telegram surface class. It's a useful abstraction for sending outgoing notifications. Correctly wraps the Necro instance. All right. No major refactoring was okayoo. Good. Uh but yeah, you get the idea. So I know it seems like a small thing that may not be necessary.
Trust me, especially for some packages, without it AI is sort of flying blind or it's going to search the web and try to find something to help it. And so often that information is wildly out ofd or doesn't match the current version you have installed. So definitely consider something like context 7. Now because Jetrains AI supports claude as one of its agents, well that means we have access to clawed features. For example, let's take a look at the terminal and boot up clawed code. And if I hit forward slash, we can see all of the various built-in clawed commands that we can run.
Now, you maybe didn't know this, but you can also write your own custom commands. And don't worry, this isn't this isn't a scary thing at all. Really, a command and claude is just an alias for a prompt that you frequently write. It's just not much more complicated than that. I'll show you a couple examples. Back to my editor. If you've ever run claude code in your project, you will have aclaude directory as you see here. Otherwise, just create it on your own. Within here, we're going to add a new directory called commands. And within here, let's create a markdown file that represents again some kind of prompt that uh we frequently write.
Why don't we call this one, let's do something simple to start. How about learn? So, just to get us started and to demonstrate how incredibly simple this is, I'm just going to say something dumb like all you need to do is say hello to me. Do nothing else. Yeah, that's it. Just to get us going and to show you you can add front matter if you want, yl front matter, but you don't have to. This will be fine. Okay, so the simple fact that we now have a commands directory with a single command, that's all we need.
It will now show up in claude code like this. Let's boot up claude one more time. And if I hit forward slash, sure enough, the top option is learn. All you need to do is say hello to me. All right. So notice that is taking the place of the description. But of course, we could add some YAML front matter to to be explicit about that. Anyways, if I give this a run, it's going to read that file and do what it says like a prompt. That's it. And it says hello. So it really is incredibly simple.
All right, let's add if you want a YAML front matter. If you're not familiar with this format, it is three dashes at the top of a file. Often it's used for static blogs and things like that to declare meta information. So in this case, we can declare the description, a simple demo greeting. All right, back to Claude. Boot up Claude one more time. Let's review our commands. And sure enough, now we are setting the description. So you get how that works. Okay. So now why don't we say I'm going to type learn and I want um Claude to teach me about that file and how it works.
So maybe something like this. And I'm just going to paste this in to save ourselves some keystrokes. All right. So we're going to explain a file or simple in plain English. Uh your senior developer explain the purpose of whatever I pass in. And notice I can use just simple common uh references here like dollar one to reference the first argument you pass in dollar two to reference the second argument. And it's probably familiar to you. Anyways, if the argument is a file path, summarize what it does. Uh if it looks like it's a function or a symbol, describe its purpose and then give me three quick things to check next.
And that's it. So again, um you know what? This actually might be more useful than you'd think. Okay, so let's give it a shot. Why don't we go into app Telegram and learn about help command? Let's just figure out what it is. Okay, so back to the terminal, open claude. I want to learn about help command. There it is. We'll give it a run. So notice this is effectively an argument and that will be sent through as dollar one. It's going to read that and explain what the file does. All right, and we're done. So, help command is a Telegram bot command handler that responds when the user types hello blah blah blah.
You get the idea. And then at the bottom, this is kind of cool. Three things to check next. Well, here's two other commands. And then also an app service provider to see how Nutgram discovers and registers the command handlers. Okay, pretty cool, right? Uh maybe we could do one more. Let's learn about how about uh Bootstrap.php. All right, that's done. So, we're going to go super quick. Uh, Bootstrap file, central configuration hub for Laravel. Uh, this is how we use it. Here's the entry points and maybe some other files you should check out next. It could be helpful.
Okay, let's do one a bit more practical now though. So, if I open up composer.json, JSON. Yeah, you'll see within the script section, I have added a composer script called format that simply defers to recctor and then PHP stan and pint. Uh it's a good habit to get into. Just run these whenever you're working on a commit and you're ready to push it up. Okay, so you'll remember in the what was it the developerdriven AI episode, we had AI work on some Telegram commands, but notice it's not honoring our formatting. So, of course, we could update our guidelines, but every once in a while, it will ignore those as well.
So, it would be nice if we could ask AI to always run this. So, here's one thing we could do. We could register it as a command right here. Create a new file. We'll call it format. All right. So, I'm going to paste this in. You don't want to watch me write this out by hand. It's a little painful. Uh, but we now have a a format command that will format, test, and prepare for a git push. It'll do that by running that composer run format uh script. If PHP stand triggers some kind of warning, it needs to fix the issue and then rerun until everything passes successfully.
And then I want it to run test. Now if the tests fail, it needs to fix the tests and then rerun composer run format just in case any discrepancies were introduced. Yeah. So again, this is the sort of thing that we could paste into a prompt ourselves. And maybe you've done this many times where you say, "Hey, do this and then this and then this." Right? Well, with a command, we're just wrapping it in an alias of sorts that we can trigger, but also the AI or Claude can trigger itself. Let's give it a shot.
So, if I open up help command, I just want you to notice that the formatting is not correct. So, we boot up Claude, run our commands, and here is format. All right, and that's done. So, take a look real quick. It ran our format script. It ran recctor and all of that stuff. It ran pint. Um then it ran our test suite which returned green. Here are the results. It fixed some files. Pint fixed some files. There were no PHP stand issues. Uh this is great, right? And here's the cool thing. Yes, we can we can…
Transcript truncated. Watch the full video for the complete content.
More from Laracasts
Get daily recaps from
Laracasts
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.









