<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>kyleundefined.dev</title><description>Just a dude who enjoys writing code and learning;</description><link>https://kyleundefined.dev</link><language>en</language><atom:link href="https://kyleundefined.dev/rss.xml" rel="self" type="application/rss+xml"/><item><title>Verk eigi orð</title><link>https://kyleundefined.dev/blog/undefined</link><guid isPermaLink="true">https://kyleundefined.dev/blog/undefined</guid><description>Deeds, not words</description><pubDate>Sun, 15 Mar 2026 08:32:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;code&gt;Verk-ay-yi-orth&lt;/code&gt;&lt;/em&gt; - How cool does that sound?! I&apos;ve always been fascinated with Norse mythology, Vikings, and the language. I&apos;m not trying to learn Old Norse, but I&apos;m weaving it into everything I touch lately.&lt;/p&gt;
&lt;p&gt;I used to not be one for having a naming scheme, or universe, for projects and such, but I spent too much time with DBA&apos;s. No matter if it was personal, or even corporate, they always had a theme going for their servers. Most time it was Star Wars, Lord or the Rings, or Cars. Don&apos;t get me wrong, I enjoy having a punchy name for a project, half the fun of the project itself is coming up with a name that just &lt;em&gt;hits&lt;/em&gt;. Could I interest you in my RuneScape bot, &lt;code&gt;Potato Extractor Extreme&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;I&apos;ve been using Obsidian a lot more recently, not only for this blog, but as a thought organizer. Instead of having a bajillion Notepad++ tabs and randomly scattered files, I&apos;ve been working on getting all of that organized and put into a system that works, for me. The main selling point of Obsidian to me, was the Graph. Being able to see how your stuff is connected, is honestly amazing. Here&apos;s what I have so far, green are tags, white are notes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://undefinedlabs.tech/content/i/gneWlmKe&quot; alt=&quot;Obsidian Graph&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Zoomed out so you don&apos;t see my secrets ;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That may look like a hot mess, but it&apos;s beautiful, and that&apos;s in the eye of the beholder. The other selling point is the Linking. You not only have tags, but you can link notes together with a really in-depth system. Taken from &lt;a href=&quot;https://obsidian.md&quot;&gt;Obsidian.md&lt;/a&gt;&apos;s website:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://undefinedlabs.tech/content/i/ucga4SRJ&quot; alt=&quot;Obsidian Linking&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And that&apos;s just the default features, there&apos;s so many Plugins you can install to enhance your setup.&lt;/p&gt;
&lt;p&gt;When I first started using Obsidian, I of course watched YouTube videos on how people used it and &quot;best setup&quot;, but honestly I think everyone should jump in head first without any of that. Not saying there&apos;s not useful info out there, or you wouldn&apos;t use it that way, but if you want to actually turn it into &lt;code&gt;a second brain&lt;/code&gt; as they call it, figure out your own workflow. The workflows looked good, until implementation and I was like yeah dawg, that&apos;s not it.&lt;/p&gt;
&lt;p&gt;I created a vault called &lt;strong&gt;Fornbok&lt;/strong&gt;, which in Old Norse roughly translates to &lt;code&gt;Old book&lt;/code&gt;, which is the exact vibe I&apos;m going for, it&apos;s a place of my knowledge. I started putting notes and random bits of info into it, and then all of my projects, getting things linked and tagged. It feels like I&apos;ve put so much into the vault, but I see how much left I have to do still...&lt;/p&gt;
&lt;p&gt;I hear a lot of people complaining about Kanban boards, and I will admit I&apos;ve never used one until recently. After getting a chunk of data in, I quickly found out I wanted a &quot;dashboard&quot; of sorts. I installed the Kanban plugin and created a board and started playing with that, and I &lt;em&gt;really&lt;/em&gt; enjoy this setup. I have a board for my tasks, projects, and books. Each of those have the same-ish list layout of Backlog, In Progress, On Hold, Done. The more data I put into the vault, the more sense it made to go this route. The list has helped wrap my brain around what I actually want/need to do or work on.&lt;/p&gt;
&lt;p&gt;It really is crazy how much I can get done when going from thinking about what I need to do, to seeing it. Just this year so far, I&apos;ve started and completed 5(-1) projects, and one of which was inspired by using Obsidian. I&apos;ve started two other projects, with a massive undertaking, and have made great progress on both. Not to mention all the tasks and &quot;mini&quot; projects I&apos;m also doing at the same time, and in between, everything.&lt;/p&gt;
&lt;p&gt;I created &lt;a href=&quot;https://github.com/Kyle-Undefined/galdur&quot;&gt;Galdur&lt;/a&gt;, which is an Obsidian Plugin that allows me to use different AI CLI tools from a side panel. This roughly translates from Old Norse to &quot;magic/incantation&quot; and it&apos;s like I&apos;m summoning the AI, ha. There were existing plugins that brought them into Obsidian, but just not how I wanted and the closest one &lt;a href=&quot;https://github.com/YishenTu/claudian&quot;&gt;Claudian&lt;/a&gt; was for one lab and is well done for a native feel. I wanted something a bit rawer, and other models/labs to play with. It&apos;s Windows only, but I just shipped WSL support, and that&apos;s all I need. I wanted to try using OpenCode CLI and the self-hosted AI on my machine I can boot up, and it is neat having an assistant and it&apos;s &quot;unlimited&quot; use. The only limiting factor in this setup is your wallet for better performance.&lt;/p&gt;
&lt;p&gt;I also created &lt;a href=&quot;https://github.com/Kyle-Undefined/sshh&quot;&gt;sshh&lt;/a&gt; for an offline terminal inspired note taking app, as a learning project for React. I also have plans to use the new TanStack Hotkeys package to replace what I have and to expand the hotkeys available. (I was too lazy to wire up more than I did, be lucky you got that!)&lt;/p&gt;
&lt;p&gt;I am working on bringing Tailwind to the &lt;a href=&quot;https://kyleundefined.dev/tera-raid-info/&quot;&gt;Tera Raid Info&lt;/a&gt; project, and redesigning it, because why not? I orchestrated my ShareX Host site, which I wrote about &lt;a href=&quot;/blog/engineering-on-vibes&quot;&gt;here&lt;/a&gt;. &lt;em&gt;Its why I subtracted one from my completed project count&lt;/em&gt;. I brought my URL Redirect and Browser Tab projects out of the shadow realm, and have made small, but good progress on the Tab one and some cleanup and updates on the other.&lt;/p&gt;
&lt;p&gt;For the ShareX site, I had to set up a VPS, and I configured Dokploy. I named it Sindri, due to him being the Dwarf smith who forged Mjölnir. If I ever need a remote build server, due to suffering from success and outgrowing GitHub Actions free tier, it will be called Eitri who is Sindri&apos;s brother. I got that naming scheme that&apos;ll...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://c.tenor.com/1jEb3J4Mtk4AAAAC/tenor.gif&quot; alt=&quot;Terry Crews Burgers&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I can&apos;t have Obsidian and not sync it across my devices, come on now, and I&apos;m definitely not going to pay for it. Enter Muninn, the CouchDB instance for the &lt;a href=&quot;https://github.com/vrtmrz/obsidian-livesync&quot;&gt;LiveSync&lt;/a&gt; plugin. A high-five if you know that reference, to being one of Odin&apos;s ravens called &quot;Memory&quot;. You got it right! High five!&lt;/p&gt;
&lt;p&gt;I then got tired of paying an increasingly amount of money a month just for freaking email, all because I chose Google Workspace since it was easy to get going. I saw that the renew date was coming up and seeing &lt;code&gt;$17&lt;/code&gt; and knew that wasn&apos;t going to cut it. Enter &lt;a href=&quot;https://purelymail.com/&quot;&gt;Purelymail&lt;/a&gt;, the best way to get email on a domain, by far. That &lt;code&gt;monthly&lt;/code&gt; fee from Google, covers more than a &lt;code&gt;year&lt;/code&gt; here!! Yes, it&apos;s just mail, but the WebMail is perfectly fine, and you can use any IMAP client you want. I went with &lt;a href=&quot;https://betterbird.eu/&quot;&gt;BetterBird&lt;/a&gt; for the PC and &lt;a href=&quot;https://k9mail.app/&quot;&gt;K9Mail&lt;/a&gt; for Android.&lt;/p&gt;
&lt;p&gt;But I couldn&apos;t stop there, I have a lot of contacts and calendar events I wanted to get out of Google land as well, since I&apos;m getting the email out, I might as well do this too. These were easily exported out via &lt;a href=&quot;https://takeout.google.com/&quot;&gt;Google Takeout&lt;/a&gt;. I could take the exported files and import them into BetterBird, but that won&apos;t sync with my phone.&lt;/p&gt;
&lt;p&gt;That&apos;s when Norn, the &lt;a href=&quot;https://sabre.io/baikal/&quot;&gt;Baikal&lt;/a&gt; server, weaves their fate. This is just a CalDav/CardDav instance that was surprisingly easy to set up, once I got past some of the Docker issues, and the email invite feature I wanted. It took me several hours of fiddling with the deployments, settings, and config before I got it working for a specific email to send out the calendar invites. Huge dopamine hit now that it&apos;s working how I wanted! I don&apos;t &lt;em&gt;need&lt;/em&gt; a special email for sending invites, but I saw it was possible and so I just had to have it.&lt;/p&gt;
&lt;p&gt;But I still have to get this shit onto my phone, how is that even going to work? Ever heard of &lt;a href=&quot;https://f-droid.org/en/&quot;&gt;F-Droid&lt;/a&gt;? The alternative Android app store, that&apos;s free and open source?! You&apos;re slackalackin! Get you some of that &lt;a href=&quot;https://www.davx5.com/&quot;&gt;DAVx5&lt;/a&gt; to sync your Calendar, Contacts, and Tasks with the previously set up Baikal server. Oh? You want an app for your Notes and Tasks? Check out &lt;a href=&quot;https://jtx.techbee.at/&quot;&gt;jtx Board&lt;/a&gt; which works super well, and is great for quick notes and such!&lt;/p&gt;
&lt;p&gt;Needless to say, I&apos;ve been busy this year, but I&apos;m having a blast. I&apos;m learning, getting things done, and making things work for me. I&apos;m nowhere close to being done, I still have to swap off of Gmail fully, finish going through Drive and Keep. Then to tackle ripping off Microsoft&apos;s hold, and then getting rid of DashLane for Vaultwarden. Plus learning the languages I want to learn, for the projects I want to build, &lt;em&gt;pluuuuuuuus&lt;/em&gt; another project I came up with while looking for a solution to compliment this stack I&apos;ve got going, and nothing sufficed.&lt;/p&gt;
&lt;p&gt;It&apos;s fun to be busy with things that excite you, and things that enrich you rather than take away. I would think that I would have been feeling the creep of burnout or boredom come on by now. Usually when I have big bursts of creative energy, I have lows that take a bit to &quot;recharge&quot;. This is different, I see all head of me and I just feel a &lt;code&gt;let&apos;s fucking do this&lt;/code&gt;, as I whip my nonexistent baseball cap backwards.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://c.tenor.com/itVAkG3UGrMAAAAC/tenor.gif&quot; alt=&quot;Ash Hat Flip Gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m building my own &lt;strong&gt;saga&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Engineering on Vibes</title><link>https://kyleundefined.dev/blog/undefined</link><guid isPermaLink="true">https://kyleundefined.dev/blog/undefined</guid><description>Experimenting with letting go of the process</description><pubDate>Sun, 15 Feb 2026 16:21:00 GMT</pubDate><content:encoded>&lt;p&gt;Buckle up, buttercup, this one is going to be girthy...&lt;/p&gt;
&lt;p&gt;As always, you can view this projects source code over on my &lt;a href=&quot;https://github.com/kyle-undefined/undefinedlabs.tech&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;A little Backstory...&lt;/h3&gt;
&lt;p&gt;I&apos;ve been in this industry for 2 decades now, if you count the high school years, and sometimes I &lt;em&gt;don&apos;t&lt;/em&gt; want to write every single line of code. Don&apos;t get me wrong, I truly enjoy what I do, and I couldn&apos;t imagine doing anything else. But as I&apos;ve gotten older, and more experienced, I have refined what I enjoy about the craft. Younger me confused the enjoyment of engineering and solving problems, with how productive I was and how &lt;em&gt;quick&lt;/em&gt; I could solve it. I still enjoy being quick and accurate, current role depends on it, but what I enjoy the most is things being done right. I&apos;m a control freak when it comes to my code, it&apos;s an unfortunate side effect of the career path I&apos;ve taken, but it stems more from pride in my work than anything else. I&apos;ve been trained to bust some ass though, I tell you h&apos;what!&lt;/p&gt;
&lt;p&gt;Just a high level of what I&apos;m talking about... First company right out of high school was building websites for clients. I learned so much being there, I have to give them their dues for that, but that&apos;s as far as it goes. Long story short, I was promised a Development Manager position as long as I busted my ass and delivered. I know for a 100% fact I did, but it was &lt;code&gt;re-promised&lt;/code&gt; to snag a potential hire. I had templated out our entire product offering, overhauled and optimized systems, implemented mobile before it was standard and was front line support. You can call that being naive, or bad management, I think it&apos;s both.&lt;/p&gt;
&lt;p&gt;A year later I had landed at a job I felt at home doing web for the marketing team, at a cybersecurity focused company. This place really kicked everything into high gear for me. For starters, I was the only developer for that department. The team I worked with, and the teams I interacted with, were amazing! (&lt;code&gt;What other job pays you to design cars in Forza just for a marketing campaign?&lt;/code&gt;) The job itself was stressful, especially when you go from &quot;being the helper&quot; to owing the entire web brand. I was building Excel sheets with more logic than I care to ever explain. Just to have RoI/Quote/etc. calculations that clients could use. Don&apos;t get me started on the marketing jargon software...&lt;/p&gt;
&lt;p&gt;The day before Christmas in 2012 I was let go from the company, all because my name was drawn from a hat, and I swear I&apos;m not making that up! I know because I was hired back a week later when the vertical I was a part of bought themselves out from the parent company, and the teams I worked with reached out. I felt like I was at my prime during these years, but also working 12-14 hour days all week, every week, is not healthy. I moved to an apartment right next to the office, so it would take me a literal minute to walk out the door and sit at my desk.&lt;/p&gt;
&lt;p&gt;With the new company, I had a much bigger role than I thought I already had, as I didn&apos;t know the horrors of &lt;code&gt;corporate rebranding&lt;/code&gt; until now. In the madness of this place, in order to meet a deadline and launch, I rolled my own CMS. Simply because the budget for the one we wanted hadn&apos;t been approved and the onboarding process was longer than we had. In a weeks time I built a fully customizable, database driven CMS that allowed the copy team to start the tedious process of putting that in, while the design team and I made it look pretty. This worked really well, up until 2 days before launch and the new group policy completely wiped the source code from my machine. All because I wasn&apos;t in the main &quot;dev group&quot; since I was in the Marketing department. To make matters worse, the files were restored, but as a giant zip that contained &lt;code&gt;file.cs, file(1).cs, file(2).cs&lt;/code&gt; and etc.&lt;/p&gt;
&lt;p&gt;Who has two thumbs and had to work overtime to restore the project one file at a time?&lt;img src=&quot;https://media.tenor.com/4vzTFsP-jNUAAAAM/office-me.gif&quot; alt=&quot;This guyyyyy meme&quot; title=&quot;This guyyyyy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thankfully, not too long after launch, the budget was finally approved and we made the swap to the much better CMS which did make my life a hell of a lot easier. Still owned all things web, but was in a properly managed system compared to what I had made in the short time I had. After a couple of years of having a rotating door of CMO&apos;s every 6 months and a new redesign every time someone joined, the team slowly went their own ways.&lt;/p&gt;
&lt;p&gt;The company I am at now, I am part of an Engineering Support team that sits between first response and devs. I joined initially as a Support person, and built the internal tool to package up our deployments that could contain 100&apos;s of files, that people (&lt;code&gt;myself included&lt;/code&gt;) were making by hand. That tool has evolved, the company has evolved, the role has evolved, and so have I.&lt;/p&gt;
&lt;h3&gt;Now with that out of the Way...&lt;/h3&gt;
&lt;p&gt;That was a bit longer of an introduction that I had planned, but I can be a yapper.&lt;/p&gt;
&lt;p&gt;With the talk over the year and a half being that &quot;&lt;code&gt;We&apos;re 6 to 8 months away from AI replacing all engineers&lt;/code&gt;&quot; every 6 months, I wanted to at least give it all an honest try. That kind of talk really did put a sour taste in my mouth and kept me hesitant. Not because I think I&apos;m irreplaceable, or a god engineer, but because every attempt I had made to use AI in some sort of workflow was just frustrating.&lt;/p&gt;
&lt;p&gt;I try to keep up to speed with AI, I think it can be a really useful tool, but it&apos;s hard to wade through all the buzzword hype nonsense and get a true understanding without getting your hands dirty. I&apos;ve been slowly utilizing AI more for brainstorming and helping me learn and understand coding projects. I haven&apos;t tried to &quot;vibecode&quot; anything, as having the model ignore the instructions of&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have created a unit test @test and it has tests for x, y, z. Please create another unit test for @service utilizing the same testing framework for these methods/functions a, b, c&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;literally sent me over the edge. Just ignore the framework I want to use, and substitute your own, anyway...&lt;/p&gt;
&lt;p&gt;The models and harnesses have improved a lot since those days, and seeing how Opus 4.6 and Codex 5.3 both dropped a day or so before I thought about this experiment, I figured there&apos;s no better time than the present. It also doesn&apos;t hurt that $20 for Codex gives you insane usage limits due to the recent model launch and them being more generous than normal. I also signed up for the $20 for Claude, as I&apos;m not trying to do Ralph loops over here.&lt;/p&gt;
&lt;p&gt;I&apos;ll go ahead and say this process was actually enjoyable, and I did have fun with this project. My only gripe is due to my lack of understanding of the API&apos;s and rate limits and best way to utilize that for stuff. However, I&apos;ll get into that later on in this post. One thing I found interesting, was that Claude &lt;em&gt;loved&lt;/em&gt; taking your change, and making sure there was no backwards compatibility issue. That&apos;s pretty neat, but did get in the way a few times during this project.&lt;/p&gt;
&lt;h3&gt;The idea&lt;/h3&gt;
&lt;p&gt;I have been wanting to build my own ShareX hosting site for a few years now, and have started it countless times with different tech stacks, methodologies, and impossible designs just to push the limit of what&apos;s capable. It&apos;s not a very high priority project for me, as you can tell, since it&apos;s taken me this long to do something so simple. It&apos;s literally a web server, a database, and some endpoints. Should have been knocked out in a weekend, but the simplicity of it made it &lt;strong&gt;booooooring&lt;/strong&gt; to me. I wanted the end product, but I didn&apos;t want to write out the same type of code I do as a job, I wanted something different.&lt;/p&gt;
&lt;p&gt;With my quest of doing more front-end stuff, I have heard about this service called &lt;a href=&quot;https://www.convex.dev/&quot;&gt;Convex&lt;/a&gt;. I have been wanting to play with it ever since I read the docs, as it&apos;s a badass service! It&apos;s a Backend as a Service (&lt;code&gt;BaaS&lt;/code&gt;) that you can host yourself or pay for them to host it (&lt;code&gt;The pricing ain&apos;t bad either&lt;/code&gt;). That really sunk deep due to the home lab I&apos;m working on setting up. Two of my recent projects I am building with the sole purpose of using Convex with, haven&apos;t even gotten to the point of setting it up.&lt;/p&gt;
&lt;p&gt;I wanted to use Blazor for this project, if I could, as I made an attempt forever ago when it was first coming around, but that didn&apos;t go so well. I did end up making my first &lt;a href=&quot;https://github.com/Kyle-Undefined/Blazaco&quot;&gt;Nuget&lt;/a&gt; package for Blazor, but that&apos;s long been dead. I wasn&apos;t fully convinced this was doable yet. Convex is mostly used with TypeScript frameworks as the database, queries/mutations, and functions are code in your project. They don&apos;t have any official C# packages, like they do for the main frameworks, including Python and Rust. So before I could try this experiment, I had to see if it was even possible.&lt;/p&gt;
&lt;p&gt;I did a lot of research into possibly having to write my own wrapper for this project, which I was down for, but wasn&apos;t looking forward to it. Luckily, I came across an &lt;a href=&quot;https://github.com/zakstam/convex-dotnet-unofficial&quot;&gt;unofficial&lt;/a&gt; .Net package which saved me all of that headache. Researching that lead to even more questions about the package, which is when I used this tool a creator I follow created, called &lt;a href=&quot;https://btca.dev/&quot;&gt;Better Context&lt;/a&gt; which is pretty neat. It allows you to clone the repo of a project and use a model to converse with the code, and isn&apos;t made for how I used it, but the free 5 questions is all I needed. Blazor is noted as &quot;Compatible&quot; and the main reason why I want to try out Convex is for the sync engine. That is their selling point, outside of being a seemingly awesome company. Having the instant sync of data from the backend to the front-end without having to do it yourself, is honestly magical. Knowing that was the main driving factor behind wanting to use Convex, I used the BTCA tool and asked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;@convexDotnetUnofficial it says that Blazor is Compatible, but asp.net core is Full Support. is the compatible in terms of just client side only Blazor, or also Blazor Server? if i was using Blazor Server, would that be fully supported? or if Blazor is only Compatible, what isn&apos;t supported on the Blazor side? the only thing i want is file storage, queries/mutations, and real-time subscriptions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It spit out a simple to understand, yet detailed breakdown of what I want and what is supported from the package. Good news, everything I wanted to utilize, I could!&lt;/p&gt;
&lt;p&gt;I guess I should stop and explain why I chose C# for this, instead of just using a more popular and supported option. I know my limits when it comes to TypeScript, and I&apos;m more proficient in the .Net ecosystem than the React/Angular/Vue side. I know I could look at the code, and say it &quot;&lt;code&gt;looks good&lt;/code&gt;&quot; but I wouldn&apos;t fully understand all of it to &lt;em&gt;know&lt;/em&gt; if it&apos;s good or bad. Don&apos;t worry your sweet little head, I am working on a couple of TanStack projects with Convex which is way more complicated than this. I just wanted to have foundational knowledge of what was being done, and not have to second guess every thing. This is just a project for myself, and seeing how far it can be taken.&lt;/p&gt;
&lt;h3&gt;The Plan&lt;/h3&gt;
&lt;p&gt;Now that I knew what I wanted to build, how I wanted it built, I just had to architect it a bit before I could begin. I started by mapping out the endpoints, the routing, data flow, auth flow, hosting, and pretty much everything else I could think of.&lt;/p&gt;
&lt;p&gt;Speaking of hosting, I knew I wanted to self-host Convex (&lt;code&gt;Why? Because why not?&lt;/code&gt;), and I knew I&apos;d need an actual VPS as this wouldn&apos;t work with my go-to, GitHub Pages. I initially started off with the thought process of wanting to use &lt;a href=&quot;https://coolify.io/&quot;&gt;Coolify&lt;/a&gt;, as it allows me to set up my own type of Auto Deploy system. I later swapped to &lt;a href=&quot;https://dokploy.com/&quot;&gt;Dokploy&lt;/a&gt; at last minute after doing more research into Coolify. The performance, alternatives, etc., I also liked the UI of Dokploy more, and it seemed more fleshed out with how I wanted to use it.&lt;/p&gt;
&lt;p&gt;There is one more step we can do, which &lt;em&gt;should&lt;/em&gt; help with the capabilities of the models, and that&apos;s called Skills. Now, I&apos;m wary of these in general, mostly because people are fast and loose with installing these without any sort of review. I did look at the official Claude and Codex skills repo and installed the C#, front-end design, and one called superpowers. These should give Claude and Codex the best shot at doing well in the upcoming tasks. Not all Skills are available for both harnesses.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Side note on Skills: If you aren&apos;t worried about them being an attack vector, just take a look at &lt;a href=&quot;https://www.paubox.com/blog/malicious-crypto-skills-compromise-openclaw-ai-assistant-users&quot;&gt;OpenClaw&lt;/a&gt; and &lt;a href=&quot;https://www.wiz.io/blog/exposed-moltbook-database-reveals-millions-of-api-keys&quot;&gt;MoltBook&lt;/a&gt;. Read the Skills files before you just add them, even from Official repos like Claude and Codex.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;People say it all starts in the prompt, and I&apos;m no prompt engineer, but I think this encapsulated everything I wanted. I opened Claude Code, set it to Opus 4.6, enabled Plan mode, and I gave it the following &lt;a href=&quot;https://undefinedlabs.tech/t/OA19vmOy&quot;&gt;prompt&lt;/a&gt;, feel free to judge. Linked it as it is &lt;em&gt;not&lt;/em&gt; short, plus you get to check out the work in action!&lt;/p&gt;
&lt;p&gt;Claude churned for a while, and came back with some questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do you already have a Convex backend deployed (with functions/schema), or should this project include the Convex TypeScript backend (convex/ directory with schema.ts, mutations, queries) as part of the repo?&lt;/li&gt;
&lt;li&gt;For image and file uploads via ShareX JSON, how will the binary data be encoded in the JSON payload? ShareX typically sends multipart/form-data, but you specified JSON.&lt;/li&gt;
&lt;li&gt;For the view URLs (e.g., /i/{id}), should the ID be a short random string (like &apos;aB3kx9&apos;) for clean URLs, or is using the Convex document ID directly acceptable?&lt;/li&gt;
&lt;li&gt;Which .NET version should the project target?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each question had a few options or an other option which I could manually type something else. I gave the following answers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Include in this repo&lt;/li&gt;
&lt;li&gt;Multipart form-data&lt;/li&gt;
&lt;li&gt;Short random ID&lt;/li&gt;
&lt;li&gt;.NET 9&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Claude churned some more, and I kept watching the Usage but it wasn&apos;t going insanely fast so I just kept it going.&lt;/p&gt;
&lt;p&gt;Finally I got a response:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have comprehensive research results. Let me now write the final plan, incorporating one key finding: the user explicitly wants text to be stored as a file in Convex storage (not just a DB field), so all three types share a consistent schema. Let me write the plan file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The plan was pretty clean, and made sense compared to what I had asked for and wanted. There was a call out regarding the package I wanted to use, the ConvexClient.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why HTTP wrapper instead of ConvexClient directly? The Convex.Client NuGet package (5.2.1-beta) is designed around real-time WebSocket subscriptions and client-side patterns. For server-side API calls (auth-gated uploads, SSR page loads), direct HTTP API calls are more predictable and debuggable. If the NuGet package proves suitable during implementation, we can swap in, but the HTTP wrapper ensures reliability.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Claude doesn&apos;t have the context that the package will indeed work for our needs, it hasn&apos;t scanned the repo for a deep dive. That&apos;s where that Better Context tool I used earlier would come in handy, could pipe that knowledge to the model so it can use that knowledge and not have to guess. This is why I think this was a fun experiment. Had I not already done all the research prior to starting this, I wouldn&apos;t have known that the package even existed, nor that it would work for what I wanted built. Sure, eventually I would have asked the AI about live polling or using the Convex sync once it had built everything around the HTTP wrapper. But I think it would have been too late, it wouldn&apos;t know what I didn&apos;t know. It probably would have gone down a path of using the already established HTTP wrapper and doing a &lt;code&gt;setTimeout()&lt;/code&gt; poll to the Convex API. Now, it may not have been that crude, but I know it wouldn&apos;t have known about the package to implement. The end product would have been way worse if I hadn&apos;t.&lt;/p&gt;
&lt;p&gt;I asked Claude about that call out, and why not use the ConvexClient on the dashboard, since that is the proper place it should be implemented. The view pages don&apos;t need it as it&apos;s just showing what it is upon load, those don&apos;t need to live update.&lt;/p&gt;
&lt;p&gt;I got back:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Great call - yes, that&apos;s the perfect use case for the Convex.Client + Convex.Client.Blazor packages. The dashboard is exactly where real-time subscriptions shine.&lt;/p&gt;
&lt;p&gt;The architecture would be a hybrid approach:&lt;/p&gt;
&lt;p&gt;HTTP wrapper (ConvexService): Upload endpoints, download endpoints, view page SSR loads - these are all one-shot request/response patterns where a direct HTTP call is simplest&lt;/p&gt;
&lt;p&gt;ConvexClient + Convex.Client.Blazor: Admin dashboard - subscribe to stats:getDashboardStats and the list queries so stats, view counts, and new uploads appear live without page refreshes. The Blazor package has SubscribeWithStateHasChanged() which auto-triggers component re-renders on data changes.&lt;/p&gt;
&lt;p&gt;Let me update the plan to reflect this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After the plan file was updated with that change, it looked good enough to implement. But why have two models if you don&apos;t utilize them? I liked the plan, and just wanted another pair of &quot;eyes&quot; to see what it thinks based on how it was trained.&lt;/p&gt;
&lt;p&gt;I opened up Codex, set it to 5.3 High, fed it the following prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;i have a PLAN.md to create a new project, is there anything missing that would stop implementation? or anything that is confusing from the plan that needs more clarification? is the point of the plan and project clearly defined? or there any gaps when it comes to the flow of data, from upload to view? what about security concerns?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know, seems silly asking AI about security concerns, but I&apos;m not just telling it to &lt;code&gt;make it secure&lt;/code&gt;. This is a plan review, if the plan doesn&apos;t make sense, or has issues, that would apply to a human engineer too. Especially if you were to hand it off like you do with AI.&lt;/p&gt;
&lt;p&gt;Codex looked angry, had 9 High to Medium level security issues. Uh-oh, that sounds awful, what did Claude do? Are these even real security concerns? Well, take a &lt;a href=&quot;https://undefinedlabs.tech/t/Q59Alsjz&quot;&gt;look&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The points about abuse controls, Convex Admin key, data consistency and contract consistency seemed reasonable, I did laugh at the fact it was so picky, that not having a &lt;code&gt;PUBLIC_BASE_URL&lt;/code&gt; set is a High security issue. Sure, it&apos;s needed for URL normalization, but that&apos;s just down to implementation. However, it&apos;s good to call out, just don&apos;t think it&apos;s that high an issue.&lt;/p&gt;
&lt;p&gt;I clarified some things with Codex, so it had more understanding since there was some gaps in the plan. I clarified the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;for clarification, this is only used by me, no one else will have access to it. so there is only one user, ever. how does that change your findings and does it get rid of any of them?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;contract mismatches: let&apos;s change the schema to fileName so it&apos;s consistent. put in other examples for the other types if that example showing you how it will be formatted is causing that much of an issue.&lt;/li&gt;
&lt;li&gt;let&apos;s create an env var to hold that base url which will be used with the return json.&lt;/li&gt;
&lt;li&gt;we don&apos;t want to orphan anything if the mutations fail. let&apos;s do a check on the mutation result and if it&apos;s a failure we delete the file and anything that was saved and return the error.&lt;/li&gt;
&lt;li&gt;view/download: how would you handle this? i was thinking on page view it would increment, same for when the download button was clicked. not too concerned about this, but interested.&lt;/li&gt;
&lt;li&gt;convex_admin_key: if i pwn myself, i pwn myself, that&apos;s fine.&lt;/li&gt;
&lt;li&gt;regarding the full table aggregation, it should be paginated with top 50 records of each, to prevent that. the dashboard shouldn&apos;t show everything unless selected to do so.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Codex loved the clarifications, and immediately went to town updating the plan. It did come back with some feedback:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Very close. I don&apos;t see major blockers now, but I&apos;d still clarify 4 things:&lt;/p&gt;
&lt;p&gt;Medium: Stats still imply full-table aggregation
PLAN.md (line 136) says aggregate totals across all records.
If your goal is to avoid heavy scans, define whether totals are precomputed counters or you accept full scans for personal scale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is where my not understanding of Convex came in, as I thought I had read enough to get started, but misunderstood the &lt;code&gt;full-table aggregation&lt;/code&gt;. I was thinking it meant that the admin pages would be dumping all the data in one page, not that the way I was &lt;em&gt;getting&lt;/em&gt; the data was by full-table aggregation. It says it right there, &lt;code&gt;precomputed counters&lt;/code&gt; which is the proper solution, but I hadn&apos;t gotten my hands dirty with Convex yet so I carried on with misunderstanding for a bit. I told Codex it should be the Total Counts of it, and not the full data, which it understood enough from my own nativity to add in the precomputed counters.&lt;/p&gt;
&lt;p&gt;After about 2 hours of planning and back and forth with Claude and Codex, I had a plan that I felt happy enough that if it was handed to me, I&apos;d understand enough to get started. I had Codex create the &lt;code&gt;AGENTS.md&lt;/code&gt; file from the &lt;code&gt;PLAN.md&lt;/code&gt;, as I&apos;ve heard this is supposed to help with implementation and the way to do things.&lt;/p&gt;
&lt;h3&gt;Prompting into Existence&lt;/h3&gt;
&lt;p&gt;I went with Codex to implement the plan, and the reason for that is up until a month ago I was paying the $10 for Copilot and had been using Opus/Sonnet through that for testing and playing around with. I know it&apos;s not the same from the native harness, but I had a plan for Claude still in this, I just wanted to test out Codex which I hadn&apos;t used at all yet.&lt;/p&gt;
&lt;p&gt;I started a new chat with Codex, leaving it on High, set it to Auto and gave it the prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AGENTS.md this is a brand new project, with a detailed agents file for you. there is also a detailed PLAN.md file in case you need it. i&apos;d like you to start working on and implementing this, and between each check point, i&apos;d like you to commit, but not push the changes. and if you have any questions, ask me, don&apos;t assume&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;About 30 minutes later, Codex had chewed through the plan, created the project layout exactly as envisioned, the Convex backend, admin pages, and even tests! It did hit the 258k token context window, and auto-compacted near the end, but I don&apos;t see any weirdness. I know for people who have been using AI like for a while now will say it&apos;s nothing special, but it is pretty neat you have to admit. I&apos;ve never given the harness full control to go, I use it as question dump and such. The C# code that was produced was not half bad too, which I was surprised about. I know the majority of the training is not on C# but it did it well enough that I couldn&apos;t complain too much. I was hoping it would have gone with &lt;code&gt;vertical slice&lt;/code&gt; instead of &lt;code&gt;minimal api&lt;/code&gt; for this, but we&apos;ll tackle that later.&lt;/p&gt;
&lt;p&gt;Codex wrapped up what it was working on and came back that the Convex backend needed real values so the backend can be deployed. I created a &lt;code&gt;.env&lt;/code&gt; to point the backend to my locally running Convex instance. Told Codex that was configured, and Codex kicked off the &lt;code&gt;bun convex deploy&lt;/code&gt; and I saw my dashboard instantly updated with the data stores and functions. That&apos;s so fucking cool! The fact that the code is what drives Convex is why I wanted to play with this, and makes me excited for my other projects!&lt;/p&gt;
&lt;p&gt;I asked Codex to run the Tests it had created to see what would happen, expecting some/most to fail, and I wasn&apos;t too far off. Most of the errors were due to the &lt;code&gt;.env&lt;/code&gt; file stuff in C# which we normally would use User Secrets. It got hung up for about 5 minutes trying to chew through that issue, and started creating its own file loader and parser and tests for said loader and parser. I stopped it as some of the blame is on me for that. Like I just mentioned, that&apos;s not typical for a C# project and I was trying to keep everything in one file across the board. I had Codex implement the &lt;a href=&quot;https://www.nuget.org/packages/DotNetEnv&quot;&gt;DotNetEnv&lt;/a&gt; package to make this possible. It still wanted to do some shenanigans with the file, but that&apos;s just because of where I placed it, moved it and that went away.&lt;/p&gt;
&lt;p&gt;Just over an hour with back and forth with Codex, the base app was ready to begin testing, let&apos;s see what&apos;s been cooked up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design is trash, but that&apos;s fine, I have a plan for that&lt;/li&gt;
&lt;li&gt;Can&apos;t login to Admin dashboard&lt;/li&gt;
&lt;li&gt;Convex backend is duplicated&lt;/li&gt;
&lt;li&gt;Still weird .env file code&lt;/li&gt;
&lt;li&gt;Convex Storage URL needs normalization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Codex cleaned up everything but the front-end, so now it was time to test the endpoints. I&apos;m lazy so I asked Codex to create the &lt;code&gt;.sxcu&lt;/code&gt; files to test from ShareX itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;in the /sharex/ folder, can you create the custom uploaders for each the text, file, and image for me? that way i can just import them into sharex.&lt;/p&gt;
&lt;p&gt;they should pass the auth token we are validaing for in the backend, which i&apos;ve now set in the .env file. however, the ones you create can be filled in using a example value and i can replace it with the proper value once imported.&lt;/p&gt;
&lt;p&gt;here is the docs on how to create a custom uploader: https://getsharex.com/docs/custom-uploader&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I imported those into ShareX and began testing the Text uploader, immediately finding an error in my logic. I had set Codex on the wrong path of using a JSON object, when it&apos;s a Form POST, and I had confused myself when looking at the ShareX app and the fields were &lt;code&gt;{json:text}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Codex easily fixed that, and I was able to send Text through ShareX to my dev setup, progress! I could see the Convex dashboard update instantly when the data came in. Upon viewing the link that was generated, I was greeted with an error which Codex fixed quickly.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Side note: I didn&apos;t note down the error I got, iirc it was related to the grabbing of the slug and fetching from Convex.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Copy Text button wasn&apos;t copying as expected, and the Download button went directly to the route instead of staying on the page. The fixing of the copy functionality took Codex a few tries, but it did get it working, noice!&lt;/p&gt;
&lt;p&gt;In testing of the file upload, it uploaded fine, but the Download button had the same issue as the Text view did. When fixing the Text view, I could have also prompted better to tell it to also fix the other views, but I also think that it should have checked to see if there was other views to fix. As soon as I told Codex the file view Download button was behaving the same as the Text view, it fixed that and &lt;em&gt;then&lt;/em&gt; automatically fixed the image view. That&apos;s why I think it should have done it to begin with, but that&apos;s just me being extra. Codex did have to fix the download not starting upon click, and the view count incrementing twice upon page load, but fixed those without issue.&lt;/p&gt;
&lt;p&gt;Now that the file, image, and text upload and view is working, time to move onto the Admin dashboard. I could login fine, awesome, but no stats were displaying on the dashboard. No errors in either console, hmm.&lt;/p&gt;
&lt;p&gt;This is where Codex went into a bit of a spiral, in my opinion, and I always start with a new chat. It did fix an issue with the JSON mappings between Convex and HTTP, but it could not figure out the Convex live subscription. I gave Codex the package docs, I saw it digging through the local package, but no matter what it did, it couldn&apos;t get the subscription working. I saw why, the IConvexClient was disposed of after it was registered, by the way Codex was invoking it. I decided to leave it for now, interesting test case for later. Codex basically said &lt;code&gt;fuck this&lt;/code&gt; and went to a single get on load, fair.&lt;/p&gt;
&lt;p&gt;Basically, the project is done, right? Well, yeah, if you like an ugly design and want to ship a vulnerable product!&lt;/p&gt;
&lt;p&gt;In Plan mode, I fed Codex the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;base functionality is done, everything is working, which is perfect.&lt;/p&gt;
&lt;p&gt;now, one thing i just thought about is, even though i&apos;m protecting the post route with the auth, it doesn&apos;t prevent bots/people from spamming the paths. i would like to implement some sort of protections, rate limitting of people spamming the endpoints and the like. def want any anti-automation (bot) controls we can implement, the better.&lt;/p&gt;
&lt;p&gt;the same protections should be for the view/download as they increment.&lt;/p&gt;
&lt;p&gt;what would be the easiest, best solution for these? are there asp.net core packages we can use that makes it easiser to implement these things? i&apos;ve watched tutorials on implementing these types of things, but it&apos;s been a year or so and i&apos;d have to hunt down where i saved those.&lt;/p&gt;
&lt;p&gt;if you have any questions, ask and don&apos;t assume. make sure you plan it with security best practices in mind so we are not exposing ourselves.&lt;/p&gt;
&lt;p&gt;maybe also investigate how we are doing the dashboard protection. i know it&apos;s from env var, and is session based and the only real risk is me exposing it. is there a more secure, better way to implement an auth but only have it for me alone to login to? i know this way i&apos;m doing it now is better than doing the validation on the front end, but if there&apos;s a way to implement an auth system i control (or even can self host) for this, that would be fine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Codex chewed through the codebase, and came back with a few questions, which I answered with the defaults.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Where should abuse protection be enforced for public/upload routes?
&lt;ul&gt;
&lt;li&gt;Hybrid app+edge&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Which admin auth model should this plan target?
&lt;ul&gt;
&lt;li&gt;Harden local auth&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose default upload size limits for abuse control.
&lt;ul&gt;
&lt;li&gt;Balanced caps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Which edge/proxy should the plan target for bot/WAF controls?
&lt;ul&gt;
&lt;li&gt;Cloudflare + app&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solid options from Codex, and Cloudflare is a perfect fit as I already use it for this domain. With the hardening plan figured out, Codex went to work and in 10 minutes the changes were implemented, absolutely insane. This included rate limiting, upload limits, allowed proxy list, and all the logic that comes with it.&lt;/p&gt;
&lt;p&gt;I had Codex implement the Scalar API behind the Admin route, so I could hit the endpoints from there without having to use ShareX.&lt;/p&gt;
&lt;h3&gt;Can It Imagine?&lt;/h3&gt;
&lt;p&gt;I watch enough content on YouTube regarding Claude and how much better it is at design than Codex, so I just had to see for myself.&lt;/p&gt;
&lt;p&gt;I used the &lt;code&gt;/using-superpowers&lt;/code&gt; plugin, as reading into this (&lt;code&gt;and the source code&lt;/code&gt;), it seems like a super plan mode so wanted to give it a shot. A creator I watch called &lt;a href=&quot;https://www.youtube.com/@t3dotgg&quot;&gt;Theo&lt;/a&gt; was showing how he used Claude for front-end so I gave it a shot:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;i have a asp.net core blazor server app, and i have all the functionality done. what i&apos;d like now is a design that&apos;s modern, sleek, minimal, but unique. all i&apos;d want done is the front end design, so if you can use that skill and knowledge, even better.&lt;/p&gt;
&lt;p&gt;i&apos;d also like you to generate 5 designs that i can compare and see which one i like the most.&lt;/p&gt;
&lt;p&gt;the general designs should be dark theme styled. i don&apos;t want a terminal look, not a fan of those for a website.&lt;/p&gt;
&lt;p&gt;i like the synthwave style for vscode (https://github.com/robb0wen/synthwave-vscode) but that isn&apos;t a requirement for them, maybe one can incorporate that color scheme. otherwise, you come up with everything.&lt;/p&gt;
&lt;p&gt;really want to be impressed!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was hoping the wanting to be impressed tidbit would really make Claude go all out. However, after the back and forth and watching it spin, I didn&apos;t feel confident. It was confident that the 5 different designs would be unique, and that the only thing that would have to change is the CSS and no HTML. I&apos;ll be the judge of that...&lt;/p&gt;
&lt;p&gt;Claude came back a bit after it had made the changes. Ha, completely ignored what I had asked, but is that Claude, the superpower, or a combination? No clue. There was indeed 5 designs, but they were reskins which is what I explicitly told Claude I &lt;em&gt;didn&apos;t&lt;/em&gt; want.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;i was hoping to see more than just palette swaps and header navigation placement changes. i will say, the midnight-rose color scheme is beautiful, i really like that, i was just hoping for a fresh layout for all of them. can you use the midnight-rose for the colors but come up with actual re-designs like i asked for? you confirmed more than just css changes and then ignored it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Have to rub it in that Claude ignored me and itself, which honestly did seem to work, finally. It created a few themes and test pages to review them. Claude took the colors from the midnight-rose I mentioned, and made a really clean design I liked, minus a few things. The other designs were okay, but just didn&apos;t &lt;em&gt;hit&lt;/em&gt; like the main one. I had Claude clean up the design a bit by removing the Header and Footer, swapping out some button/font colors, and cleaning up the view pages.&lt;/p&gt;
&lt;p&gt;While the designs it came up with were neat, I think it&apos;s still a ways away from being as good as a human designer. Now, I&apos;m sure if you fed it an image of a design, it could implement that from reference. But with AI just being an algorithm, it really doesn&apos;t have an imagination like you and I to really think outside the box. It can only go as far as its training.&lt;/p&gt;
&lt;p&gt;The color scheme that was generated is beautiful though, I can&apos;t take away from that. However, I do think about all the artists whose work was stolen for that to be possible. There really should be a way for artists and AI to be a team and compensation for their work that the models are trained on, but that&apos;s a whole other topic.&lt;/p&gt;
&lt;h3&gt;Close to the Finish Line&lt;/h3&gt;
&lt;p&gt;The base functionality was working, and just had to instruct for a 404 page to be created and used, but it&apos;s time to clean up some of the code. While it all worked, the &lt;code&gt;Program.cs&lt;/code&gt; file had become God-like and I didn&apos;t like that.&lt;/p&gt;
&lt;p&gt;Started a new chat with Codex and gave it the following prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the Program.cs is getting a little large. let&apos;s swap to the vertical slice architechture for all of these, so the architecture is cleaned up and it&apos;s easier to find everything and it makes sense. this way we can still use the minimal api&apos;s and their routes, we just have the routes in their own paths so anything related to the route can be in there with it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It went to town on the architecture changes, and remapping of everything. This is one of the things I found I enjoyed about working with AI, I&apos;ve done that type of thing a gazillion times, but I can&apos;t keep up with the speed in which it does things. Now, speed isn&apos;t always the greatest thing, but staying in the loop and actively participating does seem to be a fantastic way to compliment the speed.&lt;/p&gt;
&lt;p&gt;I was happy with the product as it was, but wanted to nail down any other other issues that may be present in the codebase. I instructed both Codex and Claude to review my current project, and look for any security concerns, gaps in logic, principle violations, etc. Here is the &lt;a href=&quot;https://undefinedlabs.tech/t/FKee1aes&quot;&gt;Codex result&lt;/a&gt; and here is the &lt;a href=&quot;https://undefinedlabs.tech/t/ivQTgUGA&quot;&gt;Claude result&lt;/a&gt;. All in all, both found good points of concern that should be investigated, Claude was more verbose which I liked, and I had Codex begin working on those that were easy to knock out after tweaking it a bit.&lt;/p&gt;
&lt;p&gt;I had been giving Codex a lot of work to try so far in this project, so I instructed Claude to migrate to User Secrets (away from the &lt;code&gt;.env&lt;/code&gt;), clean up the Convex functions, implement counters to remove Table scans, etc.&lt;/p&gt;
&lt;p&gt;Next came the Admin Tools to generate the login and ShareX hashes, as if no Environmental Variable was set, it defaulted to the hash of &quot;password&quot;. This is so I could roll the keys in case something leaks.&lt;/p&gt;
&lt;p&gt;Then came the true test, I wanted to see if Claude could get the Convex live subscription working on the Admin Dashboard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;i was trying to get the IConvexClient working on the dashboard earlier, with the live sync from convex so things would update automatically as things happened. however it just wouldn&apos;t connect. could it be because the dashboard pages don&apos;t have the interactive server like we had to do for the tools?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After some digging, I got this as a response, which lines up to exactly why it wasn&apos;t working:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, that&apos;s exactly the problem. Here&apos;s what&apos;s going on:&lt;/p&gt;
&lt;p&gt;AdminDashboard.razor has no @rendermode directive, so it renders as static SSR - the server generates HTML once, sends it to the browser, and there&apos;s no persistent SignalR circuit. Compare with AdminTools.razor:2 which has @rendermode InteractiveServer.&lt;/p&gt;
&lt;p&gt;For IConvexClient real-time subscriptions to work, you need two things:&lt;/p&gt;
&lt;p&gt;@rendermode InteractiveServer on the page - without it, there&apos;s no live SignalR circuit to push updates through. The component runs once, produces HTML, and is done. There&apos;s nothing keeping it alive to receive subscription callbacks.&lt;/p&gt;
&lt;p&gt;Inject IConvexClient instead of ConvexService - the dashboard currently uses ConvexService (your HTTP wrapper) which does one-shot request/response queries. IConvexClient from the Convex NuGet package maintains a WebSocket and can push updates when data changes.&lt;/p&gt;
&lt;p&gt;There&apos;s also a subtlety in Program.cs:212-220 - you set admin auth on IConvexClient inside a startup CreateScope() block. The IConvexClient is likely registered as a singleton by AddConvex(), so the auth should persist, but the scope itself gets disposed right after. Worth double-checking the Convex NuGet docs to make sure the auth sticks after the scope disposal.&lt;/p&gt;
&lt;p&gt;TL;DR: Add @rendermode InteractiveServer to the dashboard page, switch from ConvexService to IConvexClient, and subscribe to queries rather than one-shot fetching. That should get the live sync working.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I told Claude to get to work on that to see if it had actually found what the issue was. I had faith, but no luck, the stats were still not showing as expected. Claude put in some debugging steps, and after some trial and error back and forth, Claude finally started seeing the other issue. Instead of using the &lt;code&gt;.AddConvex()&lt;/code&gt; to register the service, it manually registered with a Singleton. Huge step to figure out the issue, now the Auth side is failing as it can&apos;t parse the JWT payload.&lt;/p&gt;
&lt;p&gt;Removing the Auth part of the Convex setup worked, and the Dashboard now showed the stats and data live as it updated! This turns the Convex &quot;public&quot; in a sense, so I will need to figure that out later.&lt;/p&gt;
&lt;p&gt;Feeling confident again, I swapped to Codex to see if it could do the other pages since now there is a working example done on the Dashboard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the AdminDashboard.razor is now working with live sync from Convex. could you wire up the rest of the admin pages (files, images, texts) to also pull the data live like the main dashboard?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had to provide logs a few times to Codex, as it just couldn&apos;t get the subscription wired up. Eventually after trial and error, the logs pointed to an actionable item. The data coming form the WebSocket was slightly off to what the Class was set-up as, so Codex created a JSON converter so data comes over from Convex as &lt;code&gt;&quot;69.0&quot;&lt;/code&gt; the conversion doesn&apos;t fail and &lt;code&gt;&quot;69&quot;&lt;/code&gt; is mapped. After this was implemented, all the Admin pages had a successful live subscription!&lt;/p&gt;
&lt;p&gt;I asked Codex to add a functionality to the Tools page that would take the key from the ShareX hash and generate the ShareX Custom Uploader using that. Easy to roll keys and make sure I don&apos;t mess anything up when doing so. No issues with that, one-shotted it.&lt;/p&gt;
&lt;p&gt;Next was adding the top links to the main dashboard page, ordered by view count. Just so I can see if anything is popping off in particular.&lt;/p&gt;
&lt;p&gt;One final change was the startup, I didn&apos;t like &quot;password&quot; being the default hashed string if the Env Vars didn&apos;t exist. So Codex changed that to a randomly generated string for both, and that was hashed. This way the default is &quot;secure&quot; but can easily get the keys from the console, and roll new ones.&lt;/p&gt;
&lt;h3&gt;&quot;Make It Secure&quot;&lt;/h3&gt;
&lt;p&gt;I like looking around GitHub for trending repos, projects, and cool ideas. I came across two AI powered Penetration Testers that seemed promising. One I just couldn&apos;t get running, but I will claim user error for that one. The other, while it worked, was hit with an API rate limit immediately. I set up an Anthropic API just for this, and threw $10 onto the credits. I was under the impression that as long as you had the funds, using the official API&apos;s was all you&apos;d have to do. I&apos;d kick off the tool, it would start &quot;Scanning endpoints&quot; and then stop with &quot;Rate Limit hit&quot; after seeing barely anything done. I could keep resuming the task, but it would work for 30 seconds to a minute and then get rate limited again. At this point I just grew frustrated, and gave up, I didn&apos;t want to try another API just for the same thing to potentially happen. I just turned to Claude and Codex with the following prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are a web application security expert conducting a comprehensive security assessment.&lt;/p&gt;
&lt;p&gt;Stack: .Net Blazor, Convex&lt;/p&gt;
&lt;p&gt;Authentication: Password login&lt;/p&gt;
&lt;p&gt;Purpose: ShareX hosting site for files, images, and text. Admin dashboard to track links.&lt;/p&gt;
&lt;p&gt;Endpoints:&lt;/p&gt;
&lt;p&gt;/admin&lt;/p&gt;
&lt;p&gt;/admin/dashboard&lt;/p&gt;
&lt;p&gt;/admin/images&lt;/p&gt;
&lt;p&gt;/admin/files&lt;/p&gt;
&lt;p&gt;/admin/texts&lt;/p&gt;
&lt;p&gt;/admin/tools&lt;/p&gt;
&lt;p&gt;/admin/api-reference&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;/i/ (POST)&lt;/p&gt;
&lt;p&gt;/i/{slug} (GET)&lt;/p&gt;
&lt;p&gt;/f/ (POST)&lt;/p&gt;
&lt;p&gt;/f/{slug} (GET)&lt;/p&gt;
&lt;p&gt;/t/ (POST)&lt;/p&gt;
&lt;p&gt;/t/{slug} (GET)&lt;/p&gt;
&lt;p&gt;Analyze the web application and provide:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;OWASP Top 10 vulnerability assessment&lt;/li&gt;
&lt;li&gt;Authentication and session management analysis&lt;/li&gt;
&lt;li&gt;Input validation and output encoding review&lt;/li&gt;
&lt;li&gt;Business logic flaw identification&lt;/li&gt;
&lt;li&gt;Client-side security assessment&lt;/li&gt;
&lt;li&gt;Detailed remediation recommendations with code examples&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know this seems silly, but given the clear context of the endpoints, the stack, purpose, and the goal, I felt like this would perform pretty well.&lt;/p&gt;
&lt;p&gt;The biggest thing both pointed out was the Convex implementation, both called out that the functions, queries, and mutations are not secure since there is no auth. That makes sense, we took it out to get it working. Claude didn&apos;t like the &lt;code&gt;Math.random()&lt;/code&gt; isn&apos;t cryptographically secure, and a few other things like CSP, admin sessions, file upload type validation, and the like. Those were cleaned up pretty easy, followed up by hardening the Convex implementation. I could spend more time by implementing auth and all of that, or just add in an Internal API Key that the Convex side and my side share to validate the requests are from my side.&lt;/p&gt;
&lt;p&gt;Codex didn&apos;t really have much to do after those were addressed, outside of some Tests and some anti-forgery stuff. It did however, suggest something I didn&apos;t think about. The image URL is directly from the Convex backend, which not only exposes the URL for the Convex but also bypasses the view/download counter (&lt;code&gt;which wasn&apos;t a huge deal to me&lt;/code&gt;). Now the endpoints use the slug to have a &lt;code&gt;/content&lt;/code&gt; and &lt;code&gt;/download&lt;/code&gt; route, which will always update properly.&lt;/p&gt;
&lt;p&gt;I then had Claude bring the &lt;code&gt;AGENTS.md&lt;/code&gt; and &lt;code&gt;README.md&lt;/code&gt; files up to speed according to the plan and the work done.&lt;/p&gt;
&lt;p&gt;Finally, I removed the &lt;code&gt;seedCounter&lt;/code&gt; Convex function, as that was no longer needed. Removed the Scalar integration, and some other minor cleanup.&lt;/p&gt;
&lt;h3&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;Before I attempt to publish this, I wanted to walk through the steps of a deployment again. So I blew away my local Convex containers, to start from scratch. I built my projects image and ran that, alongside the fresh Convex, with the necessary env vars. It was all working locally, I could use ShareX to hit the local environment, and I could see the tests appear in both dashboards instantly. Whoo!!&lt;/p&gt;
&lt;p&gt;I needed one last change, and this is just for better performance out of my VPS. Dokploy by default will build the new images on your server, unless you specify a Remote Server which I don&apos;t want to pay for right now. There is a workaround for this though, and that&apos;s GitHub Actions. I created a &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; file and set it up to build my Docker Image and push it to the GitHub Container Registry (GHCR). Then, with a webhook, the Dokploy instance can be notified a new Image is available, and spin down the current one, and spin up the new one with the proper configs.&lt;/p&gt;
&lt;p&gt;I pushed my repo, and the Tests failed, oof. Turns out, it&apos;s due to how I&apos;m handing the persistent keys. Quick fix, another push later, and my Image was successfully built by GitHub and pushed to the Registry. However, I didn&apos;t notice at the time, but my &lt;code&gt;.yml&lt;/code&gt; file was configured incorrectly, as it was pushing the webhook notify (&lt;code&gt;from commit&lt;/code&gt;) before the new Image was pushed. So the Dokploy would restart with the old Image.&lt;/p&gt;
&lt;p&gt;I noticed a few issues I didn&apos;t see at first, like page titles not being consistent, and missing Open Graph tags for rich text display. Got those taken care of easily.&lt;/p&gt;
&lt;p&gt;I then noticed the webhook issue, and swapped it to a &lt;code&gt;Dokploy Deployment Action&lt;/code&gt; which worked exactly as I needed. Once the new Image was available, then the Action would ping my Dokploy instance which would use that Image when re-creating the container.&lt;/p&gt;
&lt;p&gt;Now that it was all live, I just needed one final test of everything. I generated the new ShareX Uploaders, and added those to my setup. Clicking &lt;code&gt;Test&lt;/code&gt; and greeted with a URL on one screen, and an updated dashboard on the other!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://undefinedlabs.tech/content/i/8TkRao5F&quot; alt=&quot;Dashboard Updating with Tests&quot; title=&quot;Dashboard Updating with Tests&quot; /&gt;&lt;/p&gt;
&lt;p&gt;How cool is that!? That&apos;s why I wanted to try this project out, one see if AI could do a task it&apos;s not typically done, and two to see that sweet sweet syncing!&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Overall, I&apos;d call this a successful experiment! I got to play around with some AI, engineered a tool I wanted, and got it done faster than it took me to write this blog post!&lt;/p&gt;
&lt;p&gt;I&apos;m not going to go AI crazy, but I can see the usefulness of it and I did enjoy this process. I will continue to use AI to bounce my ideas off of, questions when I get stuck and can&apos;t figure it out on my own, and day to day stuff like that. I will be using it for more boilerplate work, as it is fantastic for that, and things I don&apos;t really care too much about and just want something created.&lt;/p&gt;
&lt;p&gt;I do feel less &lt;code&gt;connection&lt;/code&gt; with this project, in terms of the code itself. Which is strange for me, as I always &lt;em&gt;feel&lt;/em&gt; connected to the code and the finished project. It is a weird feeling, going from owning your code, to barely writing any of it. I don&apos;t think it&apos;s necessarily a bad thing, it&apos;s just different. In a way, I wish I could severe that connection and just lean in fully to AI, but then I won&apos;t learn nor grow, and I don&apos;t want that. If I just wanted to stay in my C# bubble, I would create a lot more projects utilizing AI to do the majority of it, it&apos;s easy to get something out the door and move onto the next one. I&apos;m not hating or knocking on the people who prompt and ship, it just doesn&apos;t align with my goals personally.&lt;/p&gt;
&lt;p&gt;This just makes me want to work on the other Convex projects even more, but I have a lot in the works right now. It&apos;s tough trying to balance everything out. I have a Go learning project idea that was inspired by working on this, and I just finished chewing on an idea for learning Rust. So be on the lookout for those, sooner rather than later!&lt;/p&gt;
&lt;p&gt;Never stop &lt;strong&gt;engineering&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item><item><title>I got nerd sniped</title><link>https://kyleundefined.dev/blog/undefined</link><guid isPermaLink="true">https://kyleundefined.dev/blog/undefined</guid><description>sshh, the latest brain child of mine</description><pubDate>Tue, 03 Feb 2026 21:10:00 GMT</pubDate><content:encoded>&lt;p&gt;What the hell happened? What even is &quot;nerd sniped&quot;? According to &lt;a href=&quot;http://nerd-sniping.urbanup.com/8996444&quot;&gt;Urban Dictionary&lt;/a&gt; it&apos;s&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote&amp;gt; The state of a nerd so deeply engaged in one of their areas of interest they are unaware of anything else.&amp;lt;/blockquote&amp;gt;&lt;/p&gt;
&lt;p&gt;Well, I was relaxing one evening just watching some YouTube when I came across a video titled &lt;a href=&quot;https://www.youtube.com/watch?v=JD7W0lzYHFs&quot;&gt;13 INSANE Front-End Project Ideas That Will RUIN Your Mental Health&lt;/a&gt; by a dude named &lt;code&gt;Manware&lt;/code&gt;. One of the projects he mentioned really stuck with me when I heard it. A terminal-inspired, local only, encrypted, note taking app. It instantly buried its way into my brain, and connected some dots I didn&apos;t know were floating around in there. I won&apos;t get super technical in this blog, my brain hurts from work and this project, so cut me some slack.&lt;/p&gt;
&lt;p&gt;I&apos;ve been wanting to play with React for a bit now, and have been doing some research into all the latest and greatest parts and pieces. I&apos;ve been hearing a lot about a framework for React called &lt;a href=&quot;https://tanstack.com/&quot;&gt;TanStack&lt;/a&gt; and it seemed to be a perfect fit. They have several pieces that can be plugged in, and boy does it make working with React a breeze!&lt;/p&gt;
&lt;p&gt;Angular was my entry into TypeScript, I did a lot of research into Angular and React when I was working on the Tera Raid Info project. I went with Angular at the time as it seemed more &quot;it just works&quot; out of the box. The docs made sense to me and I was able to hack my way into what that project is today. React at the time felt like it was a great framework, but the styling and the syntax honestly pushed me away.&lt;/p&gt;
&lt;p&gt;However, the new age of the web is React over Angular, and I get why after using both. Angular feels like it pushes you into a way of design and structure, which I kind of like as it&apos;s what I&apos;m used to. React on the other hand, allows you to build however you want, and just gives you the wires to make it all happen.&lt;/p&gt;
&lt;p&gt;TanStack helps leverage the power of React, by offering their Router, which is perfect for a Single Page Application (SPA) like mine. I like that it&apos;s fully TypeScript compatible, and really gives you more features than I need for this, but I can see why it&apos;s very popular. The main goal of the app was to be local first, so having it store all the data in the browser was key. I&apos;ve worked with IndexedDB in the past using Dexie and was going to use that until I saw TanStack had a &lt;a href=&quot;https://tanstack.com/db/latest&quot;&gt;DB&lt;/a&gt; package that worked with the &lt;a href=&quot;https://tanstack.com/db/latest/docs/collections/rxdb-collection&quot;&gt;RxDB Collection&lt;/a&gt;. It is more powerful than I need for this project as it offers syncing and replication, but offers a solid backbone to my needs.&lt;/p&gt;
&lt;p&gt;Next came encryption, and all of that is handled with the Web Crypto API which is standard, and won&apos;t have to reinvent anything. I planned to encrypt everything that is stored into the collections, so even a snooper couldn&apos;t just &lt;code&gt;Ctrl+Shift+I&lt;/code&gt; their way into your stuff. But that starts another problem with it being a terminal like app. It would be super expensive, not monetarily but in terms of CPU cycles and such, to have to decrypt the data in the collections every time you wanted to search for a note or do anything with the persisted data.&lt;/p&gt;
&lt;p&gt;I needed to keep a map of &lt;em&gt;some&lt;/em&gt; of the data from the collections, like note/folder name, tags, etc., without having to hit the collections each time and decrypt it just to access it. TanStack has &lt;a href=&quot;https://tanstack.com/store/latest&quot;&gt;Store&lt;/a&gt; which is exactly what I was needing, and enables what I call the &lt;code&gt;LiveMap&lt;/code&gt;. This is the layer between the terminal, and the RxDB collections. It holds the unencrypted metadata of the notes/folders but not the note content. All you have to do is basically define the store, and you have access to set/get the store data when and however you like.&lt;/p&gt;
&lt;p&gt;With all of that figured out, I began learning my way through the project. I started the project with a scaffold of TanStack Start, as that&apos;s what I thought I needed at the time, turns out I just need Router. Before I figured that out though, I made sure the project worked, and figured out how it all worked. That was a bit of a waste of time, as Start gives you everything you need for SSR (Server Side Rendering) which is not what I needed. I spent some time taking out the pieces I didn&apos;t need from the project, and converted it into a proper SPA scaffold.&lt;/p&gt;
&lt;p&gt;I ripped out all the demo and routes that came from the scaffold, swapped to Bun (Side note, really liking Bun over NPM), and started work on getting &lt;a href=&quot;https://xtermjs.org/&quot;&gt;XTerm.js&lt;/a&gt; implemented. That took me longer than I thought it would, trying to figure out how to make the terminal show up was a head scratcher, but finally figured that out and was simpler than I was making it out to be. I started playing around with the &lt;code&gt;onData&lt;/code&gt; and &lt;code&gt;attachCustomKeyEventHandler&lt;/code&gt; of the terminal to capture events and input. The issue was that everything was being done in the &lt;code&gt;useEffect&lt;/code&gt; and was not the best way to do it. So I swapped the terminal into a Service and added a hook that referenced that, and then the component just rendered the terminal. I did some more tinkering of the terminal service and cleaning up in terms of reusability and splitting out the responsibilities of the service. I created custom Keyboard Events to handle with the terminal for Copy/Paste. Created an SVG and got the PWA Asset Generation hooked up and working. Finished off with playing around with the input buffer for &lt;code&gt;Shift+Enter&lt;/code&gt; support (eventually took it out), and backspacing the newlines out.&lt;/p&gt;
&lt;p&gt;By this time, the terminal service had grown to almost 600 lines of mixed concerns out the wazoo, but this is how I like to build. I put something down, play, test, get it working and then refactor like my life depends on it. First, create the input buffer and link pop managers, these allow me to pass the input into a service that just returns the result of that, instead of the service doing all the logic. The link pop manager is just to format the links in the &lt;code&gt;motd&lt;/code&gt; so they are styled and act properly (hover state, and controlled click), like so:
[Embedded Image]&lt;/p&gt;
&lt;p&gt;I then created the terminal addon service, it just makes sure the ones I am using are loaded into the terminal instance and properly disposed of. Then I just had to create the terminal writer, just to handle all the output to the terminal better, plus gets the giant welcome message text out of the way. Finally, the terminal config file. Just sets all the config options I was using into a dedicated wrapper, not entirely needed but good for cleanup. With all of that combined, the terminal service went down to just under 300 lines!&lt;/p&gt;
&lt;p&gt;Then came time to get the encryption service implemented. I generate a salt using &lt;code&gt;Uint8Array&lt;/code&gt; with a length of 16 bytes and then pass that salt to the crypto API to &lt;code&gt;getRandomValues&lt;/code&gt; based on that salt. That salt gets stored into the config collection, but I am also going with a Canary approach, so that&apos;s why. That just means I have a piece of data that is encrypted with the Salt + Password and then that value is stored, you can use that to confirm if the user has put in the proper password. I wrote some unit tests to confirm the logic worked how I wanted, and started working on the Store implementation. I created a hook to use with it so I could track the current folder and if the vault was locked/unlocked. Finally, I just wired those pieces into what I had done and man, what great progress!&lt;/p&gt;
&lt;p&gt;Next came the RxDB and LiveMap implementations. Started with the RxDB as without the data first, the LiveMap won&apos;t do anything. Nailed down the schema&apos;s, created the storage service with CRUD like functions, and created the hook. Which at the time I thought was right, cause how else would you use the Store? Going down that route, I setup the LiveMap with the events to handle everything. In my copy/paste rename process, I got lost in the sauce and started making the LiveMap like its own Store-&amp;gt;DB collection, and basically was just done wrong. It should NEVER store its data to the collection, it is the middleman for a cache like system. A bit of refactoring of the Session store and service, unit tests of the Storage, and hey look at that it&apos;s running still and my basic operations are working.&lt;/p&gt;
&lt;p&gt;At this point, I was at a cross-roads. Do I keep chugging along with what I have, start shoving commands and handlers into the terminal service, only to end up rewriting it later? Or spend two days creating a command framework that mimics the command systems I&apos;ve used in past Discord/Twitch bots? You already &lt;strong&gt;know&lt;/strong&gt; the answer to that.&lt;/p&gt;
&lt;p&gt;First, that requires a major architectural redesign. Everything related to the terminal was stuff into &lt;code&gt;/src/services&lt;/code&gt; and if I wasn&apos;t going to be the overhaul gremlin I am, that would have been fine and worked. I changed the design to have it broken down better, with a folder for the terminal, session, storage, commands, etc. With that out of the way, I created Validators for the Names and Paths. Speaking of Paths, created a Resolver that builds the path based on the metadata and validates the path is an actual path in the collection. All of this to simulate the &lt;code&gt;cd&lt;/code&gt; nature of the terminal. I created an editor Store for when the &lt;code&gt;vi&lt;/code&gt; command is called, it opens a slim modal with the note content, this tracks that state of the modal and events. I then created a command history Store so it tracks the latest 100 successful commands entered, and can be scrolled through with the up/down arrows. Again, I &lt;em&gt;really&lt;/em&gt; wanted that terminal vibe, this idea sunk in hard. I then got side tracked with images working in the terminal, so got that knocked out after a bit of trial, error, and regex magic.&lt;/p&gt;
&lt;p&gt;Here comes the meat and potatoes of this project, in my eyes, the command system. Like I mentioned earlier, I&apos;ve written some Discord and Twitch bots, and used different frameworks for those to handle the commands. With Discord for example, the framework I last used, you&apos;d mark your command with the proper implements, and you&apos;d register the commands at build and voila, your Discord message is now a command! Granted, that&apos;s a high level view, but you get the idea.&lt;/p&gt;
&lt;p&gt;First, the Command Registry service. The point of this is to register the commands, aliases, and execution. This is what holds the information of what commands are available, what aliases, parsing the input, and command validation. Without this, what&apos;s the point of the command system? Next came the Command Initialization, and this is just what fills the Registry with the available commands and aliases. I then created a Command Context, this is so I can pass around the current folder, and the session/storage service through Dependency Injection. Next came the Command Result, so that way the command system isn&apos;t responsible for any state, UI, or terminal changes. It just passes back if it was a success, error, and metadata. Finally, came the abstract Command class. This allows you to create the commands, validate the arguments, execute, and return the result. It has a &lt;code&gt;getHelp&lt;/code&gt; method that returns the command metadata you set when creating the command, and this powers the &lt;code&gt;help&lt;/code&gt; command to get that data dynamically instead of having to hardcode anything.&lt;/p&gt;
&lt;p&gt;With that high level change done, I started creating the commands. First was the &lt;code&gt;help&lt;/code&gt; command, the class inherits the &lt;code&gt;Command&lt;/code&gt; class we created earlier, set the metadata, and use the Registry to pull all available commands. For now, it just shows this command when executed, but it&apos;s a start. Wired up the &lt;code&gt;clear&lt;/code&gt; command with a &lt;code&gt;cls&lt;/code&gt; alias, took no time to implement the behavior into the UI as well. Then the laundry list of commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ls&lt;/li&gt;
&lt;li&gt;cd&lt;/li&gt;
&lt;li&gt;mkdir&lt;/li&gt;
&lt;li&gt;pwd&lt;/li&gt;
&lt;li&gt;touch&lt;/li&gt;
&lt;li&gt;motd&lt;/li&gt;
&lt;li&gt;cat&lt;/li&gt;
&lt;li&gt;mv&lt;/li&gt;
&lt;li&gt;rm&lt;/li&gt;
&lt;li&gt;find&lt;/li&gt;
&lt;li&gt;grep&lt;/li&gt;
&lt;li&gt;lock&lt;/li&gt;
&lt;li&gt;vi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I did end up adding a debug command, to track the LiveMap and make sure that was working accurately. I was planning on taking it out before &quot;launching&quot; but it is fine, it&apos;s all local and your data, and that LiveMap is cleared upon vault lock and rebuilt when it&apos;s unlocked, so it&apos;s not always kept in memory. It looks like this:
[Embedded Image]&lt;/p&gt;
&lt;p&gt;I had changed the command history schema a bit, and so this doesn&apos;t show the 100 capped list, and not doing a migration in dev mode.&lt;/p&gt;
&lt;p&gt;I added in the suite of unit tests, and got those passing.&lt;/p&gt;
&lt;p&gt;I then got an idea for someone like me, who swaps browsers a lot (I can&apos;t make up my mind, don&apos;t judge me!) and don&apos;t really use PWA sites too much. Ironic. Anyway, I added in a &lt;code&gt;tar&lt;/code&gt; command that exports your data into a &lt;code&gt;.json&lt;/code&gt; file and it is all encrypted still. Then a &lt;code&gt;mnt&lt;/code&gt; command to import that data, and re-encrypt it with your new key. It prompts for the password you used when you created the vault, so if you don&apos;t remember that, good luck!&lt;/p&gt;
&lt;p&gt;Did more code cleanup, tweaks, bug fixes, and the like, thanks to Code Rabbit annoying me about things. Added in a &lt;code&gt;autolock&lt;/code&gt; command, that allows you to configure how long the terminal is unlocked for, and can be disabled.&lt;/p&gt;
&lt;p&gt;And that&apos;s about it, really. Like I said, wasn&apos;t going into high level, I&apos;m tired, but wanted to write something about this project as it was a lot of fun and I really enjoyed making this! I do have future plans to add in autocompletion based on the command history, and add in NVim key binding support into the editor modal, as I&apos;m trying to get used to that instead of IDEs. No future plans on when those will happen, as they&apos;re not a priority and my brain feels like an itch has been scratched.&lt;/p&gt;
&lt;p&gt;You can check out the code on my &lt;a href=&quot;https://github.com/Kyle-Undefined/sshh&quot;&gt;GitHub&lt;/a&gt; or give it a &lt;a href=&quot;https://sshh.kyleundefined.dev&quot;&gt;try&lt;/a&gt;!&lt;/p&gt;
</content:encoded></item><item><title>Knocking the CSS rust off</title><link>https://kyleundefined.dev/blog/undefined</link><guid isPermaLink="true">https://kyleundefined.dev/blog/undefined</guid><description>2 divs, 1 flip</description><pubDate>Sat, 24 Jan 2026 14:42:00 GMT</pubDate><content:encoded>&lt;p&gt;Meme aside, it&apos;s pretty amazing what you can do with CSS nowadays. Like I mentioned in my previous &lt;a href=&quot;/blog/so-i-created-a-website-again&quot;&gt;post&lt;/a&gt;, CSS was my first love of the web. I wasn&apos;t doing the craziest things when I first started, but &lt;em&gt;Web 2.0&lt;/em&gt; was in its infancy years. When I started doing web, 2.0 was less than 5 years old and the focus was more on the interactivity via user generated content, API&apos;s, Ajax and early stages of Social graphs. Hell, I was still writing ActionScript at my company for our client sites that all mashed up with Classic ASP, ASP.Net, and ColdFusion.&lt;/p&gt;
&lt;p&gt;You could use the &lt;code&gt;animation&lt;/code&gt; property and &lt;code&gt;@keyframes&lt;/code&gt; at-rule then, but it was very browser specific, and in the days of IE, was a huge pain. The amount of hours I spent making something look the same across all the browsers, tweaking one prefix just slightly because Microsoft thinks they can reinvent the wheel. That kind of stuff didn&apos;t really get main-stream adoption until like 2010 or so. I had left the front-end space by that time, which is when support and adoption really took off it seems.&lt;/p&gt;
&lt;p&gt;Having to add in every prefix you wanted to hope was supported, and then a fallback, just added more headache than it was worth.&lt;/p&gt;
&lt;p&gt;For example, if you wanted to animate a div, you had to bloat your CSS like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@-webkit-keyframes slide {
	0% { -webkit-transform: translateX(-100%); } 
	100% { -webkit-transform: translateX(0); } 
}

@-moz-keyframes slide { 
	0% { -moz-transform: translateX(-100%); } 
	100% { -moz-transform: translateX(0); } 
}

@-o-keyframes slide { 
	0% { -o-transform: translateX(-100%); } 
	100% { -o-transform: translateX(0); } 
}

@keyframes slide { 
	0% { transform: translateX(-100%); } 
	100% { transform: translateX(0); } 
}

.box { 
	width: 100px; 
	height: 100px; 
	background: #4caf50; 
	-webkit-border-radius: 8px; 
	-moz-border-radius: 8px; 
	border-radius: 8px; 
	-webkit-animation: slide 1s ease-in-out infinite alternate; 
	-moz-animation: slide 1s ease-in-out infinite alternate; 
	-o-animation: slide 1s ease-in-out infinite alternate; 
	animation: slide 1s ease-in-out infinite alternate;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Opera prefix, that brings back some memories...&lt;/p&gt;
&lt;p&gt;Now you don&apos;t need all of that, you can omit the prefixes and every browser supports it. That makes it so much easier, and as a bonus CSS has advanced so much! I have the basic &lt;code&gt;@view-transition&lt;/code&gt; enabled via the &lt;code&gt;&amp;lt;ClientRouter /&amp;gt;&lt;/code&gt; in Astro, but that opens the doors for so many cool ideas!&lt;/p&gt;
&lt;p&gt;I won&apos;t be doing anything crazy or advanced in this post, just some practice with a coin flip using the CSS animations.&lt;/p&gt;
&lt;p&gt;The following code examples can be found on my &lt;a href=&quot;https://github.com/Kyle-Undefined/examples.kyle-undefined.github.io&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&apos;ll start off with a base of:
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/base.html]&lt;/p&gt;
&lt;p&gt;This is just a simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
	border: solid 1px #848bbd;
	display: flex;
	justify-content: center;
	align-items: center;
	height: 400px;
	flex-direction: column;
	text-align: center;
}
.coin {
	width: 25%;
	border: solid 1px silver;
}
.table {
	width: 75%;
	border: solid 1px brown;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;div class=&quot;coin&quot;&amp;gt;Coin&amp;lt;/div&amp;gt;
  &amp;lt;div class=&quot;table&quot;&amp;gt;Table&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&apos;s do a simple &quot;flip&quot; animation on the &lt;code&gt;coin&lt;/code&gt; div. I have it set to infinitely loop for easier viewing.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/base-ani.html]&lt;/p&gt;
