Recent Posts

blogmore.el v1.7

2 min read

Yes, the last time I mentioned blogmore.el it was v1.4 and now it's up to v1.7. So I tinkered a little with it last night, okay?

Anyway, the changes and additions keep happening as I have more fun writing some elisp again. Since the last post about the package I've:

  • Added a command to refresh the date frontmatter property
  • Added a command to add/refresh the modified frontmatter property
  • Added a command to insert a link to a previous post into what I'm writing
  • Made a few things defcustom rather than defconst for easier tweaking
  • Added a hook that can be run after a new post is started
  • Dropped the dependency on end-it and used the above hook to do the same thing

While this package is never intended for use by others, I guess it's not impossible someone might want to work with it (I had the same thing in mind with BlogMore itself yet someone else has started working with it!) and so I'm moving it in the direction of being my way by default but easy to modify to other requirements.

So, now, rather than forcing someone to have to use my obsession with end-of-file markers, I still have that without imposing it on anyone else by simply setting the hook.

(use-package blogmore
  :vc (:url "https://github.com/davep/blogmore.el" :rev :newest)
  :init (add-hook 'blogmore-new-post-hook #'end-it))

I think my favourite addition right now is blogmore-link-post. I like to cross-link posts in my blog as much as possible so having something that lets me do that and stay inside Emacs really speeds things up. So now I just run that command, I get speedy picker to find the post:

Picking a post to link

and the result is some Markdown inserted with the cursor between the two [] ready for me to write the text:

[](/2026/03/20/blogmore-el-v1-4.html)

Other things I link often are categories and tags, so I'm planning on adding commands that does something similar for those two.

Astral and OpenAI

2 min read

It's a couple of days now since the news hit that OpenAI are in the process of purchasing Astral. When I first saw this my initial reaction was pretty much "woah", followed by getting on with what I was doing.

Until, that is, I opened up the socials. On Mastodon, Reddit, BSky, Threads, etc... anywhere I followed any Python-based content, I was seeing very firm opinions posted. Plenty of folk either talking like it was the end of their tooling as they know it, or proudly boasting that they'd avoided uv and ruff (and lately ty too I guess -- not that I've really tried that yet myself) because they'd predicted this evil outcome from the start and they were untainted by this but look at all you idiots who fell for this long play!

Okay, I exaggerate slightly, but there were some pretty strong opinions kicking around, especially in the (often fairly smug) "I stayed pure and never used uv" camp.

Personally, I don't get it. The last I looked the tools I use that Astral are behind are FOSS. Also, the last I looked, plenty of FOSS tooling is written by folk who are either paid to do so (I had my moment), given some time in the day job to work on those tools, or just plain have a day job and also work on those tools. If, as plenty are speculating, the Astral purchase is an acqui-hire, the likely result is going to be one of those three scenarios.

If it isn't one of those scenarios, if work on uv and friends just ceases, well, at best some smart folk can fork the tools that are useful and keep them going (this is a major benefit of FOSS after all) and, at worst, well... we can fork them and agent the shit out of them. Right?

blogmore.el v1.4

1 min read

Following on from yesterday's post, in the evening I found myself in a cafe with my MacBook Pro and an hour to kill, so I tinkered with blogmore.el a little more. The main aim here was to add a command for adding tags to a post and I now have blogmore-add-tag as of v1.4.

One thing that stood out was just how rusty my Emacs Lisp skills are. It took me a wee while to get the code working, mostly due to me being caught out by the gotchas I'd forgotten about surrounding match data and the need to make good use of save-match-data (I had a combination of re-search-forward, string-split and replace-match going on and it was chaos for a while).

I got there in the end, though, when I bothered to RTFM with a quick C-h f string-split RET.

Documentation for string-split

So now I have the following commands in Emacs when I get the urge to do something blog-related:

  • blogmore-new starts a new blog post
  • blogmore-edit lets me edit an existing post
  • blogmore-set-category lets me set the category from existing categories, or set a new one
  • blogmore-add-tag lets me add a tag from the existing tags, or add a new one

As suggested before, I think I'll probably add some other helper commands, things such as:

  • Update the date
  • Set the cover to a particular attachment
  • Insert a particular attachment as a Markdown image
  • Insert a link to another post in the blog

I'm sure more will come to me, but they seem like the most common operations I perform that would be helped with a little bit of Emacs Lisp magic.

Some BlogMore Elisp

2 min read

