perf: replace Node.js SessionStart hook with bash (106ms → 5ms)#253
perf: replace Node.js SessionStart hook with bash (106ms → 5ms)#253KRRT7 wants to merge 3 commits intoopenai:mainfrom
Conversation
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
There was a problem hiding this comment.
💡 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".
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.
There was a problem hiding this comment.
💡 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) |
There was a problem hiding this comment.
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 👍 / 👎.
Summary
SessionStarthook with an equivalent bash scriptSessionEndstays in Node.js (requires async broker teardown and process tree management)Why
The
SessionStarthandler insession-lifecycle-hook.mjsonly appends two env vars (CODEX_COMPANION_SESSION_IDandCLAUDE_PLUGIN_DATA) toCLAUDE_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:
The actual work (
appendEnvVar× 2) adds <10ms on top. A bash script doing the same shell-escaped writes avoids V8 entirely.Changes
scripts/session-start-env.sh(new): Readssession_idfrom hook JSON input viajq, appends shell-escapedexportlines to$CLAUDE_ENV_FILE. Exact same escaping logic as the Node.jsshellEscape()function.hooks/hooks.json:SessionStartentry points to the new bash script instead ofsession-lifecycle-hook.mjs.Benchmark
macOS, Apple Silicon (M4 Max), 30 runs, 5 warmup via hyperfine:
SessionStart██████████-95%Reproduce with hyperfine
Requires hyperfine and
jq.Test plan
exportlines with identical shell escapingCODEX_COMPANION_SESSION_IDset correctly in session after startCLAUDE_PLUGIN_DATAset correctly in session after startCLAUDE_ENV_FILEexits cleanly (exit 0, no error)Generated by codeflash agent