Skip to main content
A cartoon depiction of the author, wearing a hoodie and smiling

Latest 3 Posts

Postmarks One-Month Update

First Month Review #

I announced Postmarks publicly a month ago and got a much bigger response than I was ever prepared for. Thank you to everyone who's sent in bug reports or feedback, contributed code to the project Github repo, and spun up instances of their own. I'm still blown away by the reception I received, and the progress the fediverse community has made in helping me move things forward in just one month has been incredible–all while being patient and kind with both my hacky leftover prototype code and my limited availability.

I'm still working full-time at a day job with its own demands, so I'm having to find time for this work around the edges of my responsibilities to work and family (and a big thanks to everyone in my life who's been patient with me in this past month!) That said, I'm still very excited to continue working on Postmarks and help it get to the place where it can be safe, useful, and easy to use for more people than it currently is.

New Features #

note: I didn't work on any of the things listed here; all my contributions this month were bugfixes & "glue work". For more information about who did what, check the changelog at the bottom of this section.

"Tag intersection" browsing #

You can now filter lists of bookmarks not just by individual tags, but by combination of tags. You can either edit the URLs directly and just separate them by slashes:

Or you can click on the small "+" next to any tag you see in a listed bookmark while looking at the list of bookmarks for a particular tag or set of tags.

SQLite, our database engine, actually has built-in full text search, so there's now a "Search" link in the main site navigation at the top and bottom of every page. You can search any substring in the title, description, URL, or tags of a bookmark and see the list of results.

CSV export #

You can now download your bookmarks as a .csv file! CSV import will be coming soon, using the same format to begin with. We may be able to offer import from other formats so that you can pull data in from other bookmarking services eventually.

Improved UI #

The site has been given a subtle but much appreciated upgrade to both its HTML and CSS structure and now does things like "handle narrow aspect ratios" (like, uh, smartphones). There are more enhancements coming to help you customize your install and make it look the way you want, but this gets most of the most annoying problems out of the way. It may be a more challenging git merge for anyone who's forked the project and customized it themselves, but we hope that with the upcoming customization features you won't have to worry about that too many more times.

Temporary repo governance #

Since I've seen initial interest in contributing from a number of people I decided to go ahead and give "collaborator" access to a handful of people who consented to it. We discussed in advance the idea that while I have no immediate plans to change anything, I consider this a non-permanent measure and I reserve the right to "reset" access at any point up to and including a move from my personal account to a full "Github organization".

Adding collaborators gives people the ability to create branches on the repo itself, which makes it easier for us to collaborate on PRs, and when it comes to bugfixes, they have the ability to review & approve each others' PRs. It also lets me create a "Github Project", similar to Trello or other project planning tools, and give those people access to tools that will hopefully help me communicate my priorities and thinking about the growing number of issues that are being filed on the project.

Complete changelog #

Here's what changed this month. If you read below you'll see that I eventually do plan to move to a more standard semantic-versioned release model, which will come with a changelog and so forth, but I wanted to highlight all the fantastic work that got done from the community of people who have been helping so far.

What's Next #

Upcoming Features #

Onboarding/setup flow #

The current setup process for Postmarks is pretty simple but has a few annoying bits that require you to read the instructions carefully and cause some problems if you don't interpret the wording perfectly. We'll move more things into the web admin interface with an onboarding flow that's more like a (much shorter version of an) install of hosted software like Wordpress or Mastodon.

Admin section site customizations #

There's some architectural work in progress right now that will make it easier to manage things like your site title, Fediverse actor name, avatar, and things like custom colors via the web interface. We'll also have a field where you can specify a separate CSS filename to include on all pages, which we hope will make it easier for you to customize the site more fully without worrying about Postmarks software upgrades overriding your changes. (If you're interested in how this is going to work, see the Backend Changes section below)

Network page fixes #

The "network" page, where you can follow other Postmarks instances or accounts elsewhere on the Fediverse, was kind of rushed out at the last second before launch so that I could consider the site to have a prototype of most of the major features I had in mind for the project. It's... pretty broken right now, though, and I doubt it's very useful in its current form. I'm going to spend some time cleaning up the way it detects links in the posts that your instance is able to find as a baseline, but I think we'll have plenty more to do even after that.

Miscellaneous improvements #

There are some other rough edges that I'd like to get some attention on in the short term, including making it easier & faster to discover how to follow a Postmarks instance using both ActivityPub (and Mastodon in particular) and the RSS (technically Atom, but any modern RSS reader should support it) feed.

Project Management #

note: if you're not interested in software development, you can probably feel free to stop reading at this point! Lots of technical details/jargon will follow, and is mostly meant to be of use to people who are keeping an eye on the active development of the software in particular.

Versioning #

I plan to release a new version in October that I'll bump to v0.2.0 to recognize the work that's happened so far. I would like to explore some kind of automation (via Github Actions?) for this, but at the very least will document my process so it can be automated at some point in the future.

When I do this, I would also like to provide a shell script that manages setting up a git remote pointing to the official repo & pulling down the latest released version, letting you override that remote to a fork via an ENV var if you've made your own changes that need to be included.

Once we're on the versioning train I'll follow a loose semver-like structure. I'm reserving the right to update the version to 1.0 at a future time not because of any breaking changes, but just to recognize the state of the software as being "ready" for a wider audience and to celebrate the work that has gone into getting it there. I would consider a release to be ready for 1.0 when it accomplishes all of the following:

CONTRIBUTING.MD & associated documents #

This falls into the "I didn't think there was a rush" bucket of tasks, but after being surprised to see a number of brave folks jump in, I know it's something we need to get set up in October. It's also something I need to do myself! I consider my responsibility here to be to provide the following:

My hope is that once the groundwork is laid for this documentation, it'll be easier to update it over time as we gain new tooling or make changes to how things are run.

Backend Changes #

Unified database with key/value store #

Repo collaborator John has outlined a plan for doing some refactoring of the way we store database info that should both simplify the code and also give us better capabilities for ensuring that future changes are able to be applied to existing installs.

John and I have worked together to create a migration path that ports existing data into that new unified database so that any current installs should get seamlessly ported over to the new setup, and he posted a draft of the first step of that process while I've been traveling this week that I am looking forward to reviewing this weekend.

ActivityPub compliance #

We've had a few regression bug reports and also things I hadn't considered (see the AUTHORIZED_FETCH issue on the Github repo). Right now, there aren't a lot of fully-featured guides to making a fully "compliant" app on the Fediverse–there are W3C specs for things like ActivityPub and ActivityStreams, but following them to the letter isn't even necessarily a good idea, given how it can cause problems with interoperability when other platforms have made opinionated choices about how they interpret the specs.

I expect this to be a tricky balance and one we'll be working on improving for some time to come. There's been initial meta-discussion about this in a few different places and I hope to develop a strategy for how we'll move forward on this. I personally have a lot to learn about the specs themselves, other Fediverse platforms, and tooling that's been created to do things like validate compliance.

Wrap-Up #

There's a lot more to say about the project, and I had outlined another few sections, but I think I've said plenty for now. If you have questions you can always open an issue, get in touch with me on Mastodon, or email me directly (my email address is available on my Mastodon profile). Thanks for reading!


What is Postmarks? #

I'm finally sharing my project Postmarks, a single-user bookmarking website designed to be easily hosted on Glitch.

Postmarks aims to provide a few different functions. Those functions are:

  1. Tag-indexed bookmarking
  2. ActivityPub publishing (soon to be optional!)
  3. Simple commenting, also powered by ActivityPub (also optional)

It's inspired by a number of websites I've loved over the years, including, Google Reader, and Branch.

You can see a basic demo of the site at, or an example of an instance with a lot of bookmarks in it at

Tag-indexed bookmarking #

If you're at all familiar with or Pinboard, you should hopefully be comfortable with the basics of using Postmarks to store bookmarks. If you're not already familiar, the idea is to store a collection of URLs along with some associated, browsable data—a customizable page title; a "description" field for summaries, notes or excerpts; a list of category "tags"—for your own reference over time and/or to share with other people.

On the centralized bookmarking sites of yore, you'd create an account and exist along with a collection of other people, meaning there were some lightweight community features like seeing who else bookmarked a given URL, seeing a public feed of all bookmarks for a given tag, or even "following" users. The Postmarks site itself is made to operate for one user, but the goal is to make setting one up as easy as possible so a single person can set up many of them for different purposes or keep all their bookmarks in one place and use the tagging features to make different kinds of things easily browseable.

ActivityPub publishing #

Postmarks, by default, also publishes all new bookmarks via the ActivityPub protocol, which means that people on web applications like Mastodon can "follow" your site in their timelines and lists and see new posts as you make them. And in turn, you can follow other people—other Postmarks users, or users on Mastodon, FireFish, or other text-based ActivityPub applications—and the links they share will show up on your Network page, with an easy way to grab any link you see and bookmark it for yourself.

Simple commenting, also powered by ActivityPub #

Once we've got bookmark posts showing up in Mastodon, it would be a shame if we didn't take advantage of that, right? Postmarks listens for incoming replies to its posts and absorbs them as "comments", which by default are unpublished/only visible to the admin when editing a bookmark. Controls are available at the site-wide level, and on individual bookmarks, to both auto-publish comments and just ignore them entirely.

You own your instance #

Postmarks isn't as complicated a piece of software as Mastodon! At the very least, you should feel welcome and empowered to edit the CSS to set your own color scheme, fonts, and so forth. If you're feeling more adventurous, you can reshape the Handlebars templates entirely in the src/pages directory. Or fork the project entirely and write new features from scratch! I'd love to accept general improvements on the frontend experience especially; feel free to open issues or submit pull requests on the Github repo.

A work in progress #

I've got a whole future ideas document included in the default bookmarks for the site, but to summarize I'd like to make Postmarks a fully self-sufficient platform, supporting all of its own features without ever involving a Mastodon or other microblogging platform. I'd also like to find ways to increase the usability of the site while keeping it compact, lightweight, and able to run on a broad variety of hosting platforms. I'd also like to see support for other indie web concepts, whether that's Micropub, Webmentions, or anything else I can harness to make Postmarks really useful to the people who want it!

Acknowledgements #

Thank you to Darius, Mouse, Ben, Anil, Casey, and everyone else who has inspired me, advised me, or lent a hand to Postmarks. (The more complete version is in the project README!) It's been fun to learn all the things required to make this platform come into existence and I hope to keep improving it and sharing bookmarks for a long time to come.

Importing Unread articles from Raindrop to Readwise Reader

I'm trying out Readwise Reader, starting today. I've tried... almost all of the Read It Later services, but had kind of put off checking this one out because the marketing around their original product Readwise seemed very geared towards AGGRESSIVE SILICON VALLEY EXECUTIVES who need THE POWER OF MACHINE LEARNING AND MIND HACKS to ABSORB THE MOST KNOWLEDGE and CREATE LEARNINGS FOR THE FUTURE or whatever. But some really thoughtful people I know seem to dig it, and so I wanted to give it a fair shake.

I've been using Raindrop for both bookmarks and "Read it later" for a while. The mobile app is nice-but-not-amazing, the bookmark saving workflow is nice-but-not-amazing... but it does have one really killer feature I haven't seen in other services: the ability to mass-bookmark all tabs in a given browser window. (It's even window-specific, so if you have multiple windows you can shift tabs around to control exactly which ones you want to mass-bookmark without having to temporarily close any other tabs you happen to have open).

The only problem is that getting a real test of the system into place meant importing my real backlog into Readwise Reader. Their Raindrop integration is built around their main product (Readwise, instead of Readwise Reader), which is a highlighting/knowledge-base type thing, so it only works on bookmarks in Raindrop to which you've added an annotation using their highlighting tool.

Poking around a bit, I did notice that Readwise Reader does support CSV imports, but in an undocumented format that I guess you have to join a "community Discord" to be told about. I hate this practice and would sooner walk away from a service entirely than be forced to join a Discord just to look up information, something it is not good for, but was lucky to find that a few people on Reddit (lol) have shared a link to a Google Drive URL (lol) that outlines the CSV format, so I was able to learn that they require this series of columns:


the Folder can be "Unread" or "Archive", and the Timestamp must be in "Unix time", the number of seconds elapsed since 1970-01-01 00:00:00UTC.

Raindrop offers easy exporting of any given view to CSV (along with other formats), so I was able to quickly get access to that data. Unfortunately, it wasn't quite the right CSV format. So I wrote a quick Ruby script to reformat the files:

require 'csv'
require 'time'

unless ["Unread", "Archive"].include?(ARGV[2])
raise RuntimeError, "third argument must be \"Unread\" or \"Archive\", found #{ARGV[3]}"

rows =[0])[1], "wb") do |csv|
csv << ["URL", "Title", "Selection", "Folder", "Timestamp"]
rows.drop(1).each do |row|
csv << [row[3], row[0], nil, ARGV[2], Time.parse(row[5]).to_i]

I generated two CSV files from Raindrop, one with just my "Unsorted" folder (which is where I put things when I bookmark them to read-later) and another with my "Misc" collection, which is the general-purpose collection I use for saving things that don't belong in some project-based set of bookmarks. Then I ran the command twice:

ruby csv-mutate.rb raindrop-later.csv readwise-inbox.csv Unread
ruby csv-mutate.rb raindrop-archive.csv readwise-archive.csv Archive

I imported both of these files via the "Upload file" option on Readwise Reader's Import Page and within ~5 minutes they had processed both files.

This process works as of Sep 4 2023; I can't guarantee that it will work even tomorrow. But it worked for me just now and it occurred to me that this is exactly the kind of thing I always wish would show up in search results when I have the same problem, so if that's you, good luck!

541 more posts can be found in the archive.