Posts in category "Coding"

Gemini client history

1 min read; 12 GFI

Work continues on my terminal-based Gemini client. So far today I've done a bunch of work on tweaking the presentation of a site, improving some of the widgets that go into the on-screen document. I've also added the start of a history system. So now it's easy to navigate backwards and forwards between pages.

History navigation in action

While there's still a lot of work that I want to do on it, I feel that with the addition of this feature, it might be close to time for me to make it public. It's going well and heading in the right direction, so it feels like the moment when I accept it's not going to be something I abandon, but now have to see to completion.

There are also some design choices I've made this time around that have made me want to revisit Hike at some point in the future. Not for a while yet, but I want to go back and clean up some of the code. After AI-based coding I've been doing lately, it's really nice to be hands-on again and designing every single line. It's a good reminder that working this way ensures a much bigger-picture view of how an application hangs together, and how it can benefit other applications you're maintaining.

Gemini client rendering

1 min read; 11 GFI

Yesterday I got the basic framework of my Gemini client up and going, and this evening I've been working on getting rendering of the gemtext in place. It's not the most tricky format to handle, so the parser and Textual widget to display the result have come together pretty quickly.

Browsing with the client

With this in place I've got the core of a working client now. Next up is going to be adding history with forward and backward navigation, then after that things like bookmarks and so on.

Gemini client basic framework

1 min read; 10 GFI

Following on from the initial release of Wasat yesterday, I've got a very basic proof-of-concept client up and running. So far, so good. Here it is loading up my own capsule on GemCities:

Loading my capsule

There's a lot to do yet, it'll be some time before this turns into a public project, but having it at least load up a document from a capsule means there's enough there for me to want to keep going and developing this.

Also, as I said yesterday, this is all home-grown and hand-crafted code. BlogMore has been tons of fun, but it's nice to kick off a significant bit of Python code where I'm writing it all myself. It's nice to be in that flow state once again.

BlogMore v2.43.0

1 min read; 12 GFI

After recently adding Mermaid and maths support to BlogMore, I got to thinking that it now has connections with a handful of third-party resources. While almost all of them are optional (only FontAwesome comes close to being a hard requirement), it does mean that there are resources the user doesn't directly supply or control, and for which the URLs are hard-coded in the source for BlogMore.

I wasn't keen on this. While it's my intention to keep an eye on things and, periodically, check on those libraries and see if they need an update, I felt it was important that the user could override them on their own, without waiting on me.

So v2.43.0 adds a third_party section to the configuration file to give full control over these resources. The full version of it looks like this:

third_party:
  mermaid:
    script_url: "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs"
  katex:
    css_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"
    js_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"
  mathjax:
    js_url: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
  fontawesome:
    metadata_url: "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/6.7.2/metadata/icons.json"
    webfonts_base: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts"
    css_url: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
    woff2_url: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.woff2"
  force_graph:
    js_url: "https://unpkg.com/force-graph"

Of course, it's not an all-or-nothing setting; you can just set one of the values. So if you wanted to override the force_graph value it's enough to do:

third_party:
  force_graph:
    js_url: "https://unpkg.com/force-graph"

Hopefully this adds some useful flexibility. As well as giving the option to use a different version of a resource, it also allows you to host your own copy and refer to that instead. Heck, it would even allow totally replacing a library with a different one that has the same API, should you ever find yourself in that situation.

BlogMore v2.42.0

1 min read; 10 GFI

I've released BlogMore v2.42.0. This version is all about changes to the dump command.

When I first added it it simply dumped all of the data available about posts within a blog, meaning it was possible to do all sorts of things with the data outside of BlogMore itself. Having done this, and used the result to good effect (and also having seen at least one person also make use of it), I got to thinking that I should probably expose some other data that's going to be helpful.

Given that blogmore.el needs to dive into things like available categories and tags, and given that I'd also like to add support there for the recently-added series support, I realised that dumping those values as JSON would also be helpful.

So this release extends the dump command, adding a set of sub-commands:

  • posts: dumps the data about all posts in the blog (this is the default if you just run blogmore dump, so keeping the command backward-compatible).
  • categories: dumps all categories as slug/title pairs.
  • tags: dumps all tags as slug/title pairs.
  • series: dumps all series as slug/title pairs.

For example, getting all categories from this blog:

