npm package: @sujacob/slackpilot
Description: Control GitHub Copilot CLI from Slack via ACP
Author: Suraj Jacob
Latest version: 1.0.0

# SlackPilot 🚀

> Control GitHub Copilot CLI from Slack — send prompts, get responses, with full tool access.

SlackPilot wraps Copilot CLI's [Agent Client Protocol (ACP)](https://agentclientprotocol.com) with a Slack bot, so you can talk to Copilot from your phone, another machine, or anywhere you have Slack — no terminal required.

## How It Works

```
You (Slack DM or @mention)
  → SlackPilot (Slack Bolt, Socket Mode)
    → copilot --acp --stdio (real Copilot CLI)
      → Full toolset: shell, files, GitHub, MCP servers, etc.
    ← ACP streaming response
  ← Slack message (updated live as Copilot responds)
```

Each Slack **thread** gets its own isolated Copilot session. Continue a conversation by replying in the same thread.

---

## Features

- **Full Copilot CLI** — not a stripped-down chatbot. Same tools, MCP servers, GitHub integration, and models as your terminal.
- **Streaming responses** — watch Copilot's response build up in real-time in Slack (updates every 1.5s).
- **Animated thinking** — varied status messages while waiting for Copilot, so users know it's working.
- **Session per thread** — each Slack thread gets its own Copilot session with isolated context.
- **Interactive permissions** — configurable policy: auto-approve all tools, deny all, or ask the user in Slack to approve each tool call.
- **Session management** — built-in commands to reset sessions, check status. Idle sessions auto-expire.
- **Socket Mode** — no public URL or ngrok needed. Works behind firewalls.

---

## Quick Start

### Prerequisites

| Requirement | How to check |
|---|---|
| **Node.js 18+** | `node --version` |
| **Copilot CLI** installed & authenticated | `copilot --version` |
| **Slack workspace** where you can create apps | Admin access or permission to install apps |

### 1. Install SlackPilot

#### Option A: Run with npx (no install needed)

```bash
npx slackpilot
```

This downloads and runs SlackPilot in one command. Environment variables must be set before running (see step 3).

#### Option B: Global install

```bash
npm install -g slackpilot
slackpilot
```

#### Option C: Add to Copilot CLI as an MCP server

Add SlackPilot to your Copilot CLI MCP config (`~/.copilot/mcp-config.json`):

```json
{
  "servers": {
    "slackpilot": {
      "command": "npx",
      "args": ["-y", "slackpilot"],
      "env": {
        "SLACK_BOT_TOKEN": "xoxb-your-bot-token",
        "SLACK_APP_TOKEN": "xapp-your-app-level-token",
        "COPILOT_WORK_DIR": "C:\\your\\project"
      }
    }
  }
}
```

> **Note:** This config is for reference. SlackPilot runs as a standalone server, not an MCP server — use Options A or B for normal operation.

#### Option D: Run from source

```bash
git clone https://github.com/sargemonkey/slackpilot.git
cd slackpilot
npm install
npm run build
npm start
```

### 2. Create a Slack App

