@oh-my-pi/pi-mom 0.1.0

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.
@@ -0,0 +1,153 @@
1
+ # Mom Docker Sandbox
2
+
3
+ ## Overview
4
+
5
+ Mom can run tools either directly on the host or inside a Docker container for isolation.
6
+
7
+ ## Why Docker?
8
+
9
+ When mom runs on your machine and is accessible via Slack, anyone in your workspace could potentially:
10
+ - Execute arbitrary commands on your machine
11
+ - Access your files, credentials, etc.
12
+ - Cause damage via prompt injection
13
+
14
+ The Docker sandbox isolates mom's tools to a container where she can only access what you explicitly mount.
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ # 1. Create and start the container
20
+ cd packages/mom
21
+ ./docker.sh create ./data
22
+
23
+ # 2. Run mom with Docker sandbox
24
+ mom --sandbox=docker:mom-sandbox ./data
25
+ ```
26
+
27
+ ## How It Works
28
+
29
+ ```
30
+ ┌─────────────────────────────────────────────────────┐
31
+ │ Host │
32
+ │ │
33
+ │ mom process (Node.js) │
34
+ │ ├── Slack connection │
35
+ │ ├── LLM API calls │
36
+ │ └── Tool execution ──────┐ │
37
+ │ ▼ │
38
+ │ ┌─────────────────────────┐ │
39
+ │ │ Docker Container │ │
40
+ │ │ ├── bash, git, gh, etc │ │
41
+ │ │ └── /workspace (mount) │ │
42
+ │ └─────────────────────────┘ │
43
+ └─────────────────────────────────────────────────────┘
44
+ ```
45
+
46
+ - Mom process runs on host (handles Slack, LLM calls)
47
+ - All tool execution (`bash`, `read`, `write`, `edit`) happens inside the container
48
+ - Only `/workspace` (your data dir) is accessible to the container
49
+
50
+ ## Container Setup
51
+
52
+ Use the provided script:
53
+
54
+ ```bash
55
+ ./docker.sh create <data-dir> # Create and start container
56
+ ./docker.sh start # Start existing container
57
+ ./docker.sh stop # Stop container
58
+ ./docker.sh remove # Remove container
59
+ ./docker.sh status # Check if running
60
+ ./docker.sh shell # Open shell in container
61
+ ```
62
+
63
+ Or manually:
64
+
65
+ ```bash
66
+ docker run -d --name mom-sandbox \
67
+ -v /path/to/mom-data:/workspace \
68
+ alpine:latest tail -f /dev/null
69
+ ```
70
+
71
+ ## Mom Manages Her Own Computer
72
+
73
+ The container is treated as mom's personal computer. She can:
74
+
75
+ - Install tools: `apk add github-cli git curl`
76
+ - Configure credentials: `gh auth login`
77
+ - Create files and directories
78
+ - Persist state across restarts
79
+
80
+ When mom needs a tool, she installs it. When she needs credentials, she asks you.
81
+
82
+ ### Example Flow
83
+
84
+ ```
85
+ User: "@mom check the spine-runtimes repo"
86
+ Mom: "I need gh CLI. Installing..."
87
+ (runs: apk add github-cli)
88
+ Mom: "I need a GitHub token. Please provide one."
89
+ User: "ghp_xxxx..."
90
+ Mom: (runs: echo "ghp_xxxx" | gh auth login --with-token)
91
+ Mom: "Done. Checking repo..."
92
+ ```
93
+
94
+ ## Persistence
95
+
96
+ The container persists across:
97
+ - `docker stop` / `docker start`
98
+ - Host reboots
99
+
100
+ Installed tools and configs remain until you `docker rm` the container.
101
+
102
+ To start fresh: `./docker.sh remove && ./docker.sh create ./data`
103
+
104
+ ## CLI Options
105
+
106
+ ```bash
107
+ # Run on host (default, no isolation)
108
+ mom ./data
109
+
110
+ # Run with Docker sandbox
111
+ mom --sandbox=docker:mom-sandbox ./data
112
+
113
+ # Explicit host mode
114
+ mom --sandbox=host ./data
115
+ ```
116
+
117
+ ## Security Considerations
118
+
119
+ **What the container CAN do:**
120
+ - Read/write files in `/workspace` (your data dir)
121
+ - Make network requests (for git, gh, curl, etc.)
122
+ - Install packages
123
+ - Run any commands
124
+
125
+ **What the container CANNOT do:**
126
+ - Access files outside `/workspace`
127
+ - Access your host's credentials
128
+ - Affect your host system
129
+
130
+ **For maximum security:**
131
+ 1. Create a dedicated GitHub bot account with limited repo access
132
+ 2. Only share that bot's token with mom
133
+ 3. Don't mount sensitive directories
134
+
135
+ ## Troubleshooting
136
+
137
+ ### Container not running
138
+ ```bash
139
+ ./docker.sh status # Check status
140
+ ./docker.sh start # Start it
141
+ ```
142
+
143
+ ### Reset container
144
+ ```bash
145
+ ./docker.sh remove
146
+ ./docker.sh create ./data
147
+ ```
148
+
149
+ ### Missing tools
150
+ Ask mom to install them, or manually:
151
+ ```bash
152
+ docker exec mom-sandbox apk add <package>
153
+ ```
@@ -0,0 +1,399 @@
1
+ # Minimal Slack Bot Setup (No Web Server, WebSocket Only)
2
+
3
+ Here's how to connect your Node.js agent to Slack using **Socket Mode** - no Express, no HTTP server, just WebSockets and callbacks.
4
+
5
+ ---
6
+
7
+ ## 1. Dependencies
8
+
9
+ ```bash
10
+ npm install @slack/socket-mode @slack/web-api
11
+ ```
12
+
13
+ That's it. Two packages:
14
+ - `@slack/socket-mode` - Receives events via WebSocket
15
+ - `@slack/web-api` - Sends messages back to Slack
16
+
17
+ ---
18
+
19
+ ## 2. Get Your Tokens
20
+
21
+ You need **TWO tokens**:
22
+
23
+ ### A. Bot Token (`xoxb-...`)
24
+ 1. Go to https://api.slack.com/apps
25
+ 2. Create app → "From scratch"
26
+ 3. Click "OAuth & Permissions" in sidebar
27
+ 4. Add **Bot Token Scopes** (all 16):
28
+ ```
29
+ app_mentions:read
30
+ channels:history
31
+ channels:join
32
+ channels:read
33
+ chat:write
34
+ files:read
35
+ files:write
36
+ groups:history
37
+ groups:read
38
+ im:history
39
+ im:read
40
+ im:write
41
+ mpim:history
42
+ mpim:read
43
+ mpim:write
44
+ users:read
45
+ ```
46
+ 5. Click "Install to Workspace" at top
47
+ 6. Copy the **Bot User OAuth Token** (starts with `xoxb-`)
48
+
49
+ ### B. App-Level Token (`xapp-...`)
50
+ 1. In same app, click "Basic Information" in sidebar
51
+ 2. Scroll to "App-Level Tokens"
52
+ 3. Click "Generate Token and Scopes"
53
+ 4. Name it whatever (e.g., "socket-token")
54
+ 5. Add scope: `connections:write`
55
+ 6. Click "Generate"
56
+ 7. Copy the token (starts with `xapp-`)
57
+
58
+ ---
59
+
60
+ ## 3. Enable Socket Mode
61
+
62
+ 1. Go to https://api.slack.com/apps → select your app
63
+ 2. Click **"Socket Mode"** in sidebar
64
+ 3. Toggle **"Enable Socket Mode"** to ON
65
+ 4. This routes your app's interactions and events over WebSockets instead of public HTTP endpoints
66
+ 5. Done - no webhook URL needed!
67
+
68
+ **Note:** Socket Mode is intended for internal apps in development or behind a firewall. Not for apps distributed via Slack Marketplace.
69
+
70
+ ---
71
+
72
+ ## 4. Enable Direct Messages
73
+
74
+ 1. Go to https://api.slack.com/apps → select your app
75
+ 2. Click **"App Home"** in sidebar
76
+ 3. Scroll to **"Show Tabs"** section
77
+ 4. Check **"Allow users to send Slash commands and messages from the messages tab"**
78
+ 5. Save
79
+
80
+ ---
81
+
82
+ ## 5. Subscribe to Events
83
+
84
+ 1. Go to https://api.slack.com/apps → select your app
85
+ 2. Click **"Event Subscriptions"** in sidebar
86
+ 3. Toggle **"Enable Events"** to ON
87
+ 4. **Important:** No Request URL needed (Socket Mode handles this)
88
+ 5. Expand **"Subscribe to bot events"**
89
+ 6. Click **"Add Bot User Event"** and add:
90
+ - `app_mention` (required - to see when bot is mentioned)
91
+ - `message.channels` (required - to log all channel messages for context)
92
+ - `message.groups` (optional - to see private channel messages)
93
+ - `message.im` (required - to see DMs)
94
+ 7. Click **"Save Changes"** at bottom
95
+
96
+ ---
97
+
98
+ ## 6. Store Tokens
99
+
100
+ Create `.env` file:
101
+
102
+ ```bash
103
+ SLACK_BOT_TOKEN=xoxb-your-bot-token-here
104
+ SLACK_APP_TOKEN=xapp-your-app-token-here
105
+ ```
106
+
107
+ Add to `.gitignore`:
108
+
109
+ ```bash
110
+ echo ".env" >> .gitignore
111
+ ```
112
+
113
+ ---
114
+
115
+ ## 7. Minimal Working Code
116
+
117
+ ```javascript
118
+ require('dotenv').config();
119
+ const { SocketModeClient } = require('@slack/socket-mode');
120
+ const { WebClient } = require('@slack/web-api');
121
+
122
+ const socketClient = new SocketModeClient({
123
+ appToken: process.env.SLACK_APP_TOKEN
124
+ });
125
+
126
+ const webClient = new WebClient(process.env.SLACK_BOT_TOKEN);
127
+
128
+ // Listen for app mentions (@mom do something)
129
+ socketClient.on('app_mention', async ({ event, ack }) => {
130
+ try {
131
+ // Acknowledge receipt
132
+ await ack();
133
+
134
+ console.log('Mentioned:', event.text);
135
+ console.log('Channel:', event.channel);
136
+ console.log('User:', event.user);
137
+
138
+ // Process with your agent
139
+ const response = await yourAgentFunction(event.text);
140
+
141
+ // Send response
142
+ await webClient.chat.postMessage({
143
+ channel: event.channel,
144
+ text: response
145
+ });
146
+ } catch (error) {
147
+ console.error('Error:', error);
148
+ }
149
+ });
150
+
151
+ // Start the connection
152
+ (async () => {
153
+ await socketClient.start();
154
+ console.log('⚡️ Bot connected and listening!');
155
+ })();
156
+
157
+ // Your existing agent logic
158
+ async function yourAgentFunction(text) {
159
+ // Your code here
160
+ return "I processed: " + text;
161
+ }
162
+ ```
163
+
164
+ **That's it. No web server. Just run it:**
165
+
166
+ ```bash
167
+ node bot.js
168
+ ```
169
+
170
+ ---
171
+
172
+ ## 8. Listen to ALL Events (Not Just Mentions)
173
+
174
+ If you want to see every message in channels/DMs the bot is in:
175
+
176
+ ```javascript
177
+ // Listen to all Slack events
178
+ socketClient.on('slack_event', async ({ event, body, ack }) => {
179
+ await ack();
180
+
181
+ console.log('Event type:', event.type);
182
+ console.log('Event data:', event);
183
+
184
+ if (event.type === 'message' && event.subtype === undefined) {
185
+ // Regular message (not bot message, not edited, etc.)
186
+ console.log('Message:', event.text);
187
+ console.log('Channel:', event.channel);
188
+ console.log('User:', event.user);
189
+
190
+ // Your logic here
191
+ }
192
+ });
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 9. Common Operations
198
+
199
+ ### Send a message
200
+ ```javascript
201
+ await webClient.chat.postMessage({
202
+ channel: 'C12345', // or channel ID from event
203
+ text: 'Hello!'
204
+ });
205
+ ```
206
+
207
+ ### Send a DM
208
+ ```javascript
209
+ // Open DM channel with user
210
+ const result = await webClient.conversations.open({
211
+ users: 'U12345' // user ID
212
+ });
213
+
214
+ // Send message to that DM
215
+ await webClient.chat.postMessage({
216
+ channel: result.channel.id,
217
+ text: 'Hey there!'
218
+ });
219
+ ```
220
+
221
+ ### List channels
222
+ ```javascript
223
+ const channels = await webClient.conversations.list({
224
+ types: 'public_channel,private_channel'
225
+ });
226
+ console.log(channels.channels);
227
+ ```
228
+
229
+ ### Get channel members
230
+ ```javascript
231
+ const members = await webClient.conversations.members({
232
+ channel: 'C12345'
233
+ });
234
+ console.log(members.members); // Array of user IDs
235
+ ```
236
+
237
+ ### Get user info
238
+ ```javascript
239
+ const user = await webClient.users.info({
240
+ user: 'U12345'
241
+ });
242
+ console.log(user.user.name);
243
+ console.log(user.user.real_name);
244
+ ```
245
+
246
+ ### Join a channel
247
+ ```javascript
248
+ await webClient.conversations.join({
249
+ channel: 'C12345'
250
+ });
251
+ ```
252
+
253
+ ### Upload a file
254
+ ```javascript
255
+ await webClient.files.uploadV2({
256
+ channel_id: 'C12345',
257
+ file: fs.createReadStream('./file.pdf'),
258
+ filename: 'document.pdf',
259
+ title: 'My Document'
260
+ });
261
+ ```
262
+
263
+ ---
264
+
265
+ ## 10. Complete Example with Your Agent
266
+
267
+ ```javascript
268
+ require('dotenv').config();
269
+ const { SocketModeClient } = require('@slack/socket-mode');
270
+ const { WebClient } = require('@slack/web-api');
271
+
272
+ const socketClient = new SocketModeClient({
273
+ appToken: process.env.SLACK_APP_TOKEN
274
+ });
275
+
276
+ const webClient = new WebClient(process.env.SLACK_BOT_TOKEN);
277
+
278
+ // Your existing agent/AI/whatever
279
+ class MyAgent {
280
+ async process(message, context) {
281
+ // Your complex logic here
282
+ // context has: user, channel, etc.
283
+ return `Processed: ${message}`;
284
+ }
285
+ }
286
+
287
+ const agent = new MyAgent();
288
+
289
+ // Handle mentions
290
+ socketClient.on('app_mention', async ({ event, ack }) => {
291
+ await ack();
292
+
293
+ try {
294
+ // Remove the @mention from text
295
+ const text = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
296
+
297
+ // Process with your agent
298
+ const response = await agent.process(text, {
299
+ user: event.user,
300
+ channel: event.channel
301
+ });
302
+
303
+ // Send response
304
+ await webClient.chat.postMessage({
305
+ channel: event.channel,
306
+ text: response
307
+ });
308
+ } catch (error) {
309
+ console.error('Error processing mention:', error);
310
+
311
+ // Send error message
312
+ await webClient.chat.postMessage({
313
+ channel: event.channel,
314
+ text: 'Sorry, something went wrong!'
315
+ });
316
+ }
317
+ });
318
+
319
+ // Start
320
+ (async () => {
321
+ await socketClient.start();
322
+ console.log('⚡️ Agent connected to Slack!');
323
+ })();
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 11. Available Event Types
329
+
330
+ You subscribed to these in step 4:
331
+
332
+ - `app_mention` - Someone @mentioned the bot
333
+ - `message` - Any message in a channel/DM the bot is in
334
+
335
+ Event object structure:
336
+
337
+ ```javascript
338
+ {
339
+ type: 'app_mention' or 'message',
340
+ text: 'the message text',
341
+ user: 'U12345', // who sent it
342
+ channel: 'C12345', // where it was sent
343
+ ts: '1234567890.123456' // timestamp
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## 12. Advantages of Socket Mode
350
+
351
+ ✅ **No web server needed** - just run your script
352
+ ✅ **No public URL needed** - works behind firewall
353
+ ✅ **No ngrok** - works on localhost
354
+ ✅ **Auto-reconnect** - SDK handles connection drops
355
+ ✅ **Event-driven** - just listen to callbacks
356
+
357
+ ---
358
+
359
+ ## 13. Disadvantages
360
+
361
+ ❌ Can't distribute to Slack App Directory (only for your workspace)
362
+ ❌ Script must be running to receive messages (unlike webhooks)
363
+ ❌ Max 10 concurrent connections per app
364
+
365
+ ---
366
+
367
+ ## Important Notes
368
+
369
+ 1. **You MUST call `ack()`** on every event or Slack will retry
370
+ 2. **Bot token** (`xoxb-`) is for sending messages
371
+ 3. **App token** (`xapp-`) is for receiving events via WebSocket
372
+ 4. **Connection is persistent** - your script stays running
373
+ 5. **No URL validation** needed (unlike HTTP webhooks)
374
+
375
+ ---
376
+
377
+ ## Troubleshooting
378
+
379
+ ### "invalid_auth" error
380
+ - Check you're using the right tokens
381
+ - Bot token for WebClient, App token for SocketModeClient
382
+
383
+ ### "missing_scope" error
384
+ - Make sure you added all 16 bot scopes
385
+ - Reinstall the app after adding scopes
386
+
387
+ ### Not receiving events
388
+ - Check Socket Mode is enabled
389
+ - Check you subscribed to events in "Event Subscriptions"
390
+ - Make sure bot is in the channel (or use `channels:join`)
391
+
392
+ ### Bot doesn't respond to mentions
393
+ - Must subscribe to `app_mention` event
394
+ - Bot must be installed to workspace
395
+ - Check `await ack()` is called
396
+
397
+ ---
398
+
399
+ That's it. No HTTP server bullshit. Just WebSockets and callbacks.