random hacks and pointless shenanigans

How I Take Notes (2021 Edition)

For reasons I don’t fully understand, I’ve been obsessed with keeping notes to myself in plain text files. A long time ago, this is the sort of thing I used Evernote for – until they drastically changed their pricing and plan options, anyway. Making me pay more money to use a service across multiple devices is a sure-fire way to encourage the construction of a janky half-baked self-hosted replacement.1 This mindset has put me at the intersection of a few rocks and hard places:

  • I stopped using Dropbox for a number of reasons, not the least of which is that I already pay Microsoft for Office 365. Most importantly for this case, that means that they give me a terabyte of free storage in OneDrive.
  • My favourite text/markdown editor on iOS, 1Writer, only supports Dropbox, WebDAV, or iCloud Files/Files.app locations reliably.
  • OneDrive doesn’t work great on Files.app in iOS. At all.

On the desktop side of things, this has been a solved problem for a while. A friend of mine told me about nb, which has been working great for me as an automatic system for managing and syncing plain text or Markdown-formatted notes. Every time I open and edit a note, it commits the edit to a Git repository. When you open a note on another computer, it runs git pull first to make sure it has the latest copy. It solved almost all of my problems… except for those pesky little things called smartphones. Up until now, I had an extremely precarious system involving a WebDAV directory that was also configured as the storage directory for nb on my primary computer. This made a lot of assumptions about the availabiltiy of a WebDAV resource being shared out of my home, as well as introducing frequent merge conflicts when I’d also updated a note from another computer. Inspiration struck on how to fix this while I was setting up org-mode for myself, though.2

The new workflow works perfectly, and it looks like this:

  1. I open 1Writer on my phone, and a Shortcuts automation fires that tells Working Copy to pull my nb-notes repository every time I open that app.
  2. After I close 1Writer, another Shortcuts automation fires off telling Working Copy to commit any changes in the iCloud Drive folder that both apps save files to, then to push that commit.
  3. Gitea runs a post-push webhook that connects to a machine that’s always online in my network and has nb installed. This machine runs a webhook receiver, and it scans the Gitea payload from each POST request for a commit author that matches the one I use on my phone. When it sees one, it runs nb index reconcile to scan any files that weren’t modified by nb itself.

Here are the nuts and bolts.

Webhook Receiver

webhook is an ambiguously named program that serves webhook endpoints and fires off commands when they’re accessed. After installing it, I defined a hook.

/homes/selectric/bin/hooks.json:

[
  {
    "id": "nb-sync",
    "execute-command": "/homes/selectric/bin/nb-git-hook.sh",
    "response-message": "Reconciling changes with nb...",
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "value",
            "value": "SECRET SECRET I'VE GOT A SECRET",
            "parameter":
            {
              "source": "url",
              "name": "token"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "Liz Slade (roxbury)",
            "parameter":
            {
              "source": "payload",
              "name": "commits.0.author.name"
            }
          }
        }
      ]
    }
  }
]

Gitea, like other Git servers, returns a lot of useful information in its payload – in this case, I’ve told webhook to only trigger on commits from the specific author name that Working Copy’s identity is set to on my phone.3

The script nb-git-hook.sh, in the same directory, is dead simple:

#!/bin/bash
/usr/local/bin/nb index reconcile

This command tells nb to scan its storage directory for any files that it wasn’t aware of – if it finds any, it assigns them an ID number and creates a new Git commit so that it can keep track of them in the future.

iOS Shortcut Setup

While I was writing this, I discovered that Shortcuts.app on iOS doesn’t have a great way of sharing automations. If you set up a shortcut, that at least generates an iCloud share link – for reproducibility’s sake, I’ve converted the automations to simply call a shortcut instead of having individually-defined actions.

Here are the shortcuts for pulling updates from the nb-notes repository and committing/pushing updates. Set up an automation that runs those shortucts when you open or close your favourite iOS text editor, respectively, and it should work (assuming that you have Working Copy properly configured).

For the curious, I’m using a very similar Shortcuts+Working Copy setup with beorg to use my org-mode files on my phone as well. Setting that up is what led me to working out how to make this work with my notetaking system, in fact.

  1. An obvious solution here would be to have fewer devices.

    That’s not gonna happen. ↩︎

  2. That setup might be fodder for another blog post. ↩︎

  3. For things that never/rarely leave my own Git server, I have a bad habit of setting the full name to include the machine’s hostname. It helps me keep track of things a little bit more easily. ↩︎