Tom MacWright

2025@macwright.com

Personal tools

Bob Ross painting

I used to make little applications just for myself. Sixteen years ago (oof) I wrote a habit tracking application, and a keylogger that let me keep track of when I was using a computer, and generate some pretty charts.

I've taken a long break from those kinds of things. I love my hobbies, but they've drifted toward the non-technical, and the idea of keeping a server online for a fun project is unappealing (which is something that I hope Val Town, where I work, fixes). Some folks maintain whole 'homelab' setups and run Kubernetes in their basement. Not me, at least for now.

But I have been tiptoeing back into some little custom tools that only I use, with a focus on just my own computing experience. Here's a quick tour.

Hammerspoon

Hammerspoon is an extremely powerful scripting tool for macOS that lets you write custom keyboard shortcuts, UIs, and more with the very friendly little language Lua. Right now my Hammerspoon configuration is very simple, but I think I'll use it for a lot more as time progresses. Here it is:

hs.hotkey.bind({"cmd", "shift"}, "return", function()
  local frontmost = hs.application.frontmostApplication()
  if frontmost:name() == "Ghostty" then
    frontmost:hide()
  else
    hs.application.launchOrFocus("Ghostty")
  end
end)

Not much! But I recently switched to Ghostty as my terminal, and I heavily relied on iTerm2's global show/hide shortcut. Ghostty doesn't have an equivalent, and Mikael Henriksson suggested a script like this in GitHub discussions, so I ran with it. Hammerspoon can do practically anything, so it'll probably be useful for other stuff too.

SwiftBar

I review a lot of PRs these days. I wanted an easy way to see how many were in my review queue and go to them quickly. So, this script runs with SwiftBar, which is a flexible way to put any script's output into your menu bar. It uses the GitHub CLI to list the issues, and jq to massage that output into a friendly list of issues, which I can click on to go directly to the issue on GitHub.

#!/bin/bash
# <xbar.title>GitHub PR Reviews</xbar.title>
# <xbar.version>v0.0</xbar.version>
# <xbar.author>Tom MacWright</xbar.author>
# <xbar.author.github>tmcw</xbar.author.github>
# <xbar.desc>Displays PRs that you need to review</xbar.desc>
# <xbar.image></xbar.image>
# <xbar.dependencies>Bash GNU AWK</xbar.dependencies>
# <xbar.abouturl></xbar.abouturl>

DATA=$(gh search prs --state=open -R val-town/val.town --review-requested=@me --json url,title,number,author)

echo "$(echo "$DATA" | jq 'length') PR"
echo '---'

echo "$DATA" | jq -c '.[]' | while IFS= read -r pr; do
  TITLE=$(echo "$pr" | jq -r '.title')
  AUTHOR=$(echo "$pr" | jq -r '.author.login')
  URL=$(echo "$pr" | jq -r '.url')
  echo "$TITLE ($AUTHOR) | href=$URL"
done

Tampermonkey

Tampermonkey is essentially a twist on Greasemonkey: both let you run your own JavaScript on anybody's webpage. Sidenote: Greasemonkey was created by Aaron Boodman, who went on to write Replicache, which I used in Placemark, and is now working on Zero, the successor to Replicache.

Anyway, I have a few fancy credit cards which have 'offers' which only work if you 'activate' them. This is an annoying dark pattern! And there's a solution to it - CardPointers - but I neither spend enough nor care enough about points hacking to justify the cost. Plus, I'd like to know what code is running on my bank website.

So, Tampermonkey to the rescue! I wrote userscripts for Chase, American Express, and Citi. You can check them out on this Gist but I strongly recommend to read through all the code because of the afore-mentioned risks around running untrusted code on your bank account's website!

Obsidian Freeform

This is a plugin for Obsidian, the notetaking tool that I use every day. Freeform is pretty cool, if I can say so myself (I wrote it), but could be much better. The development experience is lackluster because you can't preview output at the same time as writing code: you have to toggle between the two states. I'll fix that eventually, or perhaps Obsidian will add new API that makes it all work.

I use Freeform for a lot of private health & financial data, almost always with an Observable Plot visualization as an eventual output.

Mortgage discounts

For example, when I was switching banks and one of the considerations was mortgage discounts in case I ever buy a house (ha 😢), it was fun to chart out the % discounts versus the required AUM. It's been really nice to have this kind of visualization as 'just another document' in my notetaking app. Doesn't need another server, and Obsidian is pretty secure and private.