Category: Open Source

Personal Software

One of the most thought-provoking articles I've read on AI recently was by Oliver Roeder, writing last month in the FT. (Here, but behind a paywall). In it, he talks about his frustration with most text editors and word processors as being unsuitable for his daily job of writing articles for newspapers. "For decades", he writes, "I’ve chiselled through the thick accretion of features encrusting mass-market commercial writing software."

And so, with the help of OpenAI's Codex software, he decided to create his own.

Some extracts:

"Over a single weekend, entirely from scratch and heavily “vibe coded”, I created by some distance the best word processor I have ever used. I’ve named it vibedit. I’m writing in it right now. If there is an actually productive task for generative AI, it is as a creator of bespoke tools like this. Given this new, relative ease of app development, it is easy to imagine the atomisation of software into a mist of customised personal projects, droplets as numerous as users.
Aside from the software product, the experience had other benefits. I felt at liberty from corporate design, and could easily amend my own app as I thought of additions and deletions. And far from removing me from my work, this AI experience forced me to think carefully about how I work, and how to craft a fitting tool."

and

"Given its extensive tailoring, it is possible that vibedit would fit no one in the world except for me.
...
The only furniture in the window is a tiny word counter. There is only one typeface in only one size. More telling is what there is not: a window of templates, a title bar, a toolbar, a ruler, draggable margin setters, an option to insert tables or images, spelling and grammar check, AI 'suggestions'..."

There's more, but you get the idea. He created his own app, tailored for the job he does, and intended to be used only by him in just the way he likes.

I think this is very important.

As we enter an era where software development is much cheaper and easier, the number of people able to create their own bespoke apps will increase rapidly. Either you'll do it, or you'll pay your neighbour's son a modest amount to do it for you. Good and/or important software, to be used by large numbers of people, will still require experienced developers, though they may spend more time guiding the AI than actually typing the code. But software that is good enough for you to use yourself? That's becoming a different story.

Rather than a software company having to create one baroque and bloated product which includes every feature that might appeal to any of its customers, I think we will see a flourishing of smaller programs which leave out everything not needed by their small handful of users. To quote Antoine de Saint-Exupery, "You know you've reached perfection in design, not when there is nothing more to add, but when there is nothing more to take away."

Anyway, I've been doing the same thing as Roeder. You're looking at it.

As mentioned in my last post, I've long wanted to move my blog away from its WordPress roots. To be fair to WordPress, it has served me (and a significant chunk of the world's websites) pretty well, and for a lot longer than most pieces of software. I have had to rescue friends whose WordPress sites had been compromised by malware, but in recent years, as long as you don't install too many random plugins and are diligent about keeping both WordPress and any plugins up-to-date, it works fine.

But it also has a lot of code in it that I don't need, in a programming language I have long-since abandoned, and some of the recent design decisions weren't in a direction I would have taken. I have to adopt them, though, because I must keep updating for security reasons. And yet it is trusted with some of my most important data, and it defines the format in which that data is stored.

And so I settled on Wagtail, a Python-and-Django-based Content Management System (CMS). Unlike WordPress, which started as a blogging tool and then evolved to become a more general publishing system, Wagtail is a more general CMS, not tailored to blogging at all, but it is also a software platform which can be used to define whatever types of content you want to store, if that isn't just simple web pages. If you're creating a site advertising job vacancies, for example, you might create a JobVacancy page type which has form fields for storing metadata like location, salary, company name and description, and a template specifying how such a page should be converted into nice-looking HTML. The bits in that last sentence do require you (or somebody) to write code, so you need to be happy with that, but not very much code, since most of the hard work regarding storing, editing and publishing content under particular URLs is all done for you.

So I created content types for blog posts and comments, which largely mirrored the fields used by WordPress because I wanted minimal trouble importing my existing data. And at about this point I started enlisting Claude Code's help to do the rest of the work, and I have barely written a single line of code since.

