Summary
When a project's .workmux.yaml lists "<global>" in a hook list and the
machine's ~/.config/workmux/config.yaml has no corresponding key, the
placeholder is not resolved. It is handed to the shell verbatim, where bash
parses <global> as an input redirection and fails:
bash: -c: line 1: `<global>'
The failing hook then takes down the surrounding operation.
This matters because the two halves of <global> live in different places by
design: .workmux.yaml is committed and shared across a team, while
~/.config/workmux/config.yaml is per-machine. A repository that adopts the
documented - "<global>" pattern breaks workmux add for every contributor who
has not independently defined that same global hook — and the error names a
token from a file they may never have edited.
Reproduction
The global config path is derived from $HOME, so pointing HOME at an empty
directory stands in for a machine that has never defined a global hook. Nothing
outside the temporary directory is touched.
export HOME=$(mktemp -d)
mkdir -p "$HOME/repro" && cd "$HOME/repro" && git init -q -b main .
printf 'post_create:\n - "<global>"\n - echo project-hook\n' > .workmux.yaml
git add -A && git -c user.email=t@t -c user.name=t commit -qm init
workmux add -C probe
Actual:
bash: -c: line 1: syntax error near unexpected token `newline'
bash: -c: line 1: `<global>'
Error: Failed to create worktree environment for branch 'probe'
Caused by:
0: Failed to run post-create command: '<global>'
1: Shell command failed with exit code 2: <global>
The worktree is left unusable.
The same placeholder in pre_remove is worse — the failing hook aborts the
removal and leaves the worktree on disk:
export HOME=$(mktemp -d)
mkdir -p "$HOME/repro" && cd "$HOME/repro" && git init -q -b main .
printf 'pre_remove:\n - "<global>"\n - echo project-hook\n' > .workmux.yaml
git add -A && git -c user.email=t@t -c user.name=t commit -qm init
workmux add -C probe && workmux remove -f probe
Running pre-remove commands...
bash: -c: line 1: syntax error near unexpected token `newline'
bash: -c: line 1: `<global>'
Failed to remove 1 worktree(s):
- probe: Failed to remove worktree
Error: Some worktrees could not be removed
$HOME/repro__worktrees/probe is still present afterwards. On a real machine,
recovering needs either a global hook definition or an edit to a tracked file.
Expected
<global> with nothing to inherit should resolve to an empty list and be
dropped, leaving the remaining project hooks to run. It should never reach a
shell as a literal argument.
Resolution appears to work correctly whenever the global key is present: with
a global pre_remove defined, a project list of ["<global>", "…"] logs
cleanup:running pre-remove hooks … count=2 and both hooks run. Only the
missing-key path is affected.
Environment
- Reproduced on v0.1.236 (
workmux-linux-amd64.tar.gz release binary) and
on v0.1.234.
- Linux,
bash as the hook shell.
Minor, related
workmux config reference documents <global> under post_create
("Use <global> to inherit from global config") and under pre_merge, but
not under pre_remove, even though it is resolved there too. Worth adding for
symmetry.
Summary
When a project's
.workmux.yamllists"<global>"in a hook list and themachine's
~/.config/workmux/config.yamlhas no corresponding key, theplaceholder is not resolved. It is handed to the shell verbatim, where
bashparses
<global>as an input redirection and fails:The failing hook then takes down the surrounding operation.
This matters because the two halves of
<global>live in different places bydesign:
.workmux.yamlis committed and shared across a team, while~/.config/workmux/config.yamlis per-machine. A repository that adopts thedocumented
- "<global>"pattern breaksworkmux addfor every contributor whohas not independently defined that same global hook — and the error names a
token from a file they may never have edited.
Reproduction
The global config path is derived from
$HOME, so pointingHOMEat an emptydirectory stands in for a machine that has never defined a global hook. Nothing
outside the temporary directory is touched.
Actual:
The worktree is left unusable.
The same placeholder in
pre_removeis worse — the failing hook aborts theremoval and leaves the worktree on disk:
$HOME/repro__worktrees/probeis still present afterwards. On a real machine,recovering needs either a global hook definition or an edit to a tracked file.
Expected
<global>with nothing to inherit should resolve to an empty list and bedropped, leaving the remaining project hooks to run. It should never reach a
shell as a literal argument.
Resolution appears to work correctly whenever the global key is present: with
a global
pre_removedefined, a project list of["<global>", "…"]logscleanup:running pre-remove hooks … count=2and both hooks run. Only themissing-key path is affected.
Environment
workmux-linux-amd64.tar.gzrelease binary) andon v0.1.234.
bashas the hook shell.Minor, related
workmux config referencedocuments<global>underpost_create("Use
<global>to inherit from global config") and underpre_merge, butnot under
pre_remove, even though it is resolved there too. Worth adding forsymmetry.