What Is the Session Lifecycle Hook in the Codex Plugin?
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:
- Broker shutdown: Loads broker metadata via
loadBrokerSessionfromlib/broker-lifecycle.mjsand sends a shutdown request to the companion broker if running. - Job cleanup: Loads the workspace state using
lib/state.mjs, identifies jobs matching the ending session ID, and terminates them usingterminateProcessTreefromlib/process.mjs. - 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, 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:
{
"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: ProvidesterminateProcessTreewhich recursively kills a process tree.
Practical Examples
Manual Invocation for Debugging
You can simulate session events by piping JSON directly to the script:
# 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:
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_FILEfor downstream use. - During shutdown, it terminates running jobs with
terminateProcessTree, shuts down the broker viasendBrokerShutdown, and persists the cleaned state vialib/state.mjs. - Configuration resides in
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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →