Hooks
Hooks customize two things: how slice up presents your processes, and what happens when you create a new worktree. They're defined in the TOML output of your thinslice.new-state.
Two kinds of hooks
hooks.up
Control how slice up launches and arranges your processes.
Without a hook, slice up starts all processes as background daemons. With a hook, it arranges them in tmux according to your layout.
slice up # background all processes
slice up dev # use hooks.up.dev — arrange in tmux
slice up full # use hooks.up.full — different layout
Defined in your template output:
[hooks.up.dev]
tmux = """
new-window -n $BRANCH
split-v 70
send-top "$SHELL"
send-bottom "slice logs --follow"
focus-top
"""
[hooks.up.full]
tmux = """
new-window -n $BRANCH
split-h
split-right-v
send-left "cargo run --bin api -- --port $API_PORT"
send-topright "npm run dev -- --port $FRONTEND_HTTP_PORT"
send-bottomright "psql -p $PG_PORT"
focus-left
"""
hooks.new-worktree
Run when creating a worktree with slice local, slice tmp, or slice pr checkout. These set up your interactive working environment — typically a tmux window with a coding agent or editor on one side and slice up on the other.
The hook name is a positional argument after the worktree name and flags. Everything after the hook name is passed through as arguments.
slice tmp fix-login --from current claude -p "fix the redirect"
# ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
# hook passed as $@ to the hook
Defined in your template output:
[hooks.new-worktree.claude]
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && claude $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
[hooks.new-worktree.psql]
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && psql -p $PG_PORT $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
[hooks.new-worktree.vim]
tmux = """
new-window -n $BRANCH
split-h 70
send-left "cd $SLICE_CODE_DIR && vim $@"
send-right "cd $SLICE_CODE_DIR && slice up dev"
focus-left
"""
Note that hooks.new-worktree hooks are responsible for calling slice up themselves. This gives you control over whether processes start in the background or with a tmux layout, and which pane they run in.
Hook types
A hook can use the tmux DSL, exec a script, or both.
tmux
Define a tmux layout using the thinslice tmux DSL. This is the common case for developers working in tmux.
[hooks.new-worktree.claude]
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && claude $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
exec
Run an arbitrary script. Use this when you're not in tmux, or when you need to do something the tmux DSL doesn't cover.
[hooks.new-worktree.zellij]
exec = "$SLICE_PROJECT_DIR/scripts/start-zellij.sh $SLICE_CODE_DIR $SLICE_STATE_DIR $@"
The script receives the same environment variables as your template: $SLICE_CODE_DIR, $SLICE_STATE_DIR, $SLICE_PROJECT_DIR, $BRANCH, plus all variables from the [env] section of thinslice.toml. $@ and $1, $2, etc. come from the arguments passed after the hook name.
Both
If both tmux and exec are present, the tmux DSL runs first, then exec. This is useful for setting up terminal panes and also launching a GUI application.
[hooks.new-worktree.cursor]
tmux = """
new-window -n $BRANCH
send "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
exec = "cursor $SLICE_CODE_DIR"
Variable substitution
All hook definitions have access to these variables:
| Variable | Description |
|---|---|
$BRANCH | Branch name (e.g. tmp/fix-login) |
$SLICE_CODE_DIR | Absolute path to the worktree |
$SLICE_STATE_DIR | Absolute path to the state directory |
$SLICE_PROJECT_DIR | Project root directory |
$PG_PORT, etc. | Port variables from your process definitions |
$@ | All arguments passed after the hook name |
$1, $2, $3... | Individual positional arguments |
${@:2} | All arguments from the 2nd onward |
Precedence
Hooks can be defined in three places, in order of precedence:
- Template output — defined in the TOML your
thinslice.new-stateproduces. Project-specific. - Project hook file —
thinslice.hooks.tomlin your repo root. Checked into version control. - Global hook file —
~/.config/thinslice/hooks.toml. Personal defaults across all projects.
A hook defined in the template output overrides a project-level hook with the same name, which overrides a global hook.
This means you can define a global claude hook that works for all your projects, and override it in a specific project's template if that project needs a different layout.
Example global hooks
# ~/.config/thinslice/hooks.toml
[hooks.new-worktree.claude]
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && claude $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
[hooks.new-worktree.codex]
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && codex $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
[hooks.new-worktree.editor]
exec = "$EDITOR $SLICE_CODE_DIR"
[hooks.up.dev]
tmux = """
new-window -n $BRANCH
split-v 70
send-top "$SHELL"
send-bottom "slice logs --follow"
focus-top
"""
