Skip to content

Hooks

Hooks are repository-local executable files under .shipper/hooks/. There is no user-level hook mechanism. Shipper runs a hook only when a supported filename exists in the checkout and the file is executable.

Stage hooks run immediately before or after a supported Shipper workflow stage.

StagePre-stage hookPost-stage hook
newpre-newpost-new
groompre-groompost-groom
designpre-designpost-design
planpre-planpost-plan
implementpre-implementpost-implement
pr-reviewpre-pr-reviewpost-pr-review
mergepre-mergepost-merge

The stage names setup, unblock, adopt, reset, and init do not fire stage hooks. Creating files such as .shipper/hooks/pre-unblock or .shipper/hooks/post-init will not run.

Worktree lifecycle hooks are separate from pre-<stage> and post-<stage> hooks.

HookWorkflow point
worktree-setupRuns after Shipper creates a temporary worktree and after the configured installCommand finishes, when one is configured.
worktree-teardownRuns during cleanup before Shipper discovers or signals processes whose cwd is inside the temporary worktree, and before Shipper removes that worktree.

These hooks run for temporary worktrees created by new, groom, design, plan, implement, pr-open and pr-review. They do not run for merge, setup, unblock, adopt, reset, or init.

Repositories should use worktree-teardown to stop background services gracefully. After the hook settles, Shipper unconditionally stops anything still working inside the workspace: SIGTERM comes first, followed after a fixed two-second grace period by SIGKILL, with one further second allowed for exit. A failure to inspect or terminate a holder produces a warning but does not change stage success or prevent workspace removal. No hook timeout, flag, environment variable, setting, or command option disables or tunes this enforcement schedule.

Hook typeNon-zero exit behavior
pre-<stage>Aborts the stage.
post-<stage>Warns and continues.
worktree-setupWarns and continues.
worktree-teardownWarns and continues.

Shipper enforces hook timeouts with the hookTimeoutMinutes setting. The default is 10 minutes. Set it to 0 to disable timeout enforcement.

hookTimeoutMinutes governs only hook execution. It does not alter the fixed process-termination schedule that begins after worktree-teardown settles.

Hook typeTimeout behavior
pre-<stage>Aborts the stage.
post-<stage>Warns and continues.
worktree-setupAborts worktree setup.
worktree-teardownWarns and continues.

SIGINT or SIGTERM cancellation always aborts the current Shipper operation, including hooks that otherwise warn and continue on non-zero exit or timeout.

If a supported hook file exists but is not executable, Shipper warns and skips it without running it. Run chmod +x .shipper/hooks/<hook-name> to make the hook executable.

Shipper passes runtime context to hook scripts through environment variables.

For full per-variable detail, see Environment variables.

Hook typeVariables
Stage hooksSHIPPER_STAGE, SHIPPER_ISSUE_NUMBER, SHIPPER_BRANCH_NAME
Worktree lifecycle hooksSHIPPER_STAGE, SHIPPER_ISSUE_NUMBER, SHIPPER_BRANCH_NAME, SHIPPER_WORKTREE_PATH

SHIPPER_ISSUE_NUMBER is empty for the new stage because no issue exists yet.

Dependency bootstrap consists of the configured installCommand followed by executable .shipper/hooks/worktree-setup. worktree-setup can be part of the bootstrap for monorepos and multi-package repositories, and it can be the only configured bootstrap when no single installCommand is appropriate. An executable worktree-setup suppresses the no-bootstrap advisory warning even when installCommand is unset or empty.

Bare shipper setup --assist does not create hooks by default. In user-level assisted setup, the assistant first tries to express bootstrap as a single installCommand, including compound commands for multi-area repositories. Creating .shipper/hooks/worktree-setup during that flow is an explicit committed-footprint opt-in for bootstrap cases that genuinely cannot fit one command.

A non-zero installCommand exit is fatal to the stage — Shipper stops before the agent runs and reports the failing command and its exit code (a command-not-found exit also notes the tool appears missing or not on PATH). This is distinct from .shipper/hooks/worktree-setup, whose non-zero exit warns and continues. installCommand is not a hook, so it is absent from the hook exit-code behavior above.

Both installCommand and worktree-setup share the hookTimeoutMinutes timeout setting. See Settings for full configuration semantics.