pi-slack-bot
May 13, 2026 · View on GitHub
A Slack bot that exposes pi as a conversational coding agent. Chat with pi in Slack DMs — it streams responses, runs tools, manages sessions per thread, and lets you switch models, thinking levels, and working directories on the fly.
Features
- Threaded sessions — each Slack thread gets its own pi agent session with full conversation history
- Streaming responses — real-time updates with tool execution indicators, auto-split for long messages
- Project picker — fuzzy-matches project names or shows buttons to pick a working directory
- Interactive file picker — browse and select files via Slack buttons when the agent needs user input
- Commands —
!model,!thinking,!cwd,!cancel,!new,!sessions, and more - Prompt templates — run file-based prompt templates via
!promptwith a picker UI - Attach server — external processes can connect via WebSocket and stream to Slack threads
- Session management — configurable limits, idle timeout, automatic cleanup
Prerequisites
- Node.js >= 20
- A Slack app with Socket Mode enabled (see Slack App Setup)
- pi installed and configured
- An LLM provider (Anthropic, AWS Bedrock, etc.) with credentials configured
Installation
git clone https://github.com/samfoy/pi-slack-bot.git
cd pi-slack-bot
npm install
Configuration
Copy the example env file and fill in your values:
cp .env.example .env
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
SLACK_BOT_TOKEN | ✅ | — | Bot token (xoxb-...) |
SLACK_APP_TOKEN | ✅ | — | App-level token (xapp-...) for Socket Mode |
SLACK_USER_ID | ✅ | — | Your Slack user ID (bot only responds to you) |
PROVIDER | anthropic | LLM provider name | |
MODEL | claude-sonnet-4-5 | Model ID | |
THINKING_LEVEL | off | Thinking level: off, minimal, low, medium, high, xhigh | |
MAX_SESSIONS | 10 | Max concurrent sessions | |
SESSION_IDLE_TIMEOUT | 3600 | Idle session timeout in seconds | |
SESSION_DIR | ~/.pi-slack-bot/sessions | Session persistence directory | |
STREAM_THROTTLE_MS | 3000 | Min interval between Slack message updates | |
SLACK_MSG_LIMIT | 3900 | Max chars per Slack message before splitting | |
WORKSPACE_DIRS | ~/projects | Comma-separated dirs to scan for projects | |
ATTACH_PORT | 3001 | WebSocket port for the attach server |
Project Discovery
The bot discovers projects by scanning WORKSPACE_DIRS one level deep. For finer control, create ~/.pi-slack-bot/projects.json:
{
"scanDirs": ["~/projects", "~/work"],
"pin": ["~/dotfiles"],
"exclude": ["node_modules", "CR-*"],
"labels": {
"my-app": "🚀 My App",
"dotfiles": "⚙️ Dotfiles"
}
}
Usage
npm start
Then DM your bot in Slack. The first message starts a session:
- With a path:
~/projects/my-app fix the login bug→ starts in that directory - With a fuzzy name:
my-app fix the login bug→ matches against known projects - Plain message:
hello→ shows a project picker with buttons
Commands
| Command | Description |
|---|---|
!help | Show available commands |
!new | Start a fresh session (same thread) |
!cancel | Cancel the current stream |
!status | Show session info (model, cwd, message count) |
!model <name> | Switch model |
!thinking <level> | Set thinking level |
!sessions | List all active sessions |
!cwd <path> | Change working directory (creates a new session) |
!reload | Reload extensions and prompt templates |
!plan <idea> | Start a PDD planning session |
!prompt [name] | Run a prompt template |
Any unrecognized !command is forwarded to pi as /command (for extensions and prompt templates).
Slack App Setup
- Go to api.slack.com/apps and create a new app
- Enable Socket Mode under Settings → Socket Mode and generate an app-level token (
xapp-...) - Under OAuth & Permissions, add these bot token scopes:
chat:writeim:historyim:readim:writereactions:readreactions:write
- Under Event Subscriptions, enable events and subscribe to:
message.im
- Install the app to your workspace and copy the bot token (
xoxb-...) - Find your Slack user ID (click your profile → "..." → "Copy member ID")
Deployment (Linux / systemd)
Use run.sh as the process entry point — it handles NODE_PATH resolution for pi packages and auto-restarts on exit code 75 (issued by !restart).
./run.sh
# or in tmux:
tmux new -d -s bot './run.sh'
Heap sizing under cgroup memory limits. Node 22 auto-sizes --max-old-space-size to roughly half the cgroup MemoryMax. Under a 1 GB systemd limit this gives V8 only ~380 MB of old-gen — not enough for several active sessions. run.sh applies a safe default (NODE_OPTIONS=--max-old-space-size=768) unless you've already set it.
If you run under systemd, add MemoryHigh generously above the heap ceiling so the kernel doesn't OOM-kill before V8 can GC:
[Service]
ExecStart=/path/to/pi-slack-bot/run.sh
Restart=on-failure
RestartSec=10
StartLimitBurst=5
StartLimitIntervalSec=300
Environment=NODE_OPTIONS=--max-old-space-size=768
MemoryHigh=1200M
MemoryMax=1500M
Adjust --max-old-space-size based on how many concurrent sessions you expect (MAX_SESSIONS × ~100–150 MB/session is a reasonable estimate).
Development
# Run tests
npm test
# Type check
npm run typecheck
# Test coverage
npm run coverage
# Check code duplication
npm run duplication
Architecture
src/
├── index.ts # Entry point — boots Slack app + attach server
├── config.ts # Environment variable parsing
├── slack.ts # Slack Bolt app, event routing, project picker
├── session-manager.ts # Session lifecycle, limits, idle reaping
├── thread-session.ts # Per-thread pi AgentSession wrapper
├── streaming-updater.ts # Streams agent output to Slack with throttling
├── formatter.ts # Markdown → Slack mrkdwn conversion, splitting
├── parser.ts # Message parsing, project discovery, fuzzy match
├── commands.ts # !command dispatch
├── command-picker.ts # Prompt template button picker
├── file-picker.ts # Interactive file browser via Slack buttons
└── attach-server.ts # WebSocket server for external session attachment