> See the detailed [Setup Guide](#setup-guide) below for step-by-step instructions.

1. Go to **https://api.slack.com/apps** → Create New App → From Scratch
2. Name it (e.g., "SlackPilot") and select your workspace
3. Continue to the Setup Guide below for all required configuration

### 3. Configure

SlackPilot supports two configuration methods. You can use either or both (config file values take precedence over environment variables).

#### Option A: Config file (recommended for npx / global install)

Create a `config.json` in any of these locations:

| Location | Scope |
|---|---|
| `./config.json` (current directory) | Per-project |
| `~/.copilot/slackpilot-config.json` | Global (user-level) |
| `~/.copilot/slackpilot/config.json` | Global (user-level) |

Copy the example and edit it:

```bash
# For npx users — create a global config:
mkdir -p ~/.copilot
cp config.example.json ~/.copilot/slackpilot-config.json
```

```json
{
  "slack": {
    "botToken": "xoxb-your-bot-token",
    "appToken": "xapp-your-app-level-token"
  },
  "copilot": {
    "cliPath": "copilot",
    "workDir": "C:\\your\\project"
  },
  "permissionPolicy": "auto-approve",
  "maxSessions": 5
}
```

Then just run:

```bash
npx slackpilot
```

#### Option B: Environment variables

Set variables directly (useful for CI, Docker, or one-off runs):

**PowerShell:**
```powershell
$env:SLACK_BOT_TOKEN = "xoxb-..."
$env:SLACK_APP_TOKEN = "xapp-..."
$env:COPILOT_WORK_DIR = "C:\your\project"
npx slackpilot
```

**Bash:**
```bash
SLACK_BOT_TOKEN=xoxb-... SLACK_APP_TOKEN=xapp-... npx slackpilot
```

#### Option C: `.env` file (for source installs)

```bash
cp .env.example .env
# Edit .env with your tokens
```

> **Tip:** Only `slack.botToken` / `SLACK_BOT_TOKEN` and `slack.appToken` / `SLACK_APP_TOKEN` are required. Everything else has sensible defaults.

### 4. Build and Run

```bash
npm run build
npm start
```

You should see:
```
🚀 SlackPilot starting...
✅ SlackPilot is running! Send a message in Slack to talk to Copilot.
```

### 5. Talk to Copilot in Slack

- **DM the bot** directly — your message goes to Copilot
- **@mention the bot** in any channel — text after the mention becomes the prompt
- **Reply in a thread** — continues the same Copilot session

---

## Setup Guide

### Step 1: Create the Slack App

1. Visit **https://api.slack.com/apps**
2. Click **Create New App** → **From scratch**
3. Enter a name (e.g., `SlackPilot`) and choose your workspace
4. Click **Create App**

### Step 2: Enable Socket Mode

Socket Mode lets the bot connect outbound (no public URL needed).

1. Go to **Settings** → **Socket Mode** in the left sidebar
2. Toggle **Enable Socket Mode** → On
3. When prompted, create an **App-Level Token**:
   - Name: `slackpilot-socket`
   - Scope: `connections:write`
   - Click **Generate**
4. **Copy the token** (starts with `xapp-`) → this is your `SLACK_APP_TOKEN`

### Step 3: Add Bot Permissions

1. Go to **Features** → **OAuth & Permissions**
2. Scroll to **Scopes** → **Bot Token Scopes**
3. Add these scopes:

| Scope | Purpose |
|---|---|
| `app_mentions:read` | Receive @mention events |
| `chat:write` | Send and update messages |
| `im:history` | Read DM conversation history |
| `im:read` | Access DM information |
| `im:write` | Send DMs |

### Step 4: Subscribe to Events

1. Go to **Features** → **Event Subscriptions**
2. Toggle **Enable Events** → On
3. Under **Subscribe to bot events**, add:

| Event | Purpose |
|---|---|
| `app_mention` | Triggers when someone @mentions the bot |
| `message.im` | Triggers when someone DMs the bot |

4. Click **Save Changes**

### Step 5: Install to Workspace

1. Go to **Settings** → **Install App**
2. Click **Install to Workspace**
3. Review and allow the requested permissions
4. **Copy the Bot User OAuth Token** (starts with `xoxb-`) → this is your `SLACK_BOT_TOKEN`

### Step 6: Enable DMs (App Home)

1. Go to **Features** → **App Home**
2. Under **Show Tabs**, make sure **Messages Tab** is enabled
3. Check **Allow users to send Slash commands and messages from the messages tab**

### Step 7: Verify

1. Start SlackPilot: `npm start`
2. Open Slack → find the bot in your DMs (search for its name)
3. Send: `Hello!`
4. You should see "🤔 _Thinking..._" update to Copilot's response

---

## Built-in Commands

Send these as messages to the bot:

| Command | Description |
|---|---|
| `/slackpilot-help` | Show available commands |
| `/slackpilot-reset` | End the Copilot session for this thread |
| `/slackpilot-status` | Show how many sessions are active |

Everything else is sent to Copilot as a prompt.

---

## Configuration Reference

| Config file key | Env variable | Required | Default | Description |
|---|---|---|---|---|
| `slack.botToken` | `SLACK_BOT_TOKEN` | ✅ | — | Bot User OAuth Token (`xoxb-...`) |
| `slack.appToken` | `SLACK_APP_TOKEN` | ✅ | — | App-Level Token for Socket Mode (`xapp-...`) |
| `copilot.cliPath` | `COPILOT_CLI_PATH` | — | `copilot` | Path to the `copilot` executable |
| `copilot.workDir` | `COPILOT_WORK_DIR` | — | Current dir | Working directory for Copilot sessions. Falls back to current dir if path doesn't exist |
| `permissionPolicy` | `PERMISSION_POLICY` | — | `auto-approve` | `auto-approve` = run any tool. `deny` = block all. `ask` = prompt the user in Slack |
| `maxSessions` | `MAX_SESSIONS` | — | `5` | Maximum concurrent Copilot CLI sessions (LRU eviction) |
| `sessionCreationTimeoutMs` | `SESSION_CREATION_TIMEOUT_MS` | — | `60000` | Timeout (ms) for spawning a new Copilot CLI process |
| `sessionIdleTtlMs` | `SESSION_IDLE_TTL_MS` | — | `172800000` | How long (ms) idle sessions stay alive before auto-cleanup (48h). Set to `0` to disable |
| `permissionTimeoutMs` | `PERMISSION_TIMEOUT_MS` | — | `120000` | When policy is `ask`, how long (ms) to wait for user approval before auto-denying |

> Config file values take precedence over environment variables. Config file is searched in: `./config.json` → `~/.copilot/slackpilot-config.json` → `~/.copilot/slackpilot/config.json`.

---

## Architecture

```
slackPilot/
├── src/
│   ├── index.ts        # Entry point, graceful shutdown
│   ├── slack.ts         # Slack Bolt app (Socket Mode, DMs, @mentions)
│   ├── bridge.ts        # Routes Slack ↔ ACP, streaming updates, commands
│   ├── acp.ts           # Spawns copilot --acp --stdio, ACP protocol
│   ├── sessions.ts      # Session-per-thread management, eviction
│   └── config.ts        # Environment variable config
├── .env.example
├── package.json
└── tsconfig.json
```

### Key Design Decisions

- **Socket Mode** over webhooks — no ngrok, works behind firewalls
- **One `copilot` process per thread** — full context isolation
- **Streaming via `chat.update`** — Slack messages update every 1.5s as Copilot responds
- **LRU eviction** — when `MAX_SESSIONS` is hit, the least recently used session is destroyed
- **Idle session cleanup** — sessions auto-expire after configurable TTL (default 48h)
- **Event deduplication** — prevents double-processing of Slack message retries
- **Race condition protection** — concurrent messages to the same thread share a single session creation

---

## Security Considerations

⚠️ **`PERMISSION_POLICY=auto-approve` is powerful but dangerous.**

When set to `auto-approve`, Copilot can:
- Execute arbitrary shell commands
- Read and write files on your machine
- Make network requests
- Install packages

This is fine for personal use on your own machine. For shared workspaces:
- Use `ask` to prompt users in Slack before each tool call
- Use `deny` to limit Copilot to chat-only
- Run SlackPilot in a sandboxed environment (container, VM)
- Restrict `COPILOT_WORK_DIR` to a specific project directory

---

## Troubleshooting

| Symptom | Fix |
|---|---|
| Bot doesn't respond | Check `npm start` output for errors. Verify tokens in `.env` |
| "Copilot timed out" | Copilot took > 5 min. Try a simpler prompt |
| Messages not appearing | Ensure Event Subscriptions are enabled and the bot is in the channel |
| "Failed to start Copilot CLI" | Run `copilot --version` to check it's installed and authenticated |
| Rate limiting errors | Responses update every 1.5s to stay within Slack limits |

---

## License

MIT