Custom Hooks
Relevant source files
The following files were used as context for generating this wiki page:
Custom Hooks are an extensibility mechanism within the Oh My Pi (omp) coding agent that allow developers to intercept and augment tool execution. They enable the injection of logic before a tool runs (pre-hooks) or after a tool completes (post-hooks), facilitating tasks such as validation, state management, and automated follow-ups.
These hooks are part of the broader extensibility suite which includes Extension Modules and Custom Tools. Hooks can be defined at both the user level (globally) and the project level (repository-specific), allowing for environment-specific behaviors.
Sources: packages/coding-agent/DEVELOPMENT.md, packages/coding-agent/src/discovery/codex.ts:316-348
Hook Architecture
Hooks are categorized by their execution timing and the specific tool they target. The system recognizes two primary types: pre hooks and post hooks. These are dynamically discovered from specific directories depending on the provider used (e.g., Codex or Claude).
Hook Lifecycle
When a tool is invoked, the hook runner checks for registered hooks matching the tool's name. A pre hook executes before the core tool logic, while a post hook executes after the tool has returned its result.
The execution flow ensures that hooks can observe or influence the tool lifecycle.
Sources: packages/coding-agent/src/discovery/codex.ts:333-345, packages/coding-agent/test/discovery/codex-hooks-discovery.test.ts:54-68
Discovery and Registration
Hooks are discovered by providers that scan local and global configuration directories. The two main discovery paths follow different naming conventions and directory structures.
Codex Provider Discovery
The Codex provider looks for TypeScript or JavaScript files in hooks/ directories. For OMP to recognize them as hooks, they MUST follow a specific naming convention: pre-<tool>.<ext> or post-<tool>.<ext>. Files not matching this prefix are ignored to prevent accidental execution of scratch scripts during startup.
| Hook Type | File Naming Pattern | Example |
|---|---|---|
| Pre-execution | pre-<tool_name>.[ts|js] | pre-bash.ts |
| Post-execution | post-<tool_name>.[ts|js] | post-write.js |
Sources: packages/coding-agent/src/discovery/codex.ts:327-348, packages/coding-agent/test/discovery/codex-hooks-discovery.test.ts:70-80
Claude Provider Discovery
The Claude provider organizes hooks by directory structure rather than filename prefix. It scans subdirectories named pre/ and post/ within the .claude/hooks/ folder. The tool name is derived from the filename itself.
- User Level:
~/.claude/hooks/[pre|post]/ - Project Level:
.claude/hooks/[pre|post]/
Supported shell extensions for Claude provider hooks include .sh, .bash, .zsh, and .fish.
Sources: packages/coding-agent/src/discovery/claude.ts:285-325
Hook Implementation
Hooks are typically implemented as factory functions or scripts that receive an API object allowing interaction with the coding agent's session and TUI.
Implementation Example (TypeScript)
A hook implemented in TypeScript can export a default function. The coding agent provides the necessary context to perform operations like reading the session history or rendering TUI components.
// Example: pre-bash.ts
import { Text } from "@oh-my-pi/pi-tui";
import type { HookFactory } from "@oh-my-pi/pi-coding-agent";
export default function(pi) {
// Logic to execute before the 'bash' tool runs
console.log("Interceptor active");
}
Sources: packages/coding-agent/test/discovery/codex-hooks-discovery.test.ts:46-47, packages/coding-agent/examples/custom-tools/README.md:46-52
Hook Properties
Internally, the system represents a hook using the following data structure:
| Field | Type | Description |
|---|---|---|
name | string | The original filename (e.g., pre-bash.ts). |
path | string | Full filesystem path to the hook file. |
type | "pre" | "post" | Whether it runs before or after the tool. |
tool | string | The name of the target tool (e.g., bash, write). |
level | "user" | "project" | The scope of the hook. |
Sources: packages/coding-agent/src/discovery/codex.ts:340-347, packages/coding-agent/src/discovery/claude.ts:306-313
Summary
Custom Hooks provide a robust way to extend omp by wrapping tool execution. By strictly enforcing naming conventions (Codex) or directory structures (Claude), the system ensures that extensions are loaded safely. This mechanism allows developers to enforce repository-specific rules or global safety checks across all tool interactions within the agent session.