Host Detection
The bridge resolves the host in this order:
- Explicit
hostoption torun(hooks, { host }). --host <id>flag inprocess.argv(orargvoption). Theinstallcommand writes this into every generated config.- Confidence-scored heuristic over stdin markers.
If all three fall through without a result, run() writes a stderr error and exits 1.
Stdin scoring
Used only when no explicit host is provided.
const scores: Record<THostId, number> = { claude: 0, cursor: 0, codex: 0 };
if (typeof raw.cursor_version === "string") scores.cursor += 1.0;
if (typeof raw.conversation_id === "string" && typeof raw.generation_id === "string") scores.cursor += 0.6;
if (typeof raw.hook_event_name === "string" && /^[a-z]/.test(raw.hook_event_name)) scores.cursor += 0.4;
if (typeof raw.turn_id === "string") scores.codex += 1.0;
if (typeof raw.tool_use_id === "string") scores.codex += 0.6;
if ("last_assistant_message" in raw) scores.codex += 0.6;
if (typeof raw.model === "string" && eventNameIsPascalCase) scores.codex += 0.6;
if (eventNameIsPascalCase && scores.codex === 0) scores.claude += 0.3;
if (typeof raw.tool_input === "object" && raw.tool_input !== null) scores.claude += 0.2;
if (typeof raw.transcript_path === "string") scores.claude += 0.2;Threshold: 0.5. Below that, detection returns null.
The tool_use_id, last_assistant_message, and model + PascalCase fingerprints exist so Codex events that lack turn_id (notably SessionStart) still score above the threshold. Without them, a Codex SessionStart payload would tie-break to Claude via the PascalCase + transcript_path rule and parse against the wrong adapter.
Marker reference
| Marker | Host |
|---|---|
cursor_version: string | Cursor |
conversation_id + generation_id strings | Cursor |
camelCase hook_event_name | Cursor |
turn_id: string | Codex |
tool_use_id: string | Codex |
last_assistant_message present | Codex |
model: string + PascalCase hook_event_name | Codex |
PascalCase hook_event_name without Codex markers | Claude |
tool_input object | Claude |
transcript_path: string | Claude |
Failure mode
[agent-hooks-bridge] could not detect host from stdin (scores: {"claude":0.2,"cursor":0,"codex":0}); pass --host or { host } explicitlystdout is empty. Exit code is 1. The host treats this as a non-blocking error.
When detection runs in practice
For installs generated by bunx @pivanov/agent-hooks-bridge install, every command includes --host <host>, so detection is not on the path. Detection only runs when:
- A hook is wired by hand without the
--hostflag. - A custom transport calls
run()without options.
Debug telemetry
Set AGENT_HOOKS_BRIDGE_DEBUG=1 (or any truthy value: true, yes, on) to log the resolved host and detection scores to stderr on every event:
[agent-hooks-bridge] debug: host=claude via=argv
[agent-hooks-bridge] debug: parsed event=PreToolUse tool=Bash[agent-hooks-bridge] debug: host=codex via=detection scores={"claude":0.4,"cursor":0,"codex":2.2}
[agent-hooks-bridge] debug: parsed event=PostToolUse tool=Editvia is one of option (passed to run({ host })), argv (resolved from --host in argv), or detection (stdin scoring; the scores object is included). Falsy values disable the logging: empty string, 0, false, no, off.