Skip to main content

Codex

Run uvx jes login first. See Setup.

Install​

uvx jes codex-settings

Copy the hooks object it prints into ~/.codex/hooks.json. Codex ignores a hook until you trust its exact text with /hooks.

uvx jes codex-settings
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "uvx jes@0.0.1 codex-hook",
"timeout": 60
}
]
}
],
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "uvx jes@0.0.1 codex-hook",
"timeout": 60
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "uvx jes@0.0.1 codex-hook",
"timeout": 60
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "uvx jes@0.0.1 codex-hook",
"timeout": 60
}
]
}
]
}
}

What each hook does​

EventStageIf jes blocks
UserPromptSubmitinputReturns decision: block with the refusal as the reason.
PreToolUsetool_callDenies the call. The tool does not run.
PostToolUsetool_resultReturns decision: block, so the model reads the refusal instead of the result.
StopoutputChecks last_assistant_message and continues the turn with the refusal.

Limits​

  • PostToolUse fires after the command has run. It does not undo it. Codex doesn't apply updatedToolOutput, so jes uses decision: block instead.
  • Stop does not change text already on screen. A second Stop with stop_hook_active set is skipped, so a refusal can't loop.