Making Messaging More Direct

October 13, 2020
Tower of Babel

I love workflow improvements that reduce the amount of distance between my intent and taking action. The time saved is sometimes minimal, but it still feels great.

One of these areas is messaging. I (like everybody) send lots of messages, but often there is a gap between “I need to tell Bob about this!” as I find the right messaging app (whether it is iMessage, Slack, Messenger, etc.), find Bob in the list of people, and then finally get to type out my message. This is exacerbated by each app having a unique set of shortcuts for finding and messaging a person.

After investigating a bunch of options1, I landed on “Key People” menu activated by a global hotkey which displays a list of people. Selecting a person in the list directly opens the right app and right thread for me to message so I can start typing my message immediately.

The resulting new workflow looks like this:

Messaging demo
The Tech Details

Many native messaging apps support deep linking. iMessage supports imessage://, Slack supports deep linking with slack://, and FB messenger supports the messenger:// scheme.

First, I made a list of all the people I want to message in people.json. The userId and service is used to construct the right deep link into the appropriate app, while imageFile is just a profile picture to make people a little easier to visually identify.

[
    {
        "text": "Wife",
        "userId": "415-555-55555",
        "service": "imessage",
        "imageFile": "/.hammerspoon/images/profile_pics/e.jpeg"
    },
    {
        "text": "Boss",
        "userId": "UAXXXXXXXX",
        "service": "slack",
        "imageFile": "/.hammerspoon/images/profile_pics/aw.jpeg"
    },
    {
        "text": "Friend",
        "userId": "someone@icloud.com",
        "service": "imessage",
        "imageFile": "/.hammerspoon/images/profile_pics/someone.jpeg"
    }
]

Then, bind the hotkey you want to use and construct the right deep link. For Slack, opening slack://user?team=XXXXXX&id=YYYYYYYY will open the native Slack app, to a direct message to the person specified by id. iMessage has a different format, but overall works similarly.

The code in Hammerspoon is straightforward. Read the people.json file to get all the people I message regularly, present the list of choices in a hs.chooser, and then construct and open the right URL once a choice is made.

-- in your init.lua
-- binding Hyper-D as my hotkey to bring up the menu
hyper:bind({}, 'd', nil, function() 
    local chooser = hs.chooser.new(function(choice)
      local service = "slack"
      if (choice.service ~= nil) then service = choice.service end
      if service == "slack" then
        local slackTeamId = "TXXXXXXXXX"
        local url = "slack://user?team=" .. slackTeamId .. "&id=" .. choice.userId
        hs.urlevent.openURL(url)
      elseif service == "imessage" then
        local url = "imessage://" .. choice.userId
        hs.urlevent.openURL(url)
      end
    end)
    local choices = hs.json.read("directMessaging.json")
    for _,person in pairs(choices) do
      person.image = hs.image.imageFromPath(os.getenv("HOME") .. person.imageFile)
    end

    chooser:placeholderText("Slack...")
    :searchSubText(true)
    :choices(choices)
    :show()
  end)

  1. There are some apps that will do “unified” inbox for messaging, and I considered building thin clients to Slack et. al. using their server APIs. The unified messaging apps tend to be substandard (even before considering privacy issues), and using the server APIs directly, while powerful, would have been a ton of work for relatively little gain, for my uses. At at the end of the day, I really just wanted to solve the problem of how I get from my intent to message someone to typing that message ASAP. ↩︎