Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

uji/slack-wait

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

slack-wait

A one-shot CLI that waits for new messages in a Slack channel or thread and prints them as NDJSON to stdout, then exits. Designed for agent loops where the caller—not the tool—owns state.

slack-wait --channel C01234ABCDE --since 1748000000.000000

How it works

slack-wait polls the Slack API (conversations.history or conversations.replies) until at least one message newer than --since appears. When messages arrive it prints every one of them—one raw Slack message object per line—and exits. It never stores state; the caller tracks position by saving the latest ts and passing it back as --since on the next invocation.

Installation

1. Install the CLI

With go install:

go install github.com/uji/slack-wait@latest

With Homebrew:

brew install uji/tap/slack-wait

Or download a prebuilt binary from the releases page.

2. Create a Slack App

  1. Go to https://api.slack.com/apps and click Create New AppFrom a manifest
  2. Select your workspace
  3. Paste the following manifest:
{
  "display_information": {
    "name": "Slack Wait"
  },
  "oauth_config": {
    "redirect_urls": [
      "http://localhost:49490/callback",
      "http://localhost:49491/callback",
      "http://localhost:49492/callback",
      "http://localhost:49493/callback",
      "http://localhost:49494/callback",
      "http://localhost:49495/callback",
      "http://localhost:49496/callback",
      "http://localhost:49497/callback",
      "http://localhost:49498/callback",
      "http://localhost:49499/callback"
    ],
    "scopes": {
      "user": [
        "channels:history",
        "groups:history",
        "im:history",
        "mpim:history"
      ]
    },
    "pkce_enabled": true
  },
  "settings": {
    "org_deploy_enabled": false,
    "socket_mode_enabled": false,
    "token_rotation_enabled": true,
    "is_mcp_enabled": false
  }
}
  1. Click Create and then Install to Workspace
  2. On the Basic Information page, copy the Client ID

3. Log in

slack-wait login --client-id <YOUR_CLIENT_ID>

A browser window opens to the Slack authorization page. After you click Allow, the Client ID is saved to ~/.config/slack-wait/config.json and the credentials are stored in the OS keyring (macOS Keychain, Linux SecretService, Windows Credential Manager).

When token rotation is enabled, only the long-lived refresh token is stored in the keyring; the short-lived access token is kept in process memory and is recreated from the refresh token each run (see Design notes).

On subsequent runs, --client-id can be omitted:

slack-wait login

Usage

Wait for channel messages

slack-wait --channel C01234ABCDE --since 1748000000.000000

Wait for thread replies

slack-wait --channel C01234ABCDE \
           --since  1748000001.000000 \
           --thread 1748000000.000000

Flags

Flag Default Description
--channel (required) Slack channel ID (C…)
--since (required) Slack timestamp; only messages strictly newer than this are returned
--thread Thread timestamp (ts of the parent); switches to conversations.replies
--interval 5s How often to poll
--timeout 5m Give up and exit 124 after this duration

Output format

Each message is printed as a single JSON object (raw Slack message payload) followed by a newline—standard NDJSON. Messages are ordered oldest-first.

{"type":"message","ts":"1748000001.000100","user":"U04ABC","text":"hello"}
{"type":"message","ts":"1748000002.000200","user":"U04ABC","text":"world","thread_ts":"1748000001.000100"}

Fields depend on the Slack message type; slack-wait passes them through without modification. Refer to the Slack message object reference for the full schema.

Authentication

slack-wait uses PKCE OAuth 2.0 (RFC 7636) with no client_secret.

Logout

slack-wait logout

Removes the stored token.

Scopes requested

Scope Purpose
channels:history Public channels
groups:history Private channels
im:history Direct messages
mpim:history Group direct messages

These are user token scopes (xoxp-). No bot scopes are required.

Design notes

Stateless by design. slack-wait does not record what it has seen. The caller is responsible for saving and advancing --since. This makes it trivial to use from shell scripts, agents, or any orchestration layer without worrying about hidden state files or deduplication bugs.

Polling, not WebSocket. Socket Mode requires a bot token and a different auth flow. PKCE user tokens cannot drive Socket Mode, and the polling approach works well for the conversations.history Tier-3 rate limit (~50 req/min).

Unix-composable. The output is plain NDJSON on stdout; the exit code signals outcome. Filter, transform, and pipe as needed:

# Extract only the text of new messages
slack-wait --channel C… --since $ts | jq -r '.text'

# Collect messages into a JSON array
slack-wait --channel C… --since $ts | jq -s '.'

Access tokens stay in memory. With token rotation enabled, the access token is never persisted: only the rotating refresh token is stored in the OS keyring. During a long wait, the access token is refreshed transparently before it expires, so even an open-ended wait (--timeout 0) keeps working past the access token's lifetime without re-running login. (Non-rotating apps have no refresh token, so their long-lived access token is the only credential and is stored in the keyring.)

Future: MCP interface. The tool is designed so that a thin MCP wrapper can expose slack-wait as a tool callable by MCP clients without changing the core polling logic.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.