It's been a moment since I last wrote any Emacs Lisp code, at least anything non-trivial. I've tinkered with my Emacs configuration, I've tweaked the odd personal package here and there, but nothing fresh for ages. I actually can't remember what the last package was that I wrote.

But this morning I realised it would be handy to have a couple of functions in Emacs that let me start a new blog post, or edit an existing one. The code didn't need to be clever, just the bare minimum that gets me started; enough to reduce the friction when it comes to opening a new buffer and starting to write.

So blogmore.el happened. Like I say: nothing clever, it simply adds blogmore-new and blogmore-edit; the former starts a new post with the bare minimum frontmatter filled in, the latter lets me quickly pick an existing post and go edit it.

blogmore-edit in action

As time goes on I might expand on this. For example: it might be useful to have a command that updates the date frontmatter; perhaps another to add a modified1; one to set the category from any of the categories I've used so far would be good; ditto the tags property.

I doubt this will be useful to anyone else, although I will try my best to keep it so that it's easy to configure, so it's only ever going to stay amongst my list of personal packages.

Which reminds me... this is the first personal package I've not bothered to add to delpa. That approach to managing my own packages made a ton of sense at the time, but Emacs has moved on since then. Thanks to use-package and :vc I can easily pull blogmore.el into any of my environments with a simple declaration in my .emacs.d.

(use-package blogmore
  :vc (:url "https://github.com/davep/blogmore.el" :rev :newest))

Given how simple and clean that is I'm minded to "retire" delpa and use this approach for all of my personal packages.


  1. Note to self: did I make BlogMore support modified dates? 

BlogMore v2.0.0

3 min read

Well... I thought I was done with all the major changes with BlogMore, but then a fairly simple request came in and that kicked off a whole load of changes (which in turn ran into one or two problems with GitHub Copilot).

I dived into this because I liked the idea anyway and I think it's time that I, as much as possible, moved the layout of my blog to clean URLs almost everywhere. I can't reasonably do it for actual posts because a) lots of posts point to other posts so there's a whole editing job to do there1 and b) there are some links out there that point to my blog posts2.

The result is BlogMore v2.0.0.

Anyone who's been following the experiment with BlogMore might wonder that the version number is up to v2 already, given it's barely a month old. The answer to that is pretty simple: I'm using semver for the version number and there's a breaking change in this release with no real way of maintaining backward compatibility.

So what's changed? First the simple ones: I added some more *_path configuration options to control the locations of:

All of those keep their default values from before, and so can remain backward compatible. Personally, I've updated the configuration for this blog so that I'm using:

archive_path: "/archive/index.html"
categories_path: "/categories/index.html"
search_path: "/search/index.html"
tags_path: "/tags/index.html"

which, combined with:

clean_urls: true

results in cleaner URLs for all of those site features.

Another thing that came to mind was what to do about pagination. Things like the date-based archives, categories, tags, and so on, can all run to multiple pages and so all generated pages of content using a pagination scheme. This needed its own approach. I decided on adding a setting to control the first page of content (page_1_path) and a setting for all subsequent pages (page_n_path). But there was a problem here: to keep this approach backward compatible I'd need to have different settings per area of the blog. That would mean something like tags_page_1_path, tags_page_n_path, year_page_1_path, year_page_n_path, month_page_1_path, month_page_n_path, and so on; the reason being each one would need its own set of variables so the user can set where {tag} goes in the path, or {year}, or {month}, but one of those is no use in another context, and so on.

All of this would have been total overkill and an unnecessary explosion of things that can and might need to be modified in the configuration file; it would also be a nightmare to document.

So I decided this: the page_1_path and page_n_path settings simply describe what goes on the end of any other URL in the blog, and because of that the defaults would have to be incompatible. I think the result is a lot tidier.

This also felt like a good time to make this change because, aside from one other blog out there, I don't think anyone else other than me is using BlogMore at the moment.

This change did mean that I'd need to edit some of the posts in my blog to update for the slightly changed layout, but it was a small enough job with minimal impact so it was worth it. I also used a tweaked setting for page_n_path:

page_n_path: "/page/{page}/index.html"

so that any paginated page has a URL that ends something like .../page/2/. This holds for any page on the blog that has multiple pages.

This is the point where I'd say something about how I think that's all the big changes in this project done... but I'm starting to suspect this isn't the plan the coding gods have for BlogMore.


  1. Although I suspect I could agent the shit out of that problem

  2. Although few enough that I probably should't let it stop me doing this. 

Too much work for Copilot?

2 min read

