Slack Bridge
The adapter that puts Pinet in your Slack sidebar. Socket Mode ingress, default-deny access, inbox tools, canvases, uploads, modals, and a manifest that configures the app for you.
$ pi install npm:@pinet/slack-bridgepin a version with @0.2.2 · node ≥ 22 · a workspace where you can install apps
Create the app from the manifest
- Open api.slack.com/apps.
Select "Create New App", then "From a manifest", then your workspace.
- Paste the manifest.
Use
slack-bridge/manifest.yaml. It configures Socket Mode, the assistant view, bot scopes, event subscriptions, and slash commands in one paste. - Optional: rename the slash command.
Change
features.slash_commands[0].commandbefore creating, and setslackCommandNameinsettings.jsonto match.
scopes the manifest grants
app_mentions:read assistant:write bookmarks:read
bookmarks:write canvases:read canvases:write
channels:history channels:read chat:write
commands files:read files:write
groups:history groups:read im:history
im:read im:write pins:read
pins:write reactions:read reactions:write
users:readfiles:read looks odd but is real: Slack paginates canvas comments through files.info.
Two tokens
| Token | Where | Format |
|---|---|---|
| App-level token | Basic Information → App-Level Tokens → Generate, with connections:write | xapp-1-… |
| Bot token | OAuth & Permissions → Install to Workspace → Bot User OAuth Token | xoxb-… |
Put them in ~/.pi/agent/settings.json, or exportSLACK_BOT_TOKEN / SLACK_APP_TOKEN; settings override the environment. Never commit tokens; use separate apps for development and production.
{
"slack-bridge": {
"botToken": "xoxb-your-bot-token",
"appToken": "xapp-your-app-token",
"runtimeMode": "single",
"allowedUsers": ["U_YOUR_USER_ID"]
}
}Start pi. Pinet appears in your sidebar. Pinet stays off unless runtimeMode,autoConnect, or autoFollow says otherwise.
Who gets in
Slack access is default-deny. Until you configure one of these, nobody can use Pinet:
- allowedUsers
- A list of Slack user IDs. To find one, open a profile and select "Copy member ID".
- allowAllWorkspaceUsers
- Everyone in the workspace. An explicit opt-in, never a default.
ingress guard
Authorization decides who can use Pinet. The ingress guard decides when a mention is required. In busy channels you can require an explicit @pinet before the bot engages, with trusted-user carve-outs for mixed-participant threads:
{
"slack-bridge": {
"ingressGuard": {
"requireMention": {
"channels": ["C_CHANNEL_ID"],
"mixedParticipantThreads": {
"enabled": true,
"trustedUsers": ["U_TRUSTED_USER"]
}
}
}
}
}Talking to Pinet
In Slack: DM the bot, mention @pinet in a channel, or use the slash command,/pinet agents list. In pi, the command set splits by role:
| Command | Effect |
|---|---|
/pinet status | Current Pinet state for this session. |
/pinet logs | Recent broker activity. |
/pinet rename [name] | Rename this agent. |
/pinet free | Mark this agent idle. |
/pinet start | Become the broker. |
/pinet follow / unfollow | Join or leave the mesh. |
/pinet reload <agent> | Ask another agent to reload. |
/pinet exit <agent> | Ask another agent to exit. |
/pinet snooze [duration] | Quiet empty RALPH cycles. |
/pinet subtree … | Manage subtree broker mode. |
Configuration
| Setting | Description | Default |
|---|---|---|
botToken | Bot User OAuth Token | required |
appToken | App-level token for Socket Mode | required |
runtimeMode | off · single · broker · follower | off |
allowedUsers | Slack user IDs allowed to use Pinet | unset (deny all) |
allowAllWorkspaceUsers | Allow every workspace member | false |
defaultChannel | Where Pinet posts updates | unset |
logChannel | Where Pinet posts logs | unset |
logLevel | errors · actions · verbose | actions |
autoConnect | Start as single instance when runtimeMode unset | false |
autoFollow | Start as follower if a broker exists | false |
ralphLoopIntervalMs | Stall-check interval | 300000 |
meshSecret / meshSecretPath | Shared-secret mesh auth | off |
suggestedPrompts | Prompt chips in the assistant view | unset |
mesh authentication
Optional shared-secret auth between broker and followers. Settings override environment variables (PINET_MESH_SECRET, PINET_MESH_SECRET_PATH); inline secrets override file paths. Brokers create the secret file if it does not exist; followers need an existing one. Unset means mesh auth is off.
Security posture
- default-deny
- No
allowedUsers, no access. There is no permissive default to forget. - confirmation gates
- Require explicit confirmation per action:
"security": { "requireConfirmation": ["slack:create_channel", "slack:upload", "slack:delete"] } - read-only mode
"security": { "readOnly": true }blocks all modifications.- guardrail naming
- Every cold action carries a precise name (
slack:upload,slack:canvas_update) so policies can target exactly one capability.
When something misbehaves
- no bot in sidebar
- Both tokens present in settings? App installed to the workspace? pi running?
- websocket errors
- Validate the app token, confirm Socket Mode is enabled, check connectivity. Slack caps connections at ten per app.
- no response
- Socket Mode shows "Connected"? Event subscriptions enabled? Sender in
allowedUsers? The log channel usually names the culprit. - permission errors
- Invite the bot (
/invite @pinet), verify scopes against the manifest, reinstall the app after scope changes. - stalled work
/pinet status, then/pinet logs. RALPH releases stale claims on its next cycle; lowerralphLoopIntervalMsfor faster recovery.