bcbd1bdb22
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
332 lines
8.9 KiB
Plaintext
332 lines
8.9 KiB
Plaintext
---
|
|
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/
|
|
<channel-name>__<channel-id>/
|
|
<yyyy-mm-dd>/
|
|
chat.jsonl
|
|
files/
|
|
<name>__<F-id>.<ext>
|
|
dms/
|
|
<user-name>__<dm-id>/
|
|
<yyyy-mm-dd>/
|
|
chat.jsonl
|
|
files/
|
|
<name>__<F-id>.<ext>
|
|
users/
|
|
<username>__<user-id>.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.
|