Lifecycle Hooks
Run rift init inside a git project to create a rift.yaml at the repo root. This file configures per-project settings and lifecycle hooks.
Project Overrides
You can override the global editor and agent settings on a per-project basis:
editor: cursor
agent: claude
hooks:
open: "bun install"
editor— the editor command to use for this project (e.g.code,cursor,windsurf). Overrides the global config.agent— the coding agent command to use for this project (e.g.claude,copilot,codex). Overrides the global config.
Hooks
Run commands on lifecycle events:
hooks:
open: "bun install"
jump: "bun install"
close: "echo closing worktree"
purge: "echo purging all"
open— runs after a new worktree is createdjump— runs after switching to a worktreeclose— runs before a worktree is removedpurge— runs before each worktree is removed during purge
How Hooks Work
- Hooks are defined in
rift.yamlat the root of your repository. - Each hook value is passed to
bash -c, so you can use any shell syntax. - Hooks run synchronously — Rift waits for the command to finish before continuing.
- Hook failures are not blocking — if a hook exits with a non-zero code, Rift logs the hook execution but continues with the operation. A failing
openhook will not prevent the worktree from being created. - The working directory is the worktree directory (e.g.
~/.rift/worktrees/my-project/bold-ant). - The environment variable
RIFT_WORKTREEis set to the worktree name (e.g.bold-ant).
Common Patterns
Install dependencies on open/jump:
hooks:
open: "npm install"
jump: "npm install"
Chain multiple commands:
hooks:
open: "npm install && npm run db:migrate"
Call a script file:
hooks:
open: "bash scripts/bootstrap.sh"
This keeps complex setup logic out of rift.yaml and in a version-controlled script.
The Bootstrap Pattern
When multiple worktrees run dev servers simultaneously, they all compete for the same default ports. The bootstrap pattern solves this by running a command on the open and jump hooks that derives a deterministic port from the worktree name — the same worktree always gets the same port.
Bash script example
Create a bootstrap script manually or follow the framework guides:
#!/usr/bin/env bash
set -euo pipefail
# Derive a deterministic port from the worktree name.
# The same worktree always gets the same port (range 3000–9999).
hash=$(echo -n "$RIFT_WORKTREE" | shasum | tr -d 'a-f ' | cut -c1-4)
PORT=$(( (hash % 7000) + 3000 ))
echo "PORT=$PORT" > .env
echo "Assigned port $PORT for worktree '$RIFT_WORKTREE'"
The formula strips hex letters from the SHA hash, takes the first 4 digits, and maps them into the range 3000–9999.
Custom commands
The hook command doesn’t have to be a bash script — it can be any command your project supports. For example:
hooks:
open: "npm run bootstrap"
jump: "npm run bootstrap"
hooks:
open: "node scripts/setup.js"
jump: "node scripts/setup.js"
The RIFT_WORKTREE environment variable is available in all hook commands.
Multiple ports
If your project runs several services (frontend, API, database), derive multiple ports from the same base:
#!/usr/bin/env bash
set -euo pipefail
hash=$(echo -n "$RIFT_WORKTREE" | shasum | tr -d 'a-f ' | cut -c1-4)
BASE=$(( (hash % 7000) + 3000 ))
cat > .env <<EOF
PORT=$BASE
API_PORT=$(( BASE + 1 ))
DB_PORT=$(( BASE + 2 ))
EOF
echo "Assigned ports $BASE, $(( BASE + 1 )), $(( BASE + 2 )) for worktree '$RIFT_WORKTREE'"
Wiring it up
Add the hook command to your rift.yaml:
hooks:
open: "bash scripts/bootstrap.sh"
jump: "bash scripts/bootstrap.sh"
Running on both open and jump ensures the .env file is always present, even if the worktree was created before the script existed.
.gitignore
The generated .env file is worktree-specific and should not be committed:
# .gitignore
.env
Next steps
See the framework guides for step-by-step examples of reading the assigned port, configuring databases, and wiring up hooks, and the Docker Compose guide for isolating containerized services across worktrees.