chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user