2026-04-10 03:00:00
I love tools like Netlify and deploying my small personal sites with
git pushBut i'm not gonna lie, 2025 might be the year I go back to just doing builds locally and pushing the deploys from my computer.
I'm sick of devops'ing stupid stuff because builds work on my machine and I have to spend that extra bit of time to ensure they also work on remote linux computers.
Not sure I need the infrastructure of giant teams working together for making a small personal website.
It’s 2026 now, but I finally took my first steps towards this.
One of the ideas I really love around the “local-first” movement is this notion that everything canonical is done locally, then remote “sync” is an enhancement.
For my personal website, I want builds and deployments to work that way.
All data, build tooling, deployment, etc., happens first and foremost on my machine.
From there, having another server somewhere else do it is purely a “progressive enhancement”. If it were to fail, fine. I can resort back to doing it locally very easily because all the tooling is optimized for local build and deployment first (rather than being dependent on fixing some remote server to get builds and deployments working).
It’s amazing how many of my problems come from the struggle to get one thing to work identically across multiple computers.
I want to explore a solution that removes the cause of my problem, rather than trying to stabilize it with more time and code.
“The first rule of distributed computing is don’t distribute your computing unless you absolutely have to” — especially if you’re just building personal websites.
So I un-did stuff I previously did (that’r right, my current predicament is self-inflicted — imagine that).
My notes site used to work like this:
It worked, but sporadically. Sometimes it would fail, then start working again, all without me changing anything. And when it did work, it often would take a long time — like five, six minutes to run a build/deployment.
I never could figure out the issue. Some combination of Netlify’s servers (which I don’t control and don’t have full visibility into) talking to Dropbox’s servers (which I also don’t control and don’t have full visibility into).
I got sick of trying to make a simple (but distributed) build process work across multiple computers when 99% of the time, I really only need it to work on one computer.
So I turned off builds in Netlify, and made it so my primary, local computer does all the work. Here are the trade-offs:
The change was pretty simple.
First, I turned off builds in Netlify. Now when I git push Netlify does nothing.
Next, I changed my build process to stop pulling markdown notes from the Dropbox API and instead pull them from a local folder on my computer. Simple, fast.
And lastly, as a measure to protect myself from myself, I cloned the codebase for my notes to a second location on my computer. This way I have a “working copy” version of my site where I do local development, and I have a clean “production copy” of my site which is where I build/deploy from. This helps ensure I don’t accidentally build and deploy my “working copy” which I often leave in a weird, half-finished state.
In my package.json I have a deploy command that looks like this:
git pull && npm ci && netlify deploy --build --prod
That’s what I run from my “clean” copy. It pulls down any new changes, makes sure I have the latest deps, builds the site, then lets Netlify’s CLI deploy it.
As extra credit, I created a macOS shortcut
# So it knows where to get the right $PATH to node
source ~/.zshrc
# Then switch to my dir and run the command
cd ~/Sites/com.jim-nielsen.notes/
npm run deploy
So I can do CMD + Space, type “Deploy notes.jim-nielsen.com” to trigger a build, then watch the little shortcut run to completion in my Mac’s menubar.
I’ve been living with this setup for a few weeks now and it has worked beautifully. Best part is: I’ve never had to open up Netlify’s website to check the status of a build or troubleshoot a deployment.
That’s an enhancement I can have later — if I want to.
2026-04-07 03:00:00
Did you know that Jesus gave advice about prototyping with an LLM? Here’s Luke 14:28-30:
Suppose one of you wants to build a tower. Won’t you first sit down and estimate the cost to see if you have enough money to complete it? For if you lay the foundation and are not able to finish it, everyone who sees it will ridicule you, saying, ‘This person began to build and wasn’t able to finish.’
That pretty much sums me up when I try to vibe a prototype.
Don’t get me wrong, I’m a big advocate of prototyping.
And LLMs make prototyping really easy and interesting.
And because it’s so easy, there’s a huge temptation to jump straight to prototyping.
But what I’ve been finding in my own behavior is that I’ll be mid-prototyping with the LLM and asking myself, “What am I even trying to do here?”
And the thought I have is: “I’d be in a much more productive place right now if I’d put a tiny bit more thought upfront into what I am actually trying to build.” Instead, I just jumped right in, chasing a fuzzy feeling or idea only to end up in a place where I’m more confused about what I set out to do than when I started.
Don’t get me wrong, that’s fine. That’s part of prototyping. It’s inherent to the design process to get more confused before you find clarity.
But there’s an alternative to LLM prototyping that’s often faster and cheaper: sketching.
I’ve found many times that if I start an idea by sketching it out, do you know where I end up? At a place where I say, “Actually, I don’t want to build this.” And in that case, all I have to do is take my sketch and throw it away. It didn’t cost me any tokens or compute to figure that out. Talk about efficiency!
I suppose what I’m saying here is: it’s good to think further ahead than the tracks you’re laying out immediately in front of you. Sketching is a great way to do that.
(Thanks to Facundo for prompting these thoughts out of me.)
2026-04-06 03:00:00
Simon Willison wrote about how he vibe coded his dream presentation app for macOS.
I also took a stab at vibe coding my dream app: an RSS reader.
To clarify: Reeder is my dream RSS app and it already exists, so I guess you could say my dreams have already come true?
But I’ve kind of always wanted to try an app where my RSS feed is just a list of unread articles and clicking any one opens it in the format in which it was published (e.g. the original website).
So I took a stab at it.
(Note: the backend portion of this was already solved, as I simply connected to my Feedbin account via the API.)
First I tried a macOS app because I never would’ve tried a macOS app before. Xcode, Swift, a Developer Account? All completely outside my wheelhouse. But AI helped be get past that hurdle of going from nothing to something.

