For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /guide/cli/hooks.md.
close
  • English
  • hooks

    The rs hooks command installs, updates, and removes repository-level Git hooks. Hook scripts run in the project that installed them.

    Usage

    rs hooks [options]
    rs hooks uninstall

    Run rs hooks without a subcommand to install or update hooks.

    Alias

    rs setup is an alias for rs hooks.

    Install hooks

    By default, hook scripts are stored in .rstack/hooks at the Git repository root. If the current directory is outside a Git repository, the command skips installation.

    Add rs hooks to the prepare script of the project that owns the repository hooks:

    package.json
    {
      "scripts": {
        "prepare": "rs hooks"
      }
    }

    Run the script once to install the hooks:

    npm
    yarn
    pnpm
    bun
    npm run prepare

    For example, create a pre-commit hook that runs rs staged:

    .rstack/hooks/pre-commit
    rs staged

    You can safely run the installation more than once, and it does not load rstack.config.*. Run rs hooks again after cloning the repository or if the generated hook files are missing.

    Existing Git hook managers

    rs hooks updates the repository's core.hooksPath. If it detects another hooks path or existing Git hooks, it skips installation. Run rs hooks --force to let Rstack manage hooks instead.

    Install options

    --force

    --force (or -f) installs Rstack hooks even when another Git hook setup already exists:

    rs hooks --force

    Rstack keeps the existing hook files and points core.hooksPath to its generated hooks directory. While this setting is active, Git does not run hooks from the previous location.

    --force cannot replace hooks owned by another Rstack project.

    Tip

    Run rs hooks --force only once. Use rs hooks without --force in the prepare script.

    --hooks-dir

    Specifies a custom directory for hook scripts, relative to the Git repository root.

    rs hooks --hooks-dir config/git-hooks
    
    # Quote paths that contain spaces
    rs hooks --hooks-dir "config/git hooks"

    When using a custom directory, add the full command to the prepare script of the project that manages hooks:

    package.json
    {
      "scripts": {
        "prepare": "rs hooks --hooks-dir config/git-hooks"
      }
    }

    The path must not contain ... This prevents hook files from being created or overwritten outside the repository through a parent directory path.

    --help

    --help (or -h) displays the command's usage, subcommands, and installation options.

    rs hooks --help

    Uninstall hooks

    Run the command from the project that installed the hooks:

    rs hooks uninstall

    Rstack automatically finds the active hooks and removes the core.hooksPath setting and the generated _ directory. It does not delete project hook files such as .rstack/hooks/pre-commit. Hooks managed by another project or tool are left untouched.

    Remove rs hooks from the prepare script if you do not want the hooks to be installed again.

    If --force previously took over hooks in .git/hooks, those hooks become active again after uninstalling.

    Hook files

    The default directory structure is:

    .rstack/
    └── hooks/
        ├── pre-commit        # Repository hook script: edit and commit
        └── _/                # Generated by rs hooks; ignored by Git
            ├── .gitignore
            ├── .owner
            ├── runner
            ├── pre-commit
            ├── commit-msg
            └── ...

    Files alongside _ are repository hook scripts. The _ directory contains generated files and is ignored by Git. rs hooks points core.hooksPath to .rstack/hooks/_.

    Supported hooks

    Rstack CLI supports these client-side Git hooks:

    • pre-commit
    • pre-merge-commit
    • prepare-commit-msg
    • commit-msg
    • post-commit
    • applypatch-msg
    • pre-applypatch
    • post-applypatch
    • pre-rebase
    • post-rewrite
    • post-checkout
    • post-merge
    • pre-push
    • pre-auto-gc

    Create a file with the matching name alongside the _ directory.

    Hook runtime

    Rstack CLI runs hook scripts with POSIX sh -e. It forwards Git's arguments and standard input, then returns the hook's exit code. Before running a hook, Rstack changes to the project that installed the hooks and prepends that project's node_modules/.bin to PATH.

    Disable and debug

    Set RSTACK_HOOKS=0 to skip installation or hook execution:

    RSTACK_HOOKS=0 git commit -m "Skip hooks"

    Set RSTACK_HOOKS=2 to trace the Rstack CLI hook runtime, including how it invokes the hook script and handles its exit code; to trace commands inside the hook script, add set -x to the script:

    RSTACK_HOOKS=2 git commit -m "Trace hooks"

    Configure the hook environment

    Before running a hook script, Rstack CLI loads this optional POSIX shell file:

    ${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh

    Use it to initialize a Node.js version manager, update PATH, or set RSTACK_HOOKS=0 for the current user.

    Ownership safety

    Each generated hooks directory records its owning project. Only that project should include rs hooks in its prepare script. Rstack skips installation from any other project, even with --force, and refuses to remove hooks owned by another project.

    To transfer ownership:

    1. Remove rs hooks from the previous owner's prepare script.
    2. Run rs hooks uninstall from the previous owner.
    3. Add rs hooks to the new owner's prepare script and run it once.

    Monorepo

    In a monorepo, the project that provides Rstack CLI may live in a subdirectory such as frontend/. Running rs hooks there still installs hooks at the Git repository root:

    repo/.rstack/hooks/
    repo/.rstack/hooks/_/
    core.hooksPath=.rstack/hooks/_

    Rstack records frontend as the owning project. The hook scripts stay at the repository root but run from frontend, allowing them to use its configuration and dependencies without an explicit cd:

    .rstack/hooks/pre-commit
    rs staged

    Worktree behavior

    Rstack preserves the Git configuration scope of the active core.hooksPath. If a linked worktree uses a worktree-scoped hooks path, rs hooks --force replaces it in that scope instead of writing a local setting that Git would ignore.

    rs hooks uninstall also removes the setting from that scope. Removing a worktree-scoped installation affects only the current worktree and leaves hooks in other linked checkouts unchanged. A local core.hooksPath setting is shared across linked checkouts, so changing or removing it affects every checkout that does not override it.

    Troubleshooting

    Hook does not run

    • Check that the hook script has a supported name and is next to the _ directory.
    • Run git config --show-scope --get core.hooksPath and verify the effective scope and path.
    • Rerun rs hooks to restore generated files and executable permissions.
    • Check that RSTACK_HOOKS is not set to 0 in the environment or initialization file.
    • If another hook setup is detected, run rs hooks --force.
    • If another project is reported as the hooks owner, follow the steps in Ownership safety.

    Hook scripts do not need to be executable because Rstack CLI runs them with sh.

    Command not found

    For exit code 127, Rstack CLI prints the effective PATH. If a GUI Git client cannot find Node.js or the package manager, initialize them in hooks-init.sh.

    Windows and Yarn

    On Windows, hooks run in the POSIX shell included with Git for Windows. Use LF line endings and / path separators in hooks.

    Yarn PnP does not provide node_modules/.bin. Run tools through a Yarn script, such as yarn run test, and make Node.js and Yarn available through hooks-init.sh when needed.