# Codex Companion Lifecycle Hooks Explained: When SessionStart, SessionEnd, and Stop Fire

> Understand Codex Companion lifecycle hooks SessionStart, SessionEnd, and Stop. Learn when each hook fires for session creation, termination, and cancellation.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: internals
- Published: 2026-08-01

---

**Codex Companion registers three optional lifecycle hooks—SessionStart, SessionEnd, and Stop—in [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json) that fire on session creation, session termination, and explicit user cancellation respectively.**

The openai/codex-plugin-cc repository implements a robust hook system for managing Codex session lifecycles. Understanding when these hooks fire and what they execute is essential for customizing behavior or debugging session management issues.

## Hook Registration in hooks.json

All three hooks are defined in **[`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json)**. Each entry specifies the Node.js command to run and a timeout value that prevents indefinite hanging.

```json
// plugins/codex/hooks/hooks.json (excerpt)
{
  "SessionStart": {
    "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionStart",
    "timeout": 5000
  },
  "SessionEnd": {
    "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionEnd",
    "timeout": 5000
  },
  "Stop": {
    "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs\"",
    "timeout": 900000
  }
}

```

These hooks are **optional**—the platform only executes them if the entries exist in [`hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/hooks.json). By default, all three are configured and active.

## SessionStart Hook: Fires Immediately After Session Creation

The **SessionStart** hook triggers immediately after a new Codex session initializes.

### What It Does

In **`plugins/codex/scripts/session-lifecycle-hook.mjs`**, the `handleSessionStart` function performs essential setup:

```javascript
// session-lifecycle-hook.mjs lines 20-30
async function handleSessionStart(sessionId, transcriptPath, pluginData) {
  await appendEnvVar('CODEX_SESSION_ID', sessionId);
  await appendEnvVar('CODEX_TRANSCRIPT_PATH', transcriptPath);
  await appendEnvVar('CODEX_PLUGIN_DATA', JSON.stringify(pluginData));
}

```

This stores three critical values in the environment:
- **`CODEX_SESSION_ID`** – unique identifier for the session
- **`CODEX_TRANSCRIPT_PATH`** – location of the conversation transcript
- **`CODEX_PLUGIN_DATA`** – serialized plugin configuration

The 5-second timeout ensures rapid failure if environment setup hangs.

## SessionEnd Hook: Fires When Sessions Terminate

The **SessionEnd** hook executes whenever a Codex session ends—whether through normal completion or user cancellation.

### What It Does

The `handleSessionEnd` function in `session-lifecycle-hook.mjs` (lines 83-114) orchestrates comprehensive cleanup:

| Cleanup Action | Function Called |
|--------------|-----------------|
| Shut down broker endpoint | `sendBrokerShutdown()` |
| Remove queued and running jobs | `cleanupSessionJobs()` |
| Tear down broker session | `teardownBrokerSession()` |

```javascript
// Example: Manual SessionEnd invocation (matches platform behavior)
const { execSync } = require('child_process');

execSync('node plugins/codex/scripts/session-lifecycle-hook.mjs SessionEnd', {
  env: { CLAUDE_PLUGIN_ROOT: process.cwd() },
  timeout: 5000,
});

```

This ensures no orphaned processes or dangling job queues persist after a session closes.

## Stop Hook: Fires on Explicit User Cancellation

The **Stop** hook differs from SessionEnd—it specifically handles the **review-gate stop command** rather than general session termination.

### When It Fires

The Stop hook triggers when a user explicitly clicks "Stop" in the UI to abort a running review-gate process. This can occur independent of normal session lifecycle events.

### What It Does

The **`stop-review-gate-hook.mjs`** script executes the stop-review-gate workflow:

```javascript
// Example: Manual Stop hook invocation
execSync('node plugins/codex/scripts/stop-review-gate-hook.mjs', {
  env: { CLAUDE_PLUGIN_ROOT: process.cwd() },
  timeout: 900000, // 15 minutes
});

```

The dramatically longer timeout (900 seconds vs. 5 seconds) accommodates the complexity of aborting pending review checks and cleaning up associated state without leaving partially processed gates.

## Timeout Values and Reliability

| Hook | Timeout | Rationale |
|------|---------|-----------|
| SessionStart | 5 seconds | Environment setup should be near-instant |
| SessionEnd | 5 seconds | Cleanup operations are lightweight |
| Stop | 15 minutes | Review-gate abortion may require negotiating with external systems |

These timeouts guarantee that hook failures don't indefinitely block the main Codex process.

## Key Implementation Files

| File Path | Purpose |
|-----------|---------|
| [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json) | Hook definitions and command mappings |
| `plugins/codex/scripts/session-lifecycle-hook.mjs` | SessionStart and SessionEnd handlers |
| `plugins/codex/scripts/stop-review-gate-hook.mjs` | Stop hook implementation |

## Summary

- **SessionStart** fires after session creation, storing session metadata via `handleSessionStart` in `session-lifecycle-hook.mjs`
- **SessionEnd** fires on any session termination, cleaning up brokers and jobs via `handleSessionEnd` in the same file
- **Stop** fires only on explicit review-gate cancellation, running `stop-review-gate-hook.mjs` with a 15-minute timeout
- All hooks are optional and configured in [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json) with appropriate timeouts

## Frequently Asked Questions

### What happens if a hook times out?

The platform aborts the hook execution and continues. The main Codex session proceeds regardless of hook success or failure, ensuring reliability isn't compromised by plugin issues.

### Can I disable specific hooks?

Yes. Remove the corresponding entry from [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json). The platform checks for hook existence before execution, so missing entries are silently skipped.

### How does SessionEnd differ from Stop?

**SessionEnd** runs for every session closure—normal or abnormal—and performs general resource cleanup. **Stop** only runs when the user explicitly cancels a review-gate process and handles aborting that specific workflow.

### Where does CLAUDE_PLUGIN_ROOT come from?

The environment variable is set by the hosting platform to the absolute path of the codex-plugin-cc installation. Hook commands use it to locate scripts reliably regardless of working directory.