z The Flat Field Z
[ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ]

Armaria

I've come to realize the solution I want for managing bookmarks doesn't exist. The existing solutions suffer from vendor lock in. I want a solution where I own the data, and it works across all the browsers and platforms that I use. Since this solution doesn't exist I decided to build it.

Why

Armaria are a kind of closed, labeled cupboards that were used for book storage in ancient times up till the middle ages.

I use the excellent KeePass to manage my passwords. The way it works is straightforward: I have an encrypted password file that I sync across all my devices with Dropbox. On each device I have a native client that I can use to manage my passwords. This flow has a lot of positive attributes:

  • I can share my passwords across all my devices regardless of platform or browser
  • I own my password data
  • I can sync my password data how I see fit

I was reading another thread on cloud bookmark services and I realized that I didn't want another cloud bookmark service since I wouldn't own the data. I also didn't want to use the native bookmark support in a browser since that would lock me into that browser. I wanted a way to manage bookmarks that had all the same attributes as the KeePass model:

  • One file synced how I want it synced
  • Works on all my platforms and browsers

Since I'm unaware of such a solution I decided to build it.

What

When I think of bookmarks these are the following must-have features that come to mind:

  • Fields for URL, name, and description
  • Supports nested folder structure
  • Supports tagging
  • Full text search

For the initial release I am targeting a small number of components:

  • An underlying library that supports the targeted features
  • A CLI to prove out the library

These components must run on a small number of platforms:

  • Windows x64
  • Linux x64
  • Mac x64/arm64

How - The File Format

One of the most important decisions for this project will be what file format to store the bookmarks in. They could be stored in a proprietary format which would support arbitrary features, but ideally it would be something that is open. Enter SQLite.

SQLite supports all the features I want. Moreover it's well tested, performant, and an open format with good client support.

Here is the ERD I landed on for the bookmarks database:

#+begin_src mermaid :file "erd.svg" :pupeteer-config-file "~/.emacs.d/pupeteer-config.json" :mermaid-config-file "~/.emacs.d/mermaid-config.json" :background-color "transparent" erDiagram bookmarks ||--|{ bookmarks_tags: "" tags ||--|{ bookmarks_tags: "" bookmarks o|--o{ bookmarks: "" bookmarks { text id text parent_id integer is_folder text name text url text description text modified } tags { text tag text modified } bookmarks_tags { text bookmark_id text tag text modified } #+end_src #+RESULTS: [[file:erd.svg]]

Bookmarks Database ERD

This schema supports every desired feature except full text search. Thankfully SQLite has FTS5 for this (which even has trigram support).

How - The Programming Language

I generally write web UIs and backend services so, the appropriate language for this project was going be new to me. The programming language choice was based on these requirements:

  • Native: I don't want to have to install a runtime for this
  • Good Tooling: Building (including cross-platform), testing, linting, and dependency management should all be easy
  • Fast Enough: Performance should be good to great
  • Mature: The language should be established and have a wide selection of solid libraries

Languages that I considered and ultimately rejected:

  • Zig: Zig meets a lot of the requirements, but I don't see it as quite mature enough yet
  • C/C++: C/C++ meets every requirement, but I lack experience in them and don't trust myself to avoid memory leaks
  • Rust: Rust has a steep learning curve and I don't know it

I ultimately went with Go which meets all the requirements, and which I believed would be the easiest to learn. Indeed I found it very easy to go from not knowing the language to being productive in it. I never had trouble finding the libraries I needed, and found the tooling excellent as well.

First Release

I have released the first pre-alpha version on the GitHub repo.

There isn't enough client support for this to be useful to anyone yet, but the CLI is fully functional.

Next Steps

The next set of clients I am targeting are desktop browsers via extensions. I intend to support them using Native Messaging. Since there are system calls here (the bookmarks are a file) we need native apps.

Conclusion

I think a lot of the best software comes out of someone addressing a personal need. While it's still too early to say I hope that some day I can build Armaria into something that meets my needs, and possibly even the needs of others as well.