&lt;p&gt;This is achieved with a simple &lt;code&gt;animation:&lt;/code&gt; on the class like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.coin {
	width: 25%;
	border: solid 1px silver;
	animation: coinflip 0.75s ease-in-out infinite normal 1s;
	/*
	  animation-name: coinflip;
	  animation-duration: 1s;
	  animation-timing-function: ease-in-out;
	  animation-iteration-count: infinite;
	  animation-direction: normal;
	  animation-delay: 1s;
	*/
}
@keyframes coinflip {
	0% { transform: rotateZ(0); }
	100% { transform: rotateZ(360deg); }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s a very quick and dirty flip, but it works. So, I got the flip working, but now let&apos;s get the &quot;up&quot; of the flip working. Again, quick and dirty for the base, but I cleaned up the names a bit.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-up.html]&lt;/p&gt;
&lt;p&gt;I have to define the &quot;up&quot; and I can combine them on the &lt;code&gt;.coin&lt;/code&gt; class like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.coin {
	width: 25%;
	border: solid 1px silver;
	animation:
	  coin-up 0.75s ease-in-out infinite normal 1s,
	  coin-flip 0.75s ease-in-out infinite normal 1s;
	position: relative;
}
@keyframes coin-flip {
	0% { transform: rotateZ(0); }
	100% { transform: rotateZ(360deg); }
}

