Beancount

Back in 2021 I tried double-entry, plaintext accounting as implemented by hledger. You see, I've been into doing stuff in plaintext in Vim and Neovim, keeping it all committed to a Git repo, for a couple of decades now. First for the obvious things like code, then documents and wikis, tasks1, and email. So, trying out plaintext accounting held a natural appeal for me.

Turns out, I didn't stick with it. My motivation wasn't strong. My ledger file never even got to 200 lines. In the end, it contained only a handful of transactions.

Fast-forward to 2026, and I decided to give it another go, this time with Beancount and its slick web interace, Fava. This time, I think it's going to work. In the two or three weeks that I've been playing with Beancount, I've already found ways to make it replace a mishmash of Markdown files, Excel sheets, and plaintext notes for a bunch of different purposes:

  • Income and expense tracking: With the flexibility to do all this even though it spans multiple banks, multiple accounts (some of them shared2 accounts), multiple types (like credit cards, bank transfers, and cash), and multiple mechanisms (such as involving reimbursements, or corporate meal and transport accounts with different tax treatments).
  • Figuring out tax obligations: As an employee at a tech company, I have to deal with salary and stock-based compensation (RSUs, an ESPP program, and dividends) and currency differences; Beancount not only helps me reconcile all these things (ie. double check them in various ways to catch data entry and arithmetic errors), but it can directly spit out the exact numbers I have to fill in to each box on my tax return.
  • Tracking investment lots: Beancount knows when I bought what (and for what price), and knows how to apply "FIFO" (First-In, First-Out) rules when I make sales.
  • Building a price database: The text format is simple, and price information for currencies and index funds is freely available on the internet, so with a simple script I can pull down a detailed database of historical price movements for everything I care about.
  • Calculating and charting investment returns: Beancount can give you a chart of your net worth over time, but it also it contains all the data needed to calculate your investment returns over different time scales; this is mostly for intellectual curiosity3, and has little impact on one's daily life, but it can be fun to look at.

Does all of this sound like a lot of work? In the end, it doesn't need to be. A lot of folks use importers to process their financial statements and extract transaction info from them into a format that Beancount can read. I haven't done that yet, because I want to manually enter the data while I'm still learning the system; but I have made a little phone app so that I can enter transactions on the go with a few taps. This is partly so I can, as I said, learn the system, but it's also because I want to get a real, grounded feel for where my money is going.

That's the real reason why I became interested in expense tracking again. You can't figure out how much you actually need without doing the work of figuring out, um, what you actually need. And once you know what you're spending money on, you may find that there are adjustments that you can and perhaps should be making. There's a big difference, say, between guessing that you spend "a fair bit" eating out every month, and actually knowing the dollar amount, and furthermore knowing what proportion of all your spending it makes up. And once you know that dollar amount, you can figure out from there what it will mean for the arc of your life4.

  1. I looked into Taskwarrior but never adopted it; I do, however, store informal "TODO" lists in Markdown documents all over the place. I am sure if I was an Emacs user, I'd be all-in on Org Mode.

  2. And not simply shared with a 50:50 split, but more complicated arrangements than that.

  3. For example, you might answer a question like "what was my annual return in 2025, and how did it compare to the S&P 500 index that year?".

  4. This may sound familiar to those who have read "Your Money or Your Life" by Vicki Robin and Joe Dominguez, but they give a bunch of vivid examples of how an unregulated and ultimately unnecessary spending habit can be the difference between retiring early (or at least on time) and laboring to death.

Sync in 2026

File this one under "betting on the wrong horse", because I'm about to tell you how — yet again — I've migrated an important piece of my digital life to a new platform. This chapter's subject is file syncing.

Many years ago I started off as a free-tier Dropbox user. I became a paying user for a while as my storage needs grew, but I eventually felt the need to move away given their gradual transmogrification into an evil megacorp. By this time, my needs were clear: I wanted something that allowed me to view my files in the native file browser on my Mac, and an iOS app so that I could both view files and save files in a way that shared them back to my laptop. At times I would sync to multiple machines, and occasionally I'd need to share a folder with somebody else, but for the most part, what mostly concerned me was keeping one laptop in sync with one phone.

I switched to Sync (by sync.com) in order to get away from the evil. The app was uglier, and syncing was slow and inscrutable. Eventually the thing that drove me away from that was the flakiness of the sync with another computer, another user, and a shared folder in the mix; I had a support thread open for months (about synchronization that silently failed to complete) and never got a resolution. Finally, I got sick of waiting and switched again.

I can't remember exactly where in this chronology, but along the way I experimented with both Google Drive and Microsoft OneDrive. Both proved to be — wait for it — slow, unreliable, and inscrutable. These attributes seem to be a recurring theme in this space...

Syncthing would have been the obvious choice — open source, popular, battle-tested — but it lacked an official iOS app, and the most popular third-party one, Möbius Sync, seemed to be in maintenance limbo. So I ended up going with Resilio Sync. Like sync.com's Sync, this one was closed source and proprietary, but it also happened to be free. I wouldn't have minded paying for it if it had been good (I'd paid Dropbox, Sync, Google, and Microsoft in the past, after all), but it turned out that I didn't have to.

In 2026, Resilio was acquired by Nasuni, and the writing very much appears to be "on the wall", so to speak. The FAQ is laden with the usual verbiage that "future updates or options will be communicated clearly and well in advance", and that there "are no immediate changes to product availability or customer support processes", but the release cadence of late and the number of historical bug reports and feature requests makes it clear that the software is on the merest of life support. I'd been eyeing the exits for a while, ever since I adopted Resilio Sync, really, but this made me seriously consider switching solutions, yet again.

The good news is that there is a bright and upcoming third-party iOS app for Syncthing now: Synctrain. It's open source, like Syncthing itself, and feels like a real iOS app. I also tried out a couple of lightweight text-editing apps for iOS which looked like they'd integrate well with Synctrain for on-device editing of text files (something I don't often have to do, but which I like being able to do when necessary): I haven't settled on one yet, but the candidates are Runestone and Textastic.

Now Syncthing is a bit "promiscuous" out of the box, in the name of ease of use: it uses a global discovery mechanism, and there's a network of relays that anybody can participate in to shuffle encrypted traffic between devices, allowing you to sync between computers and phones regardless of which local network you're on. While your data is encrypted, metadata about your IP address, the device IDs you're talking to, and the amount of data your sending, is all available to these peers. That makes me feel a bit squeamish (Resilio Sync had a similar problem, to be fair), so it seemed reasonable to test Syncthing with all of these convenience features turned off in the name of privacy.

In my first round of testing I had everything turned off and local discovery only. Given my network topology (a mobile phone, a laptop computer mostly only used on the home network but sometimes traveling outside it, and an always-on Raspberry Pi on the home network as a centralized sync point) my plan was to test it all out while assuming the limitation that I would only actually synchronize when at home.

This worked ok, but I wanted to see if I could have my cake and eat it too. The other relatively new circumstance in my life is that last year, I picked up a decent router (a UniFi one) and it has a couple of built-in features that make it trivially easy to set up a VPN with a minimum of effort and only a single extra dependency (WireGuard) installed on the client devices1:

  • The UniFi router supports many dynamic DNS services. In my case, I'm using Cloudflare for DNS, so I minted an API key with the minimal privileges needed to edit a single DNS zone, and configured the UniFi to update an A record any time my public IP changes (fortunately, my ISP assigns a dynamic public IP without any CGNAT nonsense in the way). This means my devices can find my router's public IP by name (router.example.com) whenever they need it.
  • The router also let's you create WireGuard VPNs with a few clicks, and set up client configurations that you can use on your laptop (by importing a file into the open source WireGuard app, which you can get from the App Store) and your phone (by scanning a QR code).
  • Both WireGuard on iOS and macOS let's you configure a VPN as "On-Demand", which means that it can automatically connect to the VPN as soon as you leave the home network, and disconnect when you come back to it.

The combination of the dynamic DNS and the VPN mean your devices can always see the home network, no matter where they are, which means that Syncthing on the Raspberry Pi or the laptop, and Synctrain on the phone, can sync up at any time. The "On-Demand" activation means you don't even need to think about the connection.

Overall, I am pretty happy with this setup so far. There are lots more details that I could go into, but nothing that a quick search or LLM query can't rapidly resolve, so I won't bore you any further. I certainly didn't have to get very far into the weeds at all to make this work. Here's hoping it keeps working for a good few years now, so I don't end up having to write another "wrong horse" post too soon in the future.

  1. Only needed on the client devices that will be outside the home network (ie. the laptop and the phone, but notably not the Raspberry Pi).

Markdown fatigue

My relationship with Markdown has traversed the following arc: Contempt, Acceptance, Resignation

Contempt

In 2009, I thought "Markdown sucks". There was a burgeoning assortment of markup languages, having been driven by (and driving) the rising tide of the blogosphere, and Markdown seemed to be decidedly inferior. I knew about "Worse is better" back then, but I didn't have the acumen to realize I was seeing it in action.

Acceptance

By 2015, I recognized that Markdown had won, and in choosing Wikitext I had been "Betting on the wrong horse". I eventually moved all my content to Markdown, and found myself relishing its simplicity and ubiquity. GitHub continued the trend started in the blogosphere, inducting wave upon wave of developer into the Church of Markdown. Many of the rough edges and ambiguities were smoothed over by efforts such as CommonMark.

Resignation

In 2025, with the rise of agentic AI, I found myself wearying of Markdown.

First, I was annoyed and frustrated to see deterministic configuration and code replaced by non-deterministic natural language suggestions (in Markdown, of course). Skill files started to pile up in repos like so much cruft, only to be deleted as we were forced to admit that the agents were often better off without them.

But worse than that, has been the rising flood of AI-generated Markdown text written — purportedly — for human consumption. As it stands right now, there is something difficult to stomach about LLM-generated text. Many of us are developing an "allergy" to it. And now it's everywhere: in commit messages, PR descriptions, project READMEs, wiki pages, and so on. For the unwary, the near constant exposure to this homogenous slop may slowly infect them: the human, imitating the machine, which was trained to imitate the human.

The LLM's literal raison d'etre is to generate text, tirelessly, one token after another, until the requester's API credits have run out. So, we now have wall-of-text PR descriptions densely peppered with Markdown backticks and other formatting, producing a tiring assault on the senses that no human developer would have the patience to construct by hand. I used to take pride in my detailed and well-formatted PR descriptions, but now every PR is a pantomime of a carefully crafted message: exhaustively formatted and spelled out by the practically unbounded patience of the next-token-predictor machinery.

My heart sinks every time I read one of these PRs. And when I write my own PR descriptions, I can't shake the feeling that any care I take in wrapping symbol names in backticks or inserting expository asides between em dashes is only going to risk miscuing my readers and leading them to think that I, too, might be a bot.

But, who am I kidding, anyway? The slop economy is training us all to barely skim or not even read these artifacts any more, so maybe it doesn't matter. Perhaps all this indescribably unpalatable Markdown will eventually be like the Great Pacific Garbage Patch: ugly, enormous, and drifting endlessly on distant digital currents where few will ever go to see it.

Signed, Yours truly, in Markdown.

Arq restore notes →

All blog posts