Under new management

Blue Angels, Seattle, WA

It’s hard to avoid going stale. A person, a business, a store, a band, a job, a friendship, a relationship. They can all go stale. They want to go stale. They naturally tend towards staleness if you don’t keep steering and pushing and lifting and refreshing.


stale - adjective
1: tasteless or unpalatable from age
stale bread
2: tedious from familiarity
a stale routine
3: impaired in legal force or effect by reason of being allowed to rest without timely use, action, or demand
a stale affidavit
a stale debt
4: impaired in vigor or effectiveness

Can you believe “stalely” is a word?

Staleness is one of those spiraling states that promote their own entrenchment. Once a thing starts going stale, it’s that less attractive to you, you’re less likely to touch it, eat it, deepen it, grow it, have fun with it. The less you do any of that, the more stale it goes. And so it goes.

Also known as being in a rut.

Fresh starts are so tempting. Drastic action feels so much easier doesn’t it? When you’re stale for so long you feel numb, and drastic action feels like something. Gradual repair is such a drag in comparison. Can you even tell anything is happening? It feels like nothing.

Fresh starts help you save face, kinda. I think they’re often about you saying to the world, to yourself, “hey, I’m aware of what has been happening. I take it seriously. Don’t you worry about whether I’m aware, I am. Here I’ll prove it to you.”

There’s no new redesign, no grand breaks with the past or promises about the future here. Frankly it’s just that I’ve thought of the expression “under new management” on an almost daily basis for weeks and I wanted to write something about it.

And since we’re here, I’ll tell you that I’m aware that ever since I put on my big boy pants and started my first full time job at $COMPANY in early 2017, my creative output has gone to shit. Writing, personal projects, photography, all those links on the chain are rusty as heck, sabbatical having come and gone. As you can see. But there are no new year’s resolutions or grand declarations here. Any action taken will be gradual, and in fact may not feel like much of anything.

One last something. Think of anything you’ve liked for a long time. Maybe it’s a shop that’s been a little bla, maybe what used to never miss the mark at the restaurant has been hit or miss lately. One day you show up and you see a sign: under new management. How do you feel? I’ll tell you how I felt when the exact same thing happened to my favorite restaurant in Seattle that had been slipping for a while: I did not feel good. I don’t think I’ve ever felt excited about new management.

You almost never want new management, you usually just want the old management to regroup and tighten shit up. I think if you’re excited about new management, you want a different thing altogether.

Shortcut: Dispatch Bulletin

Dispatch Bulletin notification

I’m late to the Shortcuts game.1 I’ve seen others build impressive shortcuts for years but for some reason it took me until late last year to start building some of my own. And really it was my loss, because Shortcuts have long stopped being just a gimmick. They are not a serious tool to mix point-and-click with code to build some serious workflows.

This post is about an iOS Shortcut that I use to publish short posts and photos to my Micro.blog site Bulletin. I call it ‘Dispatch Bulletin’.


Bulletin is built using Jekyll, meaning it’s a static website that needs to be generated each time I make a change, and the generated pages need to be hosted somewhere. Bulletin’s source code lives in a privare GitHub repo, and the site is hosted on Netlify.2

You tell Netlify to watch your site’s repo, and it will automatically build and serve your site whenever it sees a new commit in the branch of choice. It’s really cool.


The Shortcut relies on two third-party apps:

  • Scriptable. To run a script that identifies the local timezone and returns its TZ database name.3
  • Working Copy. Critical since that’s how the shortcut can add posts and photos to the site’s git repo.


Brief overview of how it all works. The shortcut…

  1. Receives text input.
  2. Detects the local timezone to use later in the post frontmatter.
  3. Prompts the user for file suffix. i.e., what to add after the date in the post filename.
  4. Pulls the latest updates to the repo in Working Copy.
  5. Asks the user if they want to attach a photo.
  6. If Yes, prompts the user to select the photo from Files.app and generated the body of a photo post. If No, generates a text only post.
  7. Writes the post and optional image to the repo in Working Copy.
  8. Commits changes and pushes to remote.
  9. Displays a notification that the bulletin was published.


Let’s get into it.

