I’ve been wanting to blog more, but it’s always seemed like such a hassle. I appreciate the speed and flexibility of statically-generated sites, but the authoring experience around them isn’t that great. On the other hand, the authoring experience on hosted solutions (like Wordpress or Medium) is fantastic, but you lose a lot of the speed of a static site, and the ownership becomes more murky.

When I sit down to write a blog post, I don’t want to think about all the minutiae that goes in to keeping my blog up and running; instead, I want to be thinking about the content of the post.

What I really want is an authoring experience that gives me native Mac (and ideally, iPad) apps, but that works with my static site files. I’m willing to do the odd git commit and git push commands to actually publish the content, but I still want things like spell checking, drag-and-drop to embed media, and so on.

For a long time, it seemed like there was never a happy medium, and it’s something that occasionally rears its head and results in a frustrated tweet:

This time around, I had an idea and decided to run with it.

First, I’m a big fan of indie software and in particular, I’m a long-time user of Daniel Jalkut’s great app MarsEdit. Yesterday I was poking around in the app and I had one of those ideas that seems crazy enough to actually work.

MarsEdit has support for a bunch of standard kinds of blogs, like WordPress and Tumblr, etc. But the real power behind it is that it’ll work with any blogging system that uses one of a few standard kinds of APIs. These APIs tend to be of the “XML-RPC” variety.

This got me thinking… what if I exposed my Jekyll blog via an XML-RPC interface? Then I could add it in MarsEdit and write and edit posts there. I’d get all of the features of the MarsEdit authoring experience, but the benefits of a static site that I rather enjoy.

So, the past 36 hours have been a frenzied coding storm of me writing a Swift package that implements an XMLRPC server to serve up the source files of my website, all so I can write posts in MarsEdit.

As it happens, it works really well. I can write in Markdown, I can drag-and-drop images, I can save and edit posts as published or drafts, I can alter tags, edit HTML, and do just about everything I want to do with the content of my site without worrying at all about making sure I get files in the right folder and naming them correctly and manually resizing images…

As is typically of my side projects, this one follows my side-project philosophy:

Anything worth doing is worth over-doing

I ended up building an entire XML-RPC Server, including custom XMLRPCEncoder and XMLRPCDecoder types so that I can write the actual request and response objects as normal Swift Codable structs. I started off only focusing on the MetaWeblog API, but it turned out to not be quite descriptive enough for my purposes (it doesn’t have a way to describe post tags, for example).

So, because I had this massively over-engineered system in place, I was able to quickly add support for most of the Wordpress XML-RPC API with structs that look roughly like this:

enum Wordpress {
    struct GetPost: XMLRPCMethod {
        typealias XMLRPCMethodResult = Post
        static let methodCalls: Set<String> = ["wp.getPost"]
        let username: String
        let password: String
        let postID: String
        func execute(with site: JekyllSite) throws -> XMLRPCMethodResult {
            return Post(try site.getPost(postID))
    struct Post: Codable {
        let post_id: String?
        let post_title: String
        let post_date_gmt: Date?
        let post_type: String
        let post_status: String
        let post_author: String
        let post_content: String
        let terms: Array<Term>

I’m very pleased with how this has turned out. It’s been a great weekend project, and it’s made it much simpler for me to blog again. So, hopefully, expect to see more posts from me in the future.

And sorry, this code will likely not be open-sourced. I’m offering it to Daniel, so maybe a future version of MarsEdit will have support for this sort of thing natively (but you’ll have to pester him about that).