--- title: Slack description: Mount Slack channels, DMs, messages, users, and shared files as a Mirage virtual filesystem for Python agents. icon: slack --- The Slack resource exposes a Slack workspace as a virtual filesystem mounted at some prefix such as `/slack/`. For token setup, see [Slack Setup](/python/setup/slack). ## Config ```python import os from mirage import MountMode, Workspace from mirage.resource.slack import SlackConfig, SlackResource config = SlackConfig(token=os.environ["SLACK_BOT_TOKEN"]) resource = SlackResource(config=config) ws = Workspace({"/slack": resource}, mode=MountMode.READ) ``` ## Filesystem Layout ```text /slack/ channels/ __/ / chat.jsonl files/ __. dms/ __/ / chat.jsonl files/ __. users/ __.json ... ``` Example: ```text /slack/ channels/ general__C04KEPWF6V7/ 2026-04-04/ chat.jsonl files/ 2026-04-05/ chat.jsonl files/ random__C04JVGZM7UN/ 2026-04-11/ chat.jsonl files/ dms/ alice__D0AQDJ5FP9V/ 2026-04-04/ chat.jsonl files/ slackbot__D0ARPA1QSPJ/ 2026-04-04/ chat.jsonl files/ users/ alice__U12345678.json bob__U87654321.json ``` Directory names embed the Slack ID so that write commands (`slack-post-message --channel_id`, etc.) can reference the correct resource without extra lookups. ### Channels `/slack/channels/` lists public and private channels the bot has access to. The channel ID is appended after `__`. Each channel directory contains day-partitioned directories for the last 90 days (or since channel creation, whichever is shorter). Each date directory contains `chat.jsonl` plus a `files/` directory for attachments shared that day. The date range is derived from the channel's `created` timestamp. ### DMs `/slack/dms/` lists direct message conversations. The DM ID is appended after `__`. Like channels, DM directories contain daily directories with `chat.jsonl` and `files/`. ### Users `/slack/users/` lists one `.json` file per non-deleted, non-bot user. Reading a user file calls `get_user_profile()` and returns the full profile JSON from the Slack API. ## Cache The Slack resource uses `IndexCacheStore` (same as Discord and other resources). Index entries store channel IDs, DM IDs, user IDs, and channel creation timestamps for date range computation. There is no separate content cache - file content caching is handled by the workspace `IOResult` mechanism. ## Example ```python import asyncio import os from dotenv import load_dotenv from mirage import MountMode, Workspace from mirage.resource.slack import SlackConfig, SlackResource load_dotenv(".env.development") config = SlackConfig(token=os.environ["SLACK_BOT_TOKEN"]) resource = SlackResource(config=config) async def main(): ws = Workspace({"/slack": resource}, mode=MountMode.READ) # List structure r = await ws.execute("ls /slack/") print(await r.stdout_str()) # List channels r = await ws.execute("ls /slack/channels/") print(await r.stdout_str()) ch = r.stdout_str().strip().splitlines()[0].strip() base = f"/slack/channels/{ch}" # Read messages from a specific date r = await ws.execute(f'cat "{base}/2026-04-04/chat.jsonl" | head -n 3') print(await r.stdout_str()) # Read user profile r = await ws.execute("cat /slack/users/alice__U12345678.json") print(await r.stdout_str()) # Extract message text with jq r = await ws.execute( f'cat "{base}/2026-04-04/chat.jsonl"' ' | jq -r ".[] | .text" | head -n 5') print(await r.stdout_str()) # Search across channel (scans all date files) r = await ws.execute(f'rg message "{base}/"') print(await r.stdout_str()) # Tree view r = await ws.execute("tree -L 1 /slack/") print(await r.stdout_str()) # Navigate with cd/pwd await ws.execute(f'cd "{base}"') r = await ws.execute("pwd") print(await r.stdout_str()) if __name__ == "__main__": asyncio.run(main()) ``` See `examples/python/slack/slack.py` for the full working example. ## Finding IDs Resource-specific commands require Slack IDs (`channel_id`, `user_id`, `ts`). These can be extracted from the filesystem: ```bash # Channel ID - embedded in directory name after "__" ls /slack/channels/ # → general__C04KEPWF6V7 ← channel_id = C04KEPWF6V7 # User ID - embedded in filename after "__" ls /slack/users/ # → alice__U04K21SEVR9.json ← user_id = U04K21SEVR9 # Message timestamp (ts) - inside JSONL messages jq -r '.[] | "\(.ts) [\(.user)] \(.text)"' \ "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" # → 1712345678.123456 [U04K21SEVR9] hello world # Find a specific message then reply jq -r '.[] | select(.text | test("hello")) | .ts' \ "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" # → 1712345678.123456 slack-reply-to-thread --channel_id C04KEPWF6V7 \ --ts 1712345678.123456 --text "Reply to hello" ``` ## Working with Large Channels Channels with many messages produce large `chat.jsonl` files per day. Tips for efficient access: ```bash # Check message count per day wc -l "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" # Read only recent messages tail -n 10 "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" # Search across all dates (scans each file) rg "keyword" "/slack/channels/general__C04KEPWF6V7/" # Extract specific fields to reduce output jq -r '.[] | "\(.ts) [\(.user)] \(.text)"' \ "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" | head -n 20 # Count messages per user cat "/slack/channels/general__C04KEPWF6V7/2026-04-04/chat.jsonl" \ | jq -r '.[] | .user' | sort | uniq -c ``` ## Shell Commands Standard commands available on the mounted Slack tree: | Command | Notes | | --------------- | ------------------------------------------ | | `ls` | List channels, DMs, users, dates | | `cat` | Read `chat.jsonl`, user `.json`, or files | | `head` / `tail` | First/last N lines | | `grep` / `rg` | Pattern search (file or directory level) | | `jq` | Query JSON; use `.[]` prefix for JSONL | | `wc` | Line/word/byte counts | | `stat` | File metadata (name, size, type) | | `find` | Recursive search with `-name`, `-maxdepth` | | `tree` | Directory tree view | Resource-specific commands: ### `slack-post-message` Post a message to a channel. ```bash slack-post-message --channel_id C04KEPWF6V7 --text "Hello from MIRAGE" ``` | Option | Required | Description | | -------------- | -------- | -------------------- | | `--channel_id` | yes | Slack channel ID | | `--text` | yes | Message text to send | Returns the posted message JSON. ### `slack-reply-to-thread` Reply to a specific thread. ```bash slack-reply-to-thread --channel_id C04KEPWF6V7 --ts 1712345678.123456 --text "Thread reply" ``` | Option | Required | Description | | -------------- | -------- | ----------------------- | | `--channel_id` | yes | Slack channel ID | | `--ts` | yes | Thread parent timestamp | | `--text` | yes | Reply text | The `--ts` value is the message timestamp (e.g., from a `.jsonl` entry's `ts` field). Returns the posted reply JSON. ### `slack-add-reaction` Add an emoji reaction to a message. ```bash slack-add-reaction --channel_id C04KEPWF6V7 --ts 1712345678.123456 --reaction thumbsup ``` | Option | Required | Description | | -------------- | -------- | ----------------------------- | | `--channel_id` | yes | Slack channel ID | | `--ts` | yes | Message timestamp to react to | | `--reaction` | yes | Emoji name (without colons) | ### `slack-get-users` Search for users by name, real name, or email. ```bash slack-get-users --query "alice" ``` | Option | Required | Description | | --------- | -------- | ------------ | | `--query` | yes | Search query | Returns matching users as JSON array. ### `slack-get-user-profile` Get a single user's full profile. ```bash slack-get-user-profile --user_id U04K21SEVR9 ``` | Option | Required | Description | | ----------- | -------- | ------------- | | `--user_id` | yes | Slack user ID | Returns the user profile JSON. The user ID can be found in filenames under `/slack/users/` (e.g., `alice__U04K21SEVR9.json`). ### `slack-search` Search messages across the workspace. ```bash slack-search --query "incident report" ``` | Option | Required | Description | | --------- | -------- | ------------ | | `--query` | yes | Search query | Returns search results as JSON.