DanielGGordon/slackcc
GitHub: DanielGGordon/slackcc
一个通过 Socket Mode 将 Slack 频道与 Claude Code / T3 Code AI 编码代理桥接的守护进程,支持多项目隔离、发送者权限控制和本地 prompt 注入审查。
Stars: 0 | Forks: 0
# slackcc — Slack ↔ Claude Code / T3 Code 桥接器
一个 Socket Mode 守护进程,允许已配置 Slack 频道中的人员与 AI 编码代理进行**自主**(来回交互,无需人类介入)对话,每个频道对应一个独立项目——具备基于发送者的权限,并在访客前端提供本地 prompt 保护审查机制。
## 工作原理
```
Slack channel ──(Socket Mode)──> slackcc daemon ──┬──> backend "claude": claude -p in project cwd
│ └──> backend "t3": HTTP dispatch into a T3 Code
│ project thread (live in the T3 GUI, one
│ Slack thread <-> one T3 thread, mirrored
│ bidirectionally)
└── guests only: blocking pps check (local LLM judge) before dispatch
```
- **作用域限制:** 机器人仅会在 `config/channels.json` 列出的频道中做出反应。每个频道映射到一个项目(对于 `claude` 后端是 `cwd` + persona,或对于 `t3` 后端是一个 T3 项目 ID)。
- **发送者权限**(`config/senders.json`):owner 拥有完全访问权限;其他所有人均为 guest——消息会经过 pps(Prompt Protection Service)审查,这是一个本地沙盒化的 LLM 判定器,负责拦截,并在失败时阻断(fail-closed),且他们的对话轮次将运行于 `approval-required` 模式,因此高风险的 tool 调用需等待 owner 批准。在每个桥接项目中的 PreToolUse 守卫 hook 会确定性地拦截批量删除、机密文件读取和 env 泄露行为,无论任何模型作出何种决定。
- **双向镜像(t3 后端):** 在源自 Slack 的线程中,于 T3 GUI 内输入的消息会被回传至 Slack 线程(“_Owner 对代理说:_ …”),且回复会同时出现在两侧。在 T3 UI 中结束聊天会在 Slack 线程中发布通知;在 Slack 中回复则会取消结束状态。
- **出站清洗:** 每条发布至 Slack 的消息都会被扫描,并且具有机密特征(token、密钥、JWT)的字符串会被脱敏。
- **信任边界:** pps 是审查层,因此到达代理的消息被视为受信任内容并以纯文本形式接收。残留情况——即 guest 处于 `pps_mode: "log"` 时(判定器仅监控但不拦截)——依然会被限制在 `<<>>` 标记内,并附带相应的指令(`sanitize.py`)。
- **桥接协议位于 prompt 之外:** 每一轮对话都会携带一行路由信息(`[slack channel=… thread=…]`)。如何回复、上传文件以及发布额外消息的说明已随软件包附带(`src/slackcc/data/slack-bridge.md`),并通过其 system prompt(`claude` 后端)或项目的 `CLAUDE.md`(`t3` 后端——见第 4 步)传递给代理。
## 1. 创建 Slack 应用(一次性操作)
你需要一个 **bot token**(`xoxb-`)和一个 **app-level token**(`xapp-`)。
1. 前往 → **Create New App** → **From scratch**。为其命名并选择你的 workspace。
2. **Socket Mode**(左侧边栏)→ 切换至 **Enable Socket Mode**。出现提示时,创建一个带有 `connections:write` scope 的 **App-Level Token**。将其复制——这就是你的 `SLACK_APP_TOKEN`(`xapp-...`)。
3. **OAuth & Permissions** → **Bot Token Scopes**,添加:
- `chat:write` — 发布消息
- `app_mentions:read` — 查看 @提及
- `channels:history` — 读取公共频道中的消息
- `groups:history` — 读取私有频道中的消息(如果你打算使用的话)
- `channels:read` — 解析频道信息
*(后续可能需要:用于语音备注/附件的 `files:read`。)*
4. **Event Subscriptions**(左侧边栏)→ **Enable Events**。(无需 Request URL——Socket Mode 会自动传递事件。)在 **Subscribe to bot events** 下,添加:
- `message.channels`, `message.groups`, `app_mention`
5. **Install App**(或 **OAuth & Permissions** → **Install to Workspace**)。批准安装。复制 **Bot User OAuth Token**——这就是 `SLACK_BOT_TOKEN`(`xoxb-...`)。*(如果以后更改了 scope,请重新安装。)*
6. 在 Slack 中,打开目标频道并**邀请该机器人**:输入 `/invite @YourBotName`。
7. 获取 **频道 ID**:右键点击频道 → *View channel details* → 它就在底部(例如 `C0123ABC`),或者它是频道 URL 的最后一段路径。
## 2. 配置
```
cd ~/projects/slack
cp .env.example .env # fill in the tokens
cp config/channels.example.json config/channels.json # map channel id -> project
cp config/senders.example.json config/senders.json # owner + guest permissions
```
编辑 `config/channels.json` —— 设置真实的频道 ID 以及 T3 项目 ID(`backend: "t3"`)或项目的 `cwd` + `persona` + `allowed_tools`(`backend: "claude"`;对于面向好友的频道,请保持最低权限原则)。
在 `config/senders.json` 中将你自己的 Slack 成员 ID 设置为 `role: "owner"` —— 其他所有人均默认为受审查且需要批准的 guest。
对于 `t3` 后端,还需在 `.env` 中设置 `SLACKCC_T3_URL`/`SLACKCC_T3_TOKEN`,并且如果你有 guest 发送者,请在 `SLACKCC_PPS_URL` 上运行 pps 判定器(独立的代码库/服务)——当其不可达时,guest 将会执行失败阻断。
## 3. 安装与运行
```
python -m venv .venv && . .venv/bin/activate
pip install -e .
./scripts/run.sh # loads .env, starts the daemon
```
现在在配置好的频道中发布一条消息——机器人会在该线程内回复,并且每个线程都会保持为一段连续的 Claude Code 对话。
## 4. 向项目传授桥接协议(仅限 `t3` 后端)
代理需要常规指令——你的回复会被自动发布,这里是上传文件的方法,这里是信任模型。在 `claude` 后端上,这些信息搭载于 system prompt 中,无需额外操作。T3 的 `thread.turn.start` 没有 system-prompt 字段,但 T3 会使用设置来源 `user,project,local` 来生成 session,因此项目自身的 `CLAUDE.md` 便是免费的传递通道:
```
slackcc init-project # every t3 channel's cwd in channels.json
slackcc init-project ~/projects/foo # or a specific project
```
这会将带有标记分隔的 `## Slack Bridge` 部分写入该项目的 `CLAUDE.md`,并在后续运行时原位重写它(你自己的内容不会被改动)。**提交它**——T3 线程可以在 git worktree 中运行,而那里只能看到已提交的文件。
跳过此步骤并不会造成致命影响:守护进程会检测到缺失的部分,并在线程的首次对话中改为内联注入协议,同时记录一条警告。这会在线程级别产生一次 token 消耗,而非完全无法使用。
## 测试
```
.venv/bin/python -m pytest tests/ # offline suite: 204 hermetic tests, ~6s
.venv/bin/python -m pytest tests/ -m live # + judge-quality tier: real inference
# against the running pps/guard LLM (~20s)
```
离线测试套件是回归防护网(无需网络,无实时服务——在任何地方都很安全,包括 CI)。`live` 层级是模型触发线:攻击性 prompt 必须被拒绝,良性的 guest 操作必须被允许——在更换守卫模型、更改量化方式或编辑判定器 prompt 后运行它。当 pps 未运行时,它会自动跳过。
## 代理发起的出站操作
要让 Claude Code(或你自己)从项目向频道发布消息:
```
slack-send C0123ABC "Here's the latest flyer draft — thoughts?"
slack-send C0123ABC "follow-up" --thread 1700000000.000100
```
## 布局
```
src/slackcc/
app.py Socket Mode daemon: routing, loop-prevention, pps gate
backend.py claude -p runner (the swappable agent seam)
backend_t3.py T3 Code turn runner (dispatch + poll over HTTP)
t3.py T3 HTTP client + mirror ledger store
t3_mirror.py background poller: T3 GUI turns -> Slack thread
pps.py client for the Prompt Protection Service judge
outbound.py secret scrubbing for everything posted to Slack
config.py env + channels.json + senders.json loading, per-sender policy
sessions.py thread -> session/thread id store (resume continuity)
sanitize.py fencing for the messages pps didn't gate
bridgedoc.py ships/renders/installs the bridge protocol
data/slack-bridge.md the protocol itself (package data)
send_cli.py `slack-send` outbound CLI
config/channels.example.json
config/senders.example.json
BACKLOG.md
```
标签:AI代理, LLM安全防护, Slack集成, 安全规则引擎, 权限控制, 自动化桥接, 逆向工具