step explanation
Step 1: Receive text input Accept text input, save value in Bulletin variable. We’ll use that later.
Step 2: Format current date and time Get current date and time in ISO 8601 format. We’ll use that later.
Step 3: Run TZIdentifier Scriptable script Run TZIdentifier script. See below for the simple code. We’ll refer to its output later.
Step 4: Ask for file suffix Prompt for the file suffix and create a text variable of the full file path. Okay you get it, I won’t keep saying “we’ll use that later”.
Step 5: Pull latest commits Pull any new commits to the local repo in Working Copy.
Step 6: Ask if you want to attach a photo Ask if I want to attach a photo to the bulletin.
Step 7: If Yes Self explanatory.
Step 8: Browse for photo then save it and stage it. Browse Files.app for the photo, save the photo to the proper path in Working Copy and stage it for commit.
Step 9: Ask for alt text Ask for image alt text.
Step 10: Create body of photo post Create the body of the photo bulletin and save it to BulletinBody variable.
Step 11: If you don't want to wattach a photo If you don’t want to attach a photo…
Step 12: Create text-only bulletin Create text only bulletin and save it to BulletinBody variable, then end the if statement.
Step 13: Save post file to repo Save BulletinBody to a Markdown file in Working Copy and stage it for commit.
Step 14: Commit and sign Commit all staged files with a simple commit message and sign the commit with the key Working Copy already has.
Step 15: Push to remote Push changes to remote.
Step 16: Show a fancy notification at the end Show a fancy notification at the end.

At this point my work is done and Netlify takes the wheel. Once the shortcut is done pushing the commit, Netlify will detect the commit to the main branch, pull it, build it, then serve it.


Here’s the TZIdentifier script run in Scriptable:

const tz = Intl.DateTimeFormat().resolvedOptions().timeZone