I don't know if it's just that GitHub Copilot is having a bad time at the moment, or if I've run into a genuine problem, but all isn't well today. After merging last night's result I kicked off another request related to a group of changes I want to make to BlogMore. It's a little involved, and it did take it a wee while to work on, but mostly it got the work done.

Again, as I said in the earlier post, I won't get into the detail of these changes yet, but they're fairly extensive and do include some breaking changes, so it's probably going to take a wee while to have it all come together. Claude's first shot at the latest change was almost there but with the glaring bug that it did all the work but didn't actually add the part that reads the configuration file settings and uses them (yeah, that's a good one, isn't it?).

So I asked it to fix it. It went off, worked on the issue, and then suddenly...

Denied

This surprised me. After the past few weeks I've had sessions where I've requested it do things way more frequently than this morning. I'm also nowhere near out of premium requests either:

Number of requests left

While the error, as shown, might be valid and might be down to my actions, it's massively unhelpful and doesn't really explain what I did to cause this or even how I can remedy it. This is made all the more frustrating by the fact that it seems to be saying I need to wait <duration> to try again. Yes, literally a placeholder of <duration>. O_o

One thing is for sure: this is another useful experiment in the current experiment. It's worth having the experience of having the tool screw with the flow. It doesn't come as a surprise, but it's a good reminder that using an agent that is hosted by someone else means you fully rely on their ability to keep it working, the whims of their API limits, and perhaps even your ability to pay.

When your model leaves you

5 min read

Yesterday evening, after dinner, but just before loading up a game released just a few hours earlier, I decided to kick off a change to BlogMore. Part of the ongoing experiment is this convenience aspect: where I can get some work going and then go and do something entirely different.

The nature of the change itself isn't important (I'll write about it when I release an update), but something that happened is. As usual, I did the prompt as an issue, and assigned it to Copilot. The first thing that was curious was that, after around 5 minutes, despite it having added the 👀 reaction (which it seems to use to indicate the agent has seen it has work to do), nothing happened. I didn't see an agent kick off doing the work. Eventually I gave up waiting and opened a Copilot session and asked it to set about dealing with the issue I'd raised.

It did as I requested, but apparently alongside another agent which had suddenly started doing the exact same work. Thinking it was a glitch (it's not like GitHub hasn't been having some trouble of late) I stopped the newest one and let the "original" go about its work.

A wee bit later, just before I started up my game and the stream, I checked in on how it was doing. It had finished, but in a quick test, I noticed a small bug. I prompted it to fix the problem, closed the tab, and went about the real business of killing bugs.

Fast forward a couple of hours, I was done with getting my arse kicked on Klendathu, I packed away my controller and headset and opened GitHub again to see where Copilot was at. It wasn't good:

@davep The model claude-sonnet-4.6 is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 79b81d32-e26a-4898-bd41-4bba088d08f6

Wait... what? I've been using this for weeks now, as best as I can tell I've generally been making all the changes and improvements using Claude Sonnet 4.6; there's never been an issue. Then, suddenly, in the middle of a PR, I don't have it?

Quickly checking elsewhere, sure enough, I had access to almost no models. I can't remember what there was, but it wasn't much and all the Claude ones had disappeared. Even if I tested in the Copilot CLI1 I saw a very limited set of models.

Around this time I had two reactions: one was something like "cool, this is an important part of the experiment, knowing how it goes if your models are taken from you", the other was a curious "but Claude and I have an understanding about this codebase I can't trust some other model I've not been using".

As it was getting late into the evening and I still wanted to watch an episode of Stargate SG-1 (yes, I'm doing a full rewatch given it's on Netflix) I closed the MacBook and decided to check in on the issue in the morning.

Fast forward one SG1 episode later and, just before I headed to bed, I decided to do a quick search. While it could be a problem with my own account, it felt like it was more of a general issue. It was more of a general issue. At that point (around 23:20 UTC), checking in the GitHub app on my phone, I could see that some, if not all, of the models I was used to seeing, had come back.

As of this morning, as of time of writing, it's all looking back to how it was.

All the models back

All of which is a great reminder, and something useful in the experiment: what does happen when some third party takes away the models you're using to get your work done? In the time I've been building up BlogMore I've come to trust the quality of Claude Sonnet (in the sense that I know when and where I have to pay closer attention to what it's done, and where it'll very likely have done a pretty good job2), so finding that I'd possibly have to switch to some other model that I've had no experience with... I genuinely had a moment of concern about how and where I was going to take BlogMore.

