Configuration
.ecluse.toml lives at repo root and is written by ecluse init. All fields are optional except mode.
mode = "hybrid"
max_slots = 8
prefix = "ecluse"
worktree_dir = ".ecluse/worktrees"
# Port collision handling (both optional)
# strict_port = false # default: search for a free port on collision
# port_search_range = 10 # how many alternatives to try (bump by max_slots each time)
# One [[services]] block per service. port = base_port + slot.
# Native services run on the host; docker services run in containers.
# The first native entry also sets the PORT alias for framework compatibility.
# Add command = "..." to have ecluse spawn the process on ecluse up.
[[services]]
name = "api"
base_port = 3000 # slot 1 → ECLUSE_API_PORT=3001 + PORT, slot 2 → 3002
command = "npm run dev" # optional — ecluse spawns this on ecluse up
# port_env = "DJANGO_PORT" # optional — also set DJANGO_PORT to the allocated port
# port_env = ["DJANGO_PORT", "APP_PORT"] # or multiple aliases
[[services]]
name = "postgres"
run = "docker"
base_port = 5432 # slot 1 → ECLUSE_POSTGRES_PORT=5433, slot 2 → 5434
# Optional: lifecycle hooks (see Hooks page for full details)
[hooks]
post_up = "npx prisma migrate deploy"
pre_down = "npx prisma migrate reset --force"
Fields
| Field | Type | Default | Description |
|---|---|---|---|
mode | string | — | container, host, or hybrid |
max_slots | integer | 8 | Maximum parallel sessions |
prefix | string | "ecluse" | Prefix for compose project names and volume names |
worktree_dir | string | ".ecluse/worktrees" | Directory for git worktrees |
strict_port | bool | false | Fail immediately on port collision instead of searching |
port_search_range | integer | 10 | How many alternatives to try on collision |
app_label | string | "ecluse.role" | Docker Compose label key used to identify app vs data services in hybrid mode |
app_label_value | string | "app" | Value of app_label that marks a service as the app (not a data service) |
[[services]]
Each [[services]] block defines one service. Each gets a stable, collision-free port per slot (base_port + slot).
| Field | Type | Description |
|---|---|---|
name | string | Service name — becomes ECLUSE_<NAME>_PORT |
base_port | integer | Port formula: base_port + slot |
run | string | "docker" to run in a container; omit for native |
command | string | Shell command ecluse spawns on ecluse up (native services only; managed by your global process_manager setting) |
port_env | string or array | Extra env var names to set to this service's allocated port — accepts a single string or an array |
The first native (non-docker) service entry also sets PORT for framework compatibility.
Omit [[services]] entirely for single-service projects — ecluse falls back to PORT = 3000 + slot.
Global config (~/.config/ecluse/config.toml)
Controls how ecluse spawns native service processes. Written by ecluse init based on what's installed.
process_manager = "tmux" # "tmux" | "nohup" | "none"
| Value | Behaviour |
|---|---|
tmux | Creates a detached tmux session ecluse-<slug> with one window per service. ecluse shell <slug> attaches to it. |
nohup | Spawns each service as a background process. Logs at .ecluse/logs/<slug>/, PIDs at .ecluse/pids/<slug>/. |
none | Spawns nothing — current behaviour before this was added. |
ecluse init sets this automatically: tmux if available, otherwise nohup. Change it at any time — the setting is per-machine, not per-repo.
Run ecluse validate to check the configured binary is installed.
[hooks]
| Field | When it runs | Env vars |
|---|---|---|
pre_up | Before any infrastructure is created | None (runs from repo root) |
post_up | After all services are up and .env.ecluse is written | All ECLUSE_* + PORT |
pre_down | Before services are stopped | All ECLUSE_* + PORT |
post_down | After all services are stopped and worktree is removed | All ECLUSE_* + PORT |
Use post_up for migrations and seeding, pre_down for teardown that needs a live database. See the Hooks page for full details and examples.