tmux-team 2.2.0 → 3.0.0-alpha.1

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **The lightweight coordination layer for terminal-based AI agents.**
4
4
 
5
- tmux-team is a protocol-agnostic "Team Lead" that enables multi-agent collaboration directly within your existing tmux workflow. It provides the transport layer, synchronization, and project management needed to turn a collection of isolated terminal panes into a coordinated AI task force.
5
+ tmux-team is a protocol-agnostic transport layer that enables multi-agent collaboration directly within your existing tmux workflow. It turns a collection of isolated terminal panes into a coordinated AI team.
6
6
 
7
7
  ---
8
8
 
@@ -34,32 +34,24 @@ Unlike heavyweight frameworks that require specific SDKs or cloud infrastructure
34
34
 
35
35
  ### 1. Deterministic Transport (`--delay` vs. `sleep`)
36
36
 
37
- **The Problem**: Tool allowlists typically approve one safe command (`tmux-team talk ...`) but not arbitrary shell commands. Using `sleep` is often blocked by security policies, requires shell availability and proper quoting, and creates a separate process that's hard to manage.
37
+ **The Problem**: Tool allowlists typically approve one safe command (`tmux-team talk ...`) but not arbitrary shell commands. Using `sleep` is often blocked by security policies.
38
38
 
39
- **The Why**: Internal delay keeps the workflow as a single tool call. This guarantees "First-Packet Integrity"—the CLI validates units (`500ms`, `2s`) and ensures the TTY buffer is ready to receive input specifically for that agent. No shell dependency, no policy friction.
39
+ **The Why**: Internal delay keeps the workflow as a single tool call. No shell dependency, no policy friction.
40
40
 
41
41
  ### 2. Stateless Handshakes (The "Nonce" Strategy)
42
42
 
43
- **The Problem**: Terminal panes are streams, not RPC channels. A simple `[DONE]` string could already be in scrollback, or the agent might say "I'm almost done" and trigger a false positive.
43
+ **The Problem**: Terminal panes are streams, not RPC channels. A simple `[DONE]` string could already be in scrollback.
44
44
 
45
- **The Why**: We use a unique **Nonce** (Number used once) for every request: `{tmux-team-end:8f3a}`.
45
+ **The Why**: We use a unique **Nonce** for every request: `{tmux-team-end:8f3a}`.
46
46
  - **Collision Avoidance** — Prevents matching markers from previous turns
47
- - **Completion Safety** — Ensures the agent has truly finished, not just paused mid-response
48
- - **Zero-API RPC** — Creates request/response semantics over a standard TTY without requiring agents to support a special protocol
49
-
50
- Combined with one-at-a-time locking, nonce markers ensure state stays consistent and debuggable.
47
+ - **Completion Safety** — Ensures the agent has truly finished
48
+ - **Zero-API RPC** — Creates request/response semantics over a standard TTY
51
49
 
52
50
  ### 3. Context Injection (Preambles)
53
51
 
54
- **The Problem**: AI agents are prone to "instruction drift." Over a long session, they might stop using your preferred format or forget constraints. Manually re-typing system instructions is a "token tax" on your own brain.
55
-
56
- **The Why**: Preambles act as a forced system prompt for CLI environments. By injecting these "hidden instructions" at the transport level, we ensure the agent remains in character (e.g., "You are the code reviewer, do not edit files") without cluttering the human's command history. It's about reducing **Cognitive Load**—the human focuses on intent, the CLI enforces protocol.
57
-
58
- ### 4. Token-Efficient Polling
52
+ **The Problem**: AI agents are prone to "instruction drift." Over a long session, they might forget constraints.
59
53
 
60
- **The Problem**: The `--wait` feature is powerful but higher-risk: long-running commands, more state to manage, potential for hung processes.
61
-
62
- **The Why**: Default to the simple mental model (send → manually check). Teams opt into `--wait` when they're ready. By capturing only the last few lines of the buffer and searching for the short, high-entropy nonce, we keep overhead near zero—we're looking for a single "heartbeat" at the TTY's edge, not re-parsing the whole history.
54
+ **The Why**: Preambles act as a forced system prompt for CLI environments. By injecting these "hidden instructions" at the transport level, we ensure the agent remains in character.
63
55
 