Ultimately it's not actually a serious concern for me: while I aim to maintain it for a very long time to come (it is how I'm creating the site for this blog after all), BlogMore isn't that critical. Moreover, I know I could cease using Copilot to create and maintain it and I could tidy up the code and hand-update and hand-manage it. There's a reason why I decided to really dive into this using a language I'm extremely confident with.

But for those applications some might now be relying on, developed by someone keen but as yet unskilled, what way forward for them if such a situation were to happen and not be resolved?


  1. Which I'm not really using at the moment, but do have installed to experiment with. 

  2. So just like working with humans, oddly enough. 

BlogMore v1.16.0

1 min read

Prompted in part by the changes I made yesterday, I've made another small release of BlogMore today. The stuff to do with human.json made mention of having a /ai page, something I remember as being part of the slash pages moment. While I've never leaned into it myself, I do consider it a fun idea and, given the current experiment, I did think it made sense to have a /ai page for this blog, at least1.

Yesterday's changes, to allow modifying the path used for pages, and also to apply the clean_urls setting to them too, meant it was easily doable now. But I also got to thinking that someone might not want the page to appear in the sidebar; perhaps they just want the page there but not obviously linked to.

So with today's release I've added an optional pages: configuration setting. If it's omitted, BlogMore works as it always did (listing every page in the sidebar). If it's included, only the pages in the given list appear in the sidebar.

Personally I think I'd prefer to have the /ai page visible in the sidebar, and that's what I've gone with. But if anyone wants the option of having better control over this, it's there now.

While I was tinkering on sidebar things I also added a setting for overriding the title of the links list. Again, I think Links works fine for my purposes, for this particular blog, but I can see the need to want to customise it.


  1. I should probably add one to my main site too now I think about it. 

BlogMore v1.15.0

1 min read

It feels like this blog has turned into the BlogMore blog at the moment, and to be fair part of the idea of BlogMore was to encourage me to blog more again. So I guess it's worked?

Anyway, another wee update with a couple of additions. The first is a follow-up to some work I did a little earlier last week that meant that the user can configure how paths for posts are created. This takes the same idea and applies it to pages too, adding a page_path setting. Pages now also make use of the recently-added clean_urls setting so you can use "clean URLs" for pages too.

Another change I've added has been, in part, prompted by a thing I've seen going around the socials the past couple of days: human.json. I did initially think about adding some special support for it1 -- allowing declaring the values in the BlogMore configuration file -- but then I decided it made more sense to just include the human.json file in the extras directory and allow for adding a header.

Now... adding custom headers can be done with BlogMore's templates, but that felt a bit heavyweight for just one simple header, so instead I've added a head configuration option that lets you inject some simple tags into every page's head.

This is good for fans of humans.txt too; something I sense could have been quickly and easily extended to serve the purposes of what human.json does, but I guess we have to reinvent wheels every so often, and using a machine-readable file format is so much more... human.


  1. Probably kind of ironic in a project that is 100% about understanding the AI-all-the-way approach to developing an application. 

BlogMore v1.14.0

2 min read

Somehow minor version numbers are tracking the day of the month at the moment, and that isn't on purpose, but here we are on March 14th with BlogMore v1.14.01.

This release has a couple of changes: one is directly practical and the other a little more experimental/hopeful.

For starters, I've added a minify_html option. Having added minification for CSS and JavaScript files, it made sense to finally do this for all the HTML that's output too. So, if minify_html is set to true in the configuration file, or --minify-html is passed on the command line, any generated HTML file will be squished down as much as possible to reduce its overall byte size.

Every little helps, right?

The second change comes from a request that I don't directly know how to handle, so this is an experiment with allowing for it. The request was for "themes". Now, from the start, I created BlogMore such that the templates can be overridden and that custom stylesheets can be used, but the idea of "themes" suggests something more formal. Allowing for this and planning for this isn't straightforward because, honestly, I'm no web developer and no designer.

So what I have done is try and ensure that the templates and stylesheet are as sensible as possible and then also expand the documentation to try and make it possible for someone to step in and write their own theme.

I've also tried to ensure that there are adequate instructions for agents in the codebase such that no breaking change will be made in the templates and styling, without this being obvious. The plan here is to keep the core of the theme support as stable as possible and to adequately alert people to any breaking change (and, ideally, to never make any breaking change).

On top of all of that, I've got Copilot to also make three example themes. None are that radical, and I might see if I can coax it into making one or two more that are a bit wilder, but they should at least be helpful for someone with skills who feels more adventurous than me (or they might at least work as examples for an agent so that more themes can be AI-generated).


  1. If only it was v3.14... 🥧