Following on from the previous release, which was all about trying to get a big PageSpeed Insights win through image optimisation, I'm chasing some more validation from that site by trying to squeeze just a little more performance out of the code that BlogMore generates.
BlogMore v2.25.0 has the following changes to allow tinkering in ways that might speed things up a touch, depending on the nature of the blog:
CSS bundling -- Every page generated by BlogMore pulls in at least these three CSS files: style.css, code.css and fontawesome.css (or their minified versions if minify_css is turned on). While this separation of concerns sits well with me, while it feels like the elegant way of doing things, there is the issue that it requires 3 trips back to the server to get base styling for any given page1.
So with this new version, if you set bundle_css to true, those three files are included and delivered as a single bundle.css (or bundle.min.css). This saves a couple of requests.
Theme helper inlining -- the lesser of the two main changes. There is some JavaScript that's part of each page that helps with theme switching and also provides the code to toggle the header display on mobile-sized screens. It's not a lot of code, but it is another file that has to be fetched. If inline_theme_js is set to true, this code will be included in the <head> of every single page generated for the site.
I suspect I'm going to leave this one off, but it's there if it's helpful to anyone (and also does let me experiment more with PageSpeed measurements).
Optimised logo -- one image that got left out of the work to optimise images was the site logo. While an optimised version of the image was created, no HTML was generated to make use of it. With this release, if optimise_images is true, <picture> will be used for this too.
With those shameless performance-measurement changes aside, there are a couple more changes in this release. The first is that the markup for the site title (that appears below the logo, if you have one) has been changed away from using a <h1> tag. The SEO gods frown on multiple <h1>s on a page and given the "main" title of any page is also a <h1>, this meant there were always 2 such tags. Now just the main title will be marked up this way; the site title becomes a <div> with appropriate styling to maintain the existing look.
Finally, this release fixes a small bug in the search index. It was being created with escaped HTML entities in any text that came out of fenced code blocks. From now on any text that goes into the search index is unescaped.
As always: if a blog-oriented static site generator that is all about Markdown sounds like your thing, check out the installation instructions and give it a go.
Yes, of course the client-side cache makes this moot after the first page is loaded. All of this is about making that first load faster, and so appeasing the PageSpeed Insights gods. ↩
Well, what a surprise, nobody could have seen it coming: it does seem to be bait and switch season in LLM/agent land.
As I mentioned earlier today, when I ran up Gemini CLI to have it work on a change to BlogMore in the background, I got a notification that I should be swapping to Antigravity CLI instead. I let Gemini CLI get on with the change anyway, but resolved to install Antigravity CLI and give it a go. While there's still a touch under a month of use of Gemini CLI to go (based on the blog post), it seems sensible to get to know the new tool as soon as possible.
Installing Antigravity was a little bit of a faff. Looking at the documentation, you have to install the main application itself first, authorise with that, and then you can install and use the CLI. Fair enough. Rather than download the DMG from their website, I decided to go with the Homebrew installation (I like to try and keep track of what I have installed and this helps me do that).
So I installed that, ran it up, went through some setup questions, then finally got dropped in something that looked like it wanted to be an IDE of sorts. Nah, I'm fine, I like to work elsewhere. But that was okay given that I just wanted to get to the CLI anyway. Before I did that though, having installed this app, I saw that it was showing a "Restart to update" notification. So I did that, waited a wee while, and then finally was presented with something that looked totally different. Now I had an application that looked almost exactly like the main Gemini website (or the Gemini macOS application).
So that was kind of weird.
Finally I was in a position to install the CLI itself. From what I can see it's not available via Homebrew yet, and the installation instructions are the usual "curl this through bash, trust me bro" affair. Having done that (yes, yes, I know...), I was all set.
Credit where it's due, when I ran it up it just worked. As in: I didn't need to authorise again or anything like that; the fact that I'd set everything up via the main application did seem to have done that job.
After this though, it kind of went a little downhill. The first thing I noticed was the set of models available was rather different from Gemini CLI. I mean, okay, that's fair, I guess you expect things like that to change, but in my inexperienced1 view of what these agentic tools offer, it looked like all the options were a little more... pricey, perhaps?
Still, I'm sure that sensible defaults are chosen out of the box, so it seemed like a good time to give this new tool a shot. I had a nice little problem for it to work on so that felt like a great test. It's hard to say for sure, but I feel like an issue like that, with the right prompt, would have used up somewhere between 3% and 5% of the daily quota in Gemini CLI, using Auto (Gemini 3). That was the default out of the box and, aside from tapping the models to try and unstick them, I've never really set it to anything else and the results have always been fine. With all this in mind I set Antigravity to work. Given that there didn't seem to be any sort of "Auto" option, I let it go with Gemini 3.5 Flash (High), which is what it was set to out of the box.
Yikes.
As I read that, and as I recall what happened, it took about 25 minutes to get to a reasonable solution to the request, with me pushing back on a couple of wild choices it made about how to change the code around. In doing this it left me with just 20% of the quota free for the next four and a half hours.
Yikes.
This is fine in this particular situation, where I'm conducting a long-term experiment and often letting the tool run at reasonably self-contained problems, in the background, while I get on with other more important things. But if I were to try and use this, as I have Gemini CLI, for an evening of sofa-hacking, refactoring lots of code or adding a handful of new features... that's not going to be sustainable. Any such session is going to grind to a halt pretty quickly. Presumably the intended solution here is that I buy myself lots of "AI credits".
I will experiment more, and intend to try and work out what the point, purpose and impact of each of the models are, as found in Antigravity. Doubtless there's a smarter approach I can take where it'll cost less quota for similar results. What is for sure though is that Antigravity CLI is not a drop-in replacement for Gemini CLI. It seems to be a different way of working, with different models, and different considerations. Also with less openness too.
None of this is shocking to me -- although I'll admit that I thought the Gemini CLI ride might last a wee while longer than it did -- nor, I'd hope, to anyone else, but it continues to be fascinating to watch the squeeze being applied all around this tool space. This is going to be an increasingly worse time for anyone wanting to mess with agents for hobby projects. The idea of a tool that lets you get unambitious projects done for the price of a coffee or two, per month: that was a reasonable prospect. When the real cost turns out to be similar to an actual utility bill for your home... I know some people have expensive hobbies, but this would not seem to be a rewarding one at the sorts of costs we're starting to look at.
Once again, it's going to be interesting to see how engineering departments, and AI-embracing companies as a whole, react, as they become more and more invested in these third-party services, and less able to actually do things themselves, while at the same time the suppliers of those services squeeze them harder to try and make this adventure pay off.
I say "inexperienced", but perhaps I'm being unfair to myself here. While I'm not 100%, all in, fully-steeped in agentic lore, and even though I've not been living this stuff full time for the past year or so, I do feel I'm a good representation of someone with a long background in the software development industry who is coming to these tools with reasonable expectations. ↩
I just sat down at my desk and fired up Gemini CLI to get it to make a change to BlogMore, and I see this:
I've yet to actually look at Antigravity, so I know pretty much nothing about it at this point. After a brief glance at the link that was given it seems like it's a positive change, perhaps. Honestly, I'm not sure. But that's kind of moot, I don't really have a choice. Within a month Gemini CLI is going to stop working anyway.
This is yet another reminder that, while plenty of folk are pushing these tools as the answer to the "problem" of software development, they're not really stable tools, it's not really a stable market, and, to some degree, if you fully rely on these tools, you're constantly at the mercy of the whims of some other company.
I'm glad I have a project where I'm forcing reliance on them as an experiment, so I can see and experience this first-hand, but I'd be very concerned for someone who's fully bought into them.
Perhaps there's a market here for a "Killed by AI" website, much like Killed by Google?
Or, maybe I'm being unfair here; it could be that this is more akin to Google solving the chat problem by constantly moving people from one chat application to another, while also having chat abilities in all sorts of other products...
Pretty much every project that I actively maintain on my GitHub account has a change log of some description. For a long time now, whenever I add a new entry to the log, I'll include a link to the PR that implements that change. Inevitably, this results in me adding the ChangeLog entry, creating the PR, then doing a follow-up change and commit now that I know the PR number, which allows me to add the link.
So I've created next-gh-pr.el to save me just a little time and let me be just a little more lazy. Inside it I've currently got a next-gh-pr-insert-markdown-link command which, when run, as you might imagine, inserts a link to the next likely PR URL as Markdown.
Working out the next URL is simple enough: get the latest issue and PR number, take whichever is the highest, and add 1. There is the wrinkle that discussions also cause this number to bump, and getting the latest discussion number is a little extra faff that I can't be bothered with right now, but my projects very seldom have discussions taking place anyway.
I've made a minor bump to OldNews, my terminal-based client for TheOldReader. There's no significant change in this release, but it does change the dependency on html-to-markdown.
Since I initially released the application, this library seems to have been through a couple of significant changes, and not every breaking change seems to have resulted in a major version bump. OldNews doesn't pin this dependency to a major version (I try not to, only ever setting lower-bounds for dependencies where possible), so it's fair that a change there can break things. I also think it's fair to hope that minor version changes won't cause trouble.
Recently, I've seen the library update with a minor version change and it's flat-out caused runtime errors, either because the API has changed, or because of an error being thrown by legitimate use of the API.
Most recently, such an error happened, and was fixed by the time I noticed it, but the release that was made never made it up to PyPI. This left OldNews stuck not working. Because of this I had to pin the library to an earlier version.
It's now been updated again and PyPI is correct, so I think it's safe to relax the pin.
Quite a few weeks ago now -- I think it was around the time I started work on blogmore.el and got the new MacBook Air -- I remember sitting in a cafe in Edinburgh and via Mastodon having a conversation with Andy about tweaking better results out of PageSpeed Insights. I seem to remember him correctly observing that one of the big hits on the performance score was the size of images, and also the format, and that some SSG engines would go to the trouble of converting to the likes of WebP and/or generating different sizes that are appropriate to different screens, that sort of thing.
I can't quite remember where we left it, but I think it was considered more work than was worth worrying about, and perhaps swapping all images on our blogs to WebP would solve most of the issues.
For a couple of different reasons, late last week, I decided it was time to play with the problem. For some reason I've been pretty cautious with this PR. I planned it out last Friday night, kicked off work on it on Saturday morning, and have then been tinkering and changing it and testing it and iterating over it all weekend. Something about the nature of the change made me want to go very slowly with this. I think it was an unease about messing with the images that would get served, the nature of the new tags that would get emitted, the fact that there would be even more HTML tinkering going on, the possible complexity of maintaining the cache... lots of things to consider and this is supposed to be a nice, simple, unfussy site generator.
Anyway, I've just released v2.24.0 with this feature added. It's off by default, and is turned on by setting optimise_images to true. Then, when you build your blog, each PNG, JPEG or WebP image will be converted into one or more WebP images stored below static/images/optimised. How many are made for each image will depend on how image_widths is set. The physical size of each image (and how the image looks) can be affected by image_quality.
This does have two very obvious effects:
It will result in your generated site being quite a bit bigger, if you have lots of images.
It will result in the build time taking much longer.
The first issue is something I can't do anything about; it is what it is. The second issue, however, is something that can be dealt with. Given I've just made a release that speeds up build times, this would be a huge step backwards. So with this in mind, as the optimised images are created, a cache of them is also created in BlogMore's cache directory. This, again, does mean that more space is taken on your local storage to build your site, but it also means that repeated builds will remain fast.
If you run into problems or need space back, don't forget you can easily clear the cache.
So what's the result of all of this? Is it worth the effort? Well, to be sure, before I upgraded the version of BlogMore that I build this site with, I measured its performance.
After upgrading and rebuilding, here is how the same home page measures up.
I was genuinely surprised by the difference. The settings I used were:
optimise_images:trueimage_quality:95
and, of course, almost all the images on this site are now WebP anyway. I think I was expecting it to have a small impact, but even having those WebP images turned into stepped sizes seems to have a very measurable effect.
I'm going to be keeping a close eye on how this works for the next few days. As I say, I've tested this as much as possible and gone over the code as carefully as time has allowed. If this feature does break something I hadn't anticipated I can always just turn it off again anyway. Meanwhile though, the improvement on mobile does seem genuinely worth it.
Over the weekend I read a comment, I think it was on Hacker News, where someone said they were having fun building things using AI. This was in response to someone saying that using AI took the fun out of programming. In their reply, the person qualified their answer with something along the lines of "the highs are higher and the lows are lower".
I think I agree.
My first ever exposure to any sort of computer was a Sinclair ZX80 that my maths teacher brought into school. After a class he plugged it in and let me and a friend take a look. To this day I still remember looking in the manual, looking at the tutorial, and at some point typing...
When I hit NEW LINE and a 2 appeared on the screen I was thrilled, I was hooked. I'd typed something that appeared on a TV screen and then I did something that made the answer appear on the TV screen. This felt like magic.
I've been hooked on writing code ever since.
In that time the highs have been high, and the lows have been low, but I think it's fair to say that I've been doing this for long enough (it's now 45 or 46 years since I typed that first instruction) that things have settled down. I still get a thrill when writing code, and I still get fed up with it from time to time, but the distance between the two isn't what it once was.
Which brings me back to the comment I read: I think I can safely say that, while properly experimenting with agents, while building BlogMore to test this approach out, I have been through a period of higher highs and lower lows when it comes to how I feel about the code and the project itself. When I kicked off development it was genuinely thrilling to have gone from an empty repository to a comprehensively-working initial version in just a matter of hours. Likewise it was thrilling to have gone from nothing to rebuilding this blog with the tool in just a few days. It would be a lie to suggest that it wasn't fun and exciting to see the result.
But, as I wrote back then, I was also very mindful of how empty the process felt at times, how I missed the whole "flow state" connection to building out the application. There have also been many moments along the way, which I've documented at times on this blog, where I've felt the project was getting stuck down a dead-end with respect to how the code was going.
And then there's all the times Copilot and/or Gemini CLI just plain stopped getting stuff done.
Given this -- given the highs especially -- I can see why some people get totally hooked, go all in, get consumed by the illusion of how powerful these tools are. I can see why they'd buy into and embrace the mindset that trots out the AI-equivalent of the crypto-hype "stay poor" retort to those who display any level of scepticism.
The first company I worked for full-time had two offices. One in the south of England, another in the north. Despite being a northern lad, I'd somehow found myself working in the southern office. While the company used a few languages, there was a split between the two offices, mostly driven by the fact that the northern office was more minicomputer-based (lots of DEC stuff as I recall), whereas at our office it was more PC-based (we were an Apricot dealership, amongst other things). At our office, the predominant language was Clipper (later to be called CA-Clipper).
At one point, at the other office, they hired someone to start doing Clipper coding up there too, and he was handed his first project, to add a new report to an existing system. After around three weeks, he just didn't turn up for work one day, called in to say he'd quit (or so I was told). Meanwhile, the work he had done didn't seem to be working. If someone took the newly-compiled system and ran the new report, nothing happened.
When the code was looked at, it became clear why. The new module had one line of code. Well, not one line of code exactly: it had a one-line comment.
* This is too hard. I can't do this.
That was it. He'd spent those weeks appearing to work on the requirement, but never produced a single line of actual code.
I felt really bad for the guy. He'd somehow managed to make it through the interview, somehow managed to convince others, and himself, that he was capable of working with Clipper and writing code (probably made easier by the fact that the office in question wasn't a "Clipper shop"). But when it came to actually getting on with a job, he'd been unable to get it done (and, apparently, had felt unable to ask anyone around him for help, which probably says a lot about that office and the industry at the time1).
I bring this up because I was reminded of this story when I was tinkering with Gemini last night. While working on the optimised images PR, towards the end of the session, I asked it to make a particular change. It then started "thinking", and after a couple of minutes appeared to get to work on the problem. It kept printing, scrubbing out and printing again, lines of text of what it was apparently doing. This went on for something like five minutes. Eventually it announced that the work had been done, explained what it had changed, and how it had implemented the requirement.
I flipped to another terminal to test out the work and... no changes. Zero changes. Nothing to diff, nothing to commit.
I flipped back to the CLI app, mentioned that nothing had changed, and it then very quickly made some edits; nothing spectacular, a 14-line diff affecting five lines (to start with).
This is the first time I've seen this, and I guess yet another thing I need to keep an eye out for. Of course I would notice if I asked for some work to be done and it wasn't done (I did), but it feels like another method via which this "productivity tool" can make you less productive.
If you give me the under-qualified, solution-paralysed, entry-level developer who doesn't know how to proceed, I can help them. Their current inability to actually bash on the keyboard and make code appear isn't the problem here. Giving them a tool that will busy-work for five minutes and produce nothing isn't going to help them, neither will things improve if they're given a tool that does emit all the code. Removing the human element is going to remove safety, growth and also domain knowledge. I feel it's going to rot software engineering departments from within, if handled badly.
Watching people talk about agents as if they're the solution, and that writing code is now a solved problem, really troubles me. I won't question the idea that it can be a very useful tool -- goodness knows I've found it useful recently -- but I do question the common assertion that it finally is a silver bullet. I find this to be lazy, dangerous and harmful thinking.
Because of course we're so much better as an industry these days. ↩
Well, this week didn't quite go according to plan, so I didn't get to test out the Steam Controller straight after it arrived. This afternoon, after messing about with code and agents for a few hours, I decided it was high time I stopped doing coding things (and to some extent day-job learning things) and instead did gaming things.
I dragged the Steam Deck and its dock into the living room, hooked everything up, and had a few hours of running and shooting and stuff. Before I could get started I had to plug the "puck" into the Deck with the supplied cable, and let it update. I then had to unplug the puck and plug in the controller to do the same. Finally I had to plug the puck back in (I hadn't quite realised, but it's the wireless connector for the controller) and I was good to go.
I messed around with a few things, including Brotato, DooM II, Cyberpunk 2077 and a lot of Suit For Hire. All felt good. All worked well. For some reason, this more than ever, makes me look forward to the Steam Machine.
I have a funny feeling I'll be joining the reservation queue when I get the chance.
As for the controller itself: it's a controller. It feels good in the hand. It feels comfortable. All the buttons feel in the right place. As someone who's used a Deck for a while it feels like having all the benefits of the Deck without having to hold the Deck itself. If you are already partly in the Valve hardware ecosystem it makes perfect sense as a thing to own.
Yes, I did try dropping it (carefully). No, I didn't manage to make it scream.
Following on from this morning's initial experiment, I think I'm settling on a winner. Rather than be annoying and have you scroll to the bottom to find out: it's Gemini CLI. Here's how I found the process played out, and why I'm settling for one over the other.
Initially this was an absolute mess. After letting it initially work on the problem, the resulting code didn't even really run. The first go, and the three follow-up prompt/result cycles that followed, all resulted in code that had runtime errors. I'm pretty sure it didn't even bother to try and do any adequate testing. This is odd given I've generally seen it do an okay job when it comes to writing and running tests.
Once I had the code in a stable state, with all type checking, linting and testing passing, it still didn't work. No matter how I tried to use the new facility it just didn't make a difference. No images were optimised. In the end I dived into the code, with the help of its attempt at debugging (it added print calls to try and get to the bottom of things -- how very human!), diagnosed what I thought was the issue (it was looking in the wrong location for the files to optimise), told it my hypothesis and let it check if I was right. It concluded I was and fixed the problem.
Since then I've had a working implementation of the initial plan.
Once that was in place it's been a pretty smooth journey. I've asked it questions about the implementation, had my concerns set to rest, had some concerns addressed and fixed, improved some things here and there, added new features, etc.
All of this has left me with 18% of my daily quota used up. While I think this is the highest I've ever got while using Gemini CLI, it still feels like I got a lot of things done for not a lot of quota use.
Initially I thought this had managed to one-shot the problem. Once it had finished its initial work the code ran without incident and produced all the optimised files. Or so I thought. Doing a little more testing, though, it became clear it was only optimising a subset of the images and it didn't seem to be producing the actual HTML to use the images.
On top of this it didn't even follow the full plan that was laid out in the issue it was assigned. For example: once I'd got it doing the main part of the work, it became apparent that it had pretty much ignored the whole idea of using a cache to speed this process up. I had to remind it to do this.
At one point I switched from the in-PR web interaction with Copilot, and used the local CLI instead. When I ran that up it warned me that I was already 50% of the way through some sort of rate limit and this wouldn't reset for another 3 hours. I think I was about 40 minutes into letting it try and do the work at this point.
After a bit more testing and follow-up prompts, I got to a point where I had something that looked like it was working; albeit in a slightly different way from how Gemini CLI did it (the Copilot approach was writing the optimised images out to the extras directory, mixing them in with my own images; Gemini opted for having a separate directory for optimised images within the static hierarchy).
At this point I will admit to not having carefully reviewed the code of either agent; that's a job still to do. But while Gemini got off to a very rocky start, with a bit of guidance it seemed to arrive at an implementation I'm happy with, and one that seems to be working as intended. While it didn't anticipate all the edge cases, when I asked about them it easily found and implemented solutions for them. Moreover, the fact that I could do all of this and confidently know the "cost" made a huge difference. Copilot seems to generally approach this like a quota or rate limit should be a lovely surprise that will destroy your flow; Gemini has it there and in front of you, all the time.
As for the general idea that I'm working on: I think I'm going to implement it. Weirdly I'm slightly nervous about building the blog such that it won't be using the images I created, but I also recognise that that's a little irrational. Meanwhile I'm very curious about the impact this might have on the PageSpeed measurement of the blog. While it's far from horrific, image size optimisation and size declaration seem to be fairly high on the things that are impacting the performance score (currently sat at 89 for the front page of the blog, as I type this).
The other thing that gives me pause for thought about merging this in, and then subsequently using it, is that I've justfinished migrating all images to webp, and so saving a lot of space in the built version of the blog. Generating all the responsive sizes of the images eats that up again. With this feature off, the built version of the blog stands at about 84MB; with it on, this rises to 133MB. That extra 49MB more than eats up the 24MB saving I made earlier.
On the other hand: storage is a thing for GitHub to worry about, what I'm worrying about here, and aiming to improve, is the reader's experience.
I'm going to sit on this for a short while and play around with it, at least until I get impatient and say "what the hell" and run with it.