gitvow hook --agent <claude|codex|gemini|cursor|copilot|factory|any external name> <Event> reads the agent’s payload on stdin, normalises it, runs the corresponding gitvow handler, and answers in the agent’s form. --agent claude is the default and changes nothing.
Normalised payload
Session ids come fromsession_id (Codex, Gemini, Factory), conversation_id (Cursor) or sessionId (Copilot, whose payloads are camelCase: toolName, toolArgs).
Event mapping
Responses
- Codex, Gemini: allow is exit 0 with no stdout; deny and confirm are exit 2 with the message on stderr. Both agents document exit 2 as a block with stderr as the reason.
- Copilot CLI: stdout JSON
{"permissionDecision": "allow" | "deny" | "ask", "permissionDecisionReason": ...}, exit 0. Copilot treats exit 2 as deny too, but JSON is what lets a confirmation become its nativeask. - Factory: exit 2 with the message on stderr, as documented for
PreToolUse. - Cursor: stdout JSON. Allow is
{"permission": "allow"}. Deny is{"permission": "deny", "user_message": ..., "agent_message": ...}. Confirm is{"permission": "ask", ...}, so Cursor prompts the user natively. Exit code 0 in all cases.
Codex patch parsing
apply_patch input is a text in the *** Begin Patch format. gitvow extracts each *** Update File: <path>, *** Add File: <path> and *** Delete File: <path> block; added lines (+) become new_string and removed lines (-) become old_string for that file. Route literals and path rules are evaluated per file; a deny or confirm on any file blocks the whole patch, with the file named in the message.
Install locations
Per-repo installs (
gitvow install <repo> --agent ...) write the project-level equivalents: .codex/hooks.json, .gemini/settings.json, .cursor/hooks.json, .github/hooks/gitvow.json, .factory/hooks.json.