Modern tmux-based task manager for LLM development tools
Project description
Taskmux
Tmux session manager for development environments. Define tasks in taskmux.toml, start them in dependency order, monitor health, auto-restart on failure, read persistent timestamped logs. Every command supports --json for agents and scripts.
Features
- Task orchestration — start/stop/restart tasks with dependency ordering and signal escalation
- Persistent logs — timestamped, rotated, survives session kill (
~/.taskmux/logs/) - Health checks — custom commands with retries, used for dependency gating and auto-restart
- Restart policies —
no,on-failure(default),alwayswith exponential backoff - JSON output —
--jsonon every command for programmatic consumption - Event history — lifecycle events recorded to
~/.taskmux/events.jsonl - Lifecycle hooks — before/after start/stop at global and per-task level
- Port cleanup — kills orphaned listeners before starting
- Agent context —
taskmux initinjects usage instructions into Claude/Codex/OpenCode context files - Daemon mode — WebSocket API + config watching + health monitoring
- Tmux native —
tmux attachto see live output, interact with tasks
Install
Requires tmux and Python 3.11+.
uv tool install taskmux
Commands
All commands support --json for machine-readable output.
# Lifecycle
taskmux start # start all auto_start tasks in dependency order
taskmux start <task> [task2...] # start specific tasks
taskmux start -m # start + monitor health + auto-restart
taskmux stop # graceful stop all (C-c → SIGTERM → SIGKILL)
taskmux stop <task> [task2...] # stop specific tasks
taskmux restart # restart all
taskmux restart <task> # restart specific tasks
taskmux kill <task> # hard-kill (SIGKILL + destroy window)
# Info
taskmux status # task overview (aliases: list, ls)
taskmux health # health check table
taskmux inspect <task> # full task state as JSON
taskmux events # recent lifecycle events
taskmux events --task server # filter by task
taskmux events --since 1h # filter by time
# Logs — persistent, timestamped, stored at ~/.taskmux/logs/
taskmux logs # interleaved logs from all tasks
taskmux logs <task> # logs for one task
taskmux logs -f [task] # follow live
taskmux logs -n 200 <task> # last N lines
taskmux logs -g "error" # grep all tasks
taskmux logs -g "err" -C 5 # grep with context
taskmux logs --since 5m # last 5 minutes
taskmux logs --since "2024-01-01T14:00"
taskmux logs-clean [task] # delete log files
# Config
taskmux add <task> "<command>" # add task to taskmux.toml
taskmux remove <task> # remove task (kills if running)
taskmux init # create taskmux.toml + inject agent context
taskmux init --defaults # non-interactive
# Monitoring
taskmux watch # watch config, reload on change
taskmux daemon --port 8765 # daemon: WebSocket API + health + config watch
stop vs kill vs restart
| Command | Signal | Window | Auto-restart |
|---|---|---|---|
stop |
C-c → SIGTERM → SIGKILL | Stays alive | Blocked |
kill |
SIGKILL | Destroyed | Blocked |
restart |
Full stop + restart | Reused | Re-enabled |
stop and kill mark tasks as manually stopped — no auto-restart even with restart_policy = "always". restart or start clears this flag.
Configuration
Config file: taskmux.toml in the current directory.
Minimal
name = "myproject"
[tasks.server]
command = "npm run dev"
[tasks.build]
command = "npm run build:watch"
[tasks.db]
command = "docker compose up postgres"
auto_start = false
Full-stack example
name = "fullstack-app"
[tasks.db]
command = "docker compose up postgres redis"
health_check = "pg_isready -h localhost -p 5432"
health_interval = 3
[tasks.migrate]
command = "python manage.py migrate && echo done && sleep infinity"
cwd = "apps/api"
depends_on = ["db"]
health_check = "test -f .migrate-complete"
[tasks.api]
command = "python manage.py runserver 0.0.0.0:8000"
cwd = "apps/api"
port = 8000
depends_on = ["migrate"]
health_check = "curl -sf http://localhost:8000/health"
stop_grace_period = 10
[tasks.worker]
command = "celery -A myapp worker -l info"
cwd = "apps/api"
depends_on = ["db"]
restart_policy = "always"
max_restarts = 10
restart_backoff = 3.0
[tasks.web]
command = "bun dev"
cwd = "apps/web"
port = 3000
depends_on = ["api"]
health_check = "curl -sf http://localhost:3000"
[tasks.storybook]
command = "bun storybook"
cwd = "apps/web"
auto_start = false
On taskmux start: db starts first → migrate + worker wait for db health → api waits for migrate → web waits for api → storybook skipped (manual).
Fields
| Field | Default | Description |
|---|---|---|
name |
"taskmux" |
tmux session name |
auto_start |
true |
global toggle — false creates session but launches nothing |
hooks.* |
— | before_start, after_start, before_stop, after_stop |
| Task fields | ||
command |
required | shell command to run |
auto_start |
true |
include in taskmux start |
cwd |
— | working directory |
port |
— | port to clean up before starting |
health_check |
— | shell command (exit 0 = healthy) |
health_interval |
10 |
seconds between checks |
health_timeout |
5 |
seconds before check times out |
health_retries |
3 |
consecutive failures before restart |
stop_grace_period |
5 |
seconds after C-c before SIGTERM |
restart_policy |
"on-failure" |
"no", "on-failure", "always" |
max_restarts |
5 |
max restarts before giving up (resets after 60s healthy) |
restart_backoff |
2.0 |
exponential backoff base (capped 60s) |
log_file |
— | override log path (default: ~/.taskmux/logs/{session}/{task}.log) |
log_max_size |
"10MB" |
max size before rotation |
log_max_files |
3 |
rotated files to keep |
depends_on |
[] |
tasks that must be healthy first |
hooks.* |
— | per-task lifecycle hooks |
JSON Output
Every command supports --json. Key schemas:
taskmux status --json # {"session": "x", "running": true, "tasks": [...]}
taskmux health --json # {"healthy_count": 2, "total_count": 3, "tasks": [...]}
taskmux start server --json # {"ok": true, "task": "server", "action": "started"}
taskmux logs server --json # {"task": "server", "lines": ["2024-01-01T14:00:00 ..."]}
taskmux events --json # {"events": [...], "count": 10}
Error: {"ok": false, "error": "Task 'ghost' not found in config"}
Restart Policies
Enforced by start --monitor and daemon.
| Policy | Behavior |
|---|---|
"no" |
Never auto-restart |
"on-failure" |
(default) Restart on crash or after health_retries consecutive failures |
"always" |
Restart on any exit (including clean) |
restart_policy and auto_start are orthogonal — auto_start controls initial launch, restart_policy controls what happens after exit.
Backoff: restart_backoff ^ attempt seconds (capped 60s). Resets after 60s healthy. Stops after max_restarts.
Health Checks
If health_check is set, taskmux runs it as a shell command (exit 0 = healthy). Falls back to checking if the pane has a running process. Must fail health_retries consecutive times before triggering restart.
Used by:
taskmux health— status tabletaskmux start— dependency gatingstart --monitor/daemon— auto-restart trigger
Persistent Logs
Task output is piped to ~/.taskmux/logs/{session}/{task}.log with UTC timestamps:
2024-01-01T14:00:00.123 Server started on port 3000
2024-01-01T14:00:01.456 GET /health 200 2ms
Logs survive session kill. Rotated at log_max_size (default 10MB), keeping log_max_files (default 3). Filter with --since:
taskmux logs server --since 5m
taskmux logs --since 1h
Event History
Lifecycle events at ~/.taskmux/events.jsonl:
| Event | Trigger |
|---|---|
task_started / task_stopped / task_restarted / task_killed |
CLI commands |
session_started / session_stopped |
start/stop all |
health_check_failed |
health check fails (includes attempt count) |
auto_restart |
restart triggered (includes reason) |
max_restarts_reached |
hit limit |
config_reloaded |
config file changed |
Auto-trims to 10K lines at 15K.
Hooks
Fire order: global before_start → task before_start → run → task after_start → global after_start. Same for stop. before_* failure aborts the action.
[hooks]
before_start = "echo starting"
[tasks.api.hooks]
before_start = "python manage.py migrate"
after_stop = "echo api stopped"
Daemon & WebSocket API
taskmux daemon --port 8765
Health monitoring every 30s, auto-restart per policy, config file watching. WebSocket API:
ws.send(JSON.stringify({ command: "status" }));
ws.send(JSON.stringify({ command: "restart", params: { task: "server" } }));
ws.send(JSON.stringify({ command: "logs", params: { task: "server", lines: 50 } }));
Tmux
Taskmux creates standard tmux sessions:
tmux attach-session -t myproject # attach to see live output
# Ctrl+b 1/2/3 switch windows, Ctrl+b d detach
Links
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 taskmux-0.4.0.tar.gz.
File metadata
- Download URL: taskmux-0.4.0.tar.gz
- Upload date:
- Size: 28.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cbe8d075ee105974337224ab37843cbb3c5f812788cd1e83aecee2c4591a3c1
|
|
| MD5 |
c0a4f3b600b5651894fd664a7f575edd
|
|
| BLAKE2b-256 |
9d8f5396ebcf616605d9c50219f15c8c1958cd94ad466f52e58e2409827f0aed
|
File details
Details for the file taskmux-0.4.0-py3-none-any.whl.
File metadata
- Download URL: taskmux-0.4.0-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c379c2cdf6f1cfee5c939fd38961699c3079bbc4fa533bb4f979f6e944c04772
|
|
| MD5 |
07d7369f57c95c64c7af9296bd4dd7ca
|
|
| BLAKE2b-256 |
f203bc50b07da760fc0c06f47caad5b22a63fba166a79f921bf1ff8d71bf4c4b
|