# How hooks.json Influences OpenAI Plugin Execution Flow: A Deep Dive into the Declarative Hook System

> Discover how hooks.json directs OpenAI plugin execution flow. Learn to map lifecycle events to shell commands for custom post processing at specific points.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: deep-dive
- Published: 2026-06-27

---

**The [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file acts as a declarative configuration that maps lifecycle events like `PostToolUse` and `Stop` to custom shell commands, allowing plugins to inject post-processing scripts at specific execution points without modifying the core runtime.**

The `openai/plugins` repository implements a flexible hook system that lets developers extend plugin behavior through declarative configuration rather than code changes. By placing a [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file in a plugin's root directory, authors can intercept lifecycle events and execute custom scripts when specific tools are invoked. This mechanism keeps the core runtime generic while enabling powerful, per-plugin customizations that trigger during the execution flow.

## Understanding the hooks.json Structure

Each [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file resides in a plugin's folder (such as [`plugins/replayio/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/replayio/hooks.json) or [`plugins/figma/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/figma/hooks.json)) and contains a top-level `hooks` object that defines the extension points.

### Event-to-Command Mapping

The keys of the `hooks` object represent lifecycle events emitted by the runtime, such as `PostToolUse` and `Stop`. Each event maps to an array of **hook groups**, where every group contains a `hooks` array specifying the actions to execute. Currently, the supported hook type is `"command"`, which instructs the runtime to spawn a shell process.

### The Matcher Pattern System

Hook groups may include an optional `"matcher"` field containing a regular-expression-style pattern. When an event fires, the runtime evaluates this pattern against the tool name that triggered the event. Only groups whose matcher matches the tool name are considered for execution, enabling fine-grained control over when scripts run.

## How hooks.json Shapes Plugin Execution Flow

The integration of [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) into the plugin execution flow follows a declarative pipeline that extends the built-in behavior without requiring core engine modifications.

### Loading and Parsing

When the OpenAI plugin runtime boots a plugin, it automatically reads [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) from the plugin directory and parses the configuration. This happens during initialization, making the hook definitions available before any tools are executed.

### Event Matching and Filtering

As the execution flow progresses and events like `PostToolUse` fire, the runtime performs the following steps:

1. **Retrieves** the array of hook groups associated with the event name.
2. **Evaluates** the `matcher` pattern against the triggering tool name (e.g., checking if `"Bash"` matches the regex).
3. **Selects** only the hook groups where the matcher succeeds or where no matcher is defined (indicating the hook applies to all tools).

### Command Execution

For each matching hook group, the runtime processes the `"hooks"` array. When encountering a `"command"` type, it spawns the specified shell command in the plugin's working directory. This allows the plugin to perform side effects such as uploading artifacts, syncing state, or cleaning up resources after specific tool invocations.

## Real-World Examples from the Repository

The following examples from the `openai/plugins` repository demonstrate how [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) influences execution flow in production plugins.

### Replay.io Plugin Hooks

Located at [`plugins/replayio/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/replayio/hooks.json), this configuration intercepts two key events:

- **PostToolUse with Bash**: When the `Bash` tool completes, the matcher `"Bash"` triggers execution of [`./scripts/post_bash_upload.sh`](https://github.com/openai/plugins/blob/main/./scripts/post_bash_upload.sh), handling artifact uploads.
- **Stop event**: Without a matcher (applying to all stop events), the runtime executes [`./scripts/stop_close_and_upload.sh`](https://github.com/openai/plugins/blob/main/./scripts/stop_close_and_upload.sh) to perform cleanup and final uploads.

### Figma Plugin Hooks

The [`plugins/figma/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/figma/hooks.json) file demonstrates conditional execution based on tool patterns:

- **PostToolUse with Write or Edit**: The matcher `Write\|Edit` detects write or edit operations and runs [`./scripts/post_write_figma_parity_check.sh`](https://github.com/openai/plugins/blob/main/./scripts/post_write_figma_parity_check.sh) to validate file consistency.

These examples show how the declarative approach allows different plugins to implement specialized post-processing logic using the same core execution infrastructure.

## Runtime Dispatch Implementation

While the core runtime implementation resides elsewhere in the repository, the following TypeScript pseudo-code illustrates how the hook dispatcher processes [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json):

```typescript
// pseudo-code sketch of the hook dispatcher
import * as fs from "fs";
import { spawn } from "child_process";

interface HookSpec {
  type: "command";
  command: string;
}
interface HookGroup {
  matcher?: string;          // optional regex pattern
  hooks: HookSpec[];
}
type HooksMap = Record<string, HookGroup[]>;

function loadHooks(dir: string): HooksMap {
  const path = `${dir}/hooks.json`;
  return JSON.parse(fs.readFileSync(path, "utf‑8")).hooks;
}

function runHooks(event: string, toolName: string, dir: string) {
  const hooks = loadHooks(dir)[event] ?? [];
  for (const group of hooks) {
    if (!group.matcher || new RegExp(group.matcher).test(toolName)) {
      for (const h of group.hooks) {
        if (h.type === "command") {
          spawn(h.command, { cwd: dir, shell: true, stdio: "inherit" });
        }
      }
    }
  }
}

```

Calling `runHooks("PostToolUse", "Bash", "./plugins/replayio")` would invoke [`./scripts/post_bash_upload.sh`](https://github.com/openai/plugins/blob/main/./scripts/post_bash_upload.sh) exactly as prescribed by the JSON configuration.

## Summary

- **Declarative Configuration**: The [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file provides a JSON-based DSL for extending plugin behavior without touching the core runtime code.
- **Event-Driven Architecture**: Hooks respond to lifecycle events like `PostToolUse` and `Stop`, inserting custom commands at precise execution points.
- **Pattern Matching**: The optional `matcher` field uses regex patterns to filter which tools trigger specific hook commands, enabling granular control.
- **Command Execution**: Currently supports `"command"` type hooks that spawn shell scripts in the plugin's working directory to handle side effects.
- **Per-Plugin Scope**: Each plugin maintains its own [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file (e.g., [`plugins/replayio/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/replayio/hooks.json), [`plugins/figma/hooks.json`](https://github.com/openai/plugins/blob/main/plugins/figma/hooks.json)), ensuring isolation and easy modification.

## Frequently Asked Questions

### What lifecycle events can hooks.json respond to?

The [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) configuration can map commands to events such as `PostToolUse` (fired after tool execution) and `Stop` (fired when the session ends). These events represent specific points in the plugin execution flow where custom scripts can intervene.

### How does the matcher pattern in hooks.json work?

The `matcher` field contains a regular expression pattern that the runtime evaluates against the tool name triggering the event. For example, a pattern of `"Bash"` matches only the Bash tool, while `Write\|Edit` matches either Write or Edit operations. If the matcher is omitted, the hook group applies to all tools for that event.

### Where should the hooks.json file be located?

The [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) file must reside in the plugin's root directory, alongside the plugin's other configuration files. The runtime specifically looks for this file at paths like `plugins/{plugin_name}/hooks.json` when loading the plugin.

### Can hooks.json execute commands other than shell scripts?

Currently, the [`hooks.json`](https://github.com/openai/plugins/blob/main/hooks.json) schema supports only the `"command"` type, which spawns a shell process using the value specified in the `"command"` field. The command runs in the plugin's working directory, allowing execution of any shell script or system command available in that environment.