Problem
Each hook execution spawns a new subprocess via subprocess.Popen (async) or subprocess.run (sync). For a conversation with 3 registered hooks and 50 tool calls, that's 150 process forks. Each fork includes full JSON serialization of the event as stdin.
Location: hooks/executor.py:175, 214
Evidence
Code review of hooks/executor.py. The AsyncProcessManager.cleanup_expired() does a linear scan of all tracked processes before every hook execution.
Severity: High
Impact of fix
Eliminates hundreds of fork+exec cycles per conversation.
Suggested fixes
- Long-running hook process with stdin/stdout IPC (send events as JSON lines, receive responses).
- For trusted hooks: in-process execution via importable Python functions.
Related issues and PRs
Discovered during profiling investigation (code review), May 2026. openhands-sdk v1.19.1.
Problem
Each hook execution spawns a new subprocess via
subprocess.Popen(async) orsubprocess.run(sync). For a conversation with 3 registered hooks and 50 tool calls, that's 150 process forks. Each fork includes full JSON serialization of the event as stdin.Location:
hooks/executor.py:175, 214Evidence
Code review of
hooks/executor.py. TheAsyncProcessManager.cleanup_expired()does a linear scan of all tracked processes before every hook execution.Severity: High
Impact of fix
Eliminates hundreds of fork+exec cycles per conversation.
Suggested fixes
Related issues and PRs
Discovered during profiling investigation (code review), May 2026. openhands-sdk v1.19.1.