blogmore dump categories
[
  ["ai", "AI"],
  ["coding", "Coding"],
  ["creative", "Creative"],
  ["emacs", "Emacs"],
  ["gaming", "Gaming"],
  ["life", "Life"],
  ["meta", "Meta"],
  ["music", "Music"],
  ["python", "Python"],
  ["tech", "Tech"],
  ["til", "TIL"]
]

Or all the available series right now:

blogmore dump series
[
  ["agentic-afterthoughts", "Agentic Afterthoughts"],
  ["buying-the-steam-controller", "Buying the Steam Controller"],
  ["edinburgh-fringe-2023", "Edinburgh Fringe 2023"],
  ["reading-2bit-files-for-fun", "Reading 2bit files (for fun)"],
  ["swift-til", "Swift TIL"],
  ["the-great-github-copilot-meltdown-of-2026", "The Great GitHub Copilot Meltdown of 2026"],
  ["the-virgin-east-coast-saga", "The Virgin East Coast Saga"],
  ["emacs-d", "~/.emacs.d"]
]

While this data could have been gathered from the content of the dump of posts, this approach makes it far easier to work with and more accessible; simply put, it means there's less work for the user to do if they just want all the tags (for example). With this, and with a little bit of caching in the code (because this does require parsing all the posts every time), I think it will make for a better approach to category, tag and (when I add it) series completion while writing a post.

BlogMore v2.41.0

2 min read; 12 GFI

It's probably bad news if I have a Saturday afternoon and evening spare, a fully-charged laptop and a comfy sofa. It seems that when that happens, something like BlogMore v2.41.0 happens. This is a release where I've added two features that could be generally useful, but which I'm unlikely to use in my own blogs.

