Setup Scripts
Automatic project setup and teardown with environment variables and Docker Compose support.
Codemux can automatically run commands when workspaces are created or deleted. This is especially useful for worktree workflows where each worktree needs its own dependencies, environment files, or services.
Configuration
Via Settings UI
Open Settings > Projects to configure scripts for the active project:
- Setup — Commands that run when a new workspace is created (one per line)
- Teardown — Commands that run when a workspace is deleted (one per line)
- Run — A command to start your dev server, triggered via
Ctrl+Shift+G
Changes are saved automatically when you leave the field.
Via Config File
Create a .codemux/config.json file in your project root:
{
"setup": ["npm install", "cp .env.example .env"],
"teardown": ["docker compose down"],
"run": "npm run dev"
}Commit this file to share setup automation with your team.
Precedence: File-based config (.codemux/config.json) always takes precedence over Settings UI configuration. When a config file is detected, the Settings UI shows a notice.
Environment Variables
All scripts have access to these environment variables:
| Variable | Value |
|---|---|
$CODEMUX_ROOT_PATH | Git repository root directory |
$CODEMUX_WORKSPACE_PATH | Workspace/worktree directory |
$CODEMUX_BRANCH | Branch name for this workspace (when it has one) |
$CODEMUX_PORT | Stable per-workspace port (see Worktree Setup) |
$CODEMUX_WORKSPACE_NAME | Workspace title |
$CODEMUX_WORKSPACE_ID | Workspace unique ID |
Docker Compose Gotcha
When using Docker Compose with worktrees, each worktree has a different directory name. Docker Compose uses the directory name as the default project name, which means each worktree would create separate containers and volumes.
Codemux does not set COMPOSE_PROJECT_NAME — a regression test asserts it is never injected. If you want Compose projects namespaced per worktree, set it yourself in your setup script, e.g. export COMPOSE_PROJECT_NAME="$(basename "$CODEMUX_WORKSPACE_PATH")".
However, COMPOSE_PROJECT_NAME is not available in regular terminal sessions (e.g., when you open a terminal tab and run docker compose manually). In a regular terminal, Docker Compose falls back to using the directory name, which differs per worktree.
To make it work everywhere, add this line to your setup script so it writes the value into the project's .env file:
echo "COMPOSE_PROJECT_NAME=$(basename "$CODEMUX_WORKSPACE_PATH")" >> .envDocker Compose automatically reads .env from the working directory, so any terminal session in that worktree will pick up the correct project name — no extra environment variables needed.
Run Command
The Run command starts your dev server in a dedicated terminal tab:
- Press
Ctrl+Shift+G, click Run in the title bar, or use the command palette ("Run dev command") - A new tab named "Workspace Run" is created with your dev server running
- Pressing
Ctrl+Shift+Gagain restarts the command in the same tab (sends Ctrl+C first) - Switch back to your working terminal anytime
Setting It From the Title Bar
With no run command set, the title-bar button reads Set Run. Clicking it — or the caret beside Run at any time — opens a popover instead of sending you to Settings:
- Detected — commands Codemux found in the project, each labelled with the file it came from. One click saves the command and runs it; the saved one is marked with a check.
- Run command — a field for any other command (e.g.
npm run dev). Press Run to save and start it. - More settings… — opens Settings > Projects.
Saving only changes the run command; the project's setup, teardown, and worktree-include settings are kept.
Detection looks at:
| Source | Suggestion |
|---|---|
package.json scripts | dev, start, serve, run, watch, then variants such as dev:web or tauri:dev — run with the package manager your lockfile implies (npm when there is none). Test, build, lint, and similar watchers (test:watch) are skipped |
Makefile / justfile | Targets or recipes with those same run names, e.g. make dev, just serve |
Cargo.toml (with a [package]) | cargo run |
go.mod + main.go | go run . |
manage.py | python manage.py runserver |
compose.yaml / docker-compose.yml | docker compose up |
If the project has a .codemux/config.json, the popover doesn't offer picks — saved settings would be ignored — and points you to the file's run field instead. In a web remote client, the popover asks you to set the run command in the desktop app.
Examples
Node.js
{
"setup": ["npm install"],
"teardown": [],
"run": "npm run dev"
}Docker Compose
{
"setup": [
"echo COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME >> .env",
"docker compose up -d",
"npm install",
"npm run db:migrate"
],
"teardown": ["docker compose down -v"],
"run": "npm run dev"
}Python
{
"setup": ["python -m venv .venv", ".venv/bin/pip install -r requirements.txt"],
"teardown": [],
"run": ".venv/bin/python manage.py runserver"
}Rust
{
"setup": ["cargo build"],
"teardown": [],
"run": "cargo run"
}Full-Stack (complex setup)
{
"setup": [".codemux/setup.sh"],
"teardown": [".codemux/teardown.sh"],
"run": "npm run dev"
}For complex setups, use shell scripts and reference them from the config.
Tips
- Keep setup commands fast — they run on every workspace creation
- Setup failure does not prevent workspace use
- Use
force deleteto skip teardown if a teardown command hangs - The setup banner in the sidebar prompts you to configure scripts when you create your first worktree