slack-chat
mikesmullin/slackcommunicate via slack-chat channels and direct messages with users
SKILL.md
name: slack-chat description: communicate via slack-chat channels and direct messages with users
Slack Chat
Overview
The slack command is installed globally (located in the $PATH).
It is a dual-mode Slack client with offline-first architecture:
- Online Mode: Pull messages from Slack to local Markdown storage, resolve IDs
- Offline Mode: Query and manage stored messages without Slack connectivity
The system is designed for AI agents to integrate Slack processing into workflows, supporting:
- Batch message ingestion with deduplication
- Message marking (read/unread) with offline metadata
- ID resolution caching (users, channels)
- Integration with other tools and scripts
Uses browser-use (via Chrome DevTools Protocol) for Slack API access.
Core Concepts
Message IDs
- Slack ID:
channel_id:timestamporchannel_id:timestamp@thread_tsfor threads - SHA1 Hash: 40-character hex hash of Slack ID, used as filename
- Short ID: First 6 characters of hash (e.g.,
b89c7a), used for Git-like partial matching
Example:
Slack ID: C01TECH01:1767815267.099869
SHA1 Hash: b89c7a14755df6dca57ece8e14f38652e727cbd8
Short ID: b89c7a
# Thread reply:
Slack ID: G01GROUP01:[email protected]
SHA1 Hash: 4cea849d8625c020f8716b8024e256942d6b440b
Short ID: 4cea84
Storage Format
Each message is stored as a Markdown file in storage/ with YAML front matter containing metadata, and rendered content below:
---
channel_id: C01TECH01
timestamp: '1767815267.099869'
thread_ts: null
user_id: WNARLG5HB
type: message
text: Thank you all!
permalink: https://bigco-producta.slack.com/archives/C01TECH01/p1767815267099869
reactions: []
attachments: []
files: []
_stored_id: b89c7a14755df6dca57ece8e14f38652e727cbd8
_stored_at: '2026-01-07T20:06:28.667864+00:00'
offline:
read: false
---
# Message in C01TECH01
**From:** WNARLG5HB
**Channel:** C01TECH01
**Timestamp:** 1767815267.099869
**Permalink:** [https://...](https://...)
---
Thank you all!
ID Matching (Git-style)
All CLI commands support partial IDs. The system matches the longest unique prefix:
# These all refer to the same message:
slack-chat inbox view b89c7a14755df6dca57ece8e14f38652e727cbd8 # Full (40 chars)
slack-chat inbox view b89c7a14 # 8 chars
slack-chat inbox view b89c7a # 6 chars (short)
slack-chat inbox view b89c # 4 chars (if unique)
Error on ambiguity:
❌ Ambiguous ID 'b8' matches: b89c7a14..., b8a3f2c1...
ID Resolution Cache
User and channel IDs are cached to storage/_cache/ to reduce API calls:
storage/_cache/
├── users.yml # User ID → full profile
└── channels.yml # Channel ID → full info
When you run slack-chat user resolve or slack-chat channel resolve, the result is cached. Subsequent lookups hit the cache first.
Quick Reference
| Task | Command |
|---|---|
| Server | |
| Start Server | slack-chat server start |
| Stop Server | slack-chat server stop |
| Server Status | slack-chat server status |
| Pull (Online) | |
| Pull Messages | slack-chat pull --since "7 days ago" [--limit N] [--type TYPE] |
| Inbox (Offline) | |
| Summary | slack-chat inbox summary |
| List | slack-chat inbox list [--type TYPE] [--limit N] [--since DATE] [--all] |
| View | slack-chat inbox view <id> |
| Mark Read | slack-chat inbox read <id> |
| Mark Thread Read | slack-chat inbox mark-thread <id> |
| Mark Channel Read | slack-chat inbox mark-channel <channel_id> |
| Mark Unread | slack-chat inbox unread <id> |
| Resolve (Online, Cached) | |
| Resolve Channel | slack-chat channel resolve <channel_id> |
| Resolve User | slack-chat user resolve <user_id> |
| Lookup (Offline) | |
| List Channels | slack-chat channel list |
| Find Channels | slack-chat channel find <keyword> |
| List Users | slack-chat user list |
| Find Users | slack-chat user find <keyword> |
| Context (Online) | |
| Message Around | slack-chat message around <event_id> [-B N] [-A N] |
| View Thread | slack-chat client read-message-thread-replies <channel> <thread_ts> |
| Write (Online) | |
| Reply | slack-chat reply <id | #channel> "message" |
| React | slack-chat react <id> <emoji> |
| Mute Channel | slack-chat mute <channel_id> |
| Post Message | slack-chat client post-message <channel> "text" |
| Reply to Thread | slack-chat client post-thread-reply <channel> <thread_ts> "text" |
| Add Reaction | slack-chat client add-reaction <channel> <ts> "emoji" |
Online Mode: Fetching Messages from Slack
Command: slack-chat pull
Purpose: Fetch unread messages from Slack, store locally as Markdown files.
IMPORTANT: Always fetch with reasonable limits. Use
--limit 10or--limit 20for controlled processing. This ensures manageable batches for review.
Command:
slack-chat pull --since <date> [--limit N] [--type TYPE]
Parameters:
--since <date>: Required. Fetch messages received on/after this date- Formats:
YYYY-MM-DD,yesterday,"7 days ago","1 day ago"
- Formats:
--limit <n>: Optional. Max messages per category (default: 100)--type <type>: Optional. Filter:channels,dms,threads,mentions,all(default:all)--quiet: Suppress verbose output
Behavior:
- Fetches unread channels, DMs, subscribed threads, and @mentions
- Skips already-stored files (deduplication via SHA1)
- Stores each message as Markdown under
storage/<id>.md - Does NOT mark as read on Slack (that's done via
inbox read) - Prints progress for each stored message
Examples:
# Pull from last 24 hours
slack-chat pull --since "1 day ago" --limit 10
# Pull only threads
slack-chat pull --since yesterday --type threads
# Pull everything from past week (use with caution)
slack-chat pull --since "7 days ago"
# Quiet mode for scripts
slack-chat pull --since yesterday --limit 50 --quiet
Output Example:
📥 Pulling messages since 2026-01-06...
📢 Fetching channel messages...
+ 19aaf82d... (C02PROJ01)
+ 60e86087... (CL80UCYF5)
💬 Fetching DM messages...
🧵 Fetching thread replies...
+ e04ada37... (thread in C0919MFSA4X)
+ 8e206898... (thread in C098Q7ALDNU)
📣 Fetching mentions...
+ b89c7a14... (mention)
✅ Done: 11 stored, 0 skipped, 23 fetched total
Best Practices:
- Use
--limit 10or--limit 20for manageable batches - Use
--since "1 day ago"for daily processing - After pulling, use
slack-chat inbox listto review new messages - The
permalinkfield in stored files opens the message in Slack
Offline Mode: Analysis & Metadata
All slack-chat inbox commands work offline, reading/writing files in storage/.
Command: slack-chat inbox summary
Purpose: Get overall message statistics from local storage.
Command:
slack-chat inbox summary
Output:
summary:
unread: 11
read: 0
total: 11
by_type:
channel: 6
dm: 0
thread: 5
mention: 0
Use Cases:
- Verify message counts before processing
- Track unread vs read ratio
- Check if pull was successful
Online Mode: Add --online to fetch live counts from Slack API instead.
Command: slack-chat inbox list
Purpose: List messages with filtering.
Command:
slack-chat inbox list [--type TYPE] [--limit N] [--since DATE] [--all]
Options:
-t, --type <type>: Filter by type (channels,dms,threads,mentions,all)-n, --limit <n>: Max results (default: 20)--since <date>: Filter messages after date-a, --all: Include read messages (default: unread only)--online: Use live API instead of local storage
Output Format:
<short_id> / <date> / <channel_id> / <user_id> (type)
<text preview>
Output Example:
Showing 5 of 11 messages:
b89c7a / 2026-01-07 19:47 / C01TECH01 / WNARLG5HB
Thank you all!
4aab08 / 2026-01-07 19:24 / C01TECH01 / WM1HR6E1G
ok, puppet ran, nginx restarted
e04ada / 2026-01-07 19:06 / C0919MFSA4X / U025R2RLLM8 (thread)
Have been back and forth with cloud a bit on camel support
... and 6 more
Use Cases:
- Scan unread messages
- Filter by type (threads only, DMs only, etc.)
- Find messages from specific period
Command: slack-chat inbox view <id>
Purpose: Display full content of a message.
Command:
slack-chat inbox view <id>
Supports:
- Partial IDs:
b89c7a - Full IDs:
b89c7a14755df6dca57ece8e14f38652e727cbd8 - Event ID format:
C01TECH01:1767815267.099869
Output: Complete Markdown file with YAML frontmatter and rendered body.
Use Cases:
- Read full message content
- Extract data for analysis
- Check message metadata (reactions, attachments, etc.)
Example:
# View by short ID
slack-chat inbox view b89c7a
# View by event ID
slack-chat inbox view C01TECH01:1767815267.099869
How to interpet messsages
When I ask you to view a message, the output will have ID numbers in place of channel and user names, for example:
events:
- id: D04R3C0G1JT:1766426423.335079
type: mention
channel: '#USLACKBOT'
from: slackbot
text: <@WNHDFCXTJ> archived the channel <#C08TR8S0QJ0>
timestamp: '1766426423.335079'
- id: D0849DD71UP:1765928154.858059
type: reaction
channel: '#WNHDFCXTJ'
text: From here not much needed apart from those future meetings y
timestamp: '1765928154.858059'
thread_ts: '1765321208.614079'
url: https://bigco-producta.slack.com/archives/D0849DD71UP/p1765928154858059
- id: G01GROUP01:[email protected]
type: reaction (thread reply)
channel: '#sre-nexus'
text: <@WM1HR6E1G|teddy> I want you to be the coordinator
timestamp: '1765909149.353759'
thread_ts: '1765321208.614079'
url: https://bigco-producta.slack.com/archives/G01GROUP01/p1765909149353759
where:
@WNHDFCXTJis an example of a user_id- indicated by the
@(may not always appear) as well as theWprefix (part of the identifier)
- indicated by the
#C08TR8S0QJ0is an example of a channel_id- indicated by the
#(may not always appear) as well as theCprefix (part of the identifier)
- indicated by the
thread_tsindicates the message is part of a thread (value is the parent message timestamp)- Event IDs for threaded messages use the format:
CHANNEL_ID:TIMESTAMP@THREAD_TS
Use the slack-chat channel resolve <id> and slack-chat user resolve <id> commands to find out what the human-readable version of these are, and only cite these when replying back to me (I don't want to see IDs, unless names are not available.)
Command: slack-chat inbox read <id>
Purpose: Mark a message as read.
Command:
slack-chat inbox read <id> [--offline-only]
Behavior:
- Updates
offline.read: truein local file - By default, also marks as read on Slack server
- Use
--offline-onlyto skip server-side marking
Output:
ok: true
marked_read_locally: b89c7a14...
marked_read_on_slack: true
Use Cases:
- Mark messages as processed
- Track which messages have been reviewed
Command: slack-chat inbox mark-thread <id>
Purpose: Mark all messages in a thread as read.
Command:
slack-chat inbox mark-thread <id> [--offline-only]
Behavior:
- Finds all stored messages with the same thread_ts
- Marks them all as read locally
- By default, also marks thread as read on Slack server
- Use
--offline-onlyto skip server-side marking
Output:
ok: true
thread_ts: '1767773973.649239'
channel_id: C0919MFSA4X
marked_count: 5
marked_ids:
- e04ada37
- 8e206898
- a1b2c3d4
marked_read_on_slack: true
Use Cases:
- Done reviewing a thread, mark all at once
- Clean up multiple thread replies efficiently
Command: slack-chat inbox mark-channel <channel_id>
Purpose: Mark all messages in a channel as read.
Command:
slack-chat inbox mark-channel <channel_id> [--offline-only]
Behavior:
- Finds all stored messages in the channel
- Marks them all as read locally
- By default, also marks channel as read on Slack (up to latest message)
- Use
--offline-onlyto skip server-side marking
Output:
ok: true
channel_id: C01TECH01
marked_count: 12
marked_ids:
- b89c7a14
- 4aab08f1
- 7d8e9bce
marked_read_on_slack: true
Use Cases:
- Done with a channel's backlog, mark all at once
- Clear noisy channels efficiently
Command: slack-chat inbox unread <id>
Purpose: Mark a message as unread (local only).
Command:
slack-chat inbox unread <id>
Effect:
- Sets
offline.read: falsein local file - Does NOT sync to Slack (Slack API doesn't support marking unread)
Output:
ok: true
marked_unread_locally: b89c7a14...
Use Cases:
- Recover from accidental marks
- Re-queue messages for processing
ID Resolution (Online, Cached)
Command: slack-chat channel resolve <id>
Purpose: Convert channel ID to human-readable info.
slack-chat channel resolve C01TECH01
Output:
name: engineering
is_archived: false
is_private: false
created: 1563498384
creator: U0A4DBTGDPZ
topic: Technical discussions
purpose: Engineering team collaboration
members:
- WNARLG5HB
- WMCH36A6Q
Caching: Result is saved to storage/_cache/channels.yml. Subsequent calls return cached data.
Command: slack-chat user resolve <id>
Purpose: Convert user ID to human-readable info.
slack-chat user resolve WNARLG5HB
Output:
name: Alice Johnson
is_bot: false
is_admin: false
email: [email protected]
display_name: alice
title: Software Engineer
tz: America/Los_Angeles
Caching: Result is saved to storage/_cache/users.yml. Subsequent calls return cached data.
When to use: Whenever you see a raw ID (like WNARLG5HB or C01TECH01) and need the human-readable name.
Lookup Commands (Offline)
These commands search the offline cache without making API calls.
Command: slack-chat channel list
Purpose: List all cached channels.
slack-chat channel list
Output (tab-separated columns): id | name | description
C01TECH01 prod-tech-internal-ProductA Production tech discussion
C098Q7ALDNU engineering-general General engineering chat
C6M7U8DFF ProductA-server-team ProductA server team coordination
Use Cases:
- See all channels you've resolved/cached
- Find channel IDs for posting
Command: slack-chat channel find <keyword>
Purpose: Find cached channels by name keyword.
slack-chat channel find prod
slack-chat channel find ProductA
Output (tab-separated columns): id | name | description
Matches channels whose name contains the keyword (case-insensitive).
For example, hal matches thal, fhaly, etc.
Use Cases:
- Find a channel when you only remember part of the name
- Look up channel ID before posting with
slack-chat reply
Command: slack-chat user list
Purpose: List all cached users.
slack-chat user list
Output (tab-separated columns): id | name | title | project
WNARLG5HB Alice Johnson Associate Lead Software Engineer ProductA IV
WMCH36A6Q Charlie Brown Senior Software Engineer ProductA
U04MYEUTJLU Dana Evans Engineering Manager IT Infrastructure
Use Cases:
- See all users you've resolved/cached
- Find user IDs for @ mentions
Command: slack-chat user find <keyword>
Purpose: Find cached users by keyword (searches all fields).
slack-chat user find john
slack-chat user find ProductA
slack-chat user find infrastructure
Output (tab-separated columns): id | name | title | project
Searches all fields in the user object (case-insensitive), including:
- Name, real_name, display_name
- Title, email
- Team/project custom fields
- Any other string value
Examples:
# Find by name
slack-chat user find shelly
# Find by project/team
slack-chat user find ProductA
slack-chat user find "producta"
# Find by title
slack-chat user find "software engineer"
Use Cases:
- Find a user when you only remember part of the name
- Find all users on a specific team/project
- Look up user ID for mentions
Context Commands (Online)
Often, viewing one message in isolation does not provide enough information; To truly understand a given message, often its necessary to look at messages in the surrounding (channel/thread) context (before and after), similar to grep -B and -A flags.
Command: slack-chat message around <event_id>
Purpose: View messages before/after a target message for context.
slack-chat message around C6M7U8DFF:1766558024.931179 -B 3 -A 3
Options:
-B <n>: Number of messages before (default: 3)-A <n>: Number of messages after (default: 3)
Use Cases:
- Understand conversation context
- See what led to a message
- Review thread context
Command: slack-chat inbox context <event_id>
Purpose: View surrounding context (thread or channel messages).
slack-chat inbox context C6M7U8DFF:1766558024.931179 --limit 5
Write Commands (Online)
Command: slack-chat reply <target> <message>
Purpose: Reply to a channel or thread with smart targeting.
Command:
slack-chat reply <target> "<message>"
Smart Targeting - accepts multiple ID formats:
- Channel ID:
C01TECH01→ posts to channel - Channel name:
#prod-tech-internal-ProductA→ posts to channel (looks up from cache) - Storage ID:
b89c7a→ replies to that message's thread - Event ID:
C01TECH01:1767815267.099869→ replies to thread - Event ID with thread:
C01TECH01:[email protected]
Channel Name Resolution:
When using a channel name (with # prefix), the system:
- Looks up the name in the offline cache (
storage/_cache/channels.yml) - If found, uses the cached channel ID
- If not found, returns an error with suggestion to use
slack-chat channel find
To cache a channel, use slack-chat channel resolve <id> first.
Output:
ok: true
channel: C01TECH01
message_ts: '1767820123.456789'
thread_ts: '1767815267.099869'
permalink: https://bigco-producta.slack.com/archives/...
Examples:
# Post to channel by ID
slack-chat reply C01TECH01 "Hello everyone!"
# Post to channel by name
slack-chat reply "#prod-ProductA" "Hello world!"
# Reply to a thread (by storage ID)
slack-chat reply b89c7a "Thanks for the update!"
# Reply to a thread (by event ID)
slack-chat reply C01TECH01:1767815267.099869 "Got it, will look into this."
Use Cases:
- Quick replies to messages you just viewed
- Respond to threads without looking up thread_ts manually
- Post updates to channels by name
Command: slack-chat react <target> <emoji>
Purpose: Add an emoji reaction to a message.
Command:
slack-chat react <target> <emoji>
Smart Targeting - accepts:
- Storage ID:
b89c7a→ reacts to that message - Event ID:
C01TECH01:1767815267.099869→ reacts to message - Event ID with thread:
C01TECH01:[email protected]
Emoji formats (with or without colons):
thumbsup,+1,eyes,white_check_mark:thumbsup:,:+1:,:eyes:
Output:
ok: true
channel: C01TECH01
timestamp: '1767815267.099869'
emoji: thumbsup
Examples:
# React by storage ID
slack-chat react b89c7a thumbsup
# React by event ID
slack-chat react C01TECH01:1767815267.099869 eyes
# Acknowledge with checkmark
slack-chat react b89c7a white_check_mark
Use Cases:
- Acknowledge messages quickly
- React to messages you just viewed
- Signal agreement/approval without writing a reply
Command: slack-chat mute <channel_id>
Purpose: Mute a channel to stop receiving notifications.
Command:
slack-chat mute <channel_id>
Output:
ok: true
channel: C01TECH01
muted: true
Examples:
# Mute a noisy channel
slack-chat mute C01TECH01
# Mute after resolving channel name
slack-chat channel resolve C6M7U8DFF # Check it's the right channel
slack-chat mute C6M7U8DFF
Use Cases:
- Silence noisy channels
- Stop notifications from low-priority channels
- Reduce distractions during focus time
Workflow Scenarios
Scenario 1: Daily Slack Processing
Goal: Pull messages daily, review, mark processed.
# 1. Start server
slack-chat server start
# 2. Pull recent messages
slack-chat pull --since "1 day ago" --limit 20
# 3. Check statistics
slack-chat inbox summary
# Output: unread: 15, read: 0, total: 15
# 4. List messages for review
slack-chat inbox list --limit 20
# 5. View specific message
slack-chat inbox view b89c7a
# 6. Resolve user ID to name
slack-chat user resolve WNARLG5HB
# 7. Mark as processed
slack-chat inbox read b89c7a
# 8. Verify
slack-chat inbox summary
# Output: unread: 14, read: 1, total: 15
Scenario 2: Thread-focused Processing
Goal: Focus on thread replies only.
# 1. Pull only threads
slack-chat pull --since "3 days ago" --type threads
# 2. List thread messages
slack-chat inbox list --type threads
# 3. View thread reply
slack-chat inbox view e04ada
# 4. Get full thread context (online)
slack-chat message around C0919MFSA4X:[email protected] -B 5 -A 5
# 5. Mark as read
slack-chat inbox read e04ada
Scenario 3: Incremental Processing
Goal: Process in small batches.
# Pull small batch
slack-chat pull --since yesterday --limit 5
# Process each
for id in b89c7a 4aab08 7d8e9b; do
echo "=== Message: $id ==="
slack-chat inbox view $id
# ... analyze ...
slack-chat inbox read $id
done
# Check remaining
slack-chat inbox summary
Agent Workflow: Processing Unread Activity
When the user asks to "check Slack" or "process my unreads":
Step 1: Pull Fresh Data
slack-chat pull --since "1 day ago" --limit 20
Step 2: Get Overview
slack-chat inbox summary
If all counts are 0, report "No unread activity" and stop.
Step 3: List Messages
slack-chat inbox list --limit 20
Step 4: Present Summary
Parse the output. Present to user:
- Count by type (channels, DMs, threads)
- Preview of important messages
Example:
You have 11 unread messages: 6 in channels, 5 thread replies. Notable: Thread reply from U025R2RLLM8 about "camel support"
Step 5: Drill Down (on request)
slack-chat inbox view e04ada # View message
slack-chat user resolve U025R2RLLM8 # Get user name
slack-chat channel resolve C0919MFSA4X # Get channel name
Step 6: Mark as Read (on request)
slack-chat inbox read e04ada
File Organization
slack-chat/
├── src/
│ ├── cli.py # Main CLI
│ ├── server.py # Browser server (FastAPI)
│ ├── storage.py # Storage operations
│ └── pull.py # Pull command
├── storage/ # Local message cache
│ ├── _cache/
│ │ ├── users.yml
│ │ └── channels.yml
│ ├── b89c7a14...md
│ ├── 4aab08f1...md
│ └── ...
└── doc/
└── SPEC1.md # Architecture spec
Tips for AI Agents
- Pull first: Always
slack-chat pullbefore reading messages to get fresh data - Use partial IDs:
b89c7ainstead of fullb89c7a14755df6dca... - Check summary:
slack-chat inbox summaryto understand data volume - Resolve IDs: Use
slack-chat user resolveandslack-chat channel resolveto convert IDs to names - Test with limits: Use
--limit 5when prototyping workflows - Mark processed: Always
inbox readafter processing to track state - Use relative dates:
yesterday,"7 days ago"are clearer than exact dates - Cache is your friend: ID resolution is cached, so feel free to resolve repeatedly
Architecture Notes
- Storage: All files in
storage/are Markdown with YAML frontmatter (Git-friendly) - No database: Direct filesystem access
- Offline-first: Inbox commands work without server running
- Deduplication: SHA1 hashing ensures same message = same storage file
- ID cache: User/channel info cached to reduce API calls
- Server required: For
pull, resolve commands, and write operations
Troubleshooting
- if a command returns
HTTP 500,slack-chat server status # check if server is healthy slack-chat server stop # stop it slack-chat server start # re-start it