Florian Schroedl 78a8284611 fix: send export commands into panes for env var injection
tmux set-environment only affects future windows/panes, not shells
already running. Send individual 'export K=V' via send-keys into each
pane before the window command, so env vars are available immediately.
Keep set-environment as well for any future panes.
2026-06-09 21:00:17 +02:00
2026-04-28 16:18:51 +02:00
2026-04-28 16:18:51 +02:00

tmux-dev

Babashka library for managing tmux dev sessions. Define windows and commands in a config map, get start/stop/restart/attach/logs/status for free.

Install

Add as a dependency in bb.edn:

;; local
{:deps {tmux-dev/tmux-dev {:local/root "../tmux-dev"}}}

;; git
{:deps {tmux-dev/tmux-dev {:git/url "https://gitea.florianschroedl.com/floscr/tmux-dev"
                            :git/sha "7707d5b"}}}

Usage

Define a config map with :session and :windows, then wire up tasks:

{:deps {tmux-dev/tmux-dev {:local/root "../tmux-dev"}}
 :tasks
 {:requires ([tmux-dev.core :as td])
  :init (def config {:session "my-app"
                     :windows [["frontend" "bb frontend"]
                               ["backend"  "bb backend"]]
                     :print   ["App: http://localhost:8000"
                               "API: http://localhost:3000"]})

  dev         {:task (td/start config)}
  dev:stop    {:task (td/stop config)}
  dev:restart {:task (td/restart config)}
  dev:attach  {:task (td/attach config)}
  dev:logs    {:task (td/logs config)}
  dev:status  {:task (td/status config)}}}
$ bb dev
[my-app] tmux session started
  App: http://localhost:8000
  API: http://localhost:3000
  Attach: tmux attach -t my-app

$ bb dev:status
[my-app] running
frontend: node
backend: bb

$ bb dev:logs
── frontend ──
vite v5.4.6 dev server running at http://localhost:8000

── backend ──
[main] INFO server - Started on port 3000

$ bb dev:stop
[my-app] stopped

Config

Key Required Description
:session yes tmux session name
:windows yes vector of [name command] pairs
:dir no working directory (default: cwd)
:print no lines to print after session starts

API

All functions take the config map as first argument.

Function Description
start Create session with windows. No-op if running
stop Kill the session
restart Kill + start
attach Attach to the session (interactive)
logs Capture recent pane output from all windows
status Show running state and window list

logs takes an optional second map:

(td/logs config {:window "frontend"})  ; single window
(td/logs config {:lines 100})          ; more history

Environment variables

tmux-dev.env provides helpers for reading env vars with typed fallbacks. Use these to make ports and other config overridable — this is the foundation for orchestration (e.g. auto port assignment when running multiple projects).

(require '[tmux-dev.env :as env])

(env/number "PORT_BACKEND"  3000)   ; => 3000 (or env value as long)
(env/number "PORT_FRONTEND" 8000)   ; => 8000
(env/string "HOST"          "localhost")
(env/bool   "DEBUG"         false)  ; truthy: "1", "true", "yes"

Use in your config so ports propagate from the environment:

{:tasks
 {:requires ([tmux-dev.core :as td] [tmux-dev.env :as env])
  :init (def port-fe (env/number "PORT_FRONTEND" 8000))
  :init (def port-be (env/number "PORT_BACKEND" 3000))
  :init (def config {:session "my-app"
                     :windows [["backend"  (str "PORT_BACKEND=" port-be " bb backend")]
                               ["frontend" (str "PORT_FRONTEND=" port-fe " bb frontend")]]
                     :print   [(str "App: http://localhost:" port-fe)
                               (str "API: http://localhost:" port-be)]})

  dev         {:task (td/start config)}
  dev:stop    {:task (td/stop config)}
  dev:restart {:task (td/restart config)}}}

Then override from the shell:

$ PORT_FRONTEND=9000 PORT_BACKEND=4000 bb dev
[my-app] tmux session started
  App: http://localhost:9000
  API: http://localhost:4000
S
Description
No description provided
Readme 42 KiB
Languages
Clojure 100%