Documentation Index
Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
Use this file to discover all available pages before exploring further.
The Slack resource exposes a Slack workspace as a virtual filesystem
mounted at some prefix such as /slack/.
For token setup, see Slack Setup.
Config
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
/slack/
channels/
<channel-name>__<channel-id>/
<yyyy-mm-dd>.jsonl
...
dms/
<user-name>__<dm-id>/
<yyyy-mm-dd>.jsonl
...
users/
<username>.json
...
Example:
/slack/
channels/
general__C04KEPWF6V7/
2026-04-04.jsonl
2026-04-05.jsonl
random__C04JVGZM7UN/
2026-04-11.jsonl
dms/
alice__D0AQDJ5FP9V/
2026-04-04.jsonl
slackbot__D0ARPA1QSPJ/
2026-04-04.jsonl
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 .jsonl history files for the
last 90 days (or since channel creation, whichever is shorter).
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
.jsonl history 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
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.jsonl" | head -n 3')
print(await r.stdout_str())
# Read user profile
r = await ws.execute("cat /slack/users/alice.json")
print(await r.stdout_str())
# Extract message text with jq
r = await ws.execute(
f'cat "{base}/2026-04-04.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/chat/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:
# 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.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.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 .jsonl files per day.
Tips for efficient access:
# Check message count per day
wc -l "/slack/channels/general__C04KEPWF6V7/2026-04-04.jsonl"
# Read only recent messages
tail -n 10 "/slack/channels/general__C04KEPWF6V7/2026-04-04.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.jsonl" | head -n 20
# Count messages per user
cat "/slack/channels/general__C04KEPWF6V7/2026-04-04.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 .jsonl history or user .json |
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.
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.
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.
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.
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.
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.
slack-search --query "incident report"
| Option | Required | Description |
|---|
--query | yes | Search query |
Returns search results as JSON.