Transcription: OpenAgents Episode 127 - Hello OpenPress
June 9, 2026 ยท View on GitHub
Source: https://x.com/OpenAgentsInc/status/1841932736384139366 Wiki source: https://raw.githubusercontent.com/wiki/OpenAgentsInc/openagents/Video-Series.md Media title: OpenAgents - Episode 127: Hello OpenPress We build a basic @laravelphp blog and l... Upload date: 20241003 Transcription model: gpt-4o-mini-transcribe Generated at: 2026-06-01T16:40:18Z
Machine-generated transcript. Review speaker labels and wording before using this as quote-grade source material.
[00:00] Speaker: Okay, let's launch an MVP of OpenPress in this video. So we went domain shopping, we got OpenPress.ai. The example site I wanna do for this project of mine, Atlantis Ports, we'll do that second, but first we need a website for OpenPress itself. So let's set up OpenPress.ai. Obviously, we'll set it up as an OpenPress website. So I've deployed this currently, what we did in the last video up to Laravel Forge at OpenPress.ai. You can even log in and register. This comes with the default Laravel stuff for profile, update password, delete account, just like a little profile area, a little dashboard, and the login screen. The one change that I made since the last video was I replaced the React and Inertia with just Blade and Alpine, just to like even further simplify the stack, and we can revisit React later, maybe. But I'm thinking we're gonna, we're doing Laravel, so it's gonna be a little bit different patterns than the raw PHP of the WordPress code base, but I think generally the less that we depart from that, the better. So I think we'll try to keep as close as we can to kind of like bare HTML, CSS, JavaScript served by PHP. Okay, so let's go through and add the most basic functionality to this, which is basically that I, as a user who's an admin, or we'll call them editors, I wanna be able to make a post and see the post here. We'll put a little hello OpenPress blog post there. How I usually try to code Laravel projects is a method that I learned in this, I think it's like an eight-year-old course at this point, called testdrivenlaravel.com from Adam Wathan, who's a big Laravel guy, now founder of Tailwind, but this course, you know, has taught me a lot, and I try to kind of mimic the pattern. So one of the first things that you do is you kind of sketch out what you are going to do, starting with the core feature and not worrying about anything tangential, like, I don't know, auth system or user setup. So I put a little, that's not updated, I guess I gotta push this up. Let's do this. Okay, oops, I was looking at the wrong branch. Here it is. So we have this little doc here. We've set up a fresh Laravel V11 repo with Laravel Breeze, Tailwind, SQLite, Pest. We wanna implement the following features via test-driven development using Pest. Relevant models are user and post, unit tests. User can be an editor, user can have many posts, and then the feature tests. Editor can create a post, non-editors cannot make posts. Individual posts are visible publicly at this URL. A list of all posts is visible at this. Editors can see the homepage. So this is an example of a spec doc, and in a minute, you're gonna see me, like, massage this with working with our coding agent to, like, build this directly into our GitHub repo. As we go along, if there are other features that anyone in the community wants to see added to this, I mean, you're welcome to, like, code it up and submit a PR, and we'll figure out contribution guidelines or whatever, as needed. But if you just have, like, an idea of something that you wanna flesh out or something that you would like to see built, you could just, like, write a little spec doc and, you know, throw it to me. I'll make a video about kind of working with the agents to build it quickly. So basically, I'm gonna feed this doc to our agent and, like, let's get it working. So I'm gonna do one thing first, is this post model doesn't exist, and I'm gonna use the Laravel make model with a migration and a factory for post. And then just to kind of help out the model, I'm gonna say, here's our post info. Okay. Push that up. Now, I'll go to open agents. I will start a new chat. I will make sure that I'm on the setup branch. And let's first do, let me get the relative path to this. Read and summarize in one sentence, just to make sure that it is working. Okay. So, what I wanna do is have it look at an example test. So read this as an example of pest test structure. Do I have a relevant unit test too? I'll do this here. Read these two files as examples of pest test structure. Then write all of the tests for functionality described in the doc. This is such a great flow. LLMs generally obviously have, like, sped me up as a developer. I've been using ChatGPT since day one until a year ago. Started building my own things when Claude's three models came out first. Built my own interface at OpenAI.com to let me use GPT-4 or the Claude models via an interface. Claude Artifacts came out. That was then the most productive thing. So we used that for a while until I figured out how to create a new interface, this one here, where instead of me continually copy-pasting Claude Artifacts, I just took the Sonnet model 3.5 and connected it directly to any given code base with GitHub. And, you know, you get what you see here. This saves me a lot of time. And then the next version of this that we're working on now behind the scenes called version 3 allows for a little bit more long-lived of agents. So this still is not always perfect. You gotta go in and, like, review it and stuff. But as a general rule, it saves me a lot of time. And I spend more time Git pulling than Git pushing these days. So, okay, so it made us two tests, feature test, post test, and the unit test. So let's take a look at it. So for the unit test, user can be an editor. And then it makes some decisions here about, like, do you want this to be a database field? Do we want this to be a database field? Yeah, maybe. User can be an editor. A user can have many posts. Looking at it, I would say that this looks great. This part isn't even needed there, but. Okay, let's take a look at the feature test. Editor can create a post by posting to this API endpoint. That's logical. Assert a redirect, blah, blah, blah. Not editor cannot create a post. Individual posts are visible publicly at this URL. A list of all posts is visible publicly on homepage. Yeah, that's pretty comprehensive. I'm sure there'll be other things that we'll want. I kind of let it brainstorm earlier about other things that we might want for things like non-editors cannot edit posts, blah, blah, blah, blah, blah, pagination. We're going to start with the simple core meat of it. I want to be able to make a post. Okay. I don't think we have a test here for like a form to do that. Maybe we'll do that next. Okay, so let's start by this. We currently have, well, obviously the post test will fail, but we have 26 passing tests from like the default ones that we get for authentication and the profile test that came out of the box. So we have six failing tests. Now watch this. Thanks. Now write the code to make the tests pass. Make sure to, maybe I don't need to do a make sure. Sometimes I need to do a make sure to like, make sure to look at existing files. Sometimes you gotta massage a little bit. So first let's update the user model to include the is editor attribute and the relationship with posts. Update the user model. Creating the post model. Yeah, that's where I should have reminded it to, like I put in the doc originally the links to the post stuff. So hopefully it wouldn't need to do that, but you can see that it like makes an error, but then is able to recover from it. That's quite nice. Let's create a post controller to handle post related actions. So for anything, you know, when you get into more of the like advanced stuff, sometimes the models kind of choke more often, but for basic CRUD setup, particularly in Laravel app where there's a lot of kind of opinionation and you're kind of set up for success. These kinds of like iterative basic coding agents are quite effective. And you know, what is a given WordPress site? It's really a big CRUD site more or less. Create, read, update, delete. You know, if I'm thinking about like ways that I would love to see improvements on this interface is like, as it's making these files, I'd love to see little like HUD windows pop up with the code and then kind of fade out. But you can see with this interface, we're kind of making it a little sci-fi HUD thing. I want you to feel like you're Tony Stark controlling Jarvis, you know, that's the objective. I gotta add voice to this soon. Okay, so let's see what it did. Here's the summary. We updated the user model to include the is editor attribute. All right, hang on, hang on, hang on. And the relationship with posts. Created the post model with the necessary attributes and relationship to user. Created a post controller to handle post-related actions. Indexed, show, create, store. Updated the web routes to include our new post routes and changed the homepage to use the post controller index method. Created views for posts, index, show, create. Updated the user factory to include the is editor attribute and added an editor method to create editor users. Nice. Nice touch. These changes should make all the tests pass. The functionality that we've implemented includes users can be editors controlled by the is editor attribute. Users can have many posts through the relationship defined in the user model. Editors can create posts checked in the post controller store method. Individual posts are visible
[19:59] Speaker: Register. Let's see, I need to make myself, well, let's see, I guess this is a list of posts, but I don't have, apparently I have an endpoint to make a test, make a post, but I don't have a form. Now, sometimes when these chats get too long, I need to like make another one, make another chat, just because I'm not properly handling super, super, super long conversations. But I think maybe what I wanna do first, let's do some tinker. So this is just the little like PHP environment here. What can I do? So user, let's see if I've got my first user in here. Yeah. And then, so let's create a post. And what do posts need? So let's just do post equals post create user ID one. I don't know if this will work. I don't know if our fillable guarded stuff is set up either. Hello world. Content equals, it works. Maybe? Class post not found. Okay. Gosh, I don't even know what the command to go at the beginning of the artisan line is. Okay, so let's do app models post. Okay. We've created a post in the local database. All right, everybody. Are you ready for the first post? Boom, it works. Posted by Chris. We've got a blog, everybody. Ship it. Okay, so we have a list of posts. Let's do that one more time. And we'll do content. Let's make another one. Okay, reverse chronological order. You know, we'll add timestamp and all that stuff. Okay, so obviously this is ugly and I'll separately clean it up stylistically. What do I wanna be able to do? If I am a editor, I wanna be able to see a post create form. So now add test, then functionality for a create form visible only to editors. Now, hopefully, that by this point, it has enough context that it can just do both test and functionality in a single chain of stuff. So, you know, OpenAI, which we're obviously positioning ourselves as a open competitor to, was just valued at $157 billion. And their whole new like 01 model is like this reasoning model that can like take all these multi-step actions, but they don't show you what the actual chain of thought is. They hide a bunch of that stuff from you intentionally. They say they hide it from you for various reasons, including competitive reasons. Like, okay, that's bullshit. We have basically a chain of thought and action here. You can see the steps that the agent is taking as it reasons its way through. And I really feel strongly that every intermediate step that the agent takes should be transparent, visible, you know, editable. That's really important. So, you know, you can spend billions of dollars doing their like fancy reinforcement learning version of stuff. I mean, or you can just kind of use the models paired with tool loops. Okay, so here's a problem. One of the issues is that the training data for Laravel, like this kernel path was changed in the most recent version. So now you need to create the editor middleware. Okay, create editor middleware. And then I think, so I'm gonna try this. This is Laravel 11 middleware is defined in this. I think we might be at the max length of the conversation. Yeah, it just kind of fails silently. That's just a bug. Okay, here's what I'm gonna do. I'm gonna pop over to a new chat. I'm gonna say, read doc slash this. We implemented all that and now adding the form. In a separate chat, you defined an editor middleware. Now you need to add it to this file. Do that change first. Look at any folders you need to find middleware. I mean, I guess I could pull it down. Then look at routes web.php. And by the way, post controller, post test. So we were editing this. And so right now, post test, what's failing? Post controller middleware. Okay. Yeah, this is just like a little bit of annoying discontinuity that I just need to fix. Oh, I used the wrong path there. It's like, didn't matter. So it looked at the middleware and the controller, but not the test. See, a lot of the context you can just infer from looking at Laravel because it's got so much Laravel stuff in its training data. It's like got a pretty good intuition or whatever. Okay, so let's just see where we're at with our test. In Laravel 11, the way middleware is applied to controllers has changed. Instead of using this middleware in the constructor, we need to use the middleware method in the route definition. As long as you get me to green, man, take whatever path you need to take. Don't make me look at the code and give you help, agent. You're supposed to replace me. Not good. Okay, while it goes, I'm gonna start looking at stuff. So the failing test is the new one. Let's just like read it real quick. We create a user, is editor, true, is editor, false. Acting as an editor, if we go to the post, it should be okay. If it's a non-editor, it should say forbidden. And then just like a regular guest should redirect to the login. Is that right? Sometimes you gotta pull out the caps lock. Sometimes you gotta make, you gotta yell at it a little bit. Better work, agent. Better work or I'll make a new one. What the hell? So it's just this? All right. Time to start looking at it. I'll give it one last chance. The issue is occurring because the auth middleware is still being applied before our controller logic can redirect unauthenticated users. Let's fix this by removing the auth middleware from the route and handling all the logic in the controller. Well, that's not good. But I'm not gonna worry too much about like ideal patterns. I just, I wanna get to green so we can move on. Can always re-factor as long as the test pass. Out of curiosity. It's not worth using our local database without the migrations, is it? Oops. Okay, I'm just gonna commit that anyway. Make sure we're using a SQLite memory for tests. Okay. Okay, this should be really simple. Middleware. Auth and editor. Group. Create and post. You have to be auth and an editor. Right? But why abort 403 and why not redirect? All right, here's what I'm gonna do. Start fresh. Read this. Post controller. Post test. Routes web. And editor middleware. And fix these tests. Yeah, sometimes starting fresh and just giving it the exact files. It, uh.
[39:59] Speaker: more easily to identify what's wrong. Okay, so it wants to undo the change I just made. But why do we even want to abort with a 403? Why don't we just redirect everything? I guess if it's an API request, you wouldn't want that to be a redirect. You would want a 403. Fix this. I want API calls to return 403, and I want HTTP visits to pages they shouldn't access to redirect. Edit tests if you need to. Edit any files, including tests, if you need. Okay. I understand. We need to adjust our approach to handle API calls and HTTP visits differently. Let's make the necessary changes to achieve this behavior. Almost. Shout out to Lord of the Rings Lo-Fi radio. Awesome background coding music. Redirecting unauthenticated users to the login page while authenticated non-editors are redirected to the post index. Yeah, my guess. Easy to change if we need to. So... One failed. What the heck? Is there something else that redirects to login? Still getting it. If you can't tell what is wrong from the current files, maybe the behavior is specified elsewhere, in which case, just update our test to expect that final redirect URL. I meant to paste that, but oh well. I don't really give a shit where the person is redirected, so just give me my green. Alright, we have 8 passing post tests. And we have 35 passing tests total with 88 assertions. Real nice. Now, let's actually test it. Now, earlier, before we did the SQLite thing, these were sharing a database, so what we did earlier in Tinker was wiped. Actually, I shouldn't even need to do that. Let's just actually use the thing. Okay, so I'm going to need, I think, to go into the database too. Did I even... I don't remember what I registered as. Okay. So... I don't even have a button for it. What's the route? What's the route? I need a button. Posts slash create. Well, I'm not an editor, but let's just see what happens when I go to that URL. Okay, I'm going to redirect you to the homepage. That's cool. Let's see. Let's edit our thing. Let's see, we're using SQLite. New. SQLite. Select file. Code. Open. Press. Database. Database slash SQLite. eUsers. Is editor. I am now an editor. Okay, let's go to the page. Oh. Power. Hello. Where's the submit button? How do I submit? Is it here somewhere? Oh, there it is. We have a blog, everybody. Okay. So we have basic blog functionality. Let's try... I mean, I guess I'll try pushing it up. Yeah, I guess I'll do styling separately. I just want to make sure it works live. So... Alright, so that's what we have now. Let's go to here. Set up. Add basic blog post feature. And, I'll put a little screenshot in there of our wondrous... Let's do that now. Hang on. Okay. Historic. Alright, so I'll merge this. And then I will... Let's see. Because the migration of isEditor will be edited through raw migration, I'm going to have to wipe the database. So I'll edit the deployment script to change migrate to migrateFresh. Then deploy and cross our fingers. And then go to... Openpress.ai Alright, we've got our disgusting... So I'll just do this for now. Let's just do this. I need to make myself admin. You know, I'm actually... Instead of going into the database manually, like I just did... Because I just don't want to have to hide my credentials and do that right now. I'm going to briefly show you how to make an artisan command. So I'm going to just do a little bit of intro Laravel stuff, occasionally. Make Chris admin. So make Chris admin. Make Chris editor. Okay, so make Chris editor. I will not be hardcoding stuff like this, generally. User where email is Chris at openai.com. First or fail. I think that'll work. Attempt script to make Chris editor. Because right now, if I go to posts slash create... It redirects me to the homepage. But now if I go and deploy this one more time... So you can always SSH into the underlying server. So this is Forge, which is like an orchestration layer on top of whatever cloud you're using. In this case, AWS EC2. And then you can always SSH into the raw thing to run artisan commands. But Laravel Forge gives you some things where you can go in here and do PHP artisan. PHP artisan Chris. And then let's see if this actually works. Fail. Why did it fail? No query results from model. Oh, do you know why? Because I wiped the database. Let's stop wiping the database. Thank you very much. Okay, so I refresh. You can see that I'm logged in. I am no longer logged in because I deleted the user. So let's do this again. And let's run the script again. Rerun. Finished. Posts slash create. What's going to happen? Oh my goodness. Hello, OpenPress. Should I write something epic? First post. Excited to read yours. Smiley face. Period. Thumbs up emoji. This is really important, guys. Excited to read yours. Fine. Okay, folks. We have a blog. I'm going to add a little bit of styling offline. But to get, like... And let's just make sure it works if I log out. Yeah. Okay, folks. OpenPress.ai has the world's first post on OpenPress. I'm going to make this look a little not ugly. And then, you know, not bad for less than an hour. And then we'll just start... You know, if you want to make a feature request of anything, just open up an issue. PRs are welcome. Feedback is welcome. Insults, complaints, questions, comments, metaphysical speculations. Whatever you want. See you soon.