64
56
  ---
65
57
 
@@ -69,7 +61,7 @@ Combined with one-at-a-time locking, nonce markers ensure state stays consistent
69
61
  npm install -g tmux-team
70
62
  ```
71
63
 
72
- **Requirements:** Node.js >= 16, tmux, macOS/Linux
64
+ **Requirements:** Node.js >= 18, tmux, macOS/Linux
73
65
 
74
66
  ### Shell Completion
75
67
 
@@ -139,10 +131,8 @@ Once the plugin is installed, coordinate directly from your Claude Code session:
139
131
  | `update <name> --pane/--remark` | Update agent configuration |
140
132
  | `remove <name>` | Unregister an agent |
141
133
  | `init` | Create `tmux-team.json` in current directory |
142
- | `pm init --name "Project"` | Initialize project management |
143
- | `pm m add/list/done/delete` | Manage milestones |
144
- | `pm t add/list/update/done` | Manage tasks |
145
- | `pm log` | View audit event log |
134
+ | `config [show/set/clear]` | View/modify settings |
135
+ | `preamble [show/set/clear]` | Manage agent preambles |
146
136
  | `completion [zsh\|bash]` | Output shell completion script |
147
137
 
148
138
  ---
@@ -151,15 +141,14 @@ Once the plugin is installed, coordinate directly from your Claude Code session:
151
141
 
152
142
  ### Local Config (`./tmux-team.json`)
153
143
 
154
- Per-project agent registry with optional preambles and permissions:
144
+ Per-project agent registry with optional preambles:
155
145
 
156
146
  ```json
157
147
  {
158
148
  "claude": {
159
149
  "pane": "10.0",
160
150
  "remark": "Frontend specialist",
161
- "preamble": "Focus on UI components. Ask for review before merging.",
162
- "deny": ["pm:task:update(status)"]
151
+ "preamble": "Focus on UI components. Ask for review before merging."
163
152
  },
164
153
  "codex": {
165
154
  "pane": "10.1",
@@ -174,7 +163,6 @@ Per-project agent registry with optional preambles and permissions:
174
163
  | `pane` | tmux pane ID (required) |
175
164
  | `remark` | Description shown in `list` |
176
165
  | `preamble` | Hidden instructions prepended to every message |
177
- | `deny` | Permission patterns to block (e.g., `pm:task:update(status)`) |
178
166
 
179
167
  ### Global Config (`~/.config/tmux-team/config.json`)
180
168
 
@@ -188,7 +176,7 @@ Global settings that apply to all projects:
188
176
  "timeout": 180,
189
177
  "pollInterval": 1,
190
178
  "captureLines": 100,
191
- "hideOrphanTasks": false
179
+ "preambleEvery": 3
192
180
  }
193
181
  }
194
182
  ```
@@ -200,13 +188,11 @@ Global settings that apply to all projects:
200
188
  | `defaults.timeout` | Default --wait timeout in seconds |
201
189
  | `defaults.pollInterval` | Polling interval in seconds |
202
190
  | `defaults.captureLines` | Default lines for `check` command |
203
- | `defaults.hideOrphanTasks` | Hide tasks without milestone in `pm t list` |
204
-
205
- > **Note:** Agent-specific config (preamble, deny) lives in local `tmux-team.json` only.
191
+ | `defaults.preambleEvery` | Inject preamble every N messages (default: 3) |
206
192
 
207
193
  ---
208
194
 
209
- ## ✨ v2 Features
195
+ ## ✨ Features
210
196
 
211
197
  ### 📡 Enhanced `talk` Command
212
198
 
@@ -239,96 +225,22 @@ tmux-team preamble set gemini "..." # Set preamble
239
225
  tmux-team preamble clear gemini # Remove preamble
240
226
  ```
241
227
 
