Workspace launcher — open/close entire project environments with one command
Project description
wsmux
Workspace launcher for macOS. Open and close entire project environments with one command.
One config file. One command. Your entire workspace — editors, browsers, terminals, docker, apps — opens exactly where you left it.
Install
pip install wsmux
Or install from source:
git clone https://github.com/safeersoft/wsmux.git
cd wsmux
pip install .
The CLI command is mux.
Quick Start
# Create a config in your project
cd ~/my-project
mux --init .
# Edit .mux.json to match your setup, then:
mux . # Open everything
mux -s . # Save window positions + close
mux . # Reopen — everything is where you left it
Commands
| Command | What it does |
|---|---|
mux . |
Open workspace from .mux.json |
mux -s . |
Save current state (new tabs, positions) then close |
mux -ss . |
Quick close — no config update |
mux -c . |
Capture current desktop into .mux.json |
mux -l . |
Dry run — show what would open |
mux --init . |
Create a starter .mux.json |
Named Projects
Register projects to open them from anywhere:
mux --add myapp ~/projects/myapp # Register
mux myapp # Open from anywhere
mux -s myapp # Save + close from anywhere
mux --projects # List registered projects
mux --remove myapp # Unregister
Config Format
.mux.json in your project root:
{
"name": "My Project",
"apps": [
{
"type": "vscode",
"paths": ["./frontend", "./backend"],
"windows": {
"./frontend": {"position": [0, 0], "size": [960, 1080]},
"./backend": {"position": [960, 0], "size": [960, 1080]}
}
},
{
"type": "browser",
"app": "Microsoft Edge",
"urls": ["http://localhost:3000", "https://github.com/me/repo"],
"window": {"position": [1920, 0], "size": [1680, 1050]}
},
{
"type": "terminal",
"app": "Terminal",
"tabs": [
{
"name": "server",
"command": "npm run dev",
"cwd": "./backend",
"window": {"position": [0, 600], "size": [800, 400]}
}
]
},
{
"type": "docker",
"services": ["postgres", "redis"],
"cwd": "./backend"
},
{
"type": "app",
"name": "Postman"
}
]
}
Entry Types
| Type | What it opens | Key fields |
|---|---|---|
vscode |
VS Code / Cursor windows | paths, command ("cursor"), windows (geometry) |
browser |
Browser with tabs in isolated window | app, urls, window (geometry) |
terminal |
Terminal.app / iTerm2 tabs | tabs[].name, tabs[].command, tabs[].cwd, tabs[].window |
docker |
Docker Compose services | services, cwd, file |
app |
Any macOS app | name, args |
script |
Shell command | command, cwd, stop_command |
Window Positions
Mux remembers where every window was — position, size, and which monitor.
- Auto-capture:
mux -ssaves current positions before closing - Manual capture:
mux -csnapshots your current desktop - Restore:
mux .reopens windows at their saved positions - Multi-monitor: positions use macOS unified coordinates, so windows restore to the correct monitor
Save Behavior (mux -s)
When closing with -s, mux compares your current desktop against the saved config:
- Existing entries: geometry is updated silently
- New entries (new browser tabs, apps): you're prompted for each one:
New entries detected:
+ [App] Postman [y/n/i] (yes/no/ignore forever): y
✓ Added
+ [Microsoft Edge] reddit.com + 2 more tabs [y/n/i] (yes/no/ignore forever): i
✗ Ignored forever: URL pattern 'reddit.com'
y— add to confign— skip this timei— skip and add to global ignore (never captured again)
Global Ignore
~/.mux/ignore.json — patterns that are never captured:
{
"apps": ["Slack"],
"urls": ["chatgpt.com", "claude.ai", "reddit.com"],
"paths": []
}
Browser Isolation
Each project opens its browser tabs in a new isolated window. Running mux for two different projects won't mix their tabs together.
Requirements
- macOS (uses AppleScript for window management)
- Python 3.10+
- Terminal needs Accessibility permission (System Settings > Privacy & Security > Accessibility) for window positioning
Data Files
All stored in ~/.mux/:
| File | Purpose |
|---|---|
projects.json |
Named project registry |
ignore.json |
Global ignore patterns |
states/ |
Last-opened state per project |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wsmux-0.1.0.tar.gz.
File metadata
- Download URL: wsmux-0.1.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a25550da27d59f1fe946709d803e98a6fd3b5740f23c51f51a9d526d8613ae8
|
|
| MD5 |
c97cb1e4401a3ad9c3090fc075f4f089
|
|
| BLAKE2b-256 |
4fcc789daa3ad54102c116ae58c6c01b14c4e09248eb67deebf52051d2039e43
|
File details
Details for the file wsmux-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wsmux-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6c98aa040f229f5d6633ac421075ba00cee087be5dfbdd2b8a70714200aa7a0
|
|
| MD5 |
6e6a6cefb30d0c35f7852320f20d89b7
|
|
| BLAKE2b-256 |
18876552a10d390bb604712bb5abfacce5696029af3613300334b62776eb5a01
|