It was fun to browse articles and see them in situ. A lot of folks have really great personal websites so it’s fun to see their published articles in that format.

This was pretty much pure vibes. I didn’t really look at the code at all because I knew I wouldn’t understand any of it.
I got it working the first night I sat down and tried it. It was pretty crappy but it worked.
From there I iterated. I’d use it for a day, fix things that were off, keep using it, etc.
Eventually I got to the point where I thought:
I’m picky about software, so the bar for my dreams is high. But I’m also lazy, so my patience is quite low.
The intersection of: the LLM failing over and over + my inability to troubleshoot any of it + not wanting to learn = a bad combination for persevering through debugging.
Which made me say: “Screw it, I’ll build it as a website!”
But websites don’t really work for this kind of app because of CORS. I can’t just stick an article’s URL in an <iframe> and preview it because certain sites have cross site headers that don’t allow it to display under another domain.
But that didn’t stop me. I tried building the idea anyway as just a list view. I could install this as a web app on my Mac and I'd get a simple list view:

Anytime I clicked on a link, it would open in my default browser. Actually not a bad experience.
It worked pretty decent on my phone too. Once I visited my preview deploy, I could "isntall" it to my home screen and then when I opened it, I'd have my latest unread articles. Clicking on any of them would open a webview that I could easily dismiss and get back to my list.

Not too bad.
But not what I wanted, especially on desktop.
It seemed like the only option to 1) get exactly what I wanted, and 2) distribute it — all in a way that I could understand in case something went wrong or I had to overcome an obstacle — was to make a native app.
At this point, I was thinking: “I’m too tired to learn Apple development right now, and I’ve worked for a long time on the web, so I may as well leverage the skills that I got.”
So I vibed an Electron app because Electron will let me get around the cross site request issues of a website.
This was my very first Electron app and, again, the LLM helped me go from nothing to something quite quickly (but this time I could understand my something way better).
The idea was the same: unread articles on the left, a preview of any selected articles on the right. Here’s a screenshot:

