Skip to content

feat: register hooks for OpenAI Codex CLI and GitHub Copilot CLI#51

Merged
scotthavird merged 1 commit into
mainfrom
claude/support-envelope-v1.2-Gzsge
May 16, 2026
Merged

feat: register hooks for OpenAI Codex CLI and GitHub Copilot CLI#51
scotthavird merged 1 commit into
mainfrom
claude/support-envelope-v1.2-Gzsge

Conversation

@scotthavird
Copy link
Copy Markdown
Contributor

Summary

Adds promptconduit install codex and promptconduit install copilot (plus matching uninstall), bringing live event capture to the two AI tools we already support transcript sync for. Closes the "tools we don't support at all" item from the session-running plan.

Codex CLI — 6 events at ~/.codex/hooks.json

Per the canonical spec:

Event Matcher Notes
SessionStart startup|resume|clear
PreToolUse tool name (Bash, apply_patch, mcp__*)
PermissionRequest tool name
PostToolUse tool name
UserPromptSubmit no matcher support
Stop no matcher support

Claude-Code-style nested schema, but timeout is in seconds (not millis), and the spec has no SessionEnd event.

Copilot CLI — 13 events at ~/.copilot/hooks/promptconduit.json

Per the canonical spec:

Event Matcher
sessionStart / sessionEnd
userPromptSubmitted
preToolUse tool name
postToolUse / postToolUseFailure
permissionRequest tool name
agentStop / subagentStart (agent name) / subagentStop — / regex / —
errorOccurred
preCompact manual|auto
notification notification type

Different schema from the other tools: {"version": 1, "hooks": {...}}, timeoutSec not timeout, per-handler cross-platform command field (we use that single field rather than separate bash/powershell). Copilot loads every *.json under ~/.copilot/hooks/, so we own a dedicated promptconduit.json — uninstall is just rm, no merge/strip dance.

Critical wrinkle: tool detection

Codex's hook payload uses hook_event_name — the same field name as Claude Code — so the existing detectTool heuristic in cmd/hook.go would mistag Codex events as "claude-code". Fix: add a --tool <name> flag to the hidden hook subcommand and have the install commands bake --tool codex / --tool copilot into the registered command line.

Precedence: --tool flag > PROMPTCONDUIT_TOOL env var > existing field-presence heuristic. Existing tools (Claude Code / Cursor / Gemini) are untouched — they continue to be auto-detected.

Test plan

  • go build ./... && go vet ./... && go test ./... clean
  • Smoke: install codex against a fake $HOME writes 6 events to ~/.codex/hooks.json, each command has --tool codex
  • Smoke: install copilot writes 13 events with version: 1, timeoutSec: 30, --tool copilot in every command
  • Smoke: uninstall codex removes 6 hooks; uninstall copilot deletes the file; second uninstall copilot returns cleanly on ENOENT
  • End-to-end: ran hook --tool codex with debug enabled, confirmed via /tmp/promptconduit-hook.log that Detected tool: codex and Created envelope: tool=codex, event=UserPromptSubmit
  • Run against a real Codex CLI install and a real Copilot CLI install and confirm events arrive at the platform end-to-end

Session running plan — status

  1. ✅ Gemini CLI hook coverage (feat(gemini): register all 11 hook events from the current spec #50)
  2. ✅ Claude Code WorktreeCreate — decided "skip it (status quo)" — no code change; observability still available via SessionStart's cwd
  3. ✅ Codex CLI / Copilot CLI hooks ← this PR

That closes the hook-coverage epic for now.

https://claude.ai/code/session_019CWBC2E8pQuShejfsKYrvp


Generated by Claude Code

Adds `promptconduit install codex` and `promptconduit install copilot`
(plus matching uninstall) so live event capture covers the two AI tools
we already support transcript sync for.

Codex (6 events at ~/.codex/hooks.json):
  - SessionStart, PreToolUse, PermissionRequest, PostToolUse,
    UserPromptSubmit, Stop
  - Claude-Code-style schema, but timeout is in SECONDS (not millis)
    and there is no SessionEnd event in the current spec.
  Spec: https://developers.openai.com/codex/hooks

Copilot (13 events at ~/.copilot/hooks/promptconduit.json):
  - sessionStart, sessionEnd, userPromptSubmitted, preToolUse,
    postToolUse, postToolUseFailure, permissionRequest, agentStop,
    subagentStart, subagentStop, errorOccurred, preCompact, notification
  - Different schema: {"version": 1, "hooks": {...}} with timeoutSec
    and per-handler cross-platform `command` field. Copilot loads every
    *.json under ~/.copilot/hooks/, so we own a single dedicated file
    (promptconduit.json) — uninstall is just `rm`, no merge/strip
    dance needed.
  Spec: https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-hooks-reference

Critical wrinkle handled: Codex's hook payload uses `hook_event_name`,
the same field name as Claude Code, so the existing detectTool
heuristic in cmd/hook.go would otherwise mistag Codex events as
"claude-code". Add a `--tool <name>` flag to the hidden hook
subcommand; install bakes `--tool codex` / `--tool copilot` into the
registered command. Precedence: --tool flag > PROMPTCONDUIT_TOOL env
var > field-presence heuristic. Verified end-to-end against the debug
file log:

  [...] Detected tool: codex, hook event: UserPromptSubmit
  [...] Created envelope: tool=codex, event=UserPromptSubmit

Tools enum updated in internal/envelope to include "codex" and
"copilot". install/uninstall dispatchers and Long-form help updated.
README "Real-time hooks" table expanded.

Smoke-tested in a fake $HOME:
  - install codex   → 6 events written, --tool flag in every command
  - install copilot → 13 events written, --tool flag in every command,
                      version:1 wrapper, timeoutSec:30
  - uninstall codex   → 6 hooks removed
  - uninstall copilot → file deleted, ENOENT on second uninstall is
                        handled gracefully

https://claude.ai/code/session_019CWBC2E8pQuShejfsKYrvp
@scotthavird scotthavird marked this pull request as ready for review May 16, 2026 13:49
@scotthavird scotthavird merged commit 4a52fe3 into main May 16, 2026
1 check passed
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.

2 participants