Skip to content

Commit 54afda7

Browse files
committed
fix(cli[load],docs): Tighten lifecycle hook semantics and parity claims
- on_project_start: now only fires on new session creation (not reattach) - on_project_restart: now only fires on confirmed interactive reattach (not detached loads of existing sessions) - Docs: remove "matches tmuxinator" claim for on_project_exit; document it as tmuxp-specific behavior that fires on every detach event - CHANGES: correct hook descriptions to match new semantics - Update test to assert detached loads do NOT trigger restart hook
1 parent 24770a9 commit 54afda7

File tree

4 files changed

+15
-20
lines changed

4 files changed

+15
-20
lines changed

CHANGES

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,11 @@ $ tmuxp delete old-project
6969
```
7070

7171
### Lifecycle hooks (#1025)
72-
Workspace configs now support four lifecycle hooks, matching tmuxinator's
73-
hook system:
72+
Workspace configs now support four lifecycle hooks inspired by tmuxinator:
7473

75-
- `on_project_start` — runs before session build (every invocation)
76-
- `on_project_restart` — runs when reattaching to an existing session
77-
- `on_project_exit` — runs on client detach (via tmux `client-detached` hook)
74+
- `on_project_start` — runs before session build (new session creation only)
75+
- `on_project_restart` — runs when reattaching to an existing session (confirmed attach only)
76+
- `on_project_exit` — runs on client detach (via tmux `client-detached` hook; fires on every detach event)
7877
- `on_project_stop` — runs before `tmuxp stop` kills the session
7978

8079
### Config templating (#1025)

docs/configuration/top-level.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ windows:
5959
6060
| Hook | When it runs |
6161
|------|-------------|
62-
| `on_project_start` | Before session build, every `tmuxp load` invocation |
63-
| `on_project_restart` | When reattaching to an existing session |
62+
| `on_project_start` | Before session build (new session creation only) |
63+
| `on_project_restart` | When reattaching to an existing session (confirmed attach only) |
6464
| `on_project_exit` | On client detach (tmux `client-detached` hook) |
6565
| `on_project_stop` | Before `tmuxp stop` kills the session |
6666

@@ -73,11 +73,13 @@ on_project_start:
7373
```
7474

7575
```{note}
76-
These hooks correspond to tmuxinator's `on_project_start`, `on_project_restart`, `on_project_exit`, and `on_project_stop` keys.
76+
These hooks are inspired by tmuxinator's lifecycle hooks but have tmuxp-specific semantics.
77+
`on_project_start` only fires on new session creation (not on reattach).
78+
`on_project_restart` only fires when you confirm reattaching to an existing session.
7779
```
7880

7981
```{note}
80-
`on_project_exit` uses tmux's `client-detached` hook, which fires on **any** client detach — including terminal close, SSH disconnect, or manual `tmux detach`. This matches tmuxinator's behavior.
82+
`on_project_exit` uses tmux's `client-detached` hook, which fires on **any** client detach — including terminal close, SSH disconnect, or manual `tmux detach`. Note: unlike tmuxinator (which fires `on_project_exit` once when the wrapper script exits), tmuxp's hook fires on every detach event for the lifetime of the session.
8183
```
8284

8385
## Pane titles

src/tmuxp/cli/load.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -799,21 +799,14 @@ def _cleanup_debug() -> None:
799799
color_mode=cli_colors.mode,
800800
)
801801
)
802-
if _confirmed or detached:
803-
if "on_project_start" in expanded_workspace:
804-
_hook_cwd = expanded_workspace.get("start_directory")
805-
util.run_hook_commands(
806-
expanded_workspace["on_project_start"],
807-
cwd=_hook_cwd,
808-
)
809-
# Run on_project_restart hook — fires when reattaching
802+
# Run on_project_restart hook — only when actually reattaching
803+
if _confirmed:
810804
if "on_project_restart" in expanded_workspace:
811805
_hook_cwd = expanded_workspace.get("start_directory")
812806
util.run_hook_commands(
813807
expanded_workspace["on_project_restart"],
814808
cwd=_hook_cwd,
815809
)
816-
if _confirmed:
817810
_reattach(builder, cli_colors)
818811
_cleanup_debug()
819812
return None

tests/cli/test_load.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,13 +1203,14 @@ def test_load_on_project_restart_runs_hook(
12031203
assert session is not None
12041204
assert not marker.exists()
12051205

1206-
# Second load triggers on_project_restart (session already exists)
1206+
# Second detached load does NOT trigger on_project_restart
1207+
# (restart hook only fires on confirmed interactive reattach)
12071208
load_workspace(
12081209
workspace_file,
12091210
socket_name=server.socket_name,
12101211
detached=True,
12111212
)
1212-
assert marker.exists()
1213+
assert not marker.exists()
12131214

12141215
session.kill()
12151216

0 commit comments

Comments
 (0)