It’s fine. Not really what I want. But it’s a starting point.
Is it better than Reeder? Hell no.
Is it my wildest dreams realized? Also no.
But it’s a prototype of an idea I’ve wanted to explore.
I”m not sure I’ll go any further on it. It’s hacky enough that I can grasp a vision for what it could be. The question is: do I actually want this? Is this experience something I want in the long run?
I think it could be. But I have to figure out exactly how I want to build it as a complementary experience to my preferred way of going through my RSS feed.
Which won't be your preference.
Which is why I'm not sharing it.
So what’s my takeaway from all this? I don’t know. That’s why I’m typing this all out in a blog post.
Vibe coding is kinda cool. It lets you go from “blank slate” to “something” way faster and easier than before.
But you have to be mindful of what you make easy. You know what else is easy? Fast food. But I don’t want that all the time.
In fact, vibe coding kinda left me with that feeling I get after indulging in social media, like “What just happened? Two hours have passed and what did I even spend my time doing? Just mindlessly chasing novelty?” It’s fun and easy to mindlessly chasing your whims. But part of me thinks the next best step for this is to sit and think about what I actually want, rather than just yeeting the next prompt out.
I’ve quipped before that our new timelines are something like:
The making from nothing isn't as hard anymore. But everything after that still is. Understanding it. Making it good. Distributing it. Supporting it. Maintaining it. All that stuff. When you know absolutely nothing about those — like I did with macOS development — things are still hard.
After all this time vibing, instead of feeling closer to my dream, I actually kinda feel further from it. Like the LLM helped close the gap in understanding what it would actually take for me to realize my dreams. Which made me really appreciate the folks who have poured a lot of time and thought and effort into building RSS readers I use on a day-to-day basis.
Thank you makers of Feedbin & Reeder & others through the years. I’ll gladly pay you $$$ for your thought and care.
In the meantime, I may or may not be over here slowly iterating on my own supplemental RSS experience. In fact, I might’ve just found the name: RxSSuplement.
Reply via: Email · Mastodon · Bluesky
Related posts linking here: (2026) Prototyping with LLMs
2026-04-03 03:00:00
Marcin Wichary brings attention to this lovely dialog in ClarisWorks from 1997:

