panes-cli
v0.2.6
Published
Tile multiple commands into iTerm2 split panes
Downloads
483
Readme
panes
Tile multiple commands into iTerm2 split panes. Opens a new tab and runs each command in its own pane, arranged top to bottom.
Using Claude Code? This repo ships a
use-panes-cliskill that teaches Claude Code how to wirepanes-cliinto a project (pinned devDependency,.panes/layout,dirresolution rules, wait gates). Drop it into your.claude/skills/and ask Claude to set uppanes.
Install
The npm package is panes-cli; the binary it installs is panes.
Node.js projects (recommended)
Pin panes-cli as a devDependency so every contributor and CI run uses the same version, then invoke it via an npm script:
npm install --save-dev panes-cli@<exact-version>{
"scripts": {
"dev": "panes -c .panes/dev.yaml"
},
"devDependencies": {
"panes-cli": "0.2.5"
}
}Pin the exact version (no ^ / ~) — panes drives iTerm2 via AppleScript, and small changes to pane arrangement or wait-gate semantics can subtly shift a working dev setup.
Global (ad-hoc or non-Node projects)
npm install -g panes-cliFrom source
git clone https://github.com/koyeo/panes.git
cd panes
npm install
npm install -g .Usage
Basic
-e / --exec accepts a plain command string (repeatable):
panes -e "npm run dev" -e "npm run test"For wait conditions (sleep, waitPort, waitFile), use a YAML config file (see below).
Config file (-c / --config)
Load commands from a YAML file. Each entry is either a plain string or a mapping:
dir: .
commands:
- htop
- exec: npm run dev
- exec: npm test
waitPort: 3000Mapping fields:
exec(required): command to executesleep(optional): delay N seconds before executingwaitPort(optional): wait for a TCP port on localhost to become reachablewaitFile(optional): wait for a file to appear before executing
Wait conditions are evaluated by the panes process itself — they never inject sleep/nc/loop snippets into the user's shell. The pane's shell only sees the clean exec string once the gates pass.
Multiple wait conditions can be combined. Order: sleep → waitPort → waitFile → exec
dir is optional; relative paths resolve from the config file's location.
# Load from file
panes -c panes.yaml
# File + extra commands (file commands first, -e appended)
panes -c panes.yaml -e "htop"Wait conditions example
commands:
- exec: npm run dev
- exec: npm test
waitPort: 3000 # tests wait for server port
- exec: npm start
waitFile: dist/index.js # wait for build artifact
- exec: npm run smoke
sleep: 5 # delay 5 secondsProject layout: keep configs under .panes/
For projects that use panes regularly, colocate per-workflow YAML files under a top-level .panes/ directory:
your-project/
├── .panes/
│ ├── dev.yaml # full dev stack
│ ├── e2e.yaml # services needed for e2e tests
│ └── debug.yaml # extra inspectors (htop, log tail, …)
├── package.json
└── …Commit shared recipes; leave a .panes/local.yaml slot (gitignored) for personal tweaks.
Working directory (-d / dir)
dir controls where each pane is launched. Two rules cause every surprise people hit:
- A relative
dirresolves against the YAML file's directory, NOT the current working directory. - Resolution priority: CLI
-d> YAMLdir> current working directory.
Because YAML files live under .panes/, dir: . points at .panes/, not the project root. Use dir: .. instead:
# .panes/dev.yaml — every pane launches at the project root
dir: ..
commands:
- exec: npm run server
- exec: npm run worker
waitPort: 3000When using -c, do not also pass -d. The CLI -d wins and is itself resolved relative to the YAML file's directory, so panes -c .panes/dev.yaml -d packages/web becomes <repo>/.panes/packages/web — almost always wrong. Pick one source of truth: put dir in the YAML, or use -d only with -e (no -c).
There is no per-pane dir. If panes need different directories, prefix the command:
dir: ..
commands:
- exec: cd packages/api && npm run dev
- exec: cd packages/web && npm run dev
waitPort: 4000For ad-hoc one-off runs without a config file:
panes -d /path/to/project -e "npm run dev" -e "npm test"Requirements
- macOS
- iTerm2
- Node.js >= 18
License
MIT