@keyframes coin-up {
	0% { bottom: 0px; }
	100% { bottom: 100px; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have to set the &lt;code&gt;position&lt;/code&gt; of the coin to be relative, otherwise the &lt;code&gt;bottom&lt;/code&gt; won&apos;t move the div as I expect. But, as you can see the coin just resets back to the &lt;code&gt;table&lt;/code&gt; when the animation is over.&lt;/p&gt;
&lt;p&gt;You could add a new &lt;code&gt;keyframes&lt;/code&gt; for a coin-down animation and play with the delays and orders of things, or you could just update the &lt;code&gt;coin-up&lt;/code&gt; animation-direction to be &lt;code&gt;alternate&lt;/code&gt; instead of &lt;code&gt;normal&lt;/code&gt; which does what I am looking for.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-down.html]&lt;/p&gt;
&lt;p&gt;Boom! Coin flip animated, blog post done. You wish, I have to take this further!&lt;/p&gt;
&lt;p&gt;I can combine the &lt;code&gt;keyframes&lt;/code&gt; into one as a start, this will allow me to fine tune the animation itself.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes coin-flip {
	0% { 
	  transform: rotateZ(0); 
	  bottom: 0px; 
	}
	50% { 
	  transform: rotateZ(180deg); 
	  bottom: 100px; 
	}
	100% { 
	  transform: rotateZ(360deg); 
	  bottom: 0px; 
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives one flip of the coin when it goes up and down.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-one.html]&lt;/p&gt;
&lt;p&gt;Let&apos;s add in more rotations.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes coin-flip {
	0% { 
	  transform: rotateZ(0deg); 
	  bottom: 0px; 
	}
	25% { 
	  transform: rotateZ(720deg); 
	  bottom: 75px; 
	}
	50% { 
	  transform: rotateZ(1440deg); 
	  bottom: 100px; 
	}
	75% { 
	  transform: rotateZ(2160deg); 
	  bottom: 75px; 
	}
	100% { 
	  transform: rotateZ(2880deg); 
	  bottom: 0px; 
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives a hilariously fast spin which kind of &quot;jumps&quot; in the air to do the rotations, but it&apos;s a start.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-funny.html]&lt;/p&gt;
&lt;p&gt;In order to smooth out the flips, I need to add in more steps to the &lt;code&gt;keyframes&lt;/code&gt; for more fine tune control of the transformations.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-smooth.html]&lt;/p&gt;
&lt;p&gt;That looks better, we&apos;re making progress! Isn&apos;t this so cool?! What more can I do to improve this? Well let&apos;s add in a delay after the animation is done so the coin sits on the table before the animation restarts. This can be done by adjusting the &lt;code&gt;keyframes&lt;/code&gt; so the final stage is the delay.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-delay.html]&lt;/p&gt;
&lt;p&gt;Here is how that looks in the CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes coin-flip {
	0% { 
	  transform: rotateZ(0deg); 
	  bottom: 0px; 
	}
	8% { 
	  transform: rotateZ(72deg); 
	  bottom: 20px; 
	}
	16% { 
	  transform: rotateZ(144deg); 
	  bottom: 40px; 
	}
	24% { 
	  transform: rotateZ(216deg); 
	  bottom: 60px; 
	}
	32% { 
	  transform: rotateZ(288deg); 
	  bottom: 80px; 
	}
	40% { 
	  transform: rotateZ(360deg); 
	  bottom: 100px; 
	}
	48% { 
	  transform: rotateZ(432deg); 
	  bottom: 80px; 
	}
	56% { 
	  transform: rotateZ(504deg); 
	  bottom: 60px; 
	}
	64% { 
	  transform: rotateZ(576deg); 
	  bottom: 40px; 
	}
	72% { 
	  transform: rotateZ(648deg); 
	  bottom: 20px; 
	}
	80% { 
	  transform: rotateZ(720deg); 
	  bottom: 0px; 
	}
	100% { 
	  transform: rotateZ(720deg); 
	  bottom: 0px; 
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, it&apos;s not as simple as just adjusting properties, but it&apos;s fun to figure out the stages. CSS started supporting &lt;code&gt;var()&lt;/code&gt; and &lt;code&gt;calc()&lt;/code&gt; functions that allow you to set variables that you can use throughout the file and to calculate a value. Dynamic CSS is so neat!&lt;/p&gt;
&lt;p&gt;Let&apos;s implement those functions in my example, so I can adjust the flip behavior without having to change everything.&lt;/p&gt;
&lt;p&gt;First, we&apos;ll add in the variables:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.coin {
	width: 25%;
	border: solid 1px silver;
	animation: coin-flip var(--anim-time) ease-in-out infinite normal var(--anim-delay);
	position: relative;
	
	--rotation-min: 0deg;
	--rotation-max: 720deg;
	--rotation-step: calc(var(--rotation-max) / 10);
	--height-max: 100px;
	--height-step: calc(var(--height-max) / 5);
	--anim-delay: 1s;
    --anim-time: 5s;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this does is create the variables that I can reference later. I set a Min and Max for the rotations, the Max determines how many flips is done by the coin, and is 2 flips by default. Then I set a Step for the rotations which is calculated off of the Max / 10. &lt;em&gt;Had to do math for this, ew, yuck!&lt;/em&gt; The Max Height is how far up the coin goes up off the table, and that&apos;s used to calculate the step for the up/down animation. I call the Time/Delay variables for control over that as well.&lt;/p&gt;
&lt;p&gt;With those setup, I can update the &lt;code&gt;@keyframes&lt;/code&gt; to use those variables, and do some calculations of itself for the steps:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes coin-flip {
	0% { 
	  transform: rotateZ(var(--rotation-min)); 
	  bottom: 0px; 
	}
	8% { 
	  transform: rotateZ(calc(var(--rotation-step) * 1)); 
	  bottom: calc(var(--height-step) * 1); 
	}
	16% { 
	  transform: rotateZ(calc(var(--rotation-step) * 2)); 
	  bottom: calc(var(--height-step) * 2); 
	}
	24% { 
	  transform: rotateZ(calc(var(--rotation-step) * 3)); 
	  bottom: calc(var(--height-step) * 3); 
	}
	32% { 
	  transform: rotateZ(calc(var(--rotation-step) * 4)); 
	  bottom: calc(var(--height-step) * 4); 
	}
	40% { 
	  transform: rotateZ(calc(var(--rotation-step) * 5)); 
	  bottom: var(--height-max); 
	}
	48% { 
	  transform: rotateZ(calc(var(--rotation-step) * 6)); 
	  bottom: calc(var(--height-step) * 4); 
	}
	56% { 
	  transform: rotateZ(calc(var(--rotation-step) * 7)); 
	  bottom: calc(var(--height-step) * 3); 
	}
	64% { 
	  transform: rotateZ(calc(var(--rotation-step) * 8)); 
	  bottom: calc(var(--height-step) * 2); 
	}
	72% { 
	  transform: rotateZ(calc(var(--rotation-step) * 9)); 
	  bottom: calc(var(--height-step) * 1); 
	}
	80% { 
	  transform: rotateZ(var(--rotation-max)); 
	  bottom: 0px; 
	}
	100% { 
	  transform: rotateZ(var(--rotation-max)); 
	  bottom: 0px; 
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Phew, that&apos;s a lot! Let&apos;s break that down...&lt;/p&gt;
&lt;p&gt;I start with the base step which is just the coin being on the &quot;table&quot;. I then calculate the transform value from the Step * step number, and the bottom value from the height step * step number. The step number for the &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;bottom&lt;/code&gt; is the calculated degrees/height per animation stage. The height step goes up to 4 and then back down to 1. The rotation step goes up to 9 for the pause at the end. I then end the animation with the div being &quot;reset&quot; and resting.&lt;/p&gt;
&lt;p&gt;Visually nothing changes, and technically, functionality doesn&apos;t change either. However, this now allows me to adjust the coin flip by changing a few lines instead of the whole &lt;code&gt;@keyframes&lt;/code&gt; setup.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-func.html]&lt;/p&gt;
&lt;p&gt;Want a slow mode flip? Easy, just adjust the &lt;code&gt;--anim-time&lt;/code&gt; variable to &lt;code&gt;5s&lt;/code&gt; and boom, it all updates.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-slow.html]&lt;/p&gt;
&lt;p&gt;Oh I know what you want, you want that quadruple rotation flip! Coming right up! &lt;code&gt;--rotation-max: 1440deg;&lt;/code&gt; is all you&apos;d have to adjust.
[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-four.html]&lt;/p&gt;
&lt;p&gt;I could adjust the borders to make it more coin shaped, but this is just examples and practice.&lt;/p&gt;
&lt;p&gt;Again, all the code for these examples can be found in my &lt;a href=&quot;https://github.com/Kyle-Undefined/examples.kyle-undefined.github.io&quot;&gt;examples&lt;/a&gt; repo over on GitHub. Below is a final example utilizing all of this to have separate coins flip with different animations.&lt;/p&gt;
&lt;p&gt;Catch ya on the flip side!&lt;/p&gt;
&lt;p&gt;[Note: Embedded content from https://examples.kyleundefined.dev/coin-flip/flip-final.html]&lt;/p&gt;
</content:encoded></item><item><title>So I created a website (again)</title><link>https://kyleundefined.dev/blog/undefined</link><guid isPermaLink="true">https://kyleundefined.dev/blog/undefined</guid><description>Journey into a new mindset</description><pubDate>Tue, 20 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Man, does time fly... I set out to create this site a year ago, but life got in the way. Granted, this is probably my 4th or 5th iteration of a personal site. They&apos;ve all served a purpose, been built with different technologies, and faded into the void.&lt;/p&gt;
&lt;p&gt;I originally tried this with Hugo and Obsidian after watching a YouTube video showcasing the combo. I got it up and running, but I just wasn&apos;t &lt;em&gt;feeling&lt;/em&gt; it. The setup was clunky, and I was too zeroed in on making that specific workflow work. It was more than just writing, committing, and pushing; I had to run a Python script just to convert image links from Markdown to HTML. While it worked, I could either see the images in Obsidian or on the web, but never both. For someone with my level of OCD, that was a deal breaker.&lt;/p&gt;
&lt;p&gt;I eventually dropped that project after not finding a solution to that one issue. Never finished writing my post, never hit commit, never hit &lt;strong&gt;push&lt;/strong&gt;. This year is going to be different. I have a lot of ideas bouncing around my old noggin. Many are one-offs that are &quot;meh&quot; on the totem pole of interest, but some are worth diving into just for the sake of learning. Like a browser extension for tab management (I have a problem… and a solution!).&lt;/p&gt;
&lt;p&gt;A few ideas, though, really latch onto you. My &lt;a href=&quot;https://github.com/Kyle-Undefined/PoE-Bot&quot;&gt;PoE Bot&lt;/a&gt;, for example, was more fun to build than actually playing the game. Or, what do you do while shiny hunting and waiting for DLC? You build a &lt;a href=&quot;https://kyleundefined.dev/tera-raid-info/&quot;&gt;site&lt;/a&gt; that turns Serebii data into an easy-to-digest format for Tera Raids. Lately, I&apos;ve started a project for my TCG hobby, sparked by seeing some cool card CSS (my first love of the web) I wanted to try out. That project is quickly becoming more addictive than Arc Raiders!&lt;/p&gt;
&lt;p&gt;In the past, projects like the PoE Bot were total attention hogs. I would focus on one thing until I was burnt out, leaving no energy for anything else. I don&apos;t want to do that anymore. I want to save brainpower for other interests while balancing work, socializing, and gaming. That&apos;s why I restarted this blog.&lt;/p&gt;
&lt;p&gt;I know the TCG project will take awhile, and I need a &quot;side-quest&quot; to keep from mainlining one thing at a time. When I looked back at my old Hugo site, it felt daunting. After a quick search, I found Astro, which is exactly what I was looking for. It uses TypeScript, which I know enough of to be dangerous, and generates a static site for GitHub Pages based on simple Markdown files. I created a new Obsidian vault in the &lt;code&gt;/src/content/folder&lt;/code&gt;, and now every post is just a Templater script, a commit, and a push away.&lt;/p&gt;
&lt;p&gt;Astro is really neat! I can build collections, components, modules, etc that makes it feel like working on a front-end application, but is so simple and easy that it took less than a day to get it up and running. I have already tinkered around with the limits, which is fun!&lt;/p&gt;
&lt;p&gt;I don&apos;t know how often I will post, but I already have a few ideas in mind for more in the future. I&apos;m already planning a write-up on the building and evolution of the Tera Raid website, that was a really fun learning process, and I&apos;ll definitely be doing one for the TCG project too. I&apos;m really enjoying the tools I&apos;ve built so far.&lt;/p&gt;
&lt;p&gt;I have high hopes for this blog, my little space to get things off the brain and into the void. I have several projects in the works, of varying difficulties, so I will have a lot to share this year.&lt;/p&gt;
&lt;p&gt;I&apos;ve found some old development projects from some old companies, even found one of my old PHP websites from back in the day. I&apos;m pretty sure this is the one that eventually got hacked, learned a hard lesson about securing file uploads on a server as a teen. I found some old ColdFusion projects, which brings back some memories of a dude who would use the Prod servers to do his CF work, including bringing down the site with malformed syntax.&lt;/p&gt;
&lt;p&gt;I mentioned CSS being my first love of the web, and that was powered by hatred of JavaScript. I was too young to realize it was the bad implementations I didn&apos;t like, not the entire language. It still has its issues, but what language doesn&apos;t? That was in the early days of Web 2.0 and jQuery being forced onto things that made no sense. At the company I was with at the time, I ripped out the JS powered menu for our client templates, and replaced it with full CSS and kept the same animations. They were simple &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;background:&lt;/code&gt; changes, but felt good to refactor and it still work.&lt;/p&gt;
&lt;p&gt;I want to play with and learn the Tailwind system more, I would have killed for this back in the day. I love back-end and software building, but front-end is so much fun too. I did a few CSS things for this website, and the new &lt;code&gt;@view-transition&lt;/code&gt; stuff seems really fun and impressive! Don&apos;t expect the site to always look like this, I have a lot to play around with!&lt;/p&gt;
&lt;p&gt;I don&apos;t really do New Year resolutions, but a personal change I am making, and have had great success with so far, is allowing myself to start new projects even when I&apos;m already mid-build on something else. There are too many things to learn, do, and build.&lt;/p&gt;
&lt;p&gt;But this year, I will &lt;strong&gt;create&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item></channel></rss>