> ## 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.

# Slack

> Mount Slack channels, DMs, messages, users, and shared files as a Mirage virtual filesystem for Python agents.

The Slack VFS exposes a Slack workspace as a virtual filesystem
mounted at some prefix such as `/slack/`.

For token setup, see [Slack Setup](/home/setup/slack).

## Config

```python theme={null}
import os

from mirage import MountMode, Workspace
from mirage.vfs.slack import SlackConfig, SlackVFS

config = SlackConfig(
    token=os.environ["SLACK_BOT_TOKEN"],
    search_token=os.environ.get("SLACK_USER_TOKEN"),
)
vfs = SlackVFS(config=config)
ws = Workspace({"/slack": vfs}, mode=MountMode.READ)
```

## Filesystem Layout

```text theme={null}
/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 theme={null}
/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 send-message --channel`, etc.) can reference the correct
VFS 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 VFS uses `IndexCacheStore` (same as Discord and other
mounts). 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 theme={null}
import asyncio
import os

from dotenv import load_dotenv

from mirage import MountMode, Workspace
from mirage.vfs.slack import SlackConfig, SlackVFS

load_dotenv(".env.development")

config = SlackConfig(
    token=os.environ["SLACK_BOT_TOKEN"],
    search_token=os.environ.get("SLACK_USER_TOKEN"),
)
vfs = SlackVFS(config=config)


async def main():
    ws = Workspace({"/slack": vfs}, mode=MountMode.READ)

    # List structure
    r = await ws.shell("ls /slack/")
    print(await r.stdout_str())

    # List channels
    r = await ws.shell("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.shell(f'cat "{base}/2026-04-04/chat.jsonl" | head -n 3')
    print(await r.stdout_str())

    # Read user profile
    r = await ws.shell("cat /slack/users/alice__U12345678.json")
    print(await r.stdout_str())

    # Extract message text with jq
    r = await ws.shell(
        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.shell(f'rg message "{base}/"')
    print(await r.stdout_str())

    # Tree view
    r = await ws.shell("tree -L 1 /slack/")
    print(await r.stdout_str())

    # Navigate with cd/pwd
    await ws.shell(f'cd "{base}"')
    r = await ws.shell("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

VFS-specific commands require Slack IDs (`channel_id`, `user_id`,
`ts`). These can be extracted from the filesystem:

```bash theme={null}
# 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 send-message --channel C04KEPWF6V7 \
  --thread-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 theme={null}
# 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, once per JSONL line (`-s` all) |
| `wc` | Line/word/byte counts |
| `stat` | File metadata (name, size, type) |
| `find` | Recursive search with `-name`, `-maxdepth` |
| `tree` | Directory tree view |

Acting on Slack (sending, reacting, pins, member info, search) goes
through the [slack CLI](/python/cli/slack) when installed; the mounted
tree stays read-oriented. The `<name>__<id>` path segments supply the
channel and user IDs the CLI flags take.

## Time scope

Set `start_time` and/or `end_time` in the mount's YAML `config` (or pass
`start_time`/`end_time` to Python; `startTime`/`endTime` to the TypeScript
constructor). Bounds are RFC3339 timestamps with an explicit timezone and
at most millisecond precision. Start is inclusive; end is exclusive.
An omitted or null bound is open. Start must precede end.

```yaml theme={null}
mounts:
  /history:
    vfs: slack
    mode: read
    config:
      token: "<bot-token>"
      start_time: "2026-06-01T10:00:00Z"
      end_time: "2026-06-02T00:00:00Z"
```

With a bound configured, channel listings cover the selected period rather
than the default recent window. Day directories use UTC. Messages are selected
by creation time, and attachments follow their parent messages. Direct paths,
`stat`, date globs, and `grep`/`rg` cannot escape the scope. Scoped searches scan
the filtered files instead of using unrestricted provider search. User/member
and channel/server metadata remain visible as context.

These settings apply to the VFS, not to separately installed account CLIs.
`mode: read` prevents mount writes; it does not freeze upstream edits or deletions.
Rebuild/remount the VFS to change its scope so cached listings and bytes are cleared.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.