The first, which to be fair is one I might use (I've used it in documentation plenty of times over the years), is optional Mermaid support. This is off by default, so has no overhead if you don't turn it on. It is turned on by setting with_mermaid to true. Even with this enabled, the Mermaid third-party scripts only get included on pages that include a Mermaid diagram, reducing the overhead.

To include a Mermaid diagram you use a fenced codeblock with mermaid as the language identifier. For example:

```mermaid
graph TD
    A[Start] --> B[Process]
    B --> C{Decision}
    C -->|Yes| D[Success]
    C -->|No| E[Fail]
```

If Mermaid is enabled the resulting page will show this:

Example Mermaid diagram

There are, of course, all sorts of diagrams that can be used and I'm not going to go into them here, or in the BlogMore docs; Mermaid is well known enough and well-documented enough that anyone turning this on is likely to know what they're doing, or where to go to find out what to do.

The second new feature, which I am almost certainly never going to need to use on my blog, is LaTeX-style maths support. As with Mermaid, this is off by default and has no overhead if not used. Even when turned on with the with_maths setting, the external scripts will only be pulled into pages that include maths markup.

Two providers of rendering engines are supported and this can be configured with the maths_provider setting. The available options are katex (which is also the default) and mathjax.

To use either, when turned on, you use the usual $ or $$ convention for LaTeX-maths-in-Markdown:

You can make some fun images using:

$$
z_{n+1} = z_n^2 + c
$$

We can say $z_{n+1} = z_n^2 + c$ inline too.

The result of the above will be something like:

Maths markup in action

Note that some care has been taken to ensure that ordinary use of a $, in currency values for example, is left unaffected. This can't be guaranteed in every possible case, so keep this in mind when turning on with_maths. From what I have read this is a common issue when using such markup.

Both these features were fun to add, with me planning out the implementation with Antigravity, and having a back and forth a couple of times to address issues and get it all working "just so". I'm especially pleased with the fact that it's done in a way where there is no overhead, even when either feature is enabled, if a page isn't showing a diagram or maths markup.

BlogMore v2.40.0

2 min read; 12 GFI

I've just released BlogMore v2.40.0. This version contains just one new feature: post series support.

It's hardly a novel feature, plenty of blog engines support this sort of thing; I felt it was high time I added it to BlogMore too. The idea is simple: while categories provide a method of having "sub-blogs" within a blog (they also provide their own feeds), and while tags let you group together posts that touch on related subjects, a series will let you stitch together a collection of posts as directly relating to each other.

Adding a post to a series is as simple as adding a series to the frontmatter of a post.

title: Five days with Copilot
category: AI
tags: Python, AI, LLM, Copilot, GitHub, BlogMore, coding
date: 2026-02-20 15:46:00 +0000
series: Agentic Afterthoughts

With this done, when a reader is viewing an individual post that is within a series, some new navigation appears at the top and bottom of the post that lets them know about the series, and also offers them easy navigation to the previous and next posts.

Series navigation

Also, if the reader were to click on the series title, it will take them to an archive page for that series, where the posts are presented in the usual pagination format, but where they're also presented in series order. To be clear: series order is always chronological order.

To help encourage further post discovery, if one or more series are available, a new Series link appears at the top of the blog. This links to an index of every series available.

My blog's series index

Sorted in alphabetical order, the list also shows how many posts are in each series and, if reading time is turned on, the total reading time will be shown.

Worth noting is the fact that a post doesn't have to be restricted to just one series. If you need a post to be in two or more series, you can provide the series as a list:

title: My post that crosses the streams
category: Testing
tags: BlogMore, Series, Test
date: 2022-02-22 22:22:22 +2200
series:
  - Experiments with blogging
  - Eating my own dog food
  - Testing thing

The post will then show navigation for every one of those series, and the post will be in each series' archive page.

Having added this, I've also updated the output of the dump command so that series (the series list as provided in the frontmatter), safe_series (the series list in their URL-friendly slug forms) and series_pair (a list of series title and slug pairs) properties are available.

As of the time of writing this, I have noticed one issue. The linter isn't currently aware of the URLs that are created as part of the series facility. So if you have a page or post that links to the index, or links to a particular series, there will be errors:

blogmore lint
Linting site in content...
ERROR: posts/2026/06/2026-06-06-blogmore-v2-40-0.md: Link points to non-existent internal path: /series/ (resolved to /series/)
ERROR: posts/2026/06/2026-06-06-blogmore-v2-40-0.md: Link points to non-existent internal path: /series/ (resolved to /series/)
ERROR: posts/2026/06/2026-06-06-blogmore-v2-40-0.md: Link points to non-existent internal path: /series/the-virgin-east-coast-saga/ (resolved to /series/the-virgin-east-coast-saga/)
Linting complete: 377 post(s), 4 page(s), 3 error(s), 0 warning(s) [0.45s].

This should be a straightforward fix which I'll make in a follow-up release.

BlogMore v2.39.0

1 min read; 13 GFI

BlogMore v2.39.0 has a couple of changes, one more or less cosmetic, the other a new feature that I probably should have added right near the start of the project.

First, the cosmetic: in pages and posts, when you use headings (#, ##, etc.), a is added to the end of each heading, along with some show-on-mouse-hover styling, to make it easy to grab the anchor of a particular section of a page1. A problem I'd noticed with this recently is that the shows up in the search text, and also in the content of all the feeds. While not a problem as such, it felt untidy.

So, with this release that particular character is stripped from the search index and from the feeds.

The second change is a facility that should be useful if you have legacy URLs that you really must have land on an actual page or post: redirection support.

This facility is provided by a new redirect_from frontmatter property. From now on, a page or a post can declare which URLs should be redirected to it. So, if you have a post that, given your current post location setup, would land at /2006/06/06/hello-world/, but in some other incarnation of your blog lived at /posts/2006-06-06-hello-world.html, you can now set this in the frontmatter:

redirect_from: /posts/2006-06-06-hello-world.html

and the old URL will be redirected to the new one. This is achieved by simply creating a very minimal HTML file at the old location, which contains a redirection. The content of the file will end up looking something like this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Redirecting...</title>
    <link rel="canonical" href="https://example.com/2006/06/06/hello-world/">
    <meta http-equiv="refresh" content="0; url=/2006/06/06/hello-world/">
  </head>
  <body>
    <p>Redirecting to <a href="/2006/06/06/hello-world/">/2006/06/06/hello-world/</a>...</p>
  </body>
</html>

If a blog has migrated between locations and/or generation tools over the years, and there are a number of different legacy URLs out there still pointing to a post you really want to keep readable to all, you can also redirect from multiple URLs:

redirect_from:
  - /posts/2006-06-06-hello-world.html
  - /posts/2006/06/06/hello-world.html
  - /my/really/old/blog/structure/hello-world-06-06-06.html

While all of this would have been possible anyway, by creating the appropriate file, with the appropriate content, in the extras directory, this approach helps automate the process and also means that the redirection information lives with the page or post being redirected to.


  1. The recently-added floating ToC is another way to do this now too.