What you build
A private Slack channel where team members mention @rousseau with a repo path and a question. Rousseau checks out the workspace, runs read and grep from internal/tools/builtin/, and posts a reply with quoted line references. No public HTTP surface — Slack Socket Mode drives everything from outbound WebSocket.
Estimated time: 20 minutes assuming you already have Slack admin access to a workspace.
Prerequisites
- Rousseau installed and a provider configured (see Quickstart).
- Slack workspace admin.
- A repository already checked out at some path under your
$HOME— that becomes the "workspace" the bot canread/grepover.
Step 1: create a Slack app
Slack's Socket Mode is what makes this bot possible: your daemon opens an outbound WebSocket to Slack, no ingress required.
- Head to https://api.slack.com/apps and create a new app from scratch.
- Under Socket Mode, enable it and generate an app-level token with
connections:write. Copy thexapp-...value. - Under OAuth & Permissions, add these Bot Token Scopes:
chat:writeapp_mentions:readchannels:history(orgroups:historyfor private channels)
- Install the app to your workspace. Copy the Bot User OAuth Token — the
xoxb-...value. - Under Event Subscriptions, enable events and subscribe the bot to
app_mentionandmessage.channels(ormessage.groups). - Invite the bot to the review channel:
/invite @rousseau.
Step 2: configure rousseau
Add to ~/.config/rousseau/config.yaml. The relevant fields come from SlackConfig in internal/config/config.go:
provider: claudecli # or anthropic — whatever you set in Quickstart
slack:
app_token: xapp-1-…
bot_token: xoxb-…
bot_user_id: U0ROUSSEAU # from https://api.slack.com/methods/auth.test
reply_header: "*rousseau-agent*\n\n"
allowlist:
- U01ABC… # your Slack user IDs
agent:
approver:
mode: pattern
default: deny
allow:
- {tool: read, match: ".*"}
- {tool: grep, match: ".*"}
# no bash, no write, no edit — read-only reviewer
The allowlist restricts who the router will accept messages from. The internal/transport/router.go router emits transport.rejected for any other sender.
Step 3: run the bridge
rousseau slack \
--app-token "$SLACK_APP_TOKEN" \
--bot-token "$SLACK_BOT_TOKEN" \
--bot-user-id "$SLACK_BOT_USER_ID"
--bot-user-id prevents the bot from replying to its own messages. Structured logs from internal/transport/slack/client.go will show:
INFO slack.started
INFO slack.incoming from=U01ABC channel=C01REVIEW text="…"
INFO tool.execute name=read id=t_1
INFO tool.execute name=grep id=t_2
Step 4: try it
In the review channel:
@rousseau look under /home/seb/repos/acme-api and tell me
where request logging is set up
The claudecli provider (or Anthropic — whichever you chose) will call read and grep from internal/tools/builtin/ against the workspace bind mount. Because the approver runs pattern mode with only read and grep allowlisted, the model cannot write or shell out — even if a compromised prompt asks it to.
Step 5: harden
Pattern-mode approvers are regex over the JSON tool-input. To restrict read and grep to a specific project tree:
agent:
approver:
mode: pattern
default: deny
allow:
- {tool: read, match: "\"path\":\"/home/seb/repos/acme-api/[^\"]*\""}
- {tool: grep, match: "\"path\":\"/home/seb/repos/acme-api\""}
See Tutorial: Harden the approver for the full walkthrough of default: deny + audit.
Deploying under systemd
For anything beyond a laptop session, run the Slack bridge under the Podman Quadlet unit at docker/rousseau-agent.container — swap Exec=whatsapp --allow … for Exec=slack --app-token … --bot-token …. See Deployment for the full unit.