Skip to content

Slack

Type slack (with the trailing space) to list your Slack channels, group conversations and the people of your workspace, under a few shortcuts: unread messages and Actions, plus unread threads and activity when Slack has some. Actions holds message search, people search, status, presence and snooze. Words after the keyword filter the list. With no filter, unmuted unread channels, group conversations and direct-message people appear just after the shortcuts, newest first. The remaining conversations and people keep their usual usage ordering.

To mix Slack into the main list without typing its keyword, add it under general.main_view. An empty query shows your unread or recently opened channels and direct messages (muted and unused channels stay hidden until you type or focus Slack with Ctrl+Tab); after two characters, typing searches messages. You can also list specific sub-views directly: slack.unread, slack.threads (or slack.unread_threads), slack.activity, slack.actions, slack.directs (or slack.dms), and slack.channels. Sub-views filter their loaded rows as you type instead of searching messages. Slack still needs to be enabled and configured with a token command as described below.

general:
main_view:
- slack
- slack.threads
- slack.directs
KeyAction
EnterOpen the conversation, person or message in the Slack app or the browser (open_in)
Ctrl+EnterMark an unread conversation, thread or activity item read without leaving Raffi
Ctrl+RRefresh the current view and preview
F5With raffi --cache-daemon running, have the service refresh the current Home, Unread, Threads or Activity view and reload the preview. The footer then shows F5 instead of Ctrl+R
Ctrl+TabSwitch between home, unread, threads, activity, people and actions (Shift goes back)
Ctrl+PShow the preview pane

The footer shows the current view. More on Ctrl+Tab.

Opening a person opens your direct conversation with them, or their profile when you have none. Opening an unread conversation from the home list also marks it read. Clicking a message or thread in the preview pane jumps straight to that message or thread. Raffi opens links in the Slack desktop app by default (slack:// links); set open_in: browser to open app.slack.com instead.

Compositors such as Hyprland don’t let Slack bring its own window to the front, so on Hyprland, niri and sway raffi focuses the Slack window itself after opening the link. If Slack isn’t running yet, raffi waits a few seconds for its window.

Raffi reads the token from token_command the first time the Slack list asks Slack for something in a run, so the token can live in a password manager. Two kinds of token work.

This is the token Slack supports for this. Some workspaces only let admins install apps, or ask an admin to approve them; if you cannot, use a browser session token instead.

  1. Open api.slack.com/apps, choose Create New App, then From an app manifest, and pick your workspace.

  2. Paste this manifest:

    display_information:
    name: Raffi
    oauth_config:
    scopes:
    user:
    - channels:history
    - channels:read
    - channels:write
    - dnd:read
    - dnd:write
    - groups:history
    - groups:read
    - groups:write
    - im:history
    - im:read
    - im:write
    - mpim:history
    - mpim:read
    - mpim:write
    - search:read
    - team:read
    - users.profile:read
    - users.profile:write
    - users:read
    - users:write
    settings:
    org_deploy_enabled: false
    socket_mode_enabled: false
    token_rotation_enabled: false
  3. Install the app to the workspace, then copy the User OAuth Token (xoxp-...) from OAuth & Permissions, and store it:

    Terminal window
    pass insert slack/token

Without an app, Raffi can use the session of a browser where you are logged in to Slack: an xoxc- token plus the d cookie that goes with it.

  1. Open your workspace at https://app.slack.com and open the browser developer tools.

  2. In the console, print the token of the open workspace:

    JSON.parse(localStorage.localConfig_v2).teams[location.pathname.split('/')[2]].token
  3. In the storage tab (Application in Chrome, Storage in Firefox), copy the value of the d cookie of https://app.slack.com. It starts with xoxd-. Paste it as it is, still URL encoded.

  4. Store both, for instance with pass insert slack/token and pass insert slack/cookie, and set cookie_command.

addons.slack.enabled boolean (default: false)

Turn the Slack list on. It stays off until you set this and a token_command.

addons.slack.trigger string (default: slack)

Keyword that opens the Slack list. Type it followed by a space. A script filter, text snippet source or web search with the same keyword takes precedence.

addons.slack.token_command string (required)

Shell command printing the Slack token on its first line: a user token (xoxp-) from your own Slack app, or the session token (xoxc-) of a logged-in browser. See Getting a token. It runs the first time the Slack list asks Slack for something in a run.

addons.slack.cookie_command string

Shell command printing the value of the browser’s d cookie. Required with a session (xoxc-) token, ignored with a user token.

addons.slack.warm_interval_minutes integer (default: cache_minutes when above 0)

How often raffi --cache-daemon refreshes the Slack directory, Home, Unread, Threads and Activity views while Raffi is closed. It also re-fetches the ten most recently viewed cached previews once they are stale. Leave it unset to follow cache_minutes.

addons.slack.open_in desktop | browser (default: desktop)

Where Enter opens conversations and messages: the Slack desktop app (slack:// links) or app.slack.com.

addons.slack.message_order newest_first | oldest_first (default: newest_first)

Order of the messages in the previews: the newest on top, or the oldest on top as in Slack. Thread previews always keep the first message of the thread on top, with the replies below it in this order.

addons.slack.unread_conversations list of strings (default: [])

Conversations checked by slack unread when Slack does not say which conversations have unread messages, as with user tokens: #channel, @handle for the direct conversation, or a conversation id. At most 30. See Unread messages.

addons.slack.cache_minutes integer (default: 60)

How long the cached conversations, people, muted conversations and search results count as fresh before Raffi asks Slack again. 0 asks every time. The last home rows, unread conversations and previews show right away whatever this is set to, and are replaced when Slack answers. See Caching and privacy.

addons.slack.close_on_action boolean (default: true)

Close Raffi after opening a conversation, person or message. Set it to false to stay open instead. When unset, general.close_on_action applies. Status, presence, snooze and mark-read actions keep Raffi open unless this is set to true.

addons:
slack:
enabled: true
token_command: "pass show slack/token"
cookie_command: "pass show slack/cookie" # session tokens only
open_in: browser # or desktop
message_order: oldest_first # or newest_first
unread_conversations: ["#ops", "@alice"]
cache_minutes: 30
close_on_action: false

slack actions, or the Actions row on the home list, lists Search messages, Find people and the rows that change your status, presence and snooze. The Actions row shows their current state. The home list keeps them out of the way, but typing a word such as slack snooze or slack away brings the matching ones up there too. Set status fills in slack status ; type the status after it:

slack status Lunch :pizza: 1h
slack status In a meeting 30m
slack status Away :palm_tree: today

The first :emoji: becomes the status emoji. A duration at the end (30m, 2h, 1h30m, 1d) or today clears the status after that time or at midnight; a bare number such as room 42 stays in the text. Clear status removes it.

Snooze rows pause notifications for 30 minutes, 1 hour, 2 hours or until 9:00 tomorrow, and slack snooze 45m for any other duration. Resume notifications ends the snooze. Raffi stays open after these actions and updates the rows, unless close_on_action is set to true.

slack search <words> searches your messages once you stop typing. The words use Slack’s search syntax, so in:#ops from:@alice deploy works. Replies show a Thread pill. Enter opens the message in its conversation.

slack people <name> finds people by name once you stop typing, the ones you have a conversation with first. Enter opens your direct conversation with them, or their profile.

People show their full name followed by their login in parentheses, such as Alice Adams (alice). If no full name is available, Raffi uses their display name or login.

Slack people showing full names and logins

Bots and apps show up too, after the people, with a Bot badge. The home list only shows the bots you already have a direct conversation with, such as Slackbot or a Jira bot. Enter opens that conversation in Slack.

An Enterprise Grid organization can have tens of thousands of people, so the list holds your channels, your conversations and the people you talk to. Use slack people <name> to find anyone else in the organization. That needs a browser session token. With a user token it only finds the people of your conversations, and Slack may refuse to list the conversations of the organization at all.

slack unread lists the conversations with unread messages, newest first, with your mentions there or the number of unread messages. Enter opens the conversation and marks it read; Ctrl+Enter marks it read without leaving Raffi.

Muted conversations come after the others, drawn in the theme’s muted colour with a Muted badge, and only fill the list when fewer than 30 other conversations have unread messages. Typing a filter ranks them by match like any other row.

With a browser session token Slack says which conversations have unread messages. With a user token it does not, so list the conversations to check, up to 30:

addons:
slack:
unread_conversations: ["#ops", "#releases", "@alice"]

slack threads lists the threads you follow that have unread replies, newest first. Each row shows the first line of the thread, its channel, who started it and how many replies you have not read. Enter opens the thread and marks it read; Ctrl+Enter marks it read without leaving Raffi.

slack activity lists the unread items of Slack’s Activity tab: mentions, reactions to your messages, new replies in your threads, and new messages in direct conversations and bot conversations. Enter opens the message; opening it in Slack clears it from the list. Ctrl+Enter marks the conversation or thread read up to that message without leaving Raffi. Reaction rows have no Ctrl+Enter.

Both lists need a browser session token. Slack refuses them for a user token, and Raffi says so in the list.

With the preview pane open (Ctrl+P), the selected row shows:

RowPreview
Channel or groupThe latest messages
PersonTheir avatar and your latest direct messages
Search resultThe messages around it, or its thread up to it
UnreadThe unread messages
ThreadThe thread
ActivityThe thread of the message, or the messages around it

Messages are listed newest first, under a divider for each day. Threads keep their first message on top. Set message_order: oldest_first to read them the other way.

Previews load after a short pause on a row. Errors, such as a missing scope, show in the pane.

People and direct messages show the person’s avatar, and channels show the workspace icon, since Slack has no picture per channel. Group conversations keep the generic icon. Pictures are downloaded in the background for the rows in view, up to 30 at a time, and kept on disk. The workspace icon needs the team:read scope and is asked again once a week; without it, channels keep the generic icon.

Raffi keeps what Slack last answered in ~/.cache/raffi/slack/ and shows it at once, then replaces it when Slack answers again:

  • directory.json: conversations and people, refreshed in the background once older than cache_minutes (an hour by default), or right away with Ctrl+R or the Reload conversations and people row.
  • live.json and unread.json: your status, presence and snooze, and the conversations with unread messages, asked again every time the list opens.
  • threads.json and activity.json: your unread threads and activity, asked again every time you open those lists.
  • muted.json: your muted conversations, asked again once older than cache_minutes.
  • previews/: the text of the last 500 previews, so a preview you saw before shows without waiting while Slack is asked for the current one.
  • avatars/: profile pictures and the workspace icon.

Searches are kept in memory for cache_minutes while Raffi runs, so typing back to an earlier query shows its results without asking again. Set cache_minutes: 0 to always ask Slack. Cached data is dropped after a day, or after cache_minutes if that is longer. When a refresh fails, the last answer stays: an unread list Slack could not check shows the previous one with a warning on top. How often you open each conversation is kept in usage.cache.

Each cache belongs to the Slack account and workspace that fetched it. Until Slack answers, Raffi shows the cache of the account it last used. If token_command now prints another account’s token, Raffi drops that account’s directory, searches and previews as soon as Slack says so, and fetches the new account’s.

The cache files are readable by you only, but the previews hold message text. raffi --refresh-cache removes everything but the usage counts. Raffi never writes the token or the cookie to disk and keeps them in memory only while it runs.

To open the list from a key binding, pass the keyword as the initial query:

Terminal window
raffi -i "slack "