He quips:
this breaks the rule of button copy being fully comprehensible without having to read the surrounding strings first, perhaps most well-known as the “avoid «click here»” rule. Never Register/Register Later/Register Now would solve that problem, but wouldn’t look so neat.
This got me thinking about how you judge when an interface should bend to fit systematic rules vs. exert itself and its peculiarities and context?
The trade-off Marcin points out is real: "Never Register / Register Later / Register Now" is fully self-describing and avoids the «click here» rule.
However, it kills the elegant terseness that makes that dialog so delightful. “Now / Later / Never” is three words with no filler and a perfect parallel structure.
It feels like one of those cases where the rule is sound as a guideline but a thoughtful design supersedes the baseline value provided by the rule.
Rules, in a way, are useful structures when you don’t want to think more. But more thinking can result in delightful exceptions that prove better than the outcome any rule can provide.
I suppose it really is trade-offs everywhere:
As software moves towards “scale”, I can’t help but think that systematic rules swallow all decision making because localized exceptions become points of friction — “We can’t require an experienced human give thought and care to the design of every single dialog box.”
What scale wants is automated decision making that doesn’t require skill or expertise because those things, by definition, don’t scale.
Then again, when you manufacture upon inhuman lines how can you expect humane outcomes?
2026-03-31 03:00:00
Jason Gorman writes about the word “continuous” and its place in making software. We think of making software in stages (and we often assign roles to ourselves and other people based on these stages):
the design phase, the coding phase, the testing phase, the integration phase, the release phase, and so on.
However this approach to building and distributing software isn’t necessarily well-suited to an age where everything moves at breakneck speed and changes constantly.
The moment we start writing code, we see how the design needs to change. The moment we start testing, we see how the code needs to change. The moment we integrate our changes, we see how ours or other people’s code needs to change. The moment we release working software into the world, we learn how the software needs to change.
Making software is a continuous cycle of these interconnected stages: designing, coding, testing, integrating, releasing. But the lines between these stages are very blurry, and therefore the responsibilities of people on our teams will be too.
The question is: are our cycles for these stages — and the collaborative work of the people involved in them — measured in hours or weeks? Do we complete each of these stages multiple times a day, or once every few weeks?
if we work backwards from the goal of having working software that can be shipped at any time, we inevitably arrive at the need for continuous integration, and that doesn’t work without continuous testing, and that doesn’t work if we try to design and write all the code before we do any testing. Instead, we work in micro feedback loops, progressing one small step at a time, gathering feedback throughout so we can iterate towards a good result.
Feedback on the process through the process must be evolutionary. You can’t save it all up for a post-mortem or a 1-on-1. It has to happen at the moment, evolving our understanding one piece of feedback at a time (see: Gall’s law, a complex system evolves from a simpler one).
if code craft could be crystallised in one word, that word would be “continuous”.
Your advantage in software will be your ability to evolve and change as your customers expectations evolve and change (because the world evolves and changes), which means you must be prepared to respond to, address, and deliver on changes in expectations at any given moment in time.
2026-03-25 03:00:00
Steve Krouse wrote a piece that has me nodding along:
Programming, like writing, is an activity, where one iteratively sharpens what they're doing as they do it. (You wouldn't believe how many drafts I've written of this essay.)
There’s an incredible amount of learning and improvement, i.e. sharpening, to be had through the process of iteratively building something.
As you bring each aspect of a feature into reality, it consistently confronts you with questions like, “But how will this here work?” And “Did you think of that there?”
If you jump over the process of iteratively building each part and just ask AI to generate a solution, you miss the opportunity of understanding the intricacies of each part which amounts to the summation of the whole.
I think there are a lot of details that never bubble to the surface when you generate code from English as it’s simply not precise enough for computers.
Writing code is a process that confronts you with questions about the details.
If you gloss over the details, things are going to work unexpectedly and users will discover the ambiguity in your thinking rather than you (see also: “bugs”).
Writing code is a tool of process. As you go, it sharpens your thinking and helps you discover and then formulate the correctness of your program.
If you stop writing code and start generating it, you lose a process which helped sharpen and refine your thinking.
That’s why code generation can seem so fast: it allows you to skip over the slow, painful process of sharpening without making it obvious what you’re losing along the way.
You can’t understand the trade-offs you’re making, if you’re not explicitly confronted with making them.
To help me try to explain my thinking (and understand it myself), allow me a metaphor.
Imagine mining for gold.
There are gold nuggets in the hills.
And we used to discover them by using pick axes and shovels.
Then dynamite came along. Now we just blow the hillside away. Nuggets are fragmented into smaller pieces.
Quite frankly, we didn’t even know if there were big nuggets or small flecks in the hillside because we just blasted everything before we found anything.
After blasting, we take the dirt and process it until all we have left is a bunch of gold — most likely in the form of dust.
So we turn to people, our users, and say “Here’s your gold dust!”
But what if they don’t want dust? What if they want nuggets? Our tools and their processes don’t allow us to find and discover that anymore.
Dynamite is the wrong tool for that kind of work. It’s great in other contexts. If you just want a bunch of dust and you’re gonna melt it all down, maybe that works fine. But for finding intact, golden nuggets? Probably not.
It’s not just the tool that helps you, it’s the process the tool requires. Picks and shovels facilitate a certain kind of process. Dynamite another.
Code generation is an incredible tool, but it comes with a process too. Does that process help or hurt you achieve your goals?
It’s important to be cognizant of the trade-offs we make as we choose tools and their corresponding processes for working because it’s trade-offs all the way down.