Skip to content

perf: replace Node.js SessionStart hook with bash (106ms → 5ms)#253

Open
KRRT7 wants to merge 3 commits intoopenai:mainfrom
KRRT7:perf/bash-session-start-hook
Open

perf: replace Node.js SessionStart hook with bash (106ms → 5ms)#253
KRRT7 wants to merge 3 commits intoopenai:mainfrom
KRRT7:perf/bash-session-start-hook

Conversation

@KRRT7
Copy link
Copy Markdown

@KRRT7 KRRT7 commented Apr 21, 2026

Summary

  • Replace the Node.js SessionStart hook with an equivalent bash script
  • SessionEnd stays in Node.js (requires async broker teardown and process tree management)

Why

The SessionStart handler in session-lifecycle-hook.mjs only appends two env vars (CODEX_COMPANION_SESSION_ID and CLAUDE_PLUGIN_DATA) to CLAUDE_ENV_FILE. Running this through Node.js pays ~100ms of V8 startup overhead on every session start for what amounts to two file appends.

Bare Node.js startup on this machine:

$ hyperfine --warmup 5 --runs 30 'node -e "1"'
Time (mean ± σ):  98.3 ms ± 7.4 ms

The actual work (appendEnvVar × 2) adds <10ms on top. A bash script doing the same shell-escaped writes avoids V8 entirely.

Changes

  1. scripts/session-start-env.sh (new): Reads session_id from hook JSON input via jq, appends shell-escaped export lines to $CLAUDE_ENV_FILE. Exact same escaping logic as the Node.js shellEscape() function.
  2. hooks/hooks.json: SessionStart entry points to the new bash script instead of session-lifecycle-hook.mjs.

Benchmark

macOS, Apple Silicon (M4 Max), 30 runs, 5 warmup via hyperfine:

Hook Before (Node.js) After (bash) Delta Speedup
SessionStart 106 ms 5 ms ██████████ -95% 21.2x
Reproduce with hyperfine

Requires hyperfine and jq.

# Create test input
printf '{"session_id":"test-123"}\n' > /tmp/session-input.json

# Measure Node.js version (current main)
CLAUDE_ENV_FILE=/tmp/test-env \
  hyperfine --warmup 5 --runs 30 \
  --prepare 'rm -f /tmp/test-env' \
  'node plugins/codex/scripts/session-lifecycle-hook.mjs SessionStart < /tmp/session-input.json'

# Measure bash version (this branch)
CLAUDE_ENV_FILE=/tmp/test-env \
  hyperfine --warmup 5 --runs 30 \
  --prepare 'rm -f /tmp/test-env' \
  'bash plugins/codex/scripts/session-start-env.sh < /tmp/session-input.json'

Test plan

  • Output matches Node.js version: same export lines with identical shell escaping
  • CODEX_COMPANION_SESSION_ID set correctly in session after start
  • CLAUDE_PLUGIN_DATA set correctly in session after start
  • Empty/missing CLAUDE_ENV_FILE exits cleanly (exit 0, no error)
  • Shell escaping handles single quotes in values
  • SessionEnd still routes to Node.js and tears down broker correctly

Generated by codeflash agent

The SessionStart handler only appends two env vars (session ID and
plugin data dir) to CLAUDE_ENV_FILE. Running this through Node.js
pays ~100ms of V8 startup overhead on every session.

Replace with an equivalent bash script that performs the same
shell-escaped env var exports. SessionEnd stays in Node.js since
it requires async broker teardown and process tree management.

Benchmarked on macOS (Apple Silicon):
  Before: 106 ms ± 1.3 ms
  After:    5 ms ± 5.5 ms
@KRRT7 KRRT7 requested a review from a team April 21, 2026 10:19
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da8d24dd5a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread plugins/codex/scripts/session-start-env.sh
KRRT7 added 2 commits April 21, 2026 05:30
Four tests verifying the bash replacement matches Node.js behavior:
- Basic env var export (session ID + plugin data dir)
- Shell escaping roundtrip with single quotes
- Clean exit without CLAUDE_ENV_FILE
- Byte-for-byte parity with the Node.js session-lifecycle-hook
Addresses review feedback: the Node.js version surfaces append
failures via uncaught exception, so the bash replacement should
propagate them too via set -e.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bce5e90940

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

set -euo pipefail

INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid requiring jq in SessionStart hook

This change introduces a hard runtime dependency on jq for every SessionStart via SESSION_ID=$(... | jq ...); with set -euo pipefail, systems lacking jq now fail the hook with exit 127 before writing CODEX_COMPANION_SESSION_ID/CLAUDE_PLUGIN_DATA. The previous Node.js path did not require jq, and the repo requirements only document Node, so this is a real compatibility regression that can break plugin startup on otherwise supported environments.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant