feat: add watch command for Socket Mode event streaming - #8
Merged
Merged
Conversation
Connect via Slack Socket Mode (WebSocket) and stream events as JSONL to stdout. Supports filtering by event type and channel. - slackline watch: streams messages, mentions, DMs, reactions - --events: filter by type (message,mention,reaction,dm,channel,file,member,status,all) - --channels: filter to specific channel IDs - --raw: output raw slack-morphism event JSON - token create --watch: guided Socket Mode app setup with manifest - Lazy name cache for user/channel enrichment via API lookups
- Fix with_token ignoring SLACK_APP_TOKEN env var - Add conflicts_with between --write and --watch flags - Fix subtype formatting using serde instead of Debug - Add graceful shutdown via tokio::select + ctrl_c - Resolve channel names for reaction events - Reduce boilerplate with Default derive on WatchEvent - Extract resolve_config helper to deduplicate config init
…lags - Remove separate create_watch/manifest_watch code paths - token create is read-only by default, --write and --watch are independent and combinable - Remove app_mention event (requires bot-only scope, user mentions come as messages) - Remove Mention event filter variant - Remove "for AI agents" from descriptions
…solution - --channels and --exclude-channels accept names (#general, general) or IDs - Channel names resolved to IDs at startup via conversations.list - --exclude-subtypes filters out message subtypes (e.g. bot_message) - --channels and --exclude-channels are mutually exclusive
co42
marked this pull request as ready for review
March 4, 2026 09:00
…er output - watch defaults to only channels the user is a member of (users.conversations) - add --all-channels flag to opt into workspace-wide events - add Client::resolve_channel() shared across all commands (name, #name, or ID) - enrich message_changed events with text from nested message field - enrich reaction events with the reacted-to message text via API fetch - improve human-readable output: show ID, topic, purpose, email, tz - fix token manifest command --json consistency - remove section comment blocks from watch.rs
- B1: resolve_channel now includes private/mpim/im channel types - B3: extract event type/channel cheaply before API calls, skip non-matching events without hitting Slack API (saves rate limit on busy workspaces) - I1: deduplicate ReactionAdded/ReactionRemoved into normalize_reaction helper - I2: remove redundant file_shared match in event filter - I3: add batch resolve_channels for single-scan multi-name resolution - I4: reuse SlackHyperClient between channel resolution and socket mode - I5: document --all-channels + --exclude-channels combo in help text - R1: wrap immutable WatchState fields in Arc<[T]> to avoid per-event clones - B2: document unbounded NameCache as acceptable for CLI lifetime
- B1: handle 6 missing event types (channel_created/deleted/archive/ unarchive/rename, team_join) with name caching from payloads - B2: fix user name resolution priority to display_name > real_name > name - B3: add W prefix to looks_like_id for Enterprise Grid shared channels - B4: replace expect() with ? in push_events_handler - B5: use ChannelNotFound error, collect all missing names in batch resolve - I1: move subtype filter to pre-filter (before normalize_event API calls) - I2: use ChannelNotFound instead of Api error variant - I3: cache fetch_message_text results for reactions - I4: add debug output alongside display in socket error logging - I5: replace dead All match arm with unreachable!() - I6: return None for nameless IM channels instead of caching "#" - R1: extract normalize_channel_user_event helper for 5 event types - P1: users list uses scroller pagination - P2: users search uses scroller pagination - P3: add resolve_user method, wire into users info/presence commands
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
slackline watchcommand — connects via Slack Socket Mode (WebSocket) and streams events as JSONL to stdoutusers.conversationsand filters events to those channels only--all-channelsflag opts into workspace-wide events (Socket Mode delivers everything)--events,--channels/--exclude-channels(names or IDs),--exclude-subtypes,--rawmessage_changedevents with text from nested message fieldtoken createsimplified: composable--writeand--watchflags (read-only by default, can combine both)token create --watchincludes guided setup for the optional app-level token (xapp-) needed for Socket Modegeneral,#general) or IDs (C1RCG46LS) viaClient::resolve_channel()— resolves public, private, mpim, and im channelsusers infoandusers presenceaccept@name,name, orU...ID viaClient::resolve_user()Review fixes (second round)
Bugs fixed:
users infodisplay)Wprefix tolooks_like_idfor Enterprise Grid shared channelsexpect()with?in push_events_handler (no more panic)ChannelNotFounderror variant; batch resolve reports all missing namesImprovements:
fetch_message_textresults for reactions (avoids duplicate API calls)Allmatch arm withunreachable!()Nonefor nameless IM channels instead of caching"#"Refactoring:
normalize_channel_user_eventhelper shared by 5 event typesuser_display_namehelper for consistent name priorityFirst round review fixes
resolve_channels()resolves multiple names in a single paginated scanWatchStatefields wrapped inArc<[T]>to avoid per-event vec clonesSlackHyperClientresolve_channelnow includes private/mpim/im typesnormalize_reactionhelperUsage
Test plan
cargo build+cargo clippyclean (zero warnings)slackline watch --helpshows all flagsslackline token create --watchprints setup instructions--exclude-channels/--exclude-subtypesfiltering worksslackline users listin workspace with >100 users (verify pagination)slackline users info @nameresolves correctlyThis PR was created with assistance from Claude Code.