function main() {


Final notes

I had a lot of fun building this. It holds the highest honor an automation can receive: I use it all the time. It’s the most convenient way to publish to a Jekyll site I’ve ever worked out and it’s how I publish 9/10 posts to Bulletin.

  1. A note on capitalization. “Shortcuts” is a noun but it’s also the name of the app itself. Classic Apple. My executive editorial decision is to capitalize ’Shortcuts’ and not ’shortcut’. ↩︎

  2. From what I can tell Netlify is one of the most common ways to host a Jekyll site online besides Github Pages. It’s a really pleasant experience to set up, and they have a free tier that will work for most hobbyists like me. I have nothing but good vibes for the company. ↩︎

  3. I need to run a script for this because I need the timezone database name for… uh… Jekyll reasons, and as far as I can tell there’s no other way to get that on iOS. ↩︎

Brief automations: Playing a random album from Plex

Another installment in my series on listening to music is forthcoming and it will mostly be a love letter disguised as a 1000+ word use guide for Plexamp. In the meantime, this is a slightly out of context taste.

My music library lives under the watchful eye of a Plex server. The server pulls down a lot of metadata that makes artist and album pages much more delightful to browse than iTunes/Music.app ever did. I then use Plexamp to listen to music both at and away from home. I really love this setup.

Besides the official Plex and Plexamp clients, there is an unofficial Python Plex library whose goal is to “match all capabilities of the official Plex Web Client”. I’ve been playing with it for a while, it is impressive, and this is the first of many uses I have in mind for it.

Play a random album the simple way

I keep all the albums I own as CDs in a Collection called ‘💿’.1 Sometimes I want to put on some music but I don’t have a specific album in mind and end up scrolling the collection aimlessly.

A common way to deal with this kind of choice paralysis is to let a random picker choose for you. This is very easily done using the Python library.

Here is a simple implementation.

import random
from plexapi.server import PlexServer

TOKEN = '<insert your own token here>'
plex = PlexServer(BASEURL, TOKEN)

owned = plex.library.section('Music').searchAlbums(collection='💿')


  • pip install plexapi
  • Know the local or remote IP address of your server.
  • Your X-Plex-Token for authentication. Here’s how to find it.
  • Know the name of the client that will play the album. This is cool because it doesn’t have to be on the same machine running the script! In my case I have a machine running Plexamp connected to my KEF speakers.


  • Import the random library and the PlexServer class.
  • Create an instance of your server with the correct url and token.
  • Get a list of the albums in the ‘💿’ collection.
  • Tell the client to play a random album from that collection.

So that’s amazing and simple. Here’s how you can make it amazing and a little fancy.

Playing a random album the glamorous way

A random choice from a large collection can be jarring. Too decisive, you know? One compromise you can make between that and choosing from the whole collection yourself is to get random to offer you two – or more – candidates to choose from.

The implementation is a bit involved but still pretty straightforward.

#! /usr/local/bin/python3

import random
import requests
import subprocess

from PIL import Image
from io import BytesIO
from plexapi.server import PlexServer
from rich.console import Console

CONSOLE = Console(color_system='truecolor')
TOKEN = '<insert your own token here>'

plex = PlexServer(BASEURL, TOKEN)
owned = plex.library.section('Music').searchAlbums(collection='💿')

albums = {
    album.title: album
    for album in random.sample(owned, 2)

albumart = [
    Image.open(BytesIO(requests.get(candidate.thumbUrl).content)).resize((500, 500), Image.LANCZOS)
    for candidate in albums.values()

merged = Image.new('RGBA', (1020, 500))
for ii, art in enumerate(albumart):
    padding = 0 if ii == 0 else 20
    merged.paste(art, (ii*500 + padding, 0))

subprocess.run(['/Applications/kitty.app/Contents/MacOS/kitty', 'icat', '/var/tmp/amp.png'])

CONSOLE.print('\nPick an album')
choices = ' '.join(['"'+albumtitle+'"' for albumtitle in albums.keys()])
choice = (
        f"/usr/local/bin/gum choose {choices} --cursor '' --selected.foreground='#7851a9'",


    f'\n  [italic]Now Playing: '
    f'[#9966cc]{albums[choice].title} ({albums[choice].year})[/#9966cc] '
    f'by [#47c1ff]{albums[choice].artist().title}'

Requirements: I wanted to make this aesthetically pleasing, so there are some splurgy requirements.


  • Same imports from the simple implementation. Then a few imports for image processing, reading the album art from the server, and pretty printing in the console.
  • Get a list of the albums in the ‘💿’ collection.
  • Get the titles for two random albums, then get the album art for those two albums.
  • Merge the album art into one image. I have to do this because as far as I can tell kitty won’t let me display two images next to each other in the terminal.
  • Tell kitty to display the merged image.
  • Use gum to ask the user which album to play.
  • Tell the client to play the chosen album.
  • Display a “Now Playing” status with the album title, release year, and artist.

Other notes:

  • The characters appearing as in the code are music glyphs in the PragmataPro font I use in kitty. You can see it in the video.
  • Resizing the album art to 500×500 is hardcoded across the script. You could set that as a variable to change later. Also some album art isn’t perfectly square and will look silly when resized to a square. I might deal with that later.
  • It’s more idiomatic to use tempfile to get a path to a temporary filename. You can read more about the tradeoffs here.
  • I wrote this to make it easy to accept the number of albums as an argument instead of that also being hardcoded in the script.
  • You could build this out to also ask the user which collection they want to pick from. I plan to do just that.

And that’s it. Kinda swanky.

  1. This also has music I bought from Bandcamp, Qobuz, Boomkat, etc. But it’s mostly CDs. ↩︎

Programming the Atreus Keyboard

Happy New Year.

Okay here’s a thing. About a year ago I bought a Keyboardio Atreus keyboard.1

I don’t remember what made me think that was a good idea, or how I even found out about it. I did it for my Mental Health? Some people buy a Rolex, others buy a keyboard. Let’s move on.

What’s all this then?

Keyboardio Atreus. Bright keycaps are Massdrop x MiTo XDA Canvas custom keycap set. Black keycaps came on the Atreus.

It’s a tiny little thing.

The Atreus has a learning curve, no question. Space is a key not a bar. Arrow keys, number keys, special characters, function keys, and media controls exist in Layers 1 and 2.2 This means you use Fun E / D / S / F for ↑, ↓, ←, and →. A numpad exists on the right side with its corners defined as Fun M for 1 and Fun O for 9. All special characters are accessed using Fun other keys. To access media controls, function keys, and other lesser used buttons like Page Up and Page Down keys, you need to activate Layer 2 by pressing Fun Esc then releasing them, which locks the keyboard in Layer 2 until you Esc out of it. So if you want to turn up the volume, you press Fun Esc and let go, press X for volume up, then press Esc to go back to the base layer.

It’s a lot, I know. I want to tell you it takes a week or two to get used to it, but the truth is it takes about 3-4 weeks for proficiency in typing prose and maybe double that for proficiency in writing code. That said, I love this thing so much that it activated the principle of “two is one and one is none” and I got myself a second board as a backup.


One of the big selling points of the Atreus is that it runs on open source firmware called Kaleidoscope.

Keyboard.io created a GUI interface around Kaleidoscope called Chrysalis which you can use to remap and modify some things on your keyboard without messing around with code, compilations, flashing, etc. The downside of this option is that Chrysalis doesn’t support all of Kaleidoscope’s features (yet–including the one that matters the most to me: Macros).

You might opt for modifying and building Kaleidoscope directly for any of the following reasons: You want to use a feature not exposed in Chrysalis. You want to define a complicated setup in code so you avoid forgetting what you implemented and how you did it, and so you can commit it to a dotfiles repo or something similar. Or maybe you just have a preference for code and live a terminal > GUI lifestyle.

If you’ve ever messed around with an Arduino board, it’s the same idea: you write a script encoding the behavior you want, compile it, then install it to the keyboard. In fact, Arduino software is required if you want to build and install Kaleidoscope yourself.

Quick note on why this matters: some programs will let you create macros or remap your keys. Keyboard Maestro is one example and it can do (probably?) everything Kaleidoscope can. The benefit of programming your keyboard’s firmware is that you can plug that keyboard into anything and have the same behavior come with it. Set it up once, have it everywhere. This is especially useful if you use external keyboard with an iPad like I do, where a utility like Keyboard Maestro cannot exist.


I’ll use the first macro I created in Kaleidoscope as an example.

On a Mac, the common keyboard shortcut to move to the tab to the left or right of the current one is Shift Command [ and Shift Command ] respectively.3 On a normal keyboard this chord is simple enough to type, but on an Atreus, it’s a 4-key contortion: Shift Command Fun Z for previous tab and Shift Command Fun X for next tab.

Here’s how you can modify the Atreus firmware to add a simpler macro – Fun H and Fun ; – that translates to the Mac keyboard shortcuts for switching tabs.

1) Start with the base firmware file.

2) Define the macros in macro_t constant. In this case I named them LEFT_TAB and RIGHT_TAB. This defines which keys are pressed when the macros are triggered.

const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
  if (keyToggledOn(event.state)) {
    switch (macro_id) {
    case MACRO_QWERTY:
      Macros.type(PSTR("Keyboardio Atreus - Kaleidoscope "));
    case LEFT_TAB:
      return MACRO(D(LeftShift), D(LeftGui), D(LeftBracket));
    case RIGHT_TAB:
      return MACRO(D(LeftShift), D(LeftGui), D(RightBracket));
  return MACRO_NONE;

3) Add the macros to the H and ; keys on the second layer (which is triggered by holding the FUN key). Look for M(LEFT_TAB) and M(RIGHT_TAB).

       Key_Exclamation ,Key_At           ,Key_UpArrow   ,Key_Dollar           ,Key_Percent
      ,Key_LeftParen   ,Key_LeftArrow    ,Key_DownArrow ,Key_RightArrow       ,Key_RightParen
      ,Key_LeftBracket ,Key_RightBracket ,Key_Hash      ,Key_LeftCurlyBracket ,Key_RightCurlyBracket ,Key_Caret
      ,TG(UPPER)       ,Key_Insert       ,Key_LeftGui   ,Key_LeftShift        ,Key_Delete         ,Key_LeftControl

                   ,Key_PageUp   ,Key_7 ,Key_8      ,Key_9 ,Key_Backspace
                   ,M(LEFT_TAB)  ,Key_4 ,Key_5      ,Key_6 ,M(RIGHT_TAB)
      ,Key_And     ,Key_Star     ,Key_1 ,Key_2      ,Key_3 ,Key_Plus
      ,Key_LeftAlt ,Key_Space    ,___   ,Key_Period ,Key_0 ,Key_Equals

4) Finally, add the macros to the enum declared towards the beginning of the file.

enum {

5) Follow the development guide I linked above to compile and flash this new firmware, and you’ve built your first Atreus macro

See also

  1. I’m glad you asked. Kailh BOX White switches. ↩︎

  2. What you see in the photo is Layer 0, the base layer. Because of course the layers are 0-indexed. ↩︎

  3. I just learned that Control Tab and Shift Control Tab also works. ↩︎

Listening to music: Last.fm

This is part 2 of a series on listening to music. Other parts:

  1. Beginnings
  2. Last.fm

My Last.fm account knows about every song I’ve listened to since 2008.

~6,500 artists, ~7,700 albums, ~170,000 tracks.

When I listened to the MP3 files I brought with me from high school, I made sure Last.fm was scrobbling. When I listened to the mix CDs my best friend made me, Last.fm listened too. When I tried Spotify for a few months, when I switched to Hype Machine, when I listen to the CDs I own or the albums I bought from Bandcamp, everything I’ve played in iTunes, on my iPods, on Music.app on iOS, on Marvis, during my short-lived Roon experiment, through Plexamp. It’s all there.

My life.

Last.fm remembers every day of the last fourteen years of my life.

Last.fm is an anomaly, a mutation of the internet, and a service that just celebrated its 20th birthday.

Now you could say so what, right? Myspace is still alive and its website still technically loads. Google is like, 100 years old or something. So what.

Sure. First of all Myspace launched in 2003, so it’s technically 19 years old. That’s right: Last.fm is older than Myspace! And Google is…well who gives a shit about Google. Do you feel anything when I say “Google”? No you don’t.

Also thing is, Myspace doesn’t exist the way Last.fm still exists. I don’t know what Myspace is today, it looks like it’s a social network for singers and actors? No one who uses it today sits and thinks about where it was and how it got to where it is now.

Last.fm had a lot of ups and downs. In its heyday it had a technical blog and a staff that posted photos of server rooms and office space, it had actual streaming radio that did intelligent things with music it knew you liked, they put random slogans at the bottom of site pages. It was scrappy and ambitious. They figured out how to create a plugin that automatically scrobbled what you listened to in iTunes, but that also figured out how to scrobble what you listened to on your iPod.1 As far as I know, that’s the only useful thing any third party app did with what happened on your iPod.

Everything was fine. No everything was great! Then came a redesign or two, the streaming died and got replaced with a hacky “we’ll just play YouTube videos and pretend you’re streaming” setup, Groups which was actually fun died, CBS bought the company (that was the moment I thought it was all over), and then a long silence during which it felt like every other month a piece of the site would disappear. They used to let you export your data, that went away. https://status.last.fm which was a proper service status page now redirects to a Twitter account. It all felt a little grim. Okay a lot grim.

But. Throughout all of this, the ups, downs, happy days and sad, not being owned by a large media conglomerate and being owned by a large media conglomerate, the site never stopped accepting scrobbles.2

And in a world that has turned its back on, then mooned the interconnectivity of Web 2.0, in a world where APIs get turned off and rarely on, Last.fm still commands death-defying loyalty with music listeners who demand scrobbling of old and new music apps and streaming services.

There are signs of life. The listening reports feature gets improvements every once in a while. Library search is here.3 Their Twitter account is fairly active. The site isn’t…you know, dead. Every time I update that plot I wonder how many more years of data I’ll be able to add to it. Who knows. It’s the internet, and nothing is forever, even if some things feel like they are.

Appendix: Listenbrainz

I mentioned in passing that Last.fm used to let you export your data including all scrobbles and loved tracks, and that this disappeared at some point. So how did I make the plot at the top of this post?

Listenbrainz is part of the MetaBrainz Foundation.4 Its goal is to be a “public [and] permanent” store of your listen history, to make this data available for download, and share this in some technically knowable and supported fashion.

Here is how I think of Listenbrainz: Yes we all can hardly believe that Last.fm still stands, but the clock is ticking. You know that right? Don’t you want a backup plan? Don’t you want a way to get your money outta that bank before it craters? That’s Listenbrainz.

The good. Listenbrainz will let you import all your listens from Last.fm, and will let you download it in a fairly structured payload. That’s how I made the plot at the top.

The bad. This is a manual process. You have to remember to come back and do it regularly. Why? Because it seems to basically load and scrape each page of listens from your Last.fm profile. Why? Probably because Last.fm doesn’t want them doing this, and probably has no API for it. Lord knows the APIs they do have barely work. The other reason this is bad is that it might stop working.

Listenbrainz has an API. Technically music players can start letting you authenticate with Listenbrainz in addition to or instead of Last.fm and send your listens there too. As far as I know, as of today no Mac/iOS music players do this.

  1. It wasn’t black magic, but it was still technically impressive. I don’t know if they ever officially said how that worked, but I’m fairly sure it relied on play counts. Whenever you listened to music on your iPod (or iPhone) the playcounts were incremented, and when you synced your device to your computer the playcounts in your iTunes library got updated too. Last.fm would use a track’s changed playcount and last played timestamp to decide what you listened to since the last sync. One thing I can’t remember is whether the plugin could figure out if you played tracks A -> B -> A. A’s playcount would be incremented twice, and its last played timestamp would show the latest play, so as far as the plugin could guess, what you did was B -> A -> A. So if the plugin could figure out that you played A -> B -> A, the solution must be more sophisticated than I thought. ↩︎

  2. There are frequent downtimes, but the core service seems well-designed enough that it always catches up with what I played once it’s back online. ↩︎

  3. The blog post before that one is from Feb 2019. The one before that was Sep 2017. So it’s still a little sad. ↩︎

  4. The one Metaverse that actually exists. ↩︎

Listening to music: Beginnings

This is part 1 of a series on listening to music. Other parts:

  1. Beginnings
  2. Last.fm

First, there were cassette tapes.1

I grew up in a small Arab town and didn’t get dial-up internet until I started high school. Before then, I had to walk to the record store in the nearby mall and use what I could save from my allowance to buy cassette tapes, meaning I could afford a handful every year.

At the time, the United Arab Emirates censored cassette tapes. As in, any parts of the song containing lyrics you imagine would be objectionable to the politics and morality of a thirty year old Arabian Gulf government were cut, and not in a subtle way.2

Do you know what it’s like for a middle schooler to pay what felt like a thousand dollars for a copy of the Marshall Mathers EP only to discover that all obscenities and obscene-adjacent expressions were censored? It was practically an instrumental version of the record.

Still, I played my tapes.

At some point I owned a Panasonic portable CD player, although I can’t remember if I had it before or after my first MP3 player. I also can’t remember which model it was and so I can’t find an image of it online. It was black, and I used to carry it in a custom-made black fabric case with a big red pentagram sewn on it. Thanks mom.

I had a few CD albums but I mostly used a CD-RW that I burned and re-burned multiple times a week, treating the player as a heavier and less convenient MP3 player.

This is also when I started ripping CDs and building a modest local music library in Windows Media Player (later migrating to Real One Player).

Windows Media Player as I remember it from the Windows XP days courtesy of PCMag
Real One Player from the same era courtesy of dailymotion.com

The first digital media player I ever owned was a no-name USB thumbdrive MP3 player with a janky screen. I am shocked to find that you can still exchange currency for one in this year 2022. Today you can have one for the price of an Americano, but back then it was the most precious thing I owned.

Noname MP3 player courtest of aliexpress.us

Looking at the image, I can remember how it had that cheap soft plastic smell, and how I played a lot of Three Doors Down on it.

The next evolution didn’t come until 2007, when I moved to Canada, started university, and got my first computer.3

I couldn’t give you a strong reason why, but I asked for a Mac even though that was a risk at the time. Macs were still kinda new, I had never used one, and I couldn’t be sure that I could do everything I needed to do for university on it. But, they seemed cool and the only teacher I really liked in high school had one, so I YOLO’d it and assumed it would all work out.4

Apple’s educational discounts were better back then. With my white plastic MacBook, I got a free iPod Nano 2nd generation, and a free printer (after a mail-in rebate).5

I still have my first MacBook, sans battery.
iPod Nano 2nd Gen courtesy of ifixit.com

It took me a while to get used to the iTunes/iPod model of a music library. Having spent years dealing with the files themselves (downloading the, copying them, burning them, moving them around), I couldn’t figure out why iTunes seemed to be hiding my files from me.

In the end, iTunes taught me the value of playlists and accurate MP3 tags. Despite the rocky start, I loved iTunes, and would end up moving and growing the same iTunes library from 2007 until today (although it’s been largely ceremonial since November 2020). A lot of people hated iTunes, but iTunes never let me down. Not until they started calling it Music.app.

Over the next few years I started earning some disposable income, became a regular at the local Beat Goes On, started buying a lot of CDs, and also found my way to a private site mourned by many and replaced by none. Those were heady days and the depth and breadth of my music library exploded. This was the golden era of music discovery in my life.

In 2008 friends at the campus newspaper where I volunteered (and loitered at for the majority of my undergraduate life) told me about Last.fm and I created the account I still use to this day.

In 2009, I upgraded from the iPod Nano to a refurbished 80GB black iPod Classic. It was my first, not to be the last.

iPod Classic 80GB in black, courtest of bhphotovideo.com

I loved that iPod. It was heavy, felt good in the hand, was big enough to carry my entire music library (for a while), and did one thing: played my music.

The iPod Classic times were the best of times.

After the iPod Classic came the iPod Touch, and after that came the iPhone.6 This period is marked with a lot of noise. Music no longer had a sanctum and got mixed up with everything else. With the iPod music was everything, but after that it became just an app. It became something that happened while other things happened on the same device.

I have more to say about this phase and the role iTunes played in everything, and that will come in a later post.

Next, a note about Last.fm.

  1. Which are making a comeback. You can buy tapes on Bandcamp now! A coffee shop near my place has a shelf with cassette tapes for their stereo. ↩︎

  2. I always wondered whether the music labels created special copies of these tapes for these censorial markets, or if the distributors in the UAE performed the mutilations themselves on import. Who knows, maybe the labels didn’t even know those copies existed. ↩︎

  3. Until then I used a family Pentium desktop that lived in the living room. ↩︎

  4. A highly underrated tactic. ↩︎

  5. I think I got the silver iPod. I wish I still had it. ↩︎

  6. In the mix was an iPod Shuffle 2nd gen, but it never grabbed me as much as it did other people. ↩︎


I’m out of practice when it comes to writing blog posts; writing here feels like counting backwards from 1000 while skipping all numbers divisible by six or seven: unnatural. I’m torn on whether to take this seriously and if so how seriously to take it. But I’m also out of practice because I’ve been somewhere else. In life, I’ve been working on a lot of things that aren’t technical, and in writing and communicating, I’ve been writing on my Bulletin which cross posts to my Micro.blog account.

Micro.blog is like a town square of people who want to be friends.1 People create accounts, they mostly use their names and faces, they write brief notes or post a lovely photo or two from their day, and they talk to each other. It’s wholesome and friendly, and its design, rules, and structures are very thoughtfully designed. Also it’s the most diverse crowd of internetians I’ve ever hung out with.

There are no “Likes”, you can follow accounts but no one can see a list of their own followers, there are no follower counts at all, there is no hashtag support, and there’s a Discovery stream that’s manually curated. You can search for certain types of posts using emoji, and you can discover or meet new people by following conversations the people you are already following are having with others.

Anyway, you can have Micro.blog host your blog for you, and I did that for a while. I couldn’t find a theme that I liked, and I couldn’t figure out how to modify any of the existing ones to my satisfaction, but that wasn’t a problem because after I reserved my username (@sherif) when I backed the project on Kickstarter back in 2017, I didn’t do much with it for five years. A few months ago I realized that Micro.blog was thriving, and that it was the kind of place with the kind of people I was looking for.

I love an opportunity to design something whimsical for the internet, and Bulletin is exactly that. I like thinking of my posts as dispatches from a desk or a location, and I tried to design the site with a modern telegram or chain of correspondence motif. I also had to solve some interesting technical problems with the Jekyll site, like adding a filter to handle generating the correct local and UTC timestamps for each post based on the location it was posted from. I also designed it with a focus on how it displays photos, because I think with Bulletin I finally, finally, have a place where I can post occasional photography without overthinking it.

I’m very happy with how Bulletin turned out, but the bigger point is Micro.blog is a pretty chill place to be, and you should come over and enjoy some of the best vibes currently available on the internet.

  1. For a description that’s a bit more helpful, see here↩︎


Sunset flight - sabbatical

I started working at $FAANG_COMPANY (henceforth referred to as $COMPANY) on Monday January 16, 2017, and stopped working at $COMPANY on Friday June 24, 2022. I was paid (well) to further the business interests of $COMPANY for one thousand, nine hundred, and eighty-five days, excluding most weekends. Thus was my first full time job.

I would tell you what my job title was, but it doesn’t really matter, and anyway I worry it might mislead you about what I actually did because job titles are weird. I ran and analyzed data from experiments, did some data engineering, trained a regression model or two, trained a deep learning model or two, and built a lot of automated inference and decision-making workflows that combined model outputs and business rules. Yes I did “machine learning” “in production”. I was halfway between a scientist and a developer and I liked it.

It’s important to acknowledge that there’s a lot of privilege in being able to quit a job not because you’re going to a different one, but because you’re just not happy doing it anymore.

  • Financial. I have enough money saved to support myself through a period of unemployment without getting anxious about meeting my basic needs. Multiple unlikely catastrophes would have to happen for me to be in a bad place.
  • Legal. Getting my work visa to move to the US and start my job at $COMPANY was not a smooth process, but it got done. Getting my permanent residency was far more turbulent, but despite the odds it also got done. I’m lucky to have a more stable life in this country without having to carry the work visa holder’s constant anxiety about losing or leaving a job. For those unfamiliar with that anxiety, it sucks and it warps the way you think.1
  • Social/mental. Leaving a job is a scary thing to do. I’ve had the support of some who reassured me that I wasn’t crazy, others who reassured me that I would be able to find gainful employment again, and even others who quit jobs before me and did not immediately die or combust into flames.

You do a job for a mix of intrinsic and extrinsic motivations.

Intrinsic motivations include:

  • You enjoy the ideas you’re working on, the specific problems you’re trying to solve, the product you’re trying to make better.
  • You enjoy the technical aspects of the work.
  • You value the impact of the work.

Extrinsic motivations include:

  • Compensation (salary + benefits + retirement savings + other).
  • Job stability.
  • You don’t want to leave a great manager.
  • You don’t want to leave a great team.

Different people have different intrinsic/extrinsic portfolios. Some have an intrinsic heavy ~90%/~10% mix (I’ll stereotype here, but: artists? people who work in used bookstores?), some have a ~50%/~50% mix (tough to find stereotypical examples for this), and some have an extrinsic heavy ~10%/~90% mix (people in finance, a lot of people in tech, and me at $COMPANY towards the end).

That’s the main reason I had to leave; I was running out of intrinsic motivation. For a while I was able to lean on the enjoyment of the technical aspects of the work, but they were tangential at best to my job description. I was stealing fulfillment from a role that wasn’t designed to give it to me, and my team was starting to move in the opposite direction. Not good.

I already lacked a good answer to the question “did my work delight anyone or make anyone’s life significantly better?”2 Losing the enjoyment of the craft itself made my decision easier. Going forward, I cannot not have a good answer to that question no matter what other conditions are met.

So I am taking a sabbatical. I don’t know how long it will last, and I don’t have a solid plan for it yet.

I want to travel (check), write more (check), read more (check), spend more time with people whose company I love (check, and in progress), return to and start personal projects so I can remember what it’s like to code for fun (not yet started), and explore the widest possible range of ideas for what I’m going to do for money next (not yet started).

Can I find a role defined around the technical work I enjoy? Can I walk through the valley of the shadow of death (interviewing in tech) again? Will I even go back to tech? Will I move? Will I work remotely?

All open questions.

  1. For an excellent writeup on what the US work visa and immigration process looks like, do read 18 Years A Transient – My Journey Through the American Immigration System as a Computer Engineer – Software the Hard way↩︎

  2. Thankfully I’m pretty sure my work didn’t make anyone’s life worse. A fate not trivial to avoid in tech. ↩︎