tmux-team 4.0.0-beta.1 → 4.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.
package/README.md CHANGED
@@ -18,26 +18,35 @@ npm install -g tmux-team
18
18
  # 1. Install for your AI agent
19
19
  tmt install claude # or: tmt install codex
20
20
 
21
- # 2. Go to working folder and initialize
22
- tmt init
23
-
24
- # 3. Register agents (run inside each agent's pane)
21
+ # 2. Go to working folder and register agents (run inside each agent's pane)
25
22
  tmt this claude # registers current pane as "claude"
26
23
  tmt this codex # registers current pane as "codex"
27
24
 
28
- # 4. Talk to agents
25
+ # 3. Talk to agents
29
26
  tmt talk codex "Review this code" # waits for response by default
30
27
 
31
- # 5. Update or remove an agent
28
+ # 4. Update or remove an agent
32
29
  tmt update codex --pane 2.3
33
30
  tmt rm codex
34
31
  ```
35
32
 
36
33
  > **Tip:** Most AI agents support `!` to run bash commands. From inside Claude Code, Codex, or Gemini CLI, you can run `!tmt this myname` to quickly register that pane.
37
34
 
35
+ ### How scopes work
36
+
37
+ Registrations live in tmux pane metadata, not in a JSON file you have to track.
38
+ By default they are scoped to the current **workspace** — the nearest Git root,
39
+ or the current folder when you are not inside a Git repo. So `tmt this`,
40
+ `tmt add`, `tmt rm`, `tmt update`, `tmt preamble`, and `tmt list` all act on
41
+ the workspace you are currently in.
42
+
43
+ Reach for `--team <name>` only when you want an explicit shared team that spans
44
+ folders (see [Shared Teams](#shared-teams)).
45
+
38
46
  ## Cross-Folder Collaboration
39
47
 
40
- Agents don't need to be in the same folder to collaborate. You can add an agent from one project to another:
48
+ Agents don't need to be in the same folder to collaborate. From your current
49
+ workspace you can add an agent whose pane lives in another project:
41
50
 
42
51
  ```bash
43
52
  # In project-a folder, add an agent that's running in project-b
@@ -46,6 +55,10 @@ tmt add codex-reviewer 5.1 # Use the pane ID from the other project
46
55
 
47
56
  Find pane IDs with: `tmux display-message -p "#{pane_id}"`
48
57
 
58
+ This still uses the default workspace scope: the registration is visible from
59
+ project-a, not from project-b. For long-running collaboration that should be
60
+ visible on both sides, use a [shared team](#shared-teams).
61
+
49
62
  ## Commands
50
63
 
51
64
  | Command | Description |
@@ -55,7 +68,10 @@ Find pane IDs with: `tmux display-message -p "#{pane_id}"`
55
68
  | `talk <agent> "msg"` | Send message and wait for response |
56
69
  | `talk all "msg"` | Broadcast to all agents |
57
70
  | `check <agent> [lines]` | Read agent's pane output |
58
- | `list` | Show configured agents |
71
+ | `list` | Show agents in the current workspace (or `--team <name>`) |
72
+ | `migrate [--dry-run] [--cleanup]` | Move legacy `tmux-team.json` entries into tmux pane metadata |
73
+ | `team ls [--summary\|--json]` | Inspect tmux panes grouped by scope; `--summary` aggregates shared teams |
74
+ | `team rm <team> --force` | Remove a shared team registration from every pane |
59
75
  | `learn` | Show educational guide |
60
76
 
61
77
  **Options for `talk`:**
@@ -76,39 +92,100 @@ tmt config set pasteEnterDelayMs 500
76
92
 
77
93
  ## Managing Your Team
78
94
 
79
- Configuration lives in `tmux-team.json` in your project root.
95
+ Agent registrations live in tmux pane metadata, scoped per workspace by
96
+ default. The same-folder workflow never needs `--team`.
80
97
 
81
- **List** - Show configured agents:
98
+ **List agents in this workspace:**
82
99
  ```bash
83
100
  tmt ls
101
+ tmt ls --team myproject # or list a shared team
102
+ ```
103
+
104
+ **Inspect every tmux pane** with `tmt team ls`. Output is grouped by scope —
105
+ shared teams first, then workspaces, then unregistered panes — and each
106
+ section's title lists the agents living there:
107
+
108
+ ```
109
+ Team: acme-app (codex, gemini)
110
+ PANE TARGET CWD CMD
111
+ %12 main:1.0 ~/acme/frontend node
112
+ %17 main:2.0 ~/acme/backend python
113
+
114
+ Workspace: ~/dev/tmux-team (claude)
115
+ PANE TARGET CWD CMD
116
+ %3 work:0.1 ~/dev/tmux-team node
117
+
118
+ Unregistered panes
119
+ PANE TARGET CWD CMD
120
+ %9 misc:0.0 ~/scratch zsh
84
121
  ```
85
122
 
86
- **Edit** - Modify `tmux-team.json` directly:
87
- ```json
88
- {
89
- "$config": { "pasteEnterDelayMs": 500 },
90
- "codex": { "pane": "1.1", "remark": "Code reviewer" },
91
- "gemini": { "pane": "1.2", "remark": "Documentation" }
92
- }
123
+ ```bash
124
+ tmt team ls # grouped pane inventory (default)
125
+ tmt team ls --summary # collapse to a shared-team aggregate (TEAM / AGENTS)
126
+ tmt team ls --json # { teams, panes } incl. each pane's registrations
127
+ ```
128
+
129
+ **Add an agent from any pane.** Targets can be `%pane_id`, `window.pane`, or
130
+ `session:window.pane`; tmux-team stores the canonical `%pane_id`.
131
+
132
+ ```bash
133
+ tmt add codex 1.1 "Code reviewer"
93
134
  ```
94
135
 
95
- **Remove** - Delete an agent:
136
+ **Remove an agent** from the current scope:
96
137
  ```bash
97
138
  tmt rm codex
98
139
  ```
99
140
 
141
+ **Migrate from legacy `tmux-team.json`.** Versions before v4 stored agents in
142
+ a JSON file. `tmt migrate` copies those entries into tmux pane metadata so the
143
+ new commands can see them. Run it once per project that still has the file:
144
+
145
+ ```bash
146
+ tmt migrate --dry-run # preview what would move
147
+ tmt migrate # move entries into tmux metadata
148
+ tmt migrate --cleanup # also delete the migrated entries from the JSON file
149
+ ```
150
+
151
+ `tmux-team.json` is still loaded as a fallback when no tmux metadata exists,
152
+ and it remains the home for local `$config` overrides. If you don't use it,
153
+ you can ignore it.
154
+
100
155
  ---
101
156
 
157
+ ## Agent Preambles
158
+
159
+ Set a per-agent preamble to steer behavior (stored with the pane registration):
160
+
161
+ ```bash
162
+ tmt preamble set codex "You are the code quality guard. Be strict."
163
+ ```
164
+
165
+ ### What Happens When a Preamble Is Set
166
+
167
+ When you send a message, tmux-team injects the preamble like this:
168
+
169
+ ```
170
+ [SYSTEM: You are the code quality guard. Be strict.]
171
+
172
+ Review the login flow changes.
173
+ ```
174
+
175
+ Control how often it’s injected with `preambleEvery`:
176
+
177
+ ```bash
178
+ tmt config set preambleEvery 3
179
+ ```
180
+
102
181
  ## Shared Teams
103
182
 
104
183
  > *Work on different folders but talk to the same team of agents.*
105
184
 
106
- By default, `tmux-team.json` is local to each folder. The `--team` flag lets agents across different folders share a team:
185
+ By default, registrations are scoped to the current workspace. The `--team` flag
186
+ creates an explicit shared team that works across folders:
107
187
 
108
188
  ```bash
109
- # Initialize a shared team
110
- tmt init --team myproject
111
-
112
189
  # Register agents from ANY folder
113
190
  cd ~/code/frontend && tmt this claude --team myproject
114
191
  cd ~/code/backend && tmt this codex --team myproject
@@ -128,16 +205,17 @@ tmt talk all "Starting deploy - heads up" --team myproject
128
205
 
129
206
  **Single project** (default) — agents work in the same folder:
130
207
  ```bash
131
- tmt init
132
208
  tmt this claude
133
209
  tmt add codex 1.1
134
210
  ```
135
211
 
136
212
  **Shared team** — agents work across folders but collaborate:
137
213
  ```bash
138
- tmt init --team acme-app
139
214
  tmt this frontend-claude --team acme-app # from ~/acme/frontend
140
215
  tmt this backend-codex --team acme-app # from ~/acme/backend
216
+ tmt ls --team acme-app # list members
217
+ tmt team ls --summary # all shared teams at a glance
218
+ tmt team rm acme-app --force # remove the team from every pane
141
219
  ```
142
220
 
143
221
  ### Multi-team coordination
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-team",
3
- "version": "4.0.0-beta.1",
3
+ "version": "4.1.0",
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.test.ts CHANGED
@@ -16,7 +16,14 @@ function makeStubContext(): Context {
16
16
  config: {
17
17
  mode: 'polling',
18
18
  preambleMode: 'always',
19
- defaults: { timeout: 180, pollInterval: 1, captureLines: 100, maxCaptureLines: 2000, preambleEvery: 3, pasteEnterDelayMs: 500 },
19
+ defaults: {
20
+ timeout: 180,
21
+ pollInterval: 1,
22
+ captureLines: 100,
23
+ maxCaptureLines: 2000,
24
+ preambleEvery: 3,
25
+ pasteEnterDelayMs: 500,
26
+ },
20
27
  agents: {},
21
28
  paneRegistry: {},
22
29
  },
@@ -25,6 +32,13 @@ function makeStubContext(): Context {
25
32
  capture: vi.fn(),
26
33
  listPanes: vi.fn(() => []),
27
34
  getCurrentPaneId: vi.fn(() => null),
35
+ resolvePaneTarget: vi.fn((target: string) => target),
36
+ getAgentRegistry: vi.fn(() => ({ paneRegistry: {}, agents: {} })),
37
+ setAgentRegistration: vi.fn(),
38
+ clearAgentRegistration: vi.fn(() => false),
39
+ listTeams: vi.fn(() => ({})),
40
+ listTeamPanes: vi.fn(() => []),
41
+ removeTeam: vi.fn(() => ({ removed: 0, agents: [] })),
28
42
  },
29
43
  paths: {
30
44
  globalDir: '/g',
package/src/cli.ts CHANGED
@@ -22,6 +22,8 @@ import { cmdPreamble } from './commands/preamble.js';
22
22
  import { cmdInstall } from './commands/install.js';
23
23
  import { cmdLearn } from './commands/learn.js';
24
24
  import { cmdThis } from './commands/this.js';
25
+ import { cmdMigrate } from './commands/migrate.js';
26
+ import { cmdTeam } from './commands/team.js';
25
27
 
26
28
  // ─────────────────────────────────────────────────────────────
27
29
  // Argument parsing
@@ -206,6 +208,14 @@ function main(): void {
206
208
  cmdRemove(ctx, args[0]);
207
209
  break;
208
210
 
211
+ case 'migrate':
212
+ cmdMigrate(ctx, args);
213
+ break;
214
+
215
+ case 'team':
216
+ cmdTeam(ctx, args);
217
+ break;
218
+
209
219
  case 'this':
210
220
  if (args.length < 1) {
211
221
  ctx.ui.error('Usage: tmux-team this <name> [remark]');
@@ -2,54 +2,39 @@
2
2
  // add command - register a new agent
3
3
  // ─────────────────────────────────────────────────────────────
4
4
 
5
- import fs from 'fs';
6
- import type { Context, PaneEntry } from '../types.js';
5
+ import type { Context } from '../types.js';
7
6
  import { ExitCodes } from '../exits.js';
8
- import { loadLocalConfigFile, saveLocalConfigFile, ensureTeamsDir } from '../config.js';
7
+ import { getRegistryScope, registrationFromEntry } from '../registry.js';
9
8
 
10
9
  export function cmdAdd(ctx: Context, name: string, pane: string, remark?: string): void {
11
- const { ui, config, paths, flags, exit } = ctx;
12
-
13
- // Ensure teams directory exists if using --team
14
- if (flags.team) {
15
- ensureTeamsDir(paths.globalDir);
16
- }
17
-
18
- // Create config file if it doesn't exist
19
- if (!fs.existsSync(paths.localConfig)) {
20
- fs.writeFileSync(paths.localConfig, '{}\n');
21
- if (!flags.json) {
22
- if (flags.team) {
23
- ui.info(`Created shared team "${flags.team}"`);
24
- } else {
25
- ui.info(`Created ${paths.localConfig}`);
26
- }
27
- }
28
- }
10
+ const { ui, config, tmux, flags, exit } = ctx;
29
11
 
30
12
  if (config.paneRegistry[name]) {
31
13
  ui.error(`Agent '${name}' already exists. Use 'tmux-team update' to modify.`);
32
14
  exit(ExitCodes.ERROR);
33
15
  }
34
16
 
35
- // Load existing config to preserve all fields (preamble, deny, etc.)
36
- const localConfig = loadLocalConfigFile(paths);
37
-
38
- const newEntry: PaneEntry = { pane };
39
- if (remark) {
40
- newEntry.remark = remark;
17
+ const resolvedPane = tmux.resolvePaneTarget(pane);
18
+ if (!resolvedPane) {
19
+ ui.error(`Pane '${pane}' not found. Is tmux running?`);
20
+ exit(ExitCodes.PANE_NOT_FOUND);
41
21
  }
42
- localConfig[name] = newEntry;
22
+ const paneId = resolvedPane as string;
43
23
 
44
- saveLocalConfigFile(paths, localConfig);
24
+ const scope = getRegistryScope(ctx);
25
+ const registration = registrationFromEntry(name, {
26
+ pane: paneId,
27
+ ...(remark !== undefined && { remark }),
28
+ });
29
+ tmux.setAgentRegistration(paneId, scope, registration);
45
30
 
46
31
  if (flags.json) {
47
- ui.json({ added: name, pane, remark, team: flags.team });
32
+ ui.json({ added: name, pane: paneId, remark, team: flags.team });
48
33
  } else {
49
34
  if (flags.team) {
50
- ui.success(`Added agent '${name}' to team "${flags.team}" at pane ${pane}`);
35
+ ui.success(`Added agent '${name}' to team "${flags.team}" at pane ${paneId}`);
51
36
  } else {
52
- ui.success(`Added agent '${name}' at pane ${pane}`);
37
+ ui.success(`Added agent '${name}' at pane ${paneId}`);
53
38
  }
54
39
  }
55
40
  }