Adding Custom Hooks
Relevant source files
The following files were used as context for generating this wiki page:Introduction
PreToolUse hooks are a guardrail mechanism designed to enforce specific development workflows by intercepting tool calls before they are executed. The primary purpose of these hooks is to prevent common errors, guide AI agents towards preferred practices, and avoid wasteful operations. For example, a hook can block a direct git push command to encourage using a stacked PR workflow or prevent redundant API calls by directing the agent to use a more efficient, specialized skill.
All hooks are defined in the hooks.json file at the root of the repository. An installation script (install.sh) is responsible for deploying these hook definitions to the AI agent's runtime environment, typically within a ~/.opencode/hook/ directory. This system allows for centralized management of workflow rules that are consistently applied across different agents and development sessions.
Sources: AGENTS.md:1, 33-39, 44-49
Hook Architecture
The hook system is composed of three main parts: the hook definition file (hooks.json), the installation script (install.sh), and the agent's hook execution environment. The agent, upon attempting to use a tool, first checks against the installed hooks. If a tool call matches a hook's criteria, the corresponding script is executed, which can then block or modify the original call.
Sources: AGENTS.md:19, 44-49
The diagram below illustrates the setup and execution flow of PreToolUse hooks.
Sources: AGENTS.md:19, 33-39, 44-49
Defining a Hook
Hooks are defined as JSON objects within the hooks.json file. Each hook must have a unique id, a matcher to identify which tool calls to intercept, and a purpose explaining its function.
Sources: hooks.json, AGENTS.md:35-39
Hook Definition Structure
The table below describes the fields for a hook object in hooks.json.
| Field | Type | Description |
|---|---|---|
id | String | A unique identifier for the hook (e.g., graphite-block). |
matcher | String | A regular expression used to match against the tool call command. |
purpose | String | A human-readable description of what the hook does and why. |
type | String | The type of tool the hook applies to. Currently, Bash is used. |
script | String | The relative path to the executable script that contains the hook's logic. |
Sources: hooks.json:2-22, AGENTS.md:35-39
Example Hook Definition
Here is the definition for the graphite-block hook from hooks.json.
{
"id": "graphite-block",
"matcher": "(git push|git checkout -b|gh pr create)",
"purpose": "Blocks git push, git checkout -b, gh pr create in Graphite-enabled repos",
"type": "Bash",
"script": "skills/git-graphite/scripts/graphite-block.sh"
}
Sources: hooks.json:2-8
Existing Hooks
The repository defines two primary hooks to enforce key development workflows.
graphite-block Hook
This hook is designed to enforce the use of Graphite for managing stacked pull requests. It intercepts common Git commands that conflict with the gt workflow.
- Purpose: Blocks
git push,git checkout -b, andgh pr createcommands. - Rationale: Ensures developers and AI agents use the
gtcommand-line tool, maintaining the integrity of the stacked PR history. - Matcher:
(git push|git checkout -b|gh pr create)
This hook is particularly relevant to the git-commit skill, as it guides the agent to follow the project's specific version control process after creating commits.
Sources: AGENTS.md:35-39, hooks.json:2-8, skills/git-commit/SKILL.md:1
pr-comments-block Hook
This hook prevents direct, potentially wasteful API calls to fetch PR review comments.
- Purpose: Blocks
gh apicalls that attempt to fetch PR comments from the current repository. - Rationale: Encourages the use of the specialized
resolve-pr-commentsskill, which provides a more structured and efficient way to process comment clusters. This avoids redundant data fetching and ensures the agent follows the intended workflow for PR comment resolution. - Matcher:
gh api repos/.*/pulls/.*/comments
The pr-comment-reviewer agent's workflow is directly influenced by this hook, as it steers the agent away from manual API interaction.
Sources: AGENTS.md:40-43, hooks.json:9-15, agents/pr-comment-reviewer.md:40-43
How to Add a New Hook
Adding a new custom hook involves defining its properties, creating its logic script, and ensuring it is deployed.
This flowchart outlines the process for creating and deploying a new PreToolUse hook.
Sources: AGENTS.md:19, 33-39, 44-49
- Define the Hook in
hooks.json: Add a new JSON object to thehooks.jsonarray. Fill in theid,matcher,purpose,type, andscriptfields according to the Hook Definition Structure. - Create the Hook Script: Write a shell script that contains the logic for your hook. This script will be executed when a tool call matches the
matcherregex. The script should typically print a message and exit with a non-zero status code to block the command. The path to this script must match thescriptvalue inhooks.json. - Deploy the Hook: Run the
install.shscript from the repository root. This script processeshooks.jsonand copies the hook scripts to the agent's configuration directory (e.g.,~/.opencode/hook/), making them active.
Sources: AGENTS.md:19, 33-39, 44-49
Hook Execution Flow
The following sequence diagram shows the step-by-step process of how a hook intercepts and acts on a tool call made by an AI agent.
Sources: AGENTS.md:33-39
Summary
Custom PreToolUse hooks are a core feature for maintaining workflow consistency and guiding AI agents in this repository. By defining simple JSON objects and corresponding scripts, developers can create powerful guardrails that prevent common mistakes, enforce best practices like using Graphite, and optimize agent behavior by directing them to use specialized skills. The system is extensible, allowing for new rules to be added as the project's workflow evolves.
Sources: AGENTS.md:33-39, 44-49