242
- ### 🔐 Agent Permissions
243
-
244
- Control what agents can do with `deny` patterns in `tmux-team.json`:
245
-
246
- ```json
247
- {
248
- "claude": {
249
- "pane": "10.0",
250
- "deny": ["pm:task:update(status)", "pm:milestone:update(status)"]
251
- }
252
- }
253
- ```
254
-
255
- Pattern format: `pm:<resource>:<action>(<fields>)`
256
-
257
- | Pattern | Effect |
258
- |---------|--------|
259
- | `pm:task:update(status)` | Block status changes only |
260
- | `pm:task:update(*)` | Block all task updates |
261
- | `pm:task:update` | Block entire update action |
262
-
263
- Permissions are enforced via pane identity—agents are identified by which tmux pane they run in, not environment variables.
264
-
265
- ### 🎯 Project Management
266
-
267
- ```bash
268
- # Initialize a team project
269
- tmux-team pm init --name "Auth Refactor"
270
-
271
- # Manage milestones and tasks
272
- tmux-team pm m add "MVP Release"
273
- tmux-team pm t add "Implement login" --milestone 1
274
- tmux-team pm t update 1 --status in_progress
275
- tmux-team pm t done 1
276
-
277
- # View audit log
278
- tmux-team pm log --limit 10
279
- ```
280
-
281
228
  ---
282
229
 
283
230
  ## 🚫 Non-Goals
284
231
 
285
232
  tmux-team intentionally stays lightweight:
286
233
 
287
- - **Not an orchestrator** — No automatic task routing or agent selection
288
- - **Not a session manager** — Doesn't create/manage tmux sessions or git worktrees
234
+ - **Not an orchestrator** — No automatic agent selection or routing
235
+ - **Not a session manager** — Doesn't create/manage tmux sessions
289
236
  - **Not an LLM wrapper** — Doesn't process or route messages through AI
290
237
 
291
238
  It's the plumbing layer that lets humans and AI agents coordinate via tmux, nothing more.
292
239
 
293
240
  ---
294
241
 
295
- *Built for developers who live in the terminal and want their AIs to do the same.*
296
-
297
- ---
298
-
299
242
  ## 📖 Command Reference
300
243
 
301
- ### Core Commands
302
-
303
- ```
304
- tmux-team <command> [arguments]
305
- ```
306
-
307
- | Command | Description |
308
- |---------|-------------|
309
- | `talk <target> <message>` | Send message to an agent (or `all` for broadcast) |
310
- | `check <target> [lines]` | Capture output from agent's pane (default: 100 lines) |
311
- | `list` | List all configured agents |
312
- | `add <name> <pane> [remark]` | Register a new agent |
313
- | `update <name> [options]` | Update an agent's config |
314
- | `remove <name>` | Unregister an agent |
315
- | `init` | Create empty `tmux-team.json` in current directory |
316
- | `config [show\|set\|clear]` | View/modify configuration settings |
317
- | `preamble [show\|set\|clear]` | Manage agent preambles |
318
- | `pm <subcommand>` | Project management commands |
319
- | `completion [zsh\|bash]` | Output shell completion script |
320
- | `help` | Show help message |
321
-
322
- **Aliases:** `send` = talk, `read` = check, `ls` = list, `rm` = remove
323
-
324
- ### Global Options
325
-
326
- | Option | Description |
327
- |--------|-------------|
328
- | `--json` | Output in JSON format |
329
- | `--verbose` | Show detailed output |
330
- | `--force` | Skip warnings |
331
-
332
244
  ### talk Options
333
245
 
334
246
  | Option | Description |
@@ -342,12 +254,10 @@ tmux-team <command> [arguments]
342
254
 
343
255
  ```bash
344
256
  tmux-team config show # Show current config
345
- tmux-team config set <key> <value> # Set a config value
346
257
  tmux-team config set mode wait # Enable wait mode
347
258
  tmux-team config set preambleMode disabled # Disable preambles
348
- tmux-team config set hideOrphanTasks true # Hide tasks without milestone
259
+ tmux-team config set preambleEvery 5 # Inject preamble every 5 messages
349
260
  tmux-team config clear <key> # Clear a config value
350
- tmux-team config --global set ... # Modify global config
351
261
  ```
