Thanks to visit codestin.com
Credit goes to lib.rs

#tmux #tmux-session #dsl #yaml #run #generate-and-run

app devo

Generate and run tmux workflows from a small YAML DSL

7 releases (stable)

new 1.0.5 May 15, 2026
1.0.4 May 13, 2026
1.0.0 Mar 1, 2026
0.1.0 Feb 28, 2026

#868 in Rust patterns

Apache-2.0

36KB
871 lines

devo

devo is a CLI tool that generates tmux session shell commands from a small YAML DSL and runs them via bash. The name "devo" comes from "dev orchestrator".

quick start

nix develop
make build
make plan

Run:

make run

dsl

The default config file is devo.yaml. Main keys:

  • session: optional tmux session name; defaults to SESSION_NAME. Supports shell-style variable expansion: $VAR, ${VAR}, ${VAR:-default}, ${VAR:+alt}. The default / alt segments are themselves expanded (e.g. rust-sa${SLUG:+-$SLUG} becomes rust-sa when SLUG is empty, rust-sa-foo when SLUG=foo).
  • hook_session_closed: session-closed hook command
  • inherit_env: list of environment variable names to snapshot once and source before each pane command
  • tasks: task definitions
    • id: task id
    • pane: optional; root / right_of:<task-id> / down_of:<task-id>
    • cmd: command(s) executed in that pane (string or string[])
  • focus: optional task id to focus at the end

If pane is omitted, the first task uses the root pane and later tasks are split below the previous task. If focus is omitted, devo leaves tmux focus where pane creation naturally leaves it.

examples

simple example

devo.yaml:

tasks:
  - id: editor
    cmd: nvim

  - id: logs
    cmd: tail -f /var/log/system.log

Layout result (conceptual):

+-------------------------+
| editor (root)           |
| nvim                    |
+-------------------------+
| logs (down_of:editor)   |
| tail -f ...             |
+-------------------------+

Generated command flow (simplified):

new-session -> capture root pane id
editor uses root pane
split down from editor -> logs pane
send-keys to editor and logs
select-pane editor

advanced example

devo.yaml:

hook_session_closed: run-shell 'devo dev-stop'
inherit_env:
  - DEV_CMD
  - DEV_FRONTEND
  - DEV_KINTONE_JS
  - BIND_IP
  - COMPOSE_PROJECT_NAME

tasks:
  - id: backend
    pane: root
    cmd: $DEV_CMD make start-backend-dev

  - id: repl
    pane: right_of:backend
    cmd:
      - $DEV_CMD make -C backend repl NREPL_HOST='${BIND_IP}'
      - (go)

  - id: frontend
    pane: down_of:backend
    cmd: $DEV_CMD $DEV_FRONTEND

  - id: kintone_js
    pane: down_of:frontend
    cmd: $DEV_CMD $DEV_KINTONE_JS

  - id: compose
    pane: down_of:repl
    cmd: env UID=$(id -u) GID=$(id -g) HOST_IP='${BIND_IP}' docker compose -p $COMPOSE_PROJECT_NAME up

Layout result (conceptual):

+-----------------------------+-----------------------------+
| backend (root)              | repl (right_of:backend)    |
| make start-backend-dev      | make -C backend repl       |
+-----------------------------+-----------------------------+
| frontend (down_of:backend)  | compose (down_of:repl)     |
| $DEV_FRONTEND               | docker compose up           |
+-----------------------------+-----------------------------+
| kintone_js (down_of:front.) |                             |
| $DEV_KINTONE_JS             |                             |
+-----------------------------+-----------------------------+

Execution ordering rules:

1) pane dependency: right_of/down_of requires its base pane task
2) if multiple tasks are available, file order is preserved

commands

cargo run -- plan -f devo.yaml
cargo run -- run -f devo.yaml
cargo run -- run --session my-worktree -f devo.yaml
cargo run -- run --attach-or-create --session my-worktree -f devo.yaml
cargo run -- status --json --session my-worktree -f devo.yaml
cargo run -- stop --session my-worktree -f devo.yaml

plan prints the generated shell script, and run executes it with bash.

--session overrides the session value from devo.yaml. This is intended for external tools that need to choose deterministic tmux session names per worktree or task.

--attach-or-create attaches to an existing session when it exists. If it does not exist, devo creates it from the config and attaches afterward.

status --json reports whether the tmux session exists, the configured tasks, and the current tmux panes. Devo stores each task id in the pane-local tmux option @devo_task_id when creating panes, so external tools can correlate panes with tasks.

Dependencies

~2.6–4MB
~79K SLoC