@pinet/slack-bridge 0.2.2 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +316 -451
- package/dist/activity-log.d.ts +10 -3
- package/dist/agent-event-runtime.d.ts +0 -2
- package/dist/agent-event-runtime.js +0 -1
- package/dist/agent-prompt-guidance.d.ts +1 -6
- package/dist/agent-prompt-guidance.js +1 -6
- package/dist/broker/adapters/slack.d.ts +4 -1
- package/dist/broker/adapters/slack.js +16 -9
- package/dist/broker/client.d.ts +21 -4
- package/dist/broker/client.js +65 -25
- package/dist/broker/hibernation-activation-authority.d.ts +22 -0
- package/dist/broker/hibernation-activation-authority.js +51 -0
- package/dist/broker/hibernation-activation.d.ts +75 -0
- package/dist/broker/hibernation-activation.js +95 -0
- package/dist/broker/hibernation-command-router.d.ts +54 -0
- package/dist/broker/hibernation-command-router.js +124 -0
- package/dist/broker/hibernation-runtime-adapters.d.ts +79 -0
- package/dist/broker/hibernation-runtime-adapters.js +473 -0
- package/dist/broker/hibernation-runtime-helpers.d.ts +146 -0
- package/dist/broker/hibernation-runtime-helpers.js +243 -0
- package/dist/broker/index.d.ts +16 -1
- package/dist/broker/index.js +68 -10
- package/dist/broker/lock-conflict.d.ts +109 -0
- package/dist/broker/lock-conflict.js +409 -0
- package/dist/broker/socket-server.d.ts +26 -0
- package/dist/broker/socket-server.js +287 -4
- package/dist/broker-delivery.d.ts +1 -0
- package/dist/broker-delivery.js +10 -1
- package/dist/broker-runtime.d.ts +14 -2
- package/dist/broker-runtime.js +114 -3
- package/dist/canvases.d.ts +12 -2
- package/dist/canvases.js +1 -3
- package/dist/compaction-gate.d.ts +7 -0
- package/dist/compaction-gate.js +35 -0
- package/dist/deploy-manifest.d.ts +8 -2
- package/dist/deploy-manifest.js +9 -7
- package/dist/follower-runtime.d.ts +5 -2
- package/dist/follower-runtime.js +39 -5
- package/dist/git-metadata.d.ts +5 -9
- package/dist/git-metadata.js +23 -42
- package/dist/guardrails.js +5 -0
- package/dist/helpers.d.ts +77 -27
- package/dist/helpers.js +150 -39
- package/dist/hibernation-config.d.ts +13 -0
- package/dist/hibernation-config.js +14 -0
- package/dist/home-tab.d.ts +13 -2
- package/dist/imessage-tools.d.ts +4 -1
- package/dist/inbox-drain-runtime.d.ts +1 -0
- package/dist/inbox-drain-runtime.js +5 -1
- package/dist/index.js +341 -108
- package/dist/pinet-commands.d.ts +14 -1
- package/dist/pinet-commands.js +93 -22
- package/dist/pinet-mesh-ops.d.ts +6 -4
- package/dist/pinet-mesh-ops.js +9 -1
- package/dist/pinet-runtime-composition.d.ts +2 -1
- package/dist/pinet-runtime-composition.js +14 -3
- package/dist/pinet-session-formatting.d.ts +26 -2
- package/dist/pinet-session-formatting.js +2 -0
- package/dist/pinet-tools.d.ts +14 -0
- package/dist/pinet-tools.js +355 -50
- package/dist/prompts/broker/default.md +3 -3
- package/dist/prompts/broker/tmux.md +3 -3
- package/dist/runtime-agent-context.d.ts +3 -3
- package/dist/runtime-agent-context.js +12 -6
- package/dist/runtime-mode.js +4 -0
- package/dist/session-ui-runtime.js +3 -1
- package/dist/single-player-runtime.d.ts +1 -1
- package/dist/single-player-runtime.js +21 -5
- package/dist/slack-access.d.ts +10 -2
- package/dist/slack-access.js +64 -22
- package/dist/slack-block-kit.d.ts +44 -2
- package/dist/slack-block-kit.js +5 -5
- package/dist/slack-file-access.d.ts +12 -1
- package/dist/slack-file-access.js +4 -4
- package/dist/slack-message-context.d.ts +9 -2
- package/dist/slack-modals.d.ts +4 -1
- package/dist/slack-modals.js +5 -5
- package/dist/slack-pinet-runtime-adapter.d.ts +1 -0
- package/dist/slack-pinet-runtime-adapter.js +10 -0
- package/dist/slack-presence.d.ts +5 -4
- package/dist/slack-request-runtime.d.ts +3 -2
- package/dist/slack-scope-diagnostics.d.ts +27 -2
- package/dist/slack-socket-dedup.d.ts +8 -5
- package/dist/slack-tools.d.ts +10 -0
- package/dist/slack-tools.js +51 -64
- package/dist/slack-upload.d.ts +17 -1
- package/dist/subtree-broker-runtime.d.ts +83 -2
- package/dist/subtree-broker-runtime.js +774 -109
- package/dist/tool-output-limits.d.ts +11 -0
- package/dist/tool-output-limits.js +20 -0
- package/dist/tool-registration-runtime.d.ts +3 -0
- package/dist/tool-registration-runtime.js +27 -0
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,157 +1,185 @@
|
|
|
1
1
|
# slack-bridge (Pinet)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Connect pi coding agents to Slack. Pinet provides multi-agent coordination, thread routing, and inbox tools through Socket Mode.
|
|
4
4
|
|
|
5
|
-
## Install
|
|
5
|
+
## Install Pinet
|
|
6
6
|
|
|
7
|
-
Install the latest
|
|
7
|
+
Install the latest version:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
pi install npm:@pinet/slack-bridge
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Pin a specific version:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
pi install npm:@pinet/slack-bridge@0.
|
|
16
|
+
pi install npm:@pinet/slack-bridge@0.2.2
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
For
|
|
19
|
+
For direct npm installation:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npm install @pinet/slack-bridge
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## What you need
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
- a Slack workspace where you can install apps
|
|
28
|
+
- Node.js 22 or later
|
|
29
|
+
- pi installed on your system
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
- `pi.extensions` points at the built extension entrypoint, `./dist/index.js`.
|
|
31
|
-
- `pi.skills` points at the bundled skill directory, `./skills`.
|
|
32
|
-
- No `pi.image` or `pi.video` preview is declared yet because this package does
|
|
33
|
-
not currently include a reviewed gallery image/video asset.
|
|
31
|
+
## Set up your Slack app
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
Slack app manifest, built `dist/` files, bundled `skills/`, and LICENSE. Verify
|
|
37
|
-
that locally with:
|
|
33
|
+
### Create the app
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
workflow's default dry-run/readiness path for validation; do not publish, tag, or
|
|
47
|
-
bump versions without explicit maintainer release approval.
|
|
48
|
-
|
|
49
|
-
## Prerequisites
|
|
50
|
-
|
|
51
|
-
- A Slack workspace where you have permission to install apps
|
|
52
|
-
- Node.js 22+ (uses native `fetch` and `WebSocket`)
|
|
53
|
-
- [pi](https://github.com/badlogic/pi-mono) installed
|
|
54
|
-
|
|
55
|
-
## Slack App Setup
|
|
35
|
+
1. Go to [api.slack.com/apps](https://api.slack.com/apps)
|
|
36
|
+
2. Select 'Create New App'
|
|
37
|
+
3. Choose 'From a manifest'
|
|
38
|
+
4. Select your workspace
|
|
39
|
+
5. Paste the contents of [`manifest.yaml`](./manifest.yaml)
|
|
40
|
+
6. If you want a different Slack command, change `features.slash_commands[0].command` before creating and set `slackCommandName` or `slackCommandNames` in `settings.json`
|
|
41
|
+
7. Select 'Create'
|
|
56
42
|
|
|
57
|
-
|
|
43
|
+
The manifest configures Socket Mode, the assistant view, bot scopes, event subscriptions, and slash commands automatically.
|
|
58
44
|
|
|
59
|
-
|
|
60
|
-
2. Choose **From a manifest**
|
|
61
|
-
3. Select your workspace
|
|
62
|
-
4. Paste the contents of [`manifest.yaml`](./manifest.yaml) from this directory
|
|
63
|
-
5. If the Slack app is not named Pinet, change `features.slash_commands[0].command` before creating the app (for example, Oathgate uses `/oathgate` instead of the packaged `/pinet` default)
|
|
64
|
-
6. Click **Create**
|
|
45
|
+
### Get your tokens
|
|
65
46
|
|
|
66
|
-
|
|
47
|
+
Generate two tokens:
|
|
67
48
|
|
|
68
|
-
|
|
49
|
+
| Token | Where to find it | Format |
|
|
50
|
+
| --------------- | ------------------------------------------------------------------------------- | ------------ |
|
|
51
|
+
| App-Level Token | Basic Information → App-Level Tokens → Generate (add `connections:write` scope) | `xapp-1-...` |
|
|
52
|
+
| Bot Token | OAuth & Permissions → Install to Workspace → Bot User OAuth Token | `xoxb-...` |
|
|
69
53
|
|
|
70
|
-
|
|
54
|
+
### Required bot scopes
|
|
71
55
|
|
|
72
|
-
|
|
73
|
-
| ------------------- | -------------------------------------------------------------------------------- | ------------ |
|
|
74
|
-
| **App-Level Token** | Basic Information → App-Level Tokens → Generate (with `connections:write` scope) | `xapp-1-...` |
|
|
75
|
-
| **Bot Token** | OAuth & Permissions → Install to Workspace → Bot User OAuth Token | `xoxb-...` |
|
|
76
|
-
|
|
77
|
-
### 3. Required bot scopes
|
|
78
|
-
|
|
79
|
-
These are included in the manifest, but for reference:
|
|
56
|
+
The manifest includes these scopes:
|
|
80
57
|
|
|
81
58
|
```
|
|
82
59
|
app_mentions:read assistant:write bookmarks:read
|
|
83
60
|
bookmarks:write canvases:read canvases:write
|
|
84
61
|
channels:history channels:read chat:write
|
|
85
|
-
commands files:read files:write
|
|
86
|
-
groups:read im:history
|
|
87
|
-
im:write pins:read
|
|
88
|
-
reactions:read reactions:write
|
|
62
|
+
commands files:read files:write
|
|
63
|
+
groups:history groups:read im:history
|
|
64
|
+
im:read im:write pins:read
|
|
65
|
+
pins:write reactions:read reactions:write
|
|
66
|
+
users:read
|
|
89
67
|
```
|
|
90
68
|
|
|
91
|
-
`commands`
|
|
69
|
+
The `commands` scope enables slash commands. The `files:read` scope is needed because Slack uses `files.info` for canvas comment pagination.
|
|
92
70
|
|
|
93
|
-
|
|
71
|
+
## Configure Pinet
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Add your tokens to `~/.pi/agent/settings.json`:
|
|
73
|
+
Add tokens, runtime mode, and access rules to `~/.pi/agent/settings.json`:
|
|
98
74
|
|
|
99
75
|
```json
|
|
100
76
|
{
|
|
101
77
|
"slack-bridge": {
|
|
102
78
|
"botToken": "xoxb-your-bot-token",
|
|
103
|
-
"appToken": "xapp-your-app-token"
|
|
79
|
+
"appToken": "xapp-your-app-token",
|
|
80
|
+
"runtimeMode": "single",
|
|
81
|
+
"allowedUsers": ["U_YOUR_USER_ID"]
|
|
104
82
|
}
|
|
105
83
|
}
|
|
106
84
|
```
|
|
107
85
|
|
|
108
|
-
|
|
86
|
+
Pinet stays off unless you set `runtimeMode`, `autoConnect`, or `autoFollow`. Start pi after you configure access.
|
|
109
87
|
|
|
110
|
-
###
|
|
88
|
+
### Use environment variables instead
|
|
111
89
|
|
|
112
90
|
```bash
|
|
113
91
|
export SLACK_BOT_TOKEN="xoxb-..."
|
|
114
92
|
export SLACK_APP_TOKEN="xapp-..."
|
|
115
93
|
```
|
|
116
94
|
|
|
117
|
-
Settings in `settings.json`
|
|
95
|
+
Settings in `settings.json` override environment variables.
|
|
96
|
+
|
|
97
|
+
## Control who can use Pinet
|
|
98
|
+
|
|
99
|
+
Slack access is default-deny. Configure one of these:
|
|
100
|
+
|
|
101
|
+
- `allowedUsers`: list specific Slack user IDs
|
|
102
|
+
- `allowAllWorkspaceUsers: true`: allow everyone in the workspace
|
|
103
|
+
|
|
104
|
+
Example with specific users:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"slack-bridge": {
|
|
109
|
+
"botToken": "xoxb-...",
|
|
110
|
+
"appToken": "xapp-...",
|
|
111
|
+
"allowedUsers": ["U_USER_ID_1", "U_USER_ID_2"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Find user IDs by selecting a user's profile in Slack and choosing 'Copy member ID'.
|
|
117
|
+
|
|
118
|
+
## Optional settings
|
|
118
119
|
|
|
119
|
-
###
|
|
120
|
+
### Mesh authentication
|
|
120
121
|
|
|
121
|
-
Shared-secret
|
|
122
|
+
Shared-secret authentication is optional. Configure it with settings or environment variables:
|
|
123
|
+
|
|
124
|
+
Settings:
|
|
122
125
|
|
|
123
126
|
```json
|
|
124
127
|
{
|
|
125
128
|
"slack-bridge": {
|
|
126
|
-
"meshSecret": "shared-secret"
|
|
129
|
+
"meshSecret": "your-shared-secret"
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
```
|
|
130
133
|
|
|
134
|
+
Or use a file:
|
|
135
|
+
|
|
131
136
|
```json
|
|
132
137
|
{
|
|
133
138
|
"slack-bridge": {
|
|
134
|
-
"meshSecretPath": "/
|
|
139
|
+
"meshSecretPath": "/path/to/secret.txt"
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
```
|
|
138
143
|
|
|
144
|
+
Environment variables:
|
|
145
|
+
|
|
139
146
|
```bash
|
|
140
|
-
export PINET_MESH_SECRET="shared-secret"
|
|
147
|
+
export PINET_MESH_SECRET="your-shared-secret"
|
|
141
148
|
# or
|
|
142
|
-
export PINET_MESH_SECRET_PATH="
|
|
149
|
+
export PINET_MESH_SECRET_PATH="/path/to/secret.txt"
|
|
143
150
|
```
|
|
144
151
|
|
|
145
|
-
|
|
152
|
+
How it works:
|
|
146
153
|
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
- A follower configured for mesh auth will fail closed against an older/no-auth broker with a clear compatibility error. It will **not** silently retry as an unauthenticated follower.
|
|
154
|
+
- settings override environment variables
|
|
155
|
+
- inline secrets override file paths
|
|
156
|
+
- if nothing is set, mesh auth is disabled
|
|
157
|
+
- brokers create the secret file if it does not exist
|
|
158
|
+
- followers need an existing file or will show an error
|
|
153
159
|
|
|
154
|
-
###
|
|
160
|
+
### Require mentions in channels
|
|
161
|
+
|
|
162
|
+
Make Pinet respond only when mentioned in specific channels:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"slack-bridge": {
|
|
167
|
+
"ingressGuard": {
|
|
168
|
+
"requireMention": {
|
|
169
|
+
"channels": ["C_CHANNEL_ID"],
|
|
170
|
+
"mixedParticipantThreads": {
|
|
171
|
+
"enabled": true,
|
|
172
|
+
"trustedUsers": ["U_TRUSTED_USER"]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
This is separate from `allowedUsers`. Authorization decides who can use Pinet. The guard decides when a mention is needed.
|
|
181
|
+
|
|
182
|
+
### All configuration options
|
|
155
183
|
|
|
156
184
|
```json
|
|
157
185
|
{
|
|
@@ -159,25 +187,32 @@ Behavior and precedence:
|
|
|
159
187
|
"botToken": "xoxb-...",
|
|
160
188
|
"appToken": "xapp-...",
|
|
161
189
|
"runtimeMode": "single",
|
|
162
|
-
"allowedUsers": ["
|
|
190
|
+
"allowedUsers": ["U_USER_ID"],
|
|
191
|
+
"allowAllWorkspaceUsers": false,
|
|
163
192
|
"ingressGuard": {
|
|
164
193
|
"requireMention": {
|
|
165
|
-
"channels": ["
|
|
194
|
+
"channels": ["C_CHANNEL_ID"],
|
|
166
195
|
"mixedParticipantThreads": {
|
|
167
196
|
"enabled": true,
|
|
168
|
-
"trustedUsers": ["
|
|
197
|
+
"trustedUsers": ["U_USER_ID"]
|
|
169
198
|
}
|
|
170
199
|
}
|
|
171
200
|
},
|
|
172
|
-
"defaultChannel": "
|
|
201
|
+
"defaultChannel": "C_CHANNEL_ID",
|
|
173
202
|
"logChannel": "#pinet-logs",
|
|
174
203
|
"logLevel": "actions",
|
|
175
|
-
"
|
|
204
|
+
"autoConnect": false,
|
|
205
|
+
"autoFollow": false,
|
|
176
206
|
"ralphLoopIntervalMs": 300000,
|
|
177
207
|
"ralphSnoozeAfterEmptyCycles": 0,
|
|
178
208
|
"ralphSnoozeDurationMs": 1800000,
|
|
179
|
-
"meshSecretPath": "/
|
|
180
|
-
"suggestedPrompts": [
|
|
209
|
+
"meshSecretPath": "/path/to/secret",
|
|
210
|
+
"suggestedPrompts": [
|
|
211
|
+
{
|
|
212
|
+
"title": "Status",
|
|
213
|
+
"message": "What are you working on?"
|
|
214
|
+
}
|
|
215
|
+
],
|
|
181
216
|
"security": {
|
|
182
217
|
"readOnly": false,
|
|
183
218
|
"requireConfirmation": ["slack:create_channel"],
|
|
@@ -187,450 +222,280 @@ Behavior and precedence:
|
|
|
187
222
|
}
|
|
188
223
|
```
|
|
189
224
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
|
198
|
-
|
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `logChannel` | no | Channel for broker activity logs |
|
|
206
|
-
| `logLevel` | no | `"errors"`, `"actions"` (default), or `"verbose"` |
|
|
207
|
-
| `runtimeMode` | no | Explicit startup mode: `"off"`, `"single"`, `"broker"`, or `"follower"` |
|
|
208
|
-
| `autoConnect` | no | Legacy compatibility alias for `runtimeMode: "single"` |
|
|
209
|
-
| `autoFollow` | no | Legacy compatibility alias for follower startup when a broker socket exists |
|
|
210
|
-
| `ralphLoopIntervalMs` | no | Broker RALPH maintenance cadence in milliseconds; defaults to `300000` (5 minutes), valid range `1000`-`2147483647` |
|
|
211
|
-
| `ralphSnoozeAfterEmptyCycles` | no | Broker RALPH auto-snooze trigger after N empty cycles; defaults to `0` (disabled), valid range `0`-`100` |
|
|
212
|
-
| `ralphSnoozeDurationMs` | no | Broker RALPH auto-snooze duration in milliseconds; defaults to `1800000` (30 minutes), valid range `60000`-`86400000` |
|
|
213
|
-
| `skinTheme` | no | Pinet presentation skin selected at broker startup/reload (`default`, `foundation`, `cosmere`, or free-form) |
|
|
214
|
-
| `slackCommandName` | no | Slack web app slash command name for `agents list`; defaults to `/pinet`, or `/oathgate` for Oathgate/Cosmere skins |
|
|
215
|
-
| `slackCommandNames` | no | Optional list of accepted/deployed Slack slash command aliases when one app needs multiple command names |
|
|
216
|
-
| `meshSecret` | no | Optional inline Pinet shared secret; overrides `meshSecretPath` and env fallbacks |
|
|
217
|
-
| `meshSecretPath` | no | Optional path to a shared-secret file; broker creates it if missing, followers require an existing file |
|
|
218
|
-
| `suggestedPrompts` | no | Prompts shown when a user opens a new conversation |
|
|
219
|
-
| `security.readOnly` | no | Runtime-block write-capable tools for Slack-triggered turns, including core tools like `bash`, `edit`, and `write` |
|
|
220
|
-
| `security.requireConfirmation` | no | Runtime-require Slack approval before matching tools execute; core tools need a specific Slack thread context |
|
|
221
|
-
| `security.blockedTools` | no | Runtime-block matching tools for Slack-triggered turns, including core tools |
|
|
222
|
-
|
|
223
|
-
## Scope carrier model (compatibility-first)
|
|
224
|
-
|
|
225
|
-
Slack/Pinet now threads a first-class runtime `scope` carrier through shared message contracts and runtime metadata.
|
|
226
|
-
|
|
227
|
-
For this first slice:
|
|
228
|
-
|
|
229
|
-
- **workspace/install scope** is carried as compatibility-first metadata for Slack
|
|
230
|
-
- **instance scope** is also carried as a first-class compatibility carrier
|
|
231
|
-
- today’s single-workspace deployments use one default compatibility scope
|
|
232
|
-
- a missing or empty Slack `teamId` stays **unknown** — the bridge does not invent a fake workspace ID
|
|
233
|
-
- these carriers are metadata only in this slice; enforcement and multi-install behavior land later in `#547` / `#550`
|
|
234
|
-
|
|
235
|
-
## Usage
|
|
236
|
-
|
|
237
|
-
Once configured, Pinet appears in Slack's sidebar. Users open it, type a message, and the pi agent responds.
|
|
225
|
+
| Setting | Description | Default |
|
|
226
|
+
| ------------------------ | ------------------------------------------------------ | -------------------- |
|
|
227
|
+
| `botToken` | Bot User OAuth Token (required) | none |
|
|
228
|
+
| `appToken` | App-Level Token for Socket Mode (required) | none |
|
|
229
|
+
| `runtimeMode` | How Pinet runs (`off`, `single`, `broker`, `follower`) | `off` |
|
|
230
|
+
| `allowedUsers` | Slack user IDs who can use Pinet | none |
|
|
231
|
+
| `allowAllWorkspaceUsers` | Allow all workspace members | `false` |
|
|
232
|
+
| `defaultChannel` | Where to post updates | none |
|
|
233
|
+
| `logChannel` | Where to post logs | none |
|
|
234
|
+
| `logLevel` | What to log (`errors`, `actions`, `verbose`) | `actions` |
|
|
235
|
+
| `autoConnect` | Start as a single instance when `runtimeMode` is unset | `false` |
|
|
236
|
+
| `autoFollow` | Start as follower if broker exists | `false` |
|
|
237
|
+
| `ralphLoopIntervalMs` | How often to check for stalls (milliseconds) | `300000` (5 minutes) |
|
|
238
|
+
| `meshSecret` | Shared secret for mesh auth | none |
|
|
239
|
+
| `meshSecretPath` | File containing shared secret | none |
|
|
238
240
|
|
|
239
|
-
|
|
240
|
-
User opens Pinet in Slack sidebar
|
|
241
|
-
└─► types a message
|
|
242
|
-
└─► 👀 reaction appears (thinking)
|
|
243
|
-
└─► message queued for pi agent
|
|
244
|
-
└─► agent responds via slack_send
|
|
245
|
-
└─► 👀 removed, reply appears in thread
|
|
246
|
-
```
|
|
241
|
+
## Using Pinet
|
|
247
242
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
### Reaction triggers
|
|
251
|
-
|
|
252
|
-
Slack emoji reactions are ignored by default: they do not enqueue Pinet work, trigger reviews, steer agents, interrupt owners, or cause broker/worker replies. To opt in deliberately, configure `reactionCommands` for the exact emoji aliases that should become structured Pinet requests from the reacted-to Slack message. Even configured reactions are accepted only inside an already authorized Pinet thread (for example a thread with a current Pinet owner, or persisted Slack assistant-thread context). Reaction authorization is deny-by-default: it requires an explicit broker-backed authorization gate, and a thread the adapter has merely seen or cached never qualifies on its own. Reactions in ordinary, uninvoked Slack channel threads remain no-op — even from authorized users — and they do not enqueue work, persist thread state, claim ownership, or receive a Slack ACK. Messages and interactive events from users outside the allowlist also never mint known-thread state that could later admit reactions or replies. Pinet adds ✅ only when it accepts an opt-in reaction-triggered request. If it cannot process an accepted opted-in reaction, it adds ❌; check broker logs for the underlying Slack/API error. When Slack cannot return the reacted message text, Pinet can still route configured reactions when the message timestamp itself identifies an already authorized thread; otherwise it ignores the reaction safely.
|
|
253
|
-
|
|
254
|
-
### Available tools
|
|
255
|
-
|
|
256
|
-
Slack-bridge uses progressive disclosure to keep the per-turn tool surface
|
|
257
|
-
small:
|
|
258
|
-
|
|
259
|
-
| Tool | Description |
|
|
260
|
-
| ------------- | --------------------------------------------------------------------------- |
|
|
261
|
-
| `slack_inbox` | Hot-path inbox drain for pending incoming Slack messages |
|
|
262
|
-
| `slack_send` | Hot-path reply tool for Slack assistant threads |
|
|
263
|
-
| `slack` | Dispatcher for all non-hot Slack actions; call `action: "help"` for schemas |
|
|
264
|
-
|
|
265
|
-
Cold Slack actions live behind the `slack` dispatcher:
|
|
266
|
-
|
|
267
|
-
| Dispatcher action | Description |
|
|
268
|
-
| ---------------------- | --------------------------------------------------------------------------------- |
|
|
269
|
-
| `react` | Add an emoji reaction to a message |
|
|
270
|
-
| `read` | Read messages from a thread |
|
|
271
|
-
| `upload` | Upload files, snippets, or diffs into Slack |
|
|
272
|
-
| `file` | Download Slack-hosted files to a controlled local temp cache by file ID |
|
|
273
|
-
| `schedule` | Schedule a message for later delivery |
|
|
274
|
-
| `post_channel` | Post to a channel (by name or ID) |
|
|
275
|
-
| `delete` | Delete a bot-posted message or an entire thread |
|
|
276
|
-
| `read_channel` | Read channel history or a thread in a channel |
|
|
277
|
-
| `create_channel` | Create a new Slack channel |
|
|
278
|
-
| `project_create` | Create a project channel + RFC canvas + bot invite in one call |
|
|
279
|
-
| `pin` | Pin or unpin a message |
|
|
280
|
-
| `bookmark` | Add, list, or remove channel bookmarks |
|
|
281
|
-
| `export` | Export a thread as markdown, plain text, or JSON |
|
|
282
|
-
| `presence` | Check if users are active, away, or in DND |
|
|
283
|
-
| `canvas_comments_read` | Read comments attached to a verified canvas by canvas ID or channel canvas lookup |
|
|
284
|
-
| `canvas_create` | Create a standalone or channel canvas |
|
|
285
|
-
| `canvas_update` | Append, prepend, or replace canvas content |
|
|
286
|
-
| `modal_open` | Open a modal from a trigger interaction |
|
|
287
|
-
| `modal_push` | Push a new step onto a modal stack |
|
|
288
|
-
| `modal_update` | Update an existing open modal |
|
|
289
|
-
| `confirm_action` | Request user confirmation before a dangerous action |
|
|
290
|
-
|
|
291
|
-
Use `slack` with `action: "help"` for the action catalogue, or
|
|
292
|
-
`action: "help", args: { "topic": "canvas_update" }` for a specific JSON
|
|
293
|
-
schema and example invocations. Dispatcher responses use a consistent
|
|
294
|
-
`{ "status", "data", "errors", "warnings" }` envelope. Guardrails match
|
|
295
|
-
cold Slack actions as `slack:<action>` (for example `slack:upload` or
|
|
296
|
-
`slack:canvas_update`); legacy `slack_<action>` patterns are accepted during
|
|
297
|
-
migration.
|
|
298
|
-
|
|
299
|
-
#### Tool and workflow usage notes
|
|
300
|
-
|
|
301
|
-
- **Reply where the work arrived.** Use `slack_send` for assistant-thread
|
|
302
|
-
replies. If a task was delivered in a Slack thread, acknowledge briefly,
|
|
303
|
-
do the work, report blockers immediately, and finish with the outcome. If
|
|
304
|
-
you know only a channel/thread pair, use dispatcher action `post_channel`
|
|
305
|
-
with `channel` and optional `thread_ts` instead.
|
|
306
|
-
- **Channel posting is explicit.** `post_channel` posts to a named channel or
|
|
307
|
-
channel ID. When `channel` is omitted, it first resolves a provided
|
|
308
|
-
`thread_ts` to a tracked thread channel, then falls back to `defaultChannel`
|
|
309
|
-
from settings. `slack_send` is intentionally narrower and resolves the
|
|
310
|
-
current tracked assistant thread/DM context.
|
|
311
|
-
- **Rich messages use Block Kit JSON.** Pass `blocks` directly to
|
|
312
|
-
`slack_send` or `post_channel`; keep `text` as the notification/fallback.
|
|
313
|
-
Block Kit builder tools are not registered by this package. Load the bundled
|
|
314
|
-
`slack-bridge` skill for copyable status-report, button, code, and diff
|
|
315
|
-
templates. The package also bundles `pinet-skin-creator` for safely drafting
|
|
316
|
-
or reviewing curated Pinet skin descriptors and character/status-vocabulary
|
|
317
|
-
pools before changing runtime skin wiring.
|
|
318
|
-
- **Modal helpers are patterns, not hot tools.** Use dispatcher actions
|
|
319
|
-
`modal_open`, `modal_push`, and `modal_update` with Slack view JSON. Open or
|
|
320
|
-
push immediately after receiving a fresh `trigger_id`; Slack trigger IDs
|
|
321
|
-
expire quickly. Include `thread_ts` when submissions should route back to an
|
|
322
|
-
original assistant thread.
|
|
323
|
-
- **Uploads are for bulky artifacts.** Use `upload` for logs, screenshots,
|
|
324
|
-
long diffs, and generated files instead of large inline messages. Inline
|
|
325
|
-
uploads require `filename`; path uploads are guarded and must stay within the
|
|
326
|
-
current working directory or system temp directory. `slack_send` also accepts
|
|
327
|
-
`files: [{ path, filename?, title?, filetype? }]` so one assistant-thread
|
|
328
|
-
reply can contain both text and local binary attachments in the same Slack
|
|
329
|
-
file upload message. Slack external file uploads cannot include Block Kit in
|
|
330
|
-
that same message, so omit `blocks` when sending files or send a separate
|
|
331
|
-
block-only reply.
|
|
332
|
-
- **Inbound Slack files are fetched explicitly.** Incoming file-share messages
|
|
333
|
-
preserve safe `slackFiles` metadata such as file ID, name, type, size, and
|
|
334
|
-
permalink, but private Slack download URLs are not exposed in normal tool
|
|
335
|
-
output. To inspect raw content, call dispatcher action `file` with
|
|
336
|
-
`op: "download"`, `file_id`, and optionally `thread_ts`, `message_ts`, and
|
|
337
|
-
`channel`. The bot fetches the file with Slack bot auth, stores it under the
|
|
338
|
-
system temp `pi-slack-files` cache with best-effort TTL cleanup, and returns a
|
|
339
|
-
descriptor containing the local path, filename, type, size, SHA-256, expiry,
|
|
340
|
-
and residual privacy risks.
|
|
341
|
-
- **Upload host egress note.** The second upload leg goes to Slack file upload
|
|
342
|
-
hosts (`files.slack.com`/`uploads.slack.com`) for the raw payload. In
|
|
343
|
-
environments with restricted egress this can fail with `403` (proxy
|
|
344
|
-
allowlist) or DNS errors after `files.getUploadURLExternal`; verify the proxy
|
|
345
|
-
allowlist first, or route through an environment that can reach those hosts.
|
|
346
|
-
- **Upload metadata note.** Slack snippet uploads attempt to use inferred
|
|
347
|
-
`snippet_type` values for inline content and retry with plain upload metadata
|
|
348
|
-
when Slack returns `invalid_arguments`, preserving syntax highlighting for
|
|
349
|
-
supported types while avoiding hard failures on unsupported snippet types.
|
|
350
|
-
- **Canvases are long-lived docs.** `canvas_create` creates standalone or
|
|
351
|
-
channel canvases. If Slack rejects channel tab creation with
|
|
352
|
-
`canvas_tab_creation_failed`, it falls back to a standalone canvas attached to
|
|
353
|
-
the channel, attempts to bookmark the canvas URL, and returns the fallback
|
|
354
|
-
`canvas_id` for future `canvas_update` calls. `canvas_update` can append,
|
|
355
|
-
prepend, replace the whole canvas, or replace a matched section;
|
|
356
|
-
`canvas_comments_read` is read-only and limited to verified canvas targets.
|
|
357
|
-
- **Scheduling, pins, and bookmarks are durable affordances.** Use `schedule`
|
|
358
|
-
for delayed reminders instead of waiting; use `pin` for important thread
|
|
359
|
-
messages; use `bookmark` for persistent channel-header links to repos,
|
|
360
|
-
dashboards, docs, or runbooks.
|
|
361
|
-
- **Presence helps choose timing.** Use `presence` before pinging humans when
|
|
362
|
-
active/away/DND status affects routing or whether to schedule a follow-up.
|
|
363
|
-
- **Destructive actions stay constrained.** `delete` can remove only messages
|
|
364
|
-
posted by the current bot and every delete call requires `confirm: true`.
|
|
365
|
-
Whole-thread deletion additionally requires `thread: true` and succeeds only
|
|
366
|
-
when every message in the target thread belongs to the current bot. Prefer
|
|
367
|
-
asking for explicit approval before destructive cleanup.
|
|
368
|
-
- **Confirm guarded actions in the same thread.** If guardrails require
|
|
369
|
-
confirmation, call `confirm_action` with the target `thread_ts`, exact tool
|
|
370
|
-
name, and the exact action string required by the guarded tool. The safest
|
|
371
|
-
flow is: attempt the guarded call, copy the `requires confirmation for action
|
|
372
|
-
...` string from the error, request confirmation, wait for the user's approval
|
|
373
|
-
via `slack_inbox`, then retry the guarded call unchanged. Batched
|
|
374
|
-
multi-thread Slack turns cannot satisfy a single-thread confirmation.
|
|
375
|
-
- **Plain emoji reactions are not tasks.** Slack emoji reactions are ignored
|
|
376
|
-
unless `reactionCommands` explicitly opts that emoji into structured
|
|
377
|
-
reaction-trigger handling and the reacted message belongs to an already
|
|
378
|
-
authorized Pinet thread. If an opt-in reaction-triggered request or a Block
|
|
379
|
-
Kit/modal interaction payload arrives through `slack_inbox` with metadata,
|
|
380
|
-
treat it as a user instruction tied to the referenced Slack thread or
|
|
381
|
-
message.
|
|
382
|
-
|
|
383
|
-
#### Common dispatcher examples
|
|
384
|
-
|
|
385
|
-
Reply in the current Slack assistant thread with Block Kit:
|
|
243
|
+
### In Slack
|
|
386
244
|
|
|
387
|
-
|
|
388
|
-
{
|
|
389
|
-
"text": "Deploy complete — branch main, checks passed.",
|
|
390
|
-
"blocks": [
|
|
391
|
-
{
|
|
392
|
-
"type": "section",
|
|
393
|
-
"fields": [
|
|
394
|
-
{ "type": "mrkdwn", "text": "*Branch*\n`main`" },
|
|
395
|
-
{ "type": "mrkdwn", "text": "*Checks*\n✅ lint/typecheck/test" }
|
|
396
|
-
]
|
|
397
|
-
}
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
```
|
|
245
|
+
Talk to Pinet:
|
|
401
246
|
|
|
402
|
-
|
|
247
|
+
- Direct message: open a DM with Pinet
|
|
248
|
+
- In channels: mention `@pinet` (or your app name)
|
|
249
|
+
- Slack slash command: type `/pinet agents list` or `/pinet agents list all`
|
|
403
250
|
|
|
404
|
-
|
|
405
|
-
{
|
|
406
|
-
"action": "post_channel",
|
|
407
|
-
"args": {
|
|
408
|
-
"channel": "#pinet-logs",
|
|
409
|
-
"thread_ts": "1712345678.000100",
|
|
410
|
-
"text": "PR #123 is ready for review."
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
```
|
|
251
|
+
### Pi commands
|
|
414
252
|
|
|
415
|
-
|
|
253
|
+
Run these inside pi.
|
|
416
254
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
"title": "Docs changes",
|
|
425
|
-
"thread_ts": "1712345678.000100"
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
```
|
|
255
|
+
Main commands:
|
|
256
|
+
|
|
257
|
+
- `/pinet` - show available commands
|
|
258
|
+
- `/pinet status` - show current Pinet status
|
|
259
|
+
- `/pinet logs` - show recent broker activity logs
|
|
260
|
+
- `/pinet rename [name]` - rename this agent
|
|
261
|
+
- `/pinet free` - mark this agent idle
|
|
429
262
|
|
|
430
|
-
|
|
431
|
-
|
|
263
|
+
Coordinator commands:
|
|
264
|
+
|
|
265
|
+
- `/pinet start` or `/pinet broker` - become the broker
|
|
266
|
+
- `/pinet start replace` - take over a stale or stranded broker (graceful shutdown first, then a fenced SIGTERM fallback)
|
|
267
|
+
- `/pinet follow` - become a follower
|
|
268
|
+
- `/pinet unfollow` - disconnect from broker
|
|
269
|
+
- `/pinet reload <agent>` - ask another agent to reload
|
|
270
|
+
- `/pinet exit <agent>` - ask another agent to exit
|
|
271
|
+
- `/pinet snooze [duration|off|status]` - quiet empty RALPH cycles
|
|
272
|
+
- `/pinet subtree [start|status|spawn|stop]` - manage subtree broker mode
|
|
273
|
+
|
|
274
|
+
### From pi
|
|
275
|
+
|
|
276
|
+
Use the Pinet dispatcher for agent coordination:
|
|
432
277
|
|
|
433
278
|
```json
|
|
434
279
|
{
|
|
435
|
-
"action": "
|
|
280
|
+
"action": "send",
|
|
436
281
|
"args": {
|
|
437
|
-
"
|
|
438
|
-
"
|
|
439
|
-
"action": "channel=#pinet-logs | thread_ts=1712345678.000100 | ts=1712345678.000200 | thread=false"
|
|
282
|
+
"to": "@worker",
|
|
283
|
+
"message": "Please review PR #123"
|
|
440
284
|
}
|
|
441
285
|
}
|
|
442
286
|
```
|
|
443
287
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
The `canvas_comments_read` dispatcher action is intentionally narrow:
|
|
447
|
-
|
|
448
|
-
- it validates the target with `canvases.sections.lookup` before reading comment pages via `files.info`
|
|
449
|
-
- it needs `files:read` because Slack exposes canvas comments through the file API surface
|
|
450
|
-
- it will **not** inspect generic Slack files, non-canvas file comments, or full canvas body/history
|
|
451
|
-
|
|
452
|
-
### Slash commands
|
|
453
|
-
|
|
454
|
-
| Command | Description |
|
|
455
|
-
| -------------------------- | ---------------------------------------------------------- |
|
|
456
|
-
| `/pinet <action>` | Unified Pinet command surface; run `/pinet help` for usage |
|
|
457
|
-
| `/pinet status` | Show connection status, threads, and agent identity |
|
|
458
|
-
| `/pinet rename` | Change the agent's display name |
|
|
459
|
-
| `/pinet logs` | Show recent broker activity log entries |
|
|
460
|
-
| `/<app> agents list [all]` | Slack-native broker roster, workload, task, and lane view |
|
|
288
|
+
Common actions:
|
|
461
289
|
|
|
462
|
-
|
|
290
|
+
- `send` - send a message to an agent or broker-only channel
|
|
291
|
+
- `read` - read this agent's inbox
|
|
292
|
+
- `schedule` - schedule a future wake-up
|
|
293
|
+
- `free` - mark this agent idle
|
|
294
|
+
- `help` - discover actions and schemas
|
|
463
295
|
|
|
464
|
-
`
|
|
296
|
+
Use `slack_send` for hot-path Slack replies. Use the `slack` dispatcher for uploads, canvases, pins, bookmarks, and other Slack actions.
|
|
465
297
|
|
|
466
|
-
|
|
467
|
-
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
468
|
-
| `off` | Slack bridge is loaded, but **no Slack Socket Mode ingress** and no coordination runtime are started. |
|
|
469
|
-
| `single` | One local Pi session owns Slack ingress and local thread/inbox ownership only. No broker DB/socket/client, no RALPH/control plane, no mesh auth, no multi-agent surface. |
|
|
470
|
-
| `broker` | The session runs the broker coordination runtime. |
|
|
471
|
-
| `follower` | The session connects to an existing broker as a worker runtime. |
|
|
298
|
+
## Architecture
|
|
472
299
|
|
|
473
|
-
|
|
300
|
+
### Broker and followers
|
|
474
301
|
|
|
475
|
-
|
|
476
|
-
- `autoConnect` is a legacy compatibility alias for `runtimeMode: "single"`.
|
|
477
|
-
- `autoFollow` is a legacy compatibility alias for `runtimeMode: "follower"` when a broker socket is available.
|
|
478
|
-
- explicit `runtimeMode` wins over the legacy flags.
|
|
479
|
-
- `/pinet start` and `/pinet follow` still switch the live session into broker/follower runtimes explicitly.
|
|
302
|
+
Pinet can run as:
|
|
480
303
|
|
|
481
|
-
|
|
304
|
+
- single - one instance handles everything
|
|
305
|
+
- broker - coordinates and routes messages
|
|
306
|
+
- follower - receives work from the broker
|
|
482
307
|
|
|
483
|
-
|
|
308
|
+
The broker:
|
|
484
309
|
|
|
485
|
-
-
|
|
486
|
-
-
|
|
487
|
-
-
|
|
488
|
-
-
|
|
489
|
-
- this slice is metadata/plumbing only: it does **not** change routing, enforcement, or multi-install orchestration yet
|
|
310
|
+
- watches Slack for messages
|
|
311
|
+
- assigns work to agents
|
|
312
|
+
- tracks who owns what
|
|
313
|
+
- syncs state across followers
|
|
490
314
|
|
|
491
|
-
|
|
315
|
+
Followers:
|
|
492
316
|
|
|
493
|
-
|
|
317
|
+
- connect to the broker
|
|
318
|
+
- receive assigned work
|
|
319
|
+
- stay in sync automatically
|
|
494
320
|
|
|
495
|
-
###
|
|
321
|
+
### RALPH maintenance loop
|
|
496
322
|
|
|
497
|
-
|
|
323
|
+
RALPH keeps broker state healthy. It:
|
|
498
324
|
|
|
499
|
-
|
|
325
|
+
- runs every 5 minutes by default
|
|
326
|
+
- checks worker presence
|
|
327
|
+
- releases stale claims held by unavailable workers
|
|
328
|
+
- observes pending backlog while broker maintenance handles assignment
|
|
329
|
+
- triggers wake-ups
|
|
500
330
|
|
|
501
|
-
|
|
331
|
+
Configure RALPH:
|
|
502
332
|
|
|
503
|
-
```
|
|
504
|
-
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"slack-bridge": {
|
|
336
|
+
"ralphLoopIntervalMs": 120000,
|
|
337
|
+
"ralphSnoozeAfterEmptyCycles": 3,
|
|
338
|
+
"ralphSnoozeDurationMs": 1800000
|
|
339
|
+
}
|
|
340
|
+
}
|
|
505
341
|
```
|
|
506
342
|
|
|
507
|
-
|
|
343
|
+
### Inbox and threading
|
|
508
344
|
|
|
509
|
-
|
|
510
|
-
/pinet follow
|
|
511
|
-
```
|
|
345
|
+
Pinet maintains an inbox for each agent. Messages are:
|
|
512
346
|
|
|
513
|
-
|
|
347
|
+
- routed based on thread ownership
|
|
348
|
+
- queued when agents are busy
|
|
349
|
+
- marked read when processed
|
|
350
|
+
- preserved across restarts
|
|
514
351
|
|
|
515
|
-
|
|
352
|
+
Thread ownership ensures continuity. Once an agent owns a thread, it keeps receiving those messages.
|
|
516
353
|
|
|
517
|
-
|
|
354
|
+
## Troubleshooting
|
|
518
355
|
|
|
519
|
-
|
|
520
|
-
2. user-local override: `~/.pi/agent/slack-bridge/tmux.md`
|
|
521
|
-
3. packaged default: `dist/prompts/broker/tmux.md`
|
|
356
|
+
### Socket Mode connection issues
|
|
522
357
|
|
|
523
|
-
|
|
358
|
+
If you see 'WebSocket error' or connection failures:
|
|
524
359
|
|
|
525
|
-
|
|
360
|
+
1. Check your app token is valid
|
|
361
|
+
2. Verify Socket Mode is enabled in your Slack app
|
|
362
|
+
3. Check network connectivity
|
|
363
|
+
4. Look for rate limiting (Slack allows 10 connections per app)
|
|
526
364
|
|
|
527
|
-
|
|
365
|
+
### Permission errors
|
|
528
366
|
|
|
529
|
-
|
|
367
|
+
If Pinet cannot perform actions:
|
|
530
368
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
369
|
+
1. Check the bot is in the channel (invite with `/invite @pinet`)
|
|
370
|
+
2. Verify bot scopes match the manifest
|
|
371
|
+
3. Reinstall the app to update permissions
|
|
372
|
+
4. Check `allowedUsers` includes the right user IDs
|
|
534
373
|
|
|
535
|
-
|
|
374
|
+
### Messages not received
|
|
536
375
|
|
|
537
|
-
|
|
376
|
+
If Pinet does not respond:
|
|
538
377
|
|
|
539
|
-
|
|
378
|
+
1. Check Socket Mode shows 'Connected' in Slack app settings
|
|
379
|
+
2. Verify event subscriptions are enabled
|
|
380
|
+
3. Check `allowedUsers` or `allowAllWorkspaceUsers`
|
|
381
|
+
4. Look in the log channel for errors
|
|
382
|
+
5. Try `/pinet status` to check if Pinet is running
|
|
540
383
|
|
|
541
|
-
|
|
384
|
+
### Stranded broker (lock held, controlling session lost)
|
|
542
385
|
|
|
543
|
-
|
|
386
|
+
If `/pinet start` reports that another broker is already running but you no
|
|
387
|
+
longer have that broker's Pi session (crash, laptop restart, stalled process):
|
|
544
388
|
|
|
545
|
-
|
|
389
|
+
1. Run `/pinet status` from any session — it reports machine-wide broker lock
|
|
390
|
+
ownership and socket health even while disconnected.
|
|
391
|
+
2. If the broker is healthy and you just want to participate, run
|
|
392
|
+
`/pinet follow`.
|
|
393
|
+
3. If the broker is stranded (or you need the broker in this session), run
|
|
394
|
+
`/pinet start replace`. It asks the current broker to shut down gracefully
|
|
395
|
+
over the socket, falls back to a verified SIGTERM against the recorded lock
|
|
396
|
+
owner, and never escalates to SIGKILL.
|
|
546
397
|
|
|
547
|
-
|
|
398
|
+
Two cases intentionally refuse automatic termination:
|
|
548
399
|
|
|
549
|
-
|
|
400
|
+
- **Legacy locks** (written by older builds, PID-only): there is no recorded
|
|
401
|
+
process start identity, so a SIGTERM could hit an unrelated process that
|
|
402
|
+
reused the PID. Inspect the process manually (`ps -p <pid>`), terminate it
|
|
403
|
+
yourself if it is truly the stranded broker, then run `/pinet start`.
|
|
404
|
+
- **Rejected shutdown**: a broker that responds but rejects the shutdown
|
|
405
|
+
request (usually a mesh secret mismatch) is alive, not stranded. Fix the
|
|
406
|
+
mesh secret configuration or stop that broker from its own session.
|
|
550
407
|
|
|
551
|
-
|
|
408
|
+
### Stalled agents
|
|
552
409
|
|
|
553
|
-
|
|
410
|
+
If work gets stuck:
|
|
554
411
|
|
|
555
|
-
|
|
412
|
+
1. Check `/pinet status` for current state.
|
|
413
|
+
2. Check `/pinet logs` for repeated failures.
|
|
414
|
+
3. Wait for RALPH to run automatically.
|
|
415
|
+
4. Reduce `ralphLoopIntervalMs` for faster recovery if needed.
|
|
556
416
|
|
|
557
|
-
|
|
417
|
+
## Package information
|
|
558
418
|
|
|
559
|
-
|
|
419
|
+
### Publishing metadata
|
|
560
420
|
|
|
561
|
-
|
|
562
|
-
| ------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
563
|
-
| `/pinet start` | Start as the mesh broker |
|
|
564
|
-
| `/pinet follow` | Connect as a follower worker |
|
|
565
|
-
| `/pinet unfollow` | Disconnect from the broker |
|
|
566
|
-
| `/pinet reload <agent>` | Ask another agent to reload |
|
|
567
|
-
| `/pinet exit <agent>` | Ask another agent to exit |
|
|
568
|
-
| `/pinet free` | Mark this agent as idle |
|
|
569
|
-
| `/pinet snooze [duration/off/status]` | Quiet empty RALPH cycles while preserving human-triggered wake/route behavior |
|
|
570
|
-
| `/pinet subtree [start/status/spawn/stop]` | Run this worker as a local subtree broker for child followers |
|
|
421
|
+
The package declares pi metadata in [`package.json`](./package.json):
|
|
571
422
|
|
|
572
|
-
|
|
423
|
+
- `keywords` includes `pi-package` for gallery discovery
|
|
424
|
+
- `pi.extensions` points to `./dist/index.js`
|
|
425
|
+
- `pi.skills` points to bundled skills
|
|
426
|
+
- No preview assets yet
|
|
573
427
|
|
|
574
|
-
|
|
428
|
+
Check the package contents:
|
|
575
429
|
|
|
576
|
-
|
|
430
|
+
```bash
|
|
431
|
+
cd slack-bridge
|
|
432
|
+
npm pack --dry-run
|
|
433
|
+
```
|
|
577
434
|
|
|
578
|
-
|
|
579
|
-
- `foundation` / `foundation/space` / `space` — JSON descriptor with curated institutional sci-fi characters, full-name aliases, and archive, relay, frontier, and crisis-room flavor.
|
|
580
|
-
- `cosmere` / `cosmere-inspired` / `oathgate` — JSON descriptor with curated/prebaked 1–3 word identities, static emoji, and whimsical Mistborn/Stormlight/Emberdark-inspired agents, spren, artifacts, places, and jokes while avoiding exact third-party character names.
|
|
435
|
+
### Development
|
|
581
436
|
|
|
582
|
-
|
|
437
|
+
Build the package:
|
|
583
438
|
|
|
584
|
-
|
|
439
|
+
```bash
|
|
440
|
+
cd slack-bridge
|
|
441
|
+
pnpm build
|
|
442
|
+
```
|
|
585
443
|
|
|
586
|
-
|
|
587
|
-
- **Followers** connect to the broker over a local Unix socket, poll for work, and report results
|
|
588
|
-
- Agents can optionally authenticate using a shared local secret (`meshSecret` or `meshSecretPath`); when both are unset, mesh auth is disabled
|
|
589
|
-
- Thread ownership is first-responder-wins — the first agent to reply claims the thread
|
|
444
|
+
Run tests:
|
|
590
445
|
|
|
591
|
-
|
|
446
|
+
```bash
|
|
447
|
+
pnpm test
|
|
448
|
+
```
|
|
592
449
|
|
|
593
|
-
|
|
594
|
-
- **Tool guardrails**: `security.readOnly`, `security.requireConfirmation`, and `security.blockedTools` are runtime-enforced for Slack-triggered turns, including core tools such as `bash`, `edit`, and `write`
|
|
595
|
-
- **Guardrail posture**: If Slack/Pinet access is enabled for admitted users and `security.readOnly`, `security.blockedTools`, and `security.requireConfirmation` are all effectively empty (`readOnly !== true` and both arrays are absent or empty), the bridge emits a startup/runtime warning and `/pinet status` shows `Guardrails: empty (warn-first posture; behavior unchanged)`. This is visibility-only: it does **not** auto-enable `readOnly`, block startup, or require an acknowledgement flow.
|
|
596
|
-
- **Mesh authentication**: Optional. Configure `meshSecret` or `meshSecretPath` (or `PINET_MESH_SECRET` / `PINET_MESH_SECRET_PATH`) to require a shared secret; leave them unset to disable shared-secret auth. Configured followers fail closed on missing secret files or older/no-auth brokers rather than silently downgrading.
|
|
450
|
+
Deploy the Slack manifest:
|
|
597
451
|
|
|
598
|
-
|
|
452
|
+
```bash
|
|
453
|
+
pnpm deploy:slack
|
|
454
|
+
```
|
|
599
455
|
|
|
600
|
-
|
|
456
|
+
## Security
|
|
601
457
|
|
|
602
|
-
|
|
458
|
+
### Default-deny access
|
|
603
459
|
|
|
604
|
-
|
|
460
|
+
Pinet requires explicit configuration to allow users. Without `allowedUsers` or `allowAllWorkspaceUsers`, nobody can use it.
|
|
605
461
|
|
|
606
|
-
|
|
607
|
-
pnpm run build
|
|
608
|
-
```
|
|
462
|
+
### Token safety
|
|
609
463
|
|
|
610
|
-
|
|
464
|
+
- Never commit tokens to git
|
|
465
|
+
- Use environment variables in production
|
|
466
|
+
- Rotate tokens regularly
|
|
467
|
+
- Use separate apps for development and production
|
|
611
468
|
|
|
612
|
-
|
|
613
|
-
pnpm lint
|
|
614
|
-
pnpm typecheck
|
|
615
|
-
pnpm test
|
|
616
|
-
```
|
|
469
|
+
### Confirmation for dangerous actions
|
|
617
470
|
|
|
618
|
-
|
|
471
|
+
Configure confirmation for sensitive operations:
|
|
619
472
|
|
|
620
|
-
```
|
|
621
|
-
|
|
473
|
+
```json
|
|
474
|
+
{
|
|
475
|
+
"slack-bridge": {
|
|
476
|
+
"security": {
|
|
477
|
+
"requireConfirmation": ["slack:create_channel", "slack:upload", "slack:delete"]
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
622
481
|
```
|
|
623
482
|
|
|
624
|
-
|
|
483
|
+
### Read-only mode
|
|
625
484
|
|
|
626
|
-
|
|
485
|
+
Prevent all modifications:
|
|
627
486
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
-
|
|
631
|
-
|
|
632
|
-
|
|
487
|
+
```json
|
|
488
|
+
{
|
|
489
|
+
"slack-bridge": {
|
|
490
|
+
"security": {
|
|
491
|
+
"readOnly": true
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
```
|
|
633
496
|
|
|
634
|
-
##
|
|
497
|
+
## Support
|
|
635
498
|
|
|
636
|
-
|
|
499
|
+
- [GitHub repository](https://github.com/gugu91/pinet)
|
|
500
|
+
- [Architecture documentation](../plans/)
|
|
501
|
+
- Check the log channel in Slack for runtime issues
|