@thesammykins/tether 1.0.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.
package/.env.example ADDED
@@ -0,0 +1,44 @@
1
+ # Required
2
+ DISCORD_BOT_TOKEN=your-bot-token-here
3
+
4
+ # Optional - Redis connection
5
+ REDIS_HOST=localhost
6
+ REDIS_PORT=6379
7
+
8
+ # Optional - Agent configuration
9
+ AGENT_TYPE=claude
10
+ # Options: claude, opencode, codex
11
+
12
+ # Optional - Working directory for agent sessions
13
+ CLAUDE_WORKING_DIR=/path/to/your/project
14
+
15
+ # Optional - Direct Messages (disabled by default)
16
+ ENABLE_DMS=false
17
+ # Set to "true" to allow the bot to respond to DMs.
18
+ # When enabled, users can message the bot directly without @mentioning.
19
+ # DM sessions persist per-user. Send "!reset" in DMs to start a new session.
20
+
21
+ # Optional - Allowlist (empty = allow all)
22
+ ALLOWED_USERS=
23
+ # Comma-separated Discord user IDs (e.g., 123456789,987654321)
24
+ # In DMs, only this list is checked (roles/channels don't apply)
25
+
26
+ ALLOWED_ROLES=
27
+ # Comma-separated Discord role IDs (guild only, ignored in DMs)
28
+
29
+ ALLOWED_CHANNELS=
30
+ # Comma-separated Discord channel IDs (guild only, ignored in DMs)
31
+
32
+ # Optional - Rate limiting
33
+ RATE_LIMIT_REQUESTS=5
34
+ RATE_LIMIT_WINDOW_MS=60000
35
+
36
+ # Optional - Session limits
37
+ MAX_TURNS_PER_SESSION=50
38
+ MAX_SESSION_DURATION_MS=3600000
39
+
40
+ # Optional - Database
41
+ DB_PATH=./data/threads.db
42
+
43
+ # Optional - Timezone for datetime injection
44
+ TZ=America/New_York
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 thesammykins
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,313 @@
1
+ # @thesammykins/tether
2
+
3
+ Discord bot that bridges messages to AI coding agents. Supports Claude Code, OpenCode, and Codex CLI.
4
+
5
+ Fork of [cord](https://github.com/alexknowshtml/cord) with multi-agent support and enhanced features.
6
+
7
+ ## Features
8
+
9
+ - **Multi-agent support** — Claude Code, OpenCode, Codex (switch via `AGENT_TYPE` env var)
10
+ - **Direct messages** — Chat with the bot privately via DMs (opt-in)
11
+ - **Access control** — User, role, and channel allowlists
12
+ - **Rate limiting** — Per-user sliding window
13
+ - **Session management** — Turn limits, duration limits, pause/resume
14
+ - **Smart threads** — Auto-naming, channel context for new conversations
15
+ - **Acknowledgment** — 👀 reaction on incoming messages
16
+ - **Resilient** — Exponential backoff on connection failures
17
+
18
+ ## Quick Start
19
+
20
+ ### Prerequisites
21
+
22
+ - [Bun](https://bun.sh) runtime
23
+ - [Redis](https://redis.io) (for BullMQ job queue)
24
+ - A Discord bot token ([setup guide below](#discord-bot-setup))
25
+ - An AI agent CLI installed on PATH (`claude`, `opencode`, or `codex`)
26
+
27
+ ### Install
28
+
29
+ ```bash
30
+ git clone https://github.com/thesammykins/tether.git
31
+ cd tether
32
+ bun install
33
+ ```
34
+
35
+ ### Configure
36
+
37
+ ```bash
38
+ cp .env.example .env
39
+ # Edit .env with your DISCORD_BOT_TOKEN and settings
40
+ ```
41
+
42
+ ### Run
43
+
44
+ ```bash
45
+ bun run start # Start bot + worker via CLI
46
+ # or run separately:
47
+ bun run bot # Discord gateway
48
+ bun run worker # Job processor
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Discord Bot Setup
54
+
55
+ Step-by-step guide to creating and configuring your Discord bot.
56
+
57
+ ### 1. Create a Discord Application
58
+
59
+ 1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
60
+ 2. Click **New Application** and give it a name (e.g. "Tether")
61
+ 3. Note the **Application ID** — you'll need it for the invite link
62
+
63
+ ### 2. Create the Bot User
64
+
65
+ 1. In your application, go to the **Bot** tab in the left sidebar
66
+ 2. Click **Add Bot** (if not already created)
67
+ 3. Under **Token**, click **Reset Token** and copy it — this is your `DISCORD_BOT_TOKEN`
68
+ 4. **Store this token securely** — you won't be able to see it again
69
+
70
+ ### 3. Configure Bot Permissions
71
+
72
+ Under the **Bot** tab, configure these settings:
73
+
74
+ **Privileged Gateway Intents** (toggle ON):
75
+
76
+ | Intent | Why |
77
+ |--------|-----|
78
+ | **Message Content Intent** | Required to read message text (not just metadata) |
79
+
80
+ > Without Message Content Intent enabled, the bot will connect but never see message contents.
81
+
82
+ **Bot Permissions** — the bot needs these permissions in your server:
83
+
84
+ | Permission | Why |
85
+ |------------|-----|
86
+ | Send Messages | Reply to users |
87
+ | Create Public Threads | Create conversation threads |
88
+ | Send Messages in Threads | Respond in threads |
89
+ | Manage Threads | Rename threads |
90
+ | Read Message History | Fetch channel context for new conversations |
91
+ | Add Reactions | 👀 acknowledgment emoji |
92
+ | Use Slash Commands | `/cord config` command |
93
+
94
+ ### 4. Generate the Invite Link
95
+
96
+ 1. Go to the **OAuth2** tab → **URL Generator**
97
+ 2. Under **Scopes**, select:
98
+ - `bot`
99
+ - `applications.commands`
100
+ 3. Under **Bot Permissions**, select the permissions listed above, or use the permission integer `326417588288` which includes all required permissions
101
+ 4. Copy the generated URL and open it in your browser
102
+ 5. Select the server you want to add the bot to and click **Authorize**
103
+
104
+ ### 5. Enable DMs (Optional)
105
+
106
+ If you want users to be able to DM the bot directly:
107
+
108
+ 1. In `.env`, set `ENABLE_DMS=true`
109
+ 2. In the Discord Developer Portal → **Bot** tab, make sure **Allow DMs** is not disabled
110
+
111
+ DM behavior:
112
+ - Any message sent to the bot in DMs starts or continues a conversation
113
+ - No `@mention` needed — every DM is treated as a prompt
114
+ - Sessions persist per-user until manually reset
115
+ - Send `!reset` in DMs to start a fresh session
116
+ - Only `ALLOWED_USERS` is checked for DMs (roles and channels don't apply)
117
+
118
+ ### 6. Start the Bot
119
+
120
+ ```bash
121
+ # Make sure Redis is running
122
+ redis-server
123
+
124
+ # Start tether
125
+ bun run start
126
+ ```
127
+
128
+ You should see:
129
+ ```
130
+ [bot] Connecting to Discord gateway (attempt 1)...
131
+ [bot] Logged in as YourBot#1234
132
+ [worker] Worker started, waiting for jobs...
133
+ ```
134
+
135
+ ### 7. Test It
136
+
137
+ In your Discord server, `@mention` the bot in any channel:
138
+
139
+ ```
140
+ @Tether what time is it?
141
+ ```
142
+
143
+ The bot will:
144
+ 1. React with 👀
145
+ 2. Create a thread with an auto-generated name
146
+ 3. Post a "Processing..." status message
147
+ 4. Forward the prompt to your AI agent
148
+ 5. Post the response in the thread
149
+
150
+ ---
151
+
152
+ ## Configuration
153
+
154
+ | Variable | Default | Description |
155
+ |----------|---------|-------------|
156
+ | `DISCORD_BOT_TOKEN` | required | Discord bot token |
157
+ | `AGENT_TYPE` | `claude` | Agent backend: `claude`, `opencode`, `codex` |
158
+ | `ENABLE_DMS` | `false` | Allow bot to respond to direct messages |
159
+ | `REDIS_HOST` | `localhost` | Redis host |
160
+ | `REDIS_PORT` | `6379` | Redis port |
161
+ | `ALLOWED_USERS` | (empty=all) | Comma-separated Discord user IDs |
162
+ | `ALLOWED_ROLES` | (empty=all) | Comma-separated role IDs (guild only) |
163
+ | `ALLOWED_CHANNELS` | (empty=all) | Comma-separated channel IDs (guild only) |
164
+ | `RATE_LIMIT_REQUESTS` | `5` | Max requests per window |
165
+ | `RATE_LIMIT_WINDOW_MS` | `60000` | Rate limit window (ms) |
166
+ | `MAX_TURNS_PER_SESSION` | `50` | Max turns per thread/DM session |
167
+ | `MAX_SESSION_DURATION_MS` | `3600000` | Max session duration (ms) |
168
+ | `CLAUDE_WORKING_DIR` | cwd | Default working directory for agents |
169
+ | `DB_PATH` | `./data/threads.db` | SQLite database path |
170
+ | `CORD_ALLOWED_DIRS` | (empty=any) | Comma-separated allowed working directories |
171
+
172
+ ### Finding Discord IDs
173
+
174
+ To get user, role, or channel IDs:
175
+ 1. Enable **Developer Mode** in Discord: Settings → App Settings → Advanced → Developer Mode
176
+ 2. Right-click a user, role, or channel and select **Copy ID**
177
+
178
+ ## Agent CLI Requirements
179
+
180
+ Whichever agent you choose must be installed and available on PATH:
181
+ - **Claude Code**: `claude` CLI — [Install guide](https://docs.anthropic.com/en/docs/claude-code)
182
+ - **OpenCode**: `opencode` CLI
183
+ - **Codex**: `codex` CLI
184
+
185
+ ## Architecture
186
+
187
+ Tether uses a queue-based architecture for reliable message processing:
188
+
189
+ ```
190
+ Discord Bot → BullMQ Queue → Agent Worker
191
+ (gateway) (Redis) (spawns CLI)
192
+ ```
193
+
194
+ ### Key Components
195
+
196
+ - **Bot** (`src/bot.ts`) — Discord gateway with middleware pipeline
197
+ - **Worker** (`src/worker.ts`) — Job processor using adapter registry
198
+ - **Adapters** (`src/adapters/`) — AgentAdapter interface for Claude/OpenCode/Codex
199
+ - **Middleware** (`src/middleware/`) — Allowlist, rate-limiter
200
+ - **Features** (`src/features/`) — Ack, channel-context, thread-naming, session-limits, pause-resume
201
+ - **Queue** (`src/queue.ts`) — BullMQ job queue
202
+ - **DB** (`src/db.ts`) — SQLite for thread→session mapping
203
+
204
+ ### Message Flow
205
+
206
+ **Guild channels:**
207
+ 1. User `@mentions` bot in Discord channel
208
+ 2. Bot checks allowlist → rate limiter → pause state
209
+ 3. Bot creates thread with auto-generated name
210
+ 4. Bot adds job to BullMQ queue
211
+ 5. Worker pulls job and spawns agent adapter
212
+ 6. Adapter runs CLI (`claude`/`opencode`/`codex`) with prompt
213
+ 7. Worker posts response back to Discord thread
214
+
215
+ **Direct messages:**
216
+ 1. User sends message to bot in DMs (no `@mention` needed)
217
+ 2. Bot checks user allowlist → rate limiter
218
+ 3. Bot creates or resumes session for this user
219
+ 4. Bot adds job to BullMQ queue
220
+ 5. Worker posts response back to the DM channel
221
+
222
+ ### Middleware Pipeline
223
+
224
+ Messages pass through middleware in this order:
225
+
226
+ 1. **Allowlist** — Block unauthorized users/channels/roles (DMs: user-only check)
227
+ 2. **Rate Limiter** — Sliding window per-user rate limit
228
+ 3. **Pause/Resume** — Hold messages if thread is paused (guild threads only)
229
+
230
+ ### Session Management
231
+
232
+ - **Turn limits** — Max messages per thread/DM session (prevents infinite loops)
233
+ - **Duration limits** — Max session lifetime
234
+ - **Pause/Resume** — Type `pause` to hold messages, `resume` to continue (threads only)
235
+ - **DM Reset** — Type `!reset` in DMs to start a new session
236
+ - **Auto-completion** — React with ✅ on last message to mark "Done" (threads only)
237
+
238
+ ## Working Directory Configuration
239
+
240
+ Tether supports per-channel working directories so agents operate in the correct project context.
241
+
242
+ **Channel-level configuration** (persists for all conversations in that channel):
243
+ ```
244
+ /cord config dir ~/Code/myproject
245
+ ```
246
+
247
+ **Per-message override** (one-time, just for this conversation):
248
+ ```
249
+ @bot [/other/project] what files are here?
250
+ ```
251
+
252
+ **Fallback chain**: Message override → Channel config → `CLAUDE_WORKING_DIR` env → `process.cwd()`
253
+
254
+ ### Security: Directory Allowlist
255
+
256
+ For multi-user deployments, restrict which directories users can access:
257
+
258
+ ```bash
259
+ CORD_ALLOWED_DIRS=/home/projects,/var/code
260
+ ```
261
+
262
+ If not set, any existing directory is allowed (backward compatible). When set, paths outside the allowlist are rejected.
263
+
264
+ ## Testing
265
+
266
+ ```bash
267
+ bun test # Run all tests
268
+ bun test tests/adapters/ # Adapter tests only
269
+ bun test tests/middleware/ # Middleware tests only
270
+ bun test tests/features/ # Feature tests only
271
+ bun test tests/integration/ # Integration tests only
272
+ ```
273
+
274
+ ## CLI Commands
275
+
276
+ See [skills/tether/SKILL.md](./skills/tether/SKILL.md) for full CLI documentation.
277
+
278
+ Quick reference:
279
+ - `tether send <channel> "message"` — Send text message
280
+ - `tether embed <channel> "text" --title "T"` — Send formatted embed
281
+ - `tether file <channel> ./file.txt` — Send file attachment
282
+ - `tether buttons <channel> "prompt" --button label="Yes" id="yes"` — Send interactive buttons
283
+ - `tether state <channel> <msgId> done` — Update status message
284
+ - `tether dm <user-id> "message"` — Send a DM to a user (proactive outreach)
285
+ - `tether dm <user-id> --embed "text" --title "T"` — Send an embed DM
286
+ - `tether dm <user-id> --file ./report.md` — Send a file via DM
287
+
288
+ ## HTTP API
289
+
290
+ Tether exposes an HTTP API on port 2643 for external scripts and webhooks.
291
+
292
+ See [skills/tether/HTTP-API.md](./skills/tether/HTTP-API.md) for API documentation.
293
+
294
+ ## Troubleshooting
295
+
296
+ | Problem | Solution |
297
+ |---------|----------|
298
+ | Bot connects but doesn't respond | Enable **Message Content Intent** in Developer Portal → Bot tab |
299
+ | "TokenInvalid" error | Regenerate your bot token in the Developer Portal |
300
+ | "DisallowedIntents" error | Enable the required intents in Developer Portal → Bot tab |
301
+ | Bot doesn't receive DMs | Set `ENABLE_DMS=true` in `.env` |
302
+ | "Rate limit exceeded" | Adjust `RATE_LIMIT_REQUESTS` / `RATE_LIMIT_WINDOW_MS` |
303
+ | Agent command not found | Ensure `claude`/`opencode`/`codex` is installed and on PATH |
304
+ | Redis connection refused | Start Redis: `redis-server` |
305
+ | Bot can't create threads | Check bot has **Create Public Threads** permission in your server |
306
+
307
+ ## Privacy
308
+
309
+ Tether stores only thread-to-session mappings and channel configuration (working directories). **No message content, user data, or conversation history is persisted.** Messages pass through the Redis queue transiently and are discarded after processing.
310
+
311
+ ## License
312
+
313
+ MIT