I needed a script to import all of my past content -- posts, comments, categories and tags and any uploaded media -- preserving existing URLs, and doing various conversions as it went along, e.g. from the way WordPress stored embedded images or YouTube videos to the native Wagtail style of doing the same thing. I didn't at this point know what the normal Wagtail approach was for this, but Claude did: it had read a lot more of the documentation than I had! This script was very important to get right, but I could test it repeatedly on my development system before running it on the main site. I could also give Claude prompts along the lines of "Browse the old site, pick 250 random links and check that the same URLs resolve correctly on the new site." Once I was happy with it, this script was only going to run once and then be discarded.

Then it was a case of adding the features I wanted.

  • I liked the 'Possibly related posts' links at the bottom of each article, so I asked Claude to look at the way the old PHP plugin worked and create something similar for this environment.
  • I liked the calendar in the right margin (if you're on a wide screen), allowing you to see when there were posts, and jump to them by date.
  • When I publish a new blog entry, I like to post a link on the social media platforms I use, so there's a one-button facility to put it on Mastdon, BlueSky and LinkedIn, editing the associated post text on each beforehand if wanted.
  • Spam is a real problem with blog comments, so I needed a way to handle incoming posts effectively, which involved passing them through some rules of my own devising, some that Claude suggested, and finally calling the Akismet API (which, for a modest subscription, had been very effective on the old site). At the end of this pipeline, comments will have been either marked as 'accepted', as 'spam', or as 'pending', in which case I get sent an email with a link to review them.
  • Lastly, I needed an RSS feed, both for people who read the posts using an RSS reader and because it's the basis for the email feed for those who subscribe that way.

And that was it. Though at present, on the surface, you should see very little difference as a result, my own unique blogging environment, 'Status-Q: The Platform', has all the facilities I want, none of the facilities I don't want, and I'm confident I can add or remove features in future much more easily than if I had to burrow into the WordPress source code. (Some of the changes are already planned -- watch this space!)

So far, I'm very happy with the results, and looking forward to tinkering more with my 'personal software' platform in future. Now let me click 'Publish' and see what happens...!

Goodbye Wordpress...

This blog has been running for just over a quarter of a century now, and for a significant part of that time, it has been powered by Wordpress (which I host on my own servers - I don't use wordpress.com).

I've long wanted to switch it to something else, and over the last two or three weeks I've been building a replacement based on Wagtail, which, for those who don't know, is a content management system written in Python and layered on top of the Django framework. It's a popular replacement for older PHP-based systems like Wordpress and Drupal.

This post is being published on the Wordpress site. All being well, it will be the last one before the switch, and the transition should be mostly invisible. But if you follow these posts using some other system and suddenly find, in a couple of weeks, that this is the last post you've received, please let me know!

Starting a website using Wagtail is not too hard, though it's very likely to involve some coding to get it the way you want it. But converting an existing site, which has a fair number of readers, 25 years of history, 3500 posts, various categories and tags, a custom theme, subscribers who follow it using RSS readers and others who get it in their email inboxes, and so on, is quite a different challenge. I also wanted to replicate the functionality of certain Wordpress plugins which don't exist for Wagtail, to transfer all the uploaded media, posts, comments and categories, and, most importantly, of course, to preserve the original URL structure so that all the historic posts will still be found in the same place!

All of this explains (a) why it's taken me so long to get around to this job, and (b) why I have become a convert to the use of AI for tasks like this. Because after I created the basic structure, almost everything else has been a joint effort between me and Claude Code.

I've been telling it about the components I need, it has been adding them to my framework, and I've been checking the code. There's nothing I couldn't have done myself, though it would almost certainly have taken a lot longer. But for me, the key benefit has been that small things which would be nice to have but tedious to code are now worth doing. Status-Q is now not just my own blog, it is my own software platform tailored to do the things I want it to do, without too much clutter.

I'll be writing more about this concept of 'personal software' soon. If you see any posts in the days and weeks after this one, you'll know it worked!

Freedom of the press

Imagine an inkjet printer that you could repair yourself, and where you were actually encouraged to refill the cartridges!

That's the aim of the Open Printer project.

If the idea of printing from a roll of paper seems strange, you need to know that it incorporates a cutter too, so you can print single pages, and you're not restricted to one size of paper.

If, like many of us, you don't print very much these days, wouldn't it be nice to get the printer off your desk, and hang it on the wall?

I think this is a splendid idea, and I've signed up for updates (even though we already have three large printers in the house!)

I really hope they succeed.

The success of Django... and when the machines take over.

The Django web framework is now 20 years old. Within a few months of its launch, I discovered it, liked it, and we rather daringly decided to bet on it as the basis for the software of my new startup. (Here's my post from almost exactly 20 years ago, explaining the decision.)

For those not familiar with them, web frameworks like this give you a whole lot of functionality that you need when you want to use your favourite programming language to build web sites and web services. They help you receive HTTP requests, decide what to do based on the URLs, look things up in databases, produce web pages from templates, return the resulting pages in a timely fashion, and a whole lot more besides. You still have to write the code, but you get a lot of lego bricks of the right shape to make it very much easier, and there are a lot of documented conventions about how to go about it so you don't have to learn, the hard way, the lessons that lots of others had to learn in the past!

Anyway, I had made a similar lucky bet in 1991 when the first version of the Python programming language was released, and I loved it, and was using it just a few weeks later (and have been ever since).

Django was a web framework based on Python, and it has gone on to be a huge success partly because it used Python; partly because of the great design and documentation build by its original founders; partly because of the early support it received from their employer, the Kansas newspaper Lawrence Journal-World, who had the foresight to release it as Open Source; and partly because of the non-profit Django Software Foundation which was later created to look after it.

Over the last two decades Django has gone on to power vast numbers of websites around the world, including some big names like Instagram. And I still enjoy using it after all that time, and have often earned my living from doing so, so my thanks go out to all who have contributed to making it the success story that it is!

Anyway, on a podcast this week of a 20th-birthday panel discussion with Django's creators, there was an amusing and poignant story from Adrian Holovaty, which explains the second part of the title of this post.

Adrian now runs a company called Soundslice (which also looks rather cool, BTW). And Soundslice recently had a problem: ChatGPT was asserting that their product had a feature which it didn't in fact have. (No surprises there!) They were getting lots of users signing up and then being disappointed. Adrian says:

"And it was happening, like, dozens of times per day. And so we had this inbound set of users who had a wrong expectation. So we ended up just writing the feature to appease the ChatGPT gods, which I think is the first time, at least to my knowledge, of product decisions being influenced by misinformation from LLMs."

Note this. Remember this day. It was quicker for them to implement the world as reported by ChatGPT than it was to fix the misinformation that ChatGPT was propagating.

Oh yes.

Brunch with Brent

Amongst the tech podcasts I enjoy while driving, dog-walking, etc are the ones from Jupiter Broadcasting.

The Self-Hosted show, in particular, discusses topic and news of interest to those who like to run some of their own IT infrastructure rather than outsourcing it all to third parties. It covers areas like backups, VPNs, media servers, and home automation (one of my current hobbies)!

Linux Unplugged keeps me in touch with Linux news. Even though I've been a heavy user of Linux since the days when it was first released as two floppy disk images, and I run and manage a large number of Linux servers, both personally and professionally, I haven't really used it as my desktop operating system since Apple's release of MacOS X gave me a Unix-based alternative, so this helps keep me in touch with developments there as well as on the back-end.

Anyway, I recommend these if you're interested in such geeky topics; I think they're nicely produced.

And then there's Jupiter Extras, a feed with a range of interviews and other stuff that doesn't really fit into any of the other streams. One of the Jupiter hosts, Brent Gervais, has a set of periodic interviews labelled 'Brunch with Brent', and I was delighted to be invited to join him for one of these a little while ago (published yesterday), in which he let me ramble on about everything from scuba diving to the patent system, from QWERTY keyboards to self-driving cars.

The full discussion can be found on Episode 86, and there's a shorter extract in the middle of the latest Linux Unplugged episode too.

The WhatsApp Exodus

Apparently, lots of people are leaving WhatsApp, or at least looking for alternatives. (So say articles like this and this, at least.) I've only rarely used it, since most of my close friends and family are on iMessage and both my work-related groups use Zulip. It's only the occasional extended-family discussion that ends up on WhatsApp.

But if you've missed the story, this is because they changed their Terms of Service recently, and lots of people are shocked to discover that it now says they will share your details -- location, phone number, etc -- with the rest of the Facebook group.

I actually read, or at least skimmed, the Terms when they came out, and didn't blink an eye, because I've always assumed that's what they did anyway! I deleted my Facebook account many years ago, but I was aware that they still knew a lot about me because I do still use WhatsApp and Instagram (though only about once a month). Still, that will give them things like my name, phone number and location (from my photos if not from the apps).

In the early days, by the way, WhatsApp traded, as BlackBerry had done before, on the fact that it was secure messaging -- encrypted end-to-end at least for one-on-one conversations. My understanding from those who follow these things more closely is that the security services tolerate this because the accounts are so closely tied to phone numbers, which means that, though they can only see metadata, they can get lots of it and related information because of older laws allowing phone-tracing etc. But there may be some people out there who thought that the use of WhatsApp was giving them a decent level of security, in which case this would perhaps be more of a shock.

Anyway, I too now have a Signal account, alongside Telegram, Skype, Messages... and all the others on all my devices. Actually, that was one of the reasons I disliked WhatsApp: the pain of using it on my iPad, desktop and laptop. And who wants to type things on a phone keypad when they have an alternative? You could run clients on those other devices, but (presumably because of the regulatory issues above) they had to be tied to the account running on your phone, and that connection seemed a bit fragile and had to be oft-renewed.

Signal, which I installed last night, works on a similar principle; it'll be interesting to see whether it does it better! But it looks OK on my iPad; time to go and try it on my Macs... In the meantime, you can find me on Signal, if you know my phone number (like the FBI, GCHQ and Mark Zuckerberg do). If not, they can tell you where to find me.

Pannellum in Pittenweem

I've had fun in the last year or so playing with spherical cameras (often known as 360-degree cameras) and I've posted a few on here. But they've always had a problem: you really need a plugin to view them, which is untidy. This one of the Sacré-Coeur, for example, relies on a plugin from the Ricoh site.

So I've been delighted to discover Matthew Petroff's Panellum, a panorama viewer created using just HTML5, CSS3, JavaScript, and WebGL, which means it runs in most modern browsers natively.

Here's an example from Pittenweem, a favourite spot I discovered on my campervan trip over Christmas, just north of Edinburgh.

You can drag the image around to look in different directions, and you can zoom in and out by scrolling, or using Shift & Ctrl keys.

On my early experiments, it seems to work very well, even on my fairly elderly laptop. It even has a full-screen button...

So you may be seeing a few more of these here in the near future!

Old News

A couple of days ago, I received some suggestions for improvements to a program I had written. This isn't unusual: I'm writing code all the time, and much of it needs improving. (Thanks, Sam!) No, the surprise in this case was that the suggested changes were to a little script called newslist.py that I wrote in 1994 and haven't updated since. It wasn't very important or impressive, but seeing it again made me a bit nostalgic, because it was very much an artefact of its time.

For a couple of years, I had been playing with early versions of a new programming language called Python (still at version 0.9 when first I fell in love with it). In those days, online discussions about things like new languages occurred on forums called Usenet newsgroups. (As an aside, I was also playing with a new operating system called Linux, which Linus Torvalds had announced on the comp.os.minix newsgroup with one of those throwaway phrases that have gone down in history: ""I'm doing a (free) operating system — just a hobby, won't be big and professional..."".)

Anyway, the Usenet group archives are still accessible now through web servers like Google Groups, but the usual way to read them back then was to fire up a news-reading program and point it at a local news server, which could serve up the messages to you using the 'network news transfer protocol' NNTP. Since you wouldn't necessarily have a fast connection to anywhere else in the world from your desktop, organisations such as universities and the more enlightened companies would run their own NNTP servers and arrange with their pals in other organisations to synchronise everything gradually in the background (or, at least, to synchronise the newsgroups they thought would be of local interest). When a user posted a new message, it would trickle out to most of the servers around the world, typically over the next few hours.

But another novelty was catching my attention at that time... This thing called the World Wide Web. Early web browsers generally spoke enough NNTP to be able to display a message (and maybe even the list of messages in a group), so you could include 'news://' URLs in your web pages to refer to Usenet content. But a browser wasn't much good for more general news perusal because it didn't have a way to find out which newsgroups were available on your local server. My newslist.py script was designed to fill that gap by connecting to the server, getting the list of its groups, and creating a web page with links to them displayed in a nice hierarchical structure. You could then dispense with your special newsgroup app, at least for the purposes of reading.

When version 1.1 of Python was released, Guido van Rossum added a Demo directory with some examples of things you could do with the language, and newslist.py was included. And there it remained for a couple of decades, until, I discover, it was removed in 2.7.9 because the comment I had casually included at the top about it being free ""for non-commercial use"" no longer quite fit with the current Python licensing scheme. (I would happily have changed that, had I known, but I wouldn't have imagined anybody was still using it!) The Demo directory itself was dropped in Python 3, and so newslist.py was consigned to the historical archives.

So you can understand my surprise at discovering that somebody was still experimenting with it now! I didn't know anybody had an NNTP server any more.

What's almost more surprising is that one of my two email addresses, mentioned in the code, is still working 23 years later, so he was able to write and tell me!

All of which tells me I should probably pay more attention to what I put in the comments at the top of my code in future...

Tips for using a private Docker registry

This is a geeky post for those Googling for relevant phrases. Sometimes a Docker Registry is referred to as a 'Docker repository'; technically, they're different things, but the terms are often used interchangeably.

It can be useful to have a private Docker repository for sharing images within your organisation, and from which to deploy the definitive versions of your containers to production.

At Telemarq, we do this by running:

  • a standard registry:2 container on one of our DigitalOcean servers
  • an nginx container in front of it, with basic HTTP auth enabled
  • a letsencrypt system to provide HTTPS certificates for nginx, so the communications are secure.

The registry container can, itself, handle both authentication and the certificates, but it's easier for us to deploy it this way as part of our standard infrastructure. It all works very nicely, and we're just starting to incorporate it into some of our more serious workflows.

So how do you make sure that the right images end up in your repository?

One practice we adopt for any deployment system, with or without Docker, is to require that things pushed to the servers should come directly from the git repository, so that they aren't influenced by what just happens to be in the directory on some arbitrary machine at some time. Typically we might have a script that creates a temporary directory, checks out a known version of the code, builds and deploys it to the server, and then tidies up after itself. (If you use a continuous delivery system, this may happen automatically on a regular basis.)

In the Docker world, you can take advantage of the fact that the docker command itself understands git repositories. So you can build a container from the current master branch of your github project using something like:

docker build -t myproject git@github.com:quentinsf/myproject.git

and docker will do the necessary bits behind the scenes, assuming there's a Dockerfile in the source. (More details here).

So, suppose you want to build version 1.6 of 'myapp' and upload it, appropriately tagged, to your Docker registry, you can do so with a couple of simple commands:

docker build -t dockerregistry.example.com/myapp:1.6 \
             gitrepository.example.com/myapp.git#1.6
docker push dockerregistry.example.com/myapp:1.6

I can run this on my Mac, a Windows machine, or any Linux box, and get a consistent result. Very nice. You could also tag it with the SHA1 fingerprint of the git commit, if wanted.

Listing the containers on your Docker registry

At present, there isn't a convenient command-line interface for examining what's actually stored on your registry. If I'm wondering whether one of my colleagues has already created and uploaded a container for one of our services, how would I know? There is, however, an HTTP API which will return the information as JSON, and you can then use the excellent jq utility to extract the bits you need:

curl -s -u user:password https://dockerregistry.example.com/v2/_catalog | jq .repositories[]

If you want to see the version tags available for mycontainer, you can use:

curl -s -u user:password https://dockerregistry.example.com/v2/mycontainer/tags/list | jq .tags[]

And you can of course wrap these in scripts or shell aliases if you use them often.

Hope that's useful for someone!

Optimising the size of Docker containers

Or 'Optimizing the size of Docker containers', in case people from America or from Oxford are Googling for it...

For Docker users, here are a couple of tricks when writing Dockerfiles which can help keep the resulting container images to a more manageable size.

Also available on Vimeo here.