# What Is the Session Lifecycle Hook in the Codex Plugin?

> Understand the session lifecycle hook in the Codex plugin. Learn how this built-in hook automatically manages environment setup and cleanup for every user session. Boost your plugin development.

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

---

**The session lifecycle hook is a built-in Codex Companion hook that runs automatically at the start and end of every user session to manage environment setup and cleanup.**

The session lifecycle hook in the Codex plugin orchestrates the initialization and teardown of Codex Companion sessions. Implemented in the `openai/codex-plugin-cc` repository, this hook ensures that every session begins with the correct environment variables and ends without leaving orphaned processes or stale state files.

## How the Session Lifecycle Hook Works

The session lifecycle hook operates through two distinct phases triggered by Codex events. According to the source code in `plugins/codex/scripts/session-lifecycle-hook.mjs`, the hook reads JSON input from stdin containing session metadata and executes environment-specific logic based on whether the session is starting or ending.

### SessionStart Phase

When a session begins, the hook receives a payload with `session_id`, `transcript_path`, and optional `cwd` values. It appends these as environment variables to the file referenced by `CLAUDE_ENV_FILE`, exporting `CODEX_COMPANION_SESSION_ID`, `CLAUDE_TRANSCRIPT_PATH`, and `CLAUDE_PLUGIN_DATA` for downstream commands.

### SessionEnd Phase

When a session terminates, the hook performs three critical cleanup operations:

1. **Broker shutdown**: Loads broker metadata via `loadBrokerSession` from `lib/broker-lifecycle.mjs` and sends a shutdown request to the companion broker if running.
2. **Job cleanup**: Loads the workspace state using `lib/state.mjs`, identifies jobs matching the ending session ID, and terminates them using `terminateProcessTree` from `lib/process.mjs`.
3. **State persistence**: Removes finished jobs from the state file and clears cached broker session data via `clearBrokerSession`.

## Hook Configuration and Architecture

The hook is wired through [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json), which declares the commands Codex invokes for lifecycle events.

### Registering the Hook in hooks.json

The JSON configuration tells Codex to run the same script with different arguments depending on the lifecycle event:

```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionStart",
            "timeout": 5
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionEnd",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

```

### Supporting Modules

The session lifecycle hook relies on several utility modules located in `plugins/codex/scripts/lib/`:

- **`lib/broker-lifecycle.mjs`**: Loads, stores, and tears down broker session information.
- **`lib/state.mjs`**: Reads and writes the JSON state file that tracks jobs per session.
- **`lib/process.mjs`**: Provides `terminateProcessTree` which recursively kills a process tree.

## Practical Examples

### Manual Invocation for Debugging

You can simulate session events by piping JSON directly to the script:

```bash

# Simulate a SessionStart

echo '{"session_id":"abc123","transcript_path":"/tmp/transcript.txt"}' | \
  node plugins/codex/scripts/session-lifecycle-hook.mjs SessionStart

# Simulate a SessionEnd (will clean up jobs, shutdown broker, etc.)

echo '{"session_id":"abc123","cwd":"/path/to/workspace"}' | \
  node plugins/codex/scripts/session-lifecycle-hook.mjs SessionEnd

```

### Accessing Environment Variables

After a `SessionStart`, the following environment variables are exported via the file pointed to by `CLAUDE_ENV_FILE`:

```bash
export CODEX_COMPANION_SESSION_ID='abc123'
export CLAUDE_TRANSCRIPT_PATH='/tmp/transcript.txt'
export CLAUDE_PLUGIN_DATA='...'

```

Subsequent commands can read `process.env.CODEX_COMPANION_SESSION_ID` to locate the session context.

## Summary

- The session lifecycle hook runs automatically at **SessionStart** and **SessionEnd** via `plugins/codex/scripts/session-lifecycle-hook.mjs`.
- During startup, it records **session ID**, **transcript path**, and **plugin data** to `CLAUDE_ENV_FILE` for downstream use.
- During shutdown, it terminates running jobs with `terminateProcessTree`, shuts down the broker via `sendBrokerShutdown`, and persists the cleaned state via `lib/state.mjs`.
- Configuration resides in [`plugins/codex/hooks/hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/hooks/hooks.json), which maps lifecycle events to the hook commands.

## Frequently Asked Questions

### What triggers the session lifecycle hook in the Codex plugin?

The session lifecycle hook is triggered automatically by Codex when a user session begins or ends. Codex invokes the commands defined in [`hooks.json`](https://github.com/openai/codex-plugin-cc/blob/main/hooks.json), passing either `SessionStart` or `SessionEnd` as an argument to `session-lifecycle-hook.mjs` along with session metadata via stdin.

### How does the hook prevent orphaned processes?

During `SessionEnd`, the hook loads the workspace state from `lib/state.mjs` to identify jobs belonging to the exiting session. It then calls `terminateProcessTree` from `lib/process.mjs` to recursively kill any still-running processes associated with those jobs before clearing the broker session cache.

### Where are session environment variables stored?

The hook writes environment variables to the file path specified by `CLAUDE_ENV_FILE`. This includes `CODEX_COMPANION_SESSION_ID`, `CLAUDE_TRANSCRIPT_PATH`, and `CLAUDE_PLUGIN_DATA`, which subsequent commands can source to access the session context.

### Can I test the session lifecycle hook manually?

Yes, you can manually invoke the hook by piping JSON input to the script. For example, `echo '{"session_id":"abc123","transcript_path":"/tmp/transcript.txt"}' | node plugins/codex/scripts/session-lifecycle-hook.mjs SessionStart` simulates a session start for debugging purposes.