352
262
 
353
263
  ### preamble Command
@@ -360,87 +270,7 @@ tmux-team preamble clear <agent> # Clear agent's preamble
360
270
 
361
271
  ---
362
272
 
363
- ### Project Management (`pm`)
364
-
365
- ```
366
- tmux-team pm <subcommand>
367
- ```
368
-
369
- **Shorthands:** `pm m` = milestone, `pm t` = task, `pm ls` = list
370
-
371
- #### pm init
372
-
373
- ```bash
374
- tmux-team pm init --name "Project Name"
375
- tmux-team pm init --name "Sprint 1" --backend github --repo owner/repo
376
- ```
377
-
378
- | Option | Description |
379
- |--------|-------------|
380
- | `--name <name>` | Project name (required) |
381
- | `--backend <fs\|github>` | Storage backend (default: `fs`) |
382
- | `--repo <owner/repo>` | GitHub repo (required for github backend) |
383
-
384
- #### pm list
385
-
386
- ```bash
387
- tmux-team pm list # List all teams/projects
388
- tmux-team pm ls # Shorthand
389
- ```
390
-
391
- #### pm milestone (shorthand: `pm m`)
392
-
393
- ```bash
394
- tmux-team pm m # List all milestones
395
- tmux-team pm m add "Phase 1" # Add milestone
396
- tmux-team pm m add "Phase 1" -d "..." # Add with description
397
- tmux-team pm m list # List milestones
398
- tmux-team pm m done <id> # Mark milestone complete
399
- tmux-team pm m delete <id> # Delete milestone (or: rm)
400
- tmux-team pm m doc <id> # Print milestone documentation
401
- tmux-team pm m doc <id> --edit # Edit doc in $EDITOR
402
- tmux-team pm m doc <id> ref # Print doc path/reference
403
- tmux-team pm m doc <id> --body "..." # Set doc content directly
404
- tmux-team pm m doc <id> --body-file x # Set doc content from file
405
- ```
406
-
407
- #### pm task (shorthand: `pm t`)
408
-
409
- ```bash
410
- tmux-team pm t # List all tasks
411
- tmux-team pm t add "Task title" # Add task
412
- tmux-team pm t add "..." --milestone 1 # Add task to milestone
413
- tmux-team pm t add "..." --body "..." # Add task with body
414
- tmux-team pm t add "..." -a @user # Add task with assignee
415
- tmux-team pm t list # List tasks
416
- tmux-team pm t list --status pending # Filter by status
417
- tmux-team pm t list --milestone 1 # Filter by milestone
418
- tmux-team pm t show <id> # Show task details
419
- tmux-team pm t update <id> --status in_progress
420
- tmux-team pm t update <id> -a @user # Assign task
421
- tmux-team pm t done <id> # Mark task complete
422
- tmux-team pm t doc <id> # Print task documentation
423
- tmux-team pm t doc <id> --edit # Edit doc in $EDITOR
424
- tmux-team pm t doc <id> ref # Print doc path/reference
425
- tmux-team pm t doc <id> --body "..." # Set doc content directly
426
- tmux-team pm t doc <id> --body-file x # Set doc content from file
427
- ```
428
-
429
- #### pm log
430
-
431
- ```bash
432
- tmux-team pm log # Show audit event log
433
- tmux-team pm log --limit 10 # Limit to 10 events
434
- ```
435
-
436
- ---
437
-
438
- ### Storage Backends
439
-
440
- | Backend | Description |
441
- |---------|-------------|
442
- | `fs` | Local filesystem (default). Tasks stored in `~/.config/tmux-team/teams/` |
443
- | `github` | GitHub Issues. Tasks become issues, milestones sync with GitHub |
273
+ *Built for developers who live in the terminal and want their AIs to do the same.*
444
274
 
445
275
  ---
446
276
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-team",
3
- "version": "2.2.0",
3
+ "version": "3.0.0-alpha.1",
4
4
  "description": "CLI tool for AI agent collaboration in tmux - manage cross-pane communication",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -17,7 +17,6 @@ import { cmdRemove } from './commands/remove.js';
17
17
  import { cmdTalk } from './commands/talk.js';
18
18
  import { cmdCheck } from './commands/check.js';
19
19
  import { cmdCompletion } from './commands/completion.js';
20
- import { cmdPm } from './pm/commands.js';
21
20
  import { cmdConfig } from './commands/config.js';
22
21
  import { cmdPreamble } from './commands/preamble.js';
23
22
 
@@ -203,10 +202,6 @@ function main(): void {
203
202
  cmdCheck(ctx, args[0], args[1] ? parseInt(args[1], 10) : undefined);
204
203
  break;
205
204
 
206
- case 'pm':
207
- await cmdPm(ctx, args);
208
- break;
209
-
210
205
  case 'config':
211
206
  cmdConfig(ctx, args);
212
207
  break;
@@ -15,13 +15,11 @@ import {
15
15
 
16
16
  type EnumConfigKey = 'mode' | 'preambleMode';
17
17
  type NumericConfigKey = 'preambleEvery';
18
- type BoolConfigKey = 'hideOrphanTasks';
19
- type ConfigKey = EnumConfigKey | NumericConfigKey | BoolConfigKey;
18
+ type ConfigKey = EnumConfigKey | NumericConfigKey;
20
19
 
21
20
  const ENUM_KEYS: EnumConfigKey[] = ['mode', 'preambleMode'];
22
21
  const NUMERIC_KEYS: NumericConfigKey[] = ['preambleEvery'];
23
- const BOOL_KEYS: BoolConfigKey[] = ['hideOrphanTasks'];
24
- const VALID_KEYS: ConfigKey[] = [...ENUM_KEYS, ...NUMERIC_KEYS, ...BOOL_KEYS];
22
+ const VALID_KEYS: ConfigKey[] = [...ENUM_KEYS, ...NUMERIC_KEYS];
25
23
 
26
24
  const VALID_VALUES: Record<EnumConfigKey, string[]> = {
27
25
  mode: ['polling', 'wait'],
@@ -40,10 +38,6 @@ function isNumericKey(key: ConfigKey): key is NumericConfigKey {
40
38
  return NUMERIC_KEYS.includes(key as NumericConfigKey);
41
39
  }
42
40
 
43
- function isBoolKey(key: ConfigKey): key is BoolConfigKey {
44
- return BOOL_KEYS.includes(key as BoolConfigKey);
45
- }
46
-
47
41
  function isValidValue(key: EnumConfigKey, value: string): boolean {
48
42
  return VALID_VALUES[key].includes(value);
49
43
  }
@@ -62,7 +56,6 @@ function showConfig(ctx: Context): void {
62
56
  mode: ctx.config.mode,
63
57
  preambleMode: ctx.config.preambleMode,
64
58
  preambleEvery: ctx.config.defaults.preambleEvery,
65
- hideOrphanTasks: ctx.config.defaults.hideOrphanTasks,
66
59
  defaults: ctx.config.defaults,
67
60
  },
68
61
  sources: {
@@ -78,8 +71,6 @@ function showConfig(ctx: Context): void {
78
71
  : globalConfig.defaults?.preambleEvery !== undefined
79
72
  ? 'global'
80
73
  : 'default',
81
- hideOrphanTasks:
82
- globalConfig.defaults?.hideOrphanTasks !== undefined ? 'global' : 'default',
83
74
  },
84
75
  paths: {
85
76
  global: ctx.paths.globalConfig,
@@ -102,8 +93,6 @@ function showConfig(ctx: Context): void {
102
93
  : globalConfig.defaults?.preambleEvery !== undefined
103
94
  ? '(global)'
104
95
  : '(default)';
105
- const hideOrphanSource =
106
- globalConfig.defaults?.hideOrphanTasks !== undefined ? '(global)' : '(default)';
107
96
 
108
97
  ctx.ui.info('Current configuration:\n');
109
98
  ctx.ui.table(
@@ -112,7 +101,6 @@ function showConfig(ctx: Context): void {
112
101
  ['mode', ctx.config.mode, modeSource],
113
102
  ['preambleMode', ctx.config.preambleMode, preambleSource],
114
103
  ['preambleEvery', String(ctx.config.defaults.preambleEvery), preambleEverySource],
115
- ['hideOrphanTasks', String(ctx.config.defaults.hideOrphanTasks), hideOrphanSource],
116
104
  ['defaults.timeout', String(ctx.config.defaults.timeout), '(global)'],
117
105
  ['defaults.pollInterval', String(ctx.config.defaults.pollInterval), '(global)'],
118
106
  ['defaults.captureLines', String(ctx.config.defaults.captureLines), '(global)'],
@@ -154,31 +142,6 @@ function setConfig(ctx: Context, key: string, value: string, global: boolean): v
154
142
  }
155
143
  }
156
144
 
157
- if (isBoolKey(validKey)) {
158
- if (value !== 'true' && value !== 'false') {
159
- ctx.ui.error(`Invalid value for ${key}: ${value}. Use true or false.`);
160
- ctx.exit(ExitCodes.ERROR);
161
- }
162
- }
163
-
164
- if (key === 'hideOrphanTasks') {
165
- const globalConfig = loadGlobalConfig(ctx.paths);
166
- if (!globalConfig.defaults) {
167
- globalConfig.defaults = {
168
- timeout: 180,
169
- pollInterval: 1,
170
- captureLines: 100,
171
- preambleEvery: ctx.config.defaults.preambleEvery,
172
- hideOrphanTasks: value === 'true',
173
- };
174
- } else {
175
- globalConfig.defaults.hideOrphanTasks = value === 'true';
176
- }
177
- saveGlobalConfig(ctx.paths, globalConfig);
178
- ctx.ui.success(`Set ${key}=${value} in global config`);
179
- return;
180
- }
181
-
182
145
  if (global) {
183
146
  // Set in global config
184
147
  const globalConfig = loadGlobalConfig(ctx.paths);
@@ -193,7 +156,6 @@ function setConfig(ctx: Context, key: string, value: string, global: boolean): v
193
156
  pollInterval: 1,
194
157
  captureLines: 100,
195
158
  preambleEvery: parseInt(value, 10),
196
- hideOrphanTasks: ctx.config.defaults.hideOrphanTasks,
197
159
  };
198
160
  } else {
199
161
  globalConfig.defaults.preambleEvery = parseInt(value, 10);
@@ -223,10 +185,6 @@ function clearConfig(ctx: Context, key?: string): void {
223
185
  ctx.ui.error(`Invalid key: ${key}. Valid keys: ${VALID_KEYS.join(', ')}`);
224
186
  ctx.exit(ExitCodes.ERROR);
225
187
  }
226
- if (key === 'hideOrphanTasks') {
227
- ctx.ui.error(`Cannot clear global-only key: ${key}. Edit global config instead.`);
228
- ctx.exit(ExitCodes.ERROR);
229
- }
230
188
 
231
189
  // Clear specific key from local settings
232
190
  const localConfigFile = loadLocalConfigFile(ctx.paths);
@@ -42,7 +42,6 @@ ${colors.yellow('COMMANDS')}
42
42
  ${colors.green('init')} Create empty tmux-team.json
43
43
  ${colors.green('config')} [show|set|clear] View/modify settings
44
44
  ${colors.green('preamble')} [show|set|clear] Manage agent preambles
45
- ${colors.green('pm')} <subcommand> Project management (run 'pm help')
46
45
  ${colors.green('completion')} Output shell completion script
47
46
  ${colors.green('help')} Show this help message
48
47
 
@@ -80,6 +79,5 @@ ${colors.yellow('CHANGE MODE')}
80
79
  tmux-team config set mode polling ${colors.dim('Enable polling mode (local)')}
81
80
  tmux-team config set preambleMode disabled ${colors.dim('Disable preambles (local)')}
82
81
  tmux-team config set preambleEvery 5 ${colors.dim('Inject preamble every 5 messages')}
83
- tmux-team config set hideOrphanTasks true ${colors.dim('Hide tasks without milestones (global)')}
84
82
  `);
85
83
  }