tmux-ide 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wavyrai
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,95 @@
1
+ # tmux-ide
2
+
3
+ Turn any project into a tmux-powered terminal IDE with a simple `ide.yml` config file.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g tmux-ide
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ tmux-ide init # Scaffold ide.yml (auto-detects your stack)
15
+ tmux-ide # Launch the IDE
16
+ tmux-ide stop # Kill the session
17
+ tmux-ide restart # Stop and relaunch
18
+ tmux-ide attach # Reattach to a running session
19
+ ```
20
+
21
+ ## ide.yml Format
22
+
23
+ ```yaml
24
+ name: project-name # tmux session name
25
+
26
+ before: pnpm install # optional pre-launch hook
27
+
28
+ rows:
29
+ - size: 70% # row height percentage
30
+ panes:
31
+ - title: Editor # pane border label
32
+ command: vim # command to run (optional)
33
+ size: 60% # pane width percentage (optional)
34
+ dir: apps/web # per-pane working directory (optional)
35
+ focus: true # initial focus (optional)
36
+ env: # environment variables (optional)
37
+ PORT: 3000
38
+ - title: Shell
39
+
40
+ - panes:
41
+ - title: Dev Server
42
+ command: pnpm dev
43
+ - title: Tests
44
+ command: pnpm test
45
+
46
+ theme: # optional color overrides
47
+ accent: colour75
48
+ border: colour238
49
+ bg: colour235
50
+ fg: colour248
51
+ ```
52
+
53
+ ## Commands
54
+
55
+ | Command | Description |
56
+ |---------|-------------|
57
+ | `tmux-ide` | Launch IDE from `ide.yml` |
58
+ | `tmux-ide <path>` | Launch from a specific directory |
59
+ | `tmux-ide init [--template <name>]` | Scaffold a new `ide.yml` |
60
+ | `tmux-ide stop` | Kill the current IDE session |
61
+ | `tmux-ide restart` | Stop and relaunch the IDE session |
62
+ | `tmux-ide attach` | Reattach to a running session |
63
+ | `tmux-ide ls` | List all tmux sessions |
64
+ | `tmux-ide status` | Show session status |
65
+ | `tmux-ide doctor` | Check system requirements |
66
+ | `tmux-ide validate` | Validate `ide.yml` |
67
+ | `tmux-ide detect` | Detect project stack |
68
+ | `tmux-ide detect --write` | Detect and write `ide.yml` |
69
+ | `tmux-ide config` | Dump config as JSON |
70
+ | `tmux-ide config set <path> <value>` | Set a config value |
71
+ | `tmux-ide config add-pane --row <N>` | Add a pane to a row |
72
+ | `tmux-ide config remove-pane --row <N> --pane <M>` | Remove a pane |
73
+ | `tmux-ide config add-row [--size <percent>]` | Add a new row |
74
+
75
+ All commands support `--json` for structured output.
76
+
77
+ ## Templates
78
+
79
+ Use `tmux-ide init --template <name>` with one of:
80
+
81
+ - `default` — General-purpose layout
82
+ - `nextjs` — Next.js development
83
+ - `convex` — Convex + Next.js
84
+ - `vite` — Vite project
85
+ - `python` — Python development
86
+ - `go` — Go development
87
+
88
+ ## Requirements
89
+
90
+ - **tmux** >= 3.0
91
+ - **Node.js** >= 18
92
+
93
+ ## License
94
+
95
+ [MIT](LICENSE)
package/bin/cli.js ADDED
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { createRequire } from "node:module";
4
+ import { launch } from "../src/launch.js";
5
+ import { init } from "../src/init.js";
6
+ import { stop } from "../src/stop.js";
7
+ import { attach } from "../src/attach.js";
8
+ import { ls } from "../src/ls.js";
9
+ import { doctor } from "../src/doctor.js";
10
+ import { status } from "../src/status.js";
11
+ import { validate } from "../src/validate.js";
12
+ import { detect } from "../src/detect.js";
13
+ import { config } from "../src/config.js";
14
+ import { restart } from "../src/restart.js";
15
+
16
+ const { positionals, values } = parseArgs({
17
+ allowPositionals: true,
18
+ strict: false,
19
+ options: {
20
+ json: { type: "boolean" },
21
+ row: { type: "string" },
22
+ pane: { type: "string" },
23
+ title: { type: "string" },
24
+ command: { type: "string" },
25
+ size: { type: "string" },
26
+ write: { type: "boolean" },
27
+ template: { type: "string" },
28
+ name: { type: "string" },
29
+ help: { type: "boolean", short: "h" },
30
+ version: { type: "boolean", short: "v" },
31
+ },
32
+ });
33
+
34
+ // --version / -v
35
+ if (values.version) {
36
+ const require = createRequire(import.meta.url);
37
+ const pkg = require("../package.json");
38
+ console.log(`tmux-ide v${pkg.version}`);
39
+ process.exit(0);
40
+ }
41
+
42
+ const command = positionals[0] ?? "start";
43
+ const json = values.json ?? false;
44
+
45
+ const noColor = "NO_COLOR" in process.env;
46
+ const bold = (s) => (noColor ? s : `\x1b[1m${s}\x1b[22m`);
47
+ const cyan = (s) => (noColor ? s : `\x1b[36m${s}\x1b[39m`);
48
+ const dim = (s) => (noColor ? s : `\x1b[2m${s}\x1b[22m`);
49
+
50
+ function printHelp() {
51
+ console.log(`${bold("tmux-ide")} — Terminal IDE powered by tmux
52
+
53
+ ${bold("Usage:")}
54
+ ${cyan("tmux-ide")} ${dim("Launch IDE from ide.yml")}
55
+ ${cyan("tmux-ide <path>")} ${dim("Launch from a specific directory")}
56
+ ${cyan("tmux-ide init")} [--template] ${dim("Scaffold a new ide.yml (auto-detects stack)")}
57
+ ${cyan("tmux-ide stop")} ${dim("Kill the current IDE session")}
58
+ ${cyan("tmux-ide restart")} ${dim("Stop and relaunch the IDE session")}
59
+ ${cyan("tmux-ide attach")} ${dim("Reattach to a running session")}
60
+ ${cyan("tmux-ide ls")} ${dim("List all tmux sessions")}
61
+ ${cyan("tmux-ide status")} [--json] ${dim("Show session status")}
62
+ ${cyan("tmux-ide doctor")} ${dim("Check system requirements")}
63
+ ${cyan("tmux-ide validate")} [--json] ${dim("Validate ide.yml")}
64
+ ${cyan("tmux-ide detect")} [--json] ${dim("Detect project stack")}
65
+ ${cyan("tmux-ide detect --write")} ${dim("Detect and write ide.yml")}
66
+ ${cyan("tmux-ide config")} [--json] ${dim("Dump config as JSON")}
67
+ ${cyan("tmux-ide config set")} <path> <value>
68
+ ${cyan("tmux-ide config add-pane")} --row <N> --title <T> [--command <C>]
69
+ ${cyan("tmux-ide config remove-pane")} --row <N> --pane <M>
70
+ ${cyan("tmux-ide config add-row")} [--size <percent>]
71
+ ${cyan("tmux-ide config enable-team")} [--name <N>] ${dim("Enable agent teams")}
72
+ ${cyan("tmux-ide config disable-team")} ${dim("Disable agent teams")}
73
+
74
+ ${bold("Flags:")}
75
+ ${cyan("--json")} ${dim("Output as JSON (all commands)")}
76
+ ${cyan("--template <name>")} ${dim("Use specific template for init")}
77
+ ${cyan("--write")} ${dim("Write detected config to ide.yml")}
78
+ ${cyan("-v, --version")} ${dim("Show version number")}`);
79
+ }
80
+
81
+ switch (command) {
82
+ case "start":
83
+ await launch(positionals[1]);
84
+ break;
85
+
86
+ case "init":
87
+ await init({ template: values.template, json });
88
+ break;
89
+
90
+ case "stop":
91
+ await stop(positionals[1], { json });
92
+ break;
93
+
94
+ case "attach":
95
+ await attach(positionals[1], { json });
96
+ break;
97
+
98
+ case "restart":
99
+ await restart(positionals[1]);
100
+ break;
101
+
102
+ case "ls":
103
+ await ls({ json });
104
+ break;
105
+
106
+ case "doctor":
107
+ await doctor({ json });
108
+ break;
109
+
110
+ case "status":
111
+ await status(positionals[1], { json });
112
+ break;
113
+
114
+ case "validate":
115
+ await validate(positionals[1], { json });
116
+ break;
117
+
118
+ case "detect":
119
+ await detect(positionals[1], { json, write: values.write });
120
+ break;
121
+
122
+ case "config": {
123
+ const sub = positionals[1]; // set, add-pane, remove-pane, add-row, or undefined (dump)
124
+ let action = "dump";
125
+ let configArgs = [];
126
+
127
+ if (sub === "set") {
128
+ action = "set";
129
+ configArgs = positionals.slice(2);
130
+ } else if (sub === "add-pane") {
131
+ action = "add-pane";
132
+ // Pass named flags as args array
133
+ configArgs = [];
134
+ if (values.row !== undefined) configArgs.push("--row", values.row);
135
+ if (values.title !== undefined) configArgs.push("--title", values.title);
136
+ if (values.command !== undefined) configArgs.push("--command", values.command);
137
+ if (values.size !== undefined) configArgs.push("--size", values.size);
138
+ } else if (sub === "remove-pane") {
139
+ action = "remove-pane";
140
+ configArgs = [];
141
+ if (values.row !== undefined) configArgs.push("--row", values.row);
142
+ if (values.pane !== undefined) configArgs.push("--pane", values.pane);
143
+ } else if (sub === "add-row") {
144
+ action = "add-row";
145
+ configArgs = [];
146
+ if (values.size !== undefined) configArgs.push("--size", values.size);
147
+ } else if (sub === "enable-team") {
148
+ action = "enable-team";
149
+ configArgs = [];
150
+ if (values.name !== undefined) configArgs.push("--name", values.name);
151
+ } else if (sub === "disable-team") {
152
+ action = "disable-team";
153
+ configArgs = [];
154
+ }
155
+
156
+ await config(null, { json, action, args: configArgs });
157
+ break;
158
+ }
159
+
160
+ case "help":
161
+ printHelp();
162
+ break;
163
+
164
+ default:
165
+ console.error(`Unknown command: ${command}`);
166
+ console.error('Run "tmux-ide help" for usage.');
167
+ process.exit(1);
168
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "tmux-ide",
3
+ "version": "1.0.0",
4
+ "description": "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
5
+ "type": "module",
6
+ "bin": {
7
+ "tmux-ide": "bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "scripts",
13
+ "skill",
14
+ "templates"
15
+ ],
16
+ "scripts": {
17
+ "dev": "node bin/cli.js",
18
+ "test": "node --test 'src/**/*.test.js'",
19
+ "postinstall": "node scripts/postinstall.js",
20
+ "docs": "cd docs && pnpm dev"
21
+ },
22
+ "keywords": [
23
+ "tmux",
24
+ "ide",
25
+ "terminal",
26
+ "workspace",
27
+ "developer-tools"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/wavyrai/tmux-ide.git"
35
+ },
36
+ "homepage": "https://github.com/wavyrai/tmux-ide#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/wavyrai/tmux-ide/issues"
39
+ },
40
+ "license": "MIT",
41
+ "dependencies": {
42
+ "js-yaml": "^4.1.0"
43
+ }
44
+ }
@@ -0,0 +1,13 @@
1
+ import { existsSync, mkdirSync, copyFileSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { homedir } from "node:os";
4
+
5
+ const claudeDir = resolve(homedir(), ".claude");
6
+ if (existsSync(claudeDir)) {
7
+ const skillDir = resolve(claudeDir, "skills", "tmux-ide");
8
+ mkdirSync(skillDir, { recursive: true });
9
+ const src = resolve(dirname(import.meta.dirname), "skill", "SKILL.md");
10
+ if (existsSync(src)) {
11
+ copyFileSync(src, resolve(skillDir, "SKILL.md"));
12
+ }
13
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,238 @@
1
+ # tmux-ide — Claude Code Skill
2
+
3
+ tmux-ide turns any project into a tmux-powered terminal IDE using a simple `ide.yml` config file.
4
+
5
+ ## When to use
6
+
7
+ - User mentions multi-pane, tmux, terminal IDE, or dev environment
8
+ - User wants to set up a development workspace
9
+ - User asks about running multiple terminals/tools side-by-side
10
+ - User wants to coordinate multiple Claude Code instances as a team
11
+ - User mentions agent teams, team lead, or multi-agent workflows
12
+
13
+ ## Setup workflow
14
+
15
+ 1. Check if `ide.yml` exists: `tmux-ide status --json`
16
+ 2. Auto-detect the project: `tmux-ide detect --json`
17
+ 3. **Present 2-3 layout options using ASCII diagrams** before writing config. Example:
18
+
19
+ **Option A — Dual Claude + Dev (recommended)**
20
+ ```
21
+ ┌─────────────────┬─────────────────┐
22
+ │ │ │
23
+ │ Claude 1 │ Claude 2 │ 70%
24
+ │ │ │
25
+ ├────────┬────────┴────────┬────────┤
26
+ │Dev Srv │ Tests │ Shell │ │ 30%
27
+ └────────┴─────────┴───────┘────────┘
28
+ ```
29
+
30
+ **Option B — Triple Claude**
31
+ ```
32
+ ┌───────────┬───────────┬───────────┐
33
+ │ │ │ │
34
+ │ Claude 1 │ Claude 2 │ Claude 3 │ 70%
35
+ │ │ │ │
36
+ ├───────────┴─────┬─────┴───────────┤
37
+ │ Dev Server │ Shell │ 30%
38
+ └─────────────────┴─────────────────┘
39
+ ```
40
+
41
+ **Option C — Single Claude + wide dev**
42
+ ```
43
+ ┌─────────────────────────────────────┐
44
+ │ Claude │ 60%
45
+ ├──────────┬──────────┬──────────────┤
46
+ │ Dev Srv │ Tests │ Shell │ 40%
47
+ └──────────┴──────────┴──────────────┘
48
+ ```
49
+
50
+ Adapt pane names/commands to the detected stack.
51
+
52
+ 4. Once the user picks, write the config:
53
+ - Quick: `tmux-ide detect --write` then modify
54
+ - Or build custom with `tmux-ide config` subcommands
55
+
56
+ ## Agent Teams workflow
57
+
58
+ Agent teams coordinate multiple Claude Code instances where a lead delegates tasks to teammates. Each gets its own tmux pane.
59
+
60
+ ### When to suggest agent teams
61
+
62
+ - User wants coordinated multi-agent development
63
+ - User mentions team lead, teammates, or task delegation
64
+ - User wants parallel work with inter-agent communication
65
+ - User's task benefits from specialized roles (e.g., frontend + backend + review)
66
+
67
+ ### Prerequisites
68
+
69
+ Agent teams require `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. tmux-ide sets this automatically when `team` is configured in `ide.yml`.
70
+
71
+ ### Setup from scratch
72
+
73
+ 1. **Scaffold with agent team template:**
74
+ ```bash
75
+ tmux-ide init --template agent-team
76
+ ```
77
+
78
+ 2. **Or enable teams on an existing config:**
79
+ ```bash
80
+ tmux-ide config enable-team --name "my-team"
81
+ ```
82
+ This finds all `command: claude` panes and assigns the first as `lead`, the rest as `teammate`.
83
+
84
+ 3. **Assign initial tasks to teammates:**
85
+ ```bash
86
+ tmux-ide config set rows.0.panes.1.task "Work on frontend components"
87
+ tmux-ide config set rows.0.panes.2.task "Work on API routes"
88
+ ```
89
+
90
+ 4. **Validate and launch:**
91
+ ```bash
92
+ tmux-ide validate --json
93
+ tmux-ide
94
+ ```
95
+
96
+ ### Present team layout options
97
+
98
+ When suggesting agent team layouts, show the roles:
99
+
100
+ **Option A — Lead + 2 Teammates**
101
+ ```
102
+ ┌───────────┬───────────┬───────────┐
103
+ │ │ │ │
104
+ │ Lead │Teammate 1 │Teammate 2 │ 70%
105
+ │ (claude) │ (claude) │ (claude) │
106
+ ├───────────┴─────┬─────┴───────────┤
107
+ │ Dev Server │ Shell │ 30%
108
+ └─────────────────┴─────────────────┘
109
+ ```
110
+
111
+ **Option B — Lead + 3 Specialized Teammates**
112
+ ```
113
+ ┌────────┬────────┬────────┬────────┐
114
+ │ │Frontend│Backend │ Review │
115
+ │ Lead │ Agent │ Agent │ Agent │ 70%
116
+ │ │ │ │ │
117
+ ├────────┴────────┴──┬─────┴────────┤
118
+ │ Dev Server │ Shell │ 30%
119
+ └────────────────────┴──────────────┘
120
+ ```
121
+
122
+ ### Team lead self-configuration
123
+
124
+ When running as the team lead inside a tmux-ide session, you can reconfigure the team:
125
+
126
+ ```bash
127
+ # Read current config
128
+ tmux-ide config --json
129
+
130
+ # Add a new teammate pane
131
+ tmux-ide config add-pane --row 0 --title "Reviewer" --command "claude"
132
+ tmux-ide config set rows.0.panes.3.role teammate
133
+ tmux-ide config set rows.0.panes.3.task "Review all PRs and check for issues"
134
+
135
+ # Or remove a teammate
136
+ tmux-ide config remove-pane --row 0 --pane 2
137
+
138
+ # Validate and restart to apply
139
+ tmux-ide validate --json
140
+ tmux-ide restart
141
+ ```
142
+
143
+ ### Disable teams
144
+
145
+ ```bash
146
+ tmux-ide config disable-team
147
+ ```
148
+
149
+ Removes the `team` config and all `role`/`task` fields from panes.
150
+
151
+ ## Programmatic CLI
152
+
153
+ All commands support `--json` for structured output.
154
+
155
+ ### Read commands
156
+
157
+ ```bash
158
+ tmux-ide status --json # Session status
159
+ tmux-ide validate --json # Validate config
160
+ tmux-ide detect --json # Detect project stack
161
+ tmux-ide config --json # Dump config as JSON
162
+ tmux-ide ls --json # List sessions
163
+ tmux-ide doctor --json # System health check
164
+ ```
165
+
166
+ ### Write commands
167
+
168
+ ```bash
169
+ tmux-ide detect --write # Detect and write config
170
+ tmux-ide config set name "my-app" # Set config value by dot path
171
+ tmux-ide config set rows.0.size "70%"
172
+ tmux-ide config add-pane --row 0 --title "Claude" --command "claude"
173
+ tmux-ide config remove-pane --row 1 --pane 2
174
+ tmux-ide config add-row --size "30%"
175
+ tmux-ide config enable-team --name "my-team" # Enable agent teams
176
+ tmux-ide config disable-team # Disable agent teams
177
+ ```
178
+
179
+ ### Session commands
180
+
181
+ ```bash
182
+ tmux-ide # Launch (or re-launch) IDE
183
+ tmux-ide stop # Kill session
184
+ tmux-ide restart # Stop and relaunch
185
+ tmux-ide attach # Reattach
186
+ tmux-ide init # Scaffold config
187
+ ```
188
+
189
+ ## Modification workflow
190
+
191
+ 1. Read: `tmux-ide config --json`
192
+ 2. Modify: `tmux-ide config set <path> <value>` or `add-pane`/`remove-pane`
193
+ 3. Validate: `tmux-ide validate --json`
194
+
195
+ ## Best practices
196
+
197
+ - Always use `--json` for programmatic access
198
+ - Always run `validate --json` after config mutations
199
+ - Top row ~70% height for Claude panes
200
+ - 2-3 Claude panes in the top row (or lead + 2 teammates for teams)
201
+ - Dev servers + shell in the bottom row
202
+ - Use `detect --json` first to understand the project stack
203
+ - For agent teams: assign specific tasks to teammates for focused parallel work
204
+ - The team lead should have `focus: true` for easy access
205
+
206
+ ## ide.yml format
207
+
208
+ ```yaml
209
+ name: project-name
210
+ before: pnpm install # optional pre-launch hook
211
+ team: # optional agent team config
212
+ name: my-team
213
+ rows:
214
+ - size: 70%
215
+ panes:
216
+ - title: Lead
217
+ command: claude
218
+ role: lead # "lead" or "teammate"
219
+ focus: true
220
+ - title: Teammate 1
221
+ command: claude
222
+ role: teammate
223
+ task: "Work on frontend" # initial task for teammate
224
+ - title: Teammate 2
225
+ command: claude
226
+ role: teammate
227
+ task: "Work on backend"
228
+ - panes:
229
+ - title: Dev Server
230
+ command: pnpm dev
231
+ dir: apps/web # per-pane working directory
232
+ env:
233
+ PORT: 3000
234
+ - title: Shell
235
+ theme:
236
+ accent: colour75
237
+ border: colour238
238
+ ```
package/src/attach.js ADDED
@@ -0,0 +1,22 @@
1
+ import { resolve } from "node:path";
2
+ import { execSync } from "node:child_process";
3
+ import { getSessionName } from "./lib/yaml-io.js";
4
+ import { outputError } from "./lib/output.js";
5
+
6
+ export async function attach(targetDir, { json } = {}) {
7
+ const dir = resolve(targetDir ?? ".");
8
+ const session = getSessionName(dir);
9
+
10
+ try {
11
+ execSync(`tmux has-session -t "${session}"`, { stdio: "ignore" });
12
+ } catch {
13
+ outputError(
14
+ `Session "${session}" is not running. Start it with: tmux-ide`,
15
+ "NOT_RUNNING",
16
+ { json }
17
+ );
18
+ return;
19
+ }
20
+
21
+ execSync(`tmux attach -t "${session}"`, { stdio: "inherit" });
22
+ }