via prompts.
We will describe the duty, give directions, and inform Codex what sort of outcome we anticipate. This permits us to manage how the agent approaches its work.
However generally, prompting isn’t sufficient.
We might need to additional customise the execution by working our personal logic at completely different levels of a Codex session.
So, how can we do this?
The reply is Codex hooks.
On this publish, we’ll discover the idea of hooks and perceive the place they match into the agentic loop. Then, we’ll undergo a concrete case research to show the idea.
1. Understanding Codex hooks
When Codex works on a activity, it goes via an agentic loop.
For a brand new session, the person sorts in a immediate, Codex analyzes the issue, calls instruments, and completes the duty. You may consider this complete problem-solving trajectory as a lifecycle, and at completely different factors on this lifecycle, Codex emits occasions with completely different occasion names:
SessionStart: emitted when a session begins;PreToolUse: emitted when Codex is about to name a device;PostToolUse: emitted after the device finishes;Cease: emitted when Codex is able to end its response;SessionEnd: emitted when the Codex session ends.
A Hook is the mechanism that permits us to connect our personal logic to those occasions.
For instance, we might use SessionStart hook to load extra context, or PreToolUse hook to examine a command earlier than it runs, or Cease hook to validate a outcome.
So, what does it imply to connect logic to an occasion?
Suppose we configure a hook for PreToolUse. Each time Codex is about to name a device, the hook runs a script. Codex passes details about that device name to the script as a part of the context.
Selecting PreToolUse solely identifies some extent within the lifecycle. Many various device calls can happen at that time. In consequence, we’d additionally want an identical rule to allow us to choose those we truly care about. For instance, we might run the script solely when Codex is about to execute a shell command.
Due to this fact, there are three fundamental selections when configuring a hook:
- At which level within the lifecycle ought to it run?
- Below what situations ought to it run at that time?
- What motion ought to it execute?
In Codex, these correspond to the occasion, matcher, and handler. And that is the fundamental sample behind Codex hooks.
2. Case research: Including a high quality gate to deep analysis
On this case research, we construct a small deep analysis workflow with Codex.
Particularly, we’ll ask Codex to analysis latest tendencies in a given subject. Codex will conduct net searches and determine three necessary tendencies from the previous 90 days. On the finish, it ought to return a structured analysis transient.
To showcase the hook idea, we’ll add a high quality verify simply earlier than Codex finishes. It’ll confirm that the transient comprises sufficient sources and that these sources come from an affordable number of domains.
If the transient passes, Codex can end. If it fails, the hook will ship the issues again to Codex, and Codex will proceed researching inside the identical run till it satisfies our checks.
2.1 Getting ready the Analysis Job
We’ll begin by getting ready a immediate template:
# Deep analysis activity
Analysis **{{TOPIC}}**.
Use sources revealed from **{{WINDOW_START}}** via **{{WINDOW_END}}**,
inclusive. Establish the three most necessary tendencies in that interval and put together
a concise, source-backed transient.
Return a concise, source-backed analysis transient that follows the provided schema.
To make sure structured output, we additionally put together a JSON schema:
{
"sort": "object",
"additionalProperties": false,
"required": ["summary", "trends"],
"properties": {
"abstract": {
"sort": "string"
},
"tendencies": {
"sort": "array",
"objects": {
"sort": "object",
"additionalProperties": false,
"required": ["title", "summary", "sources"],
"properties": {
"title": {
"sort": "string"
},
"abstract": {
"sort": "string"
},
"sources": {
"sort": "array",
"objects": {
"sort": "string"
}
}
}
}
}
}
}
We save this as schemas/research_brief.schema.json. Word that that is additionally the construction our hook expects.
2.2 Designing the High quality Gate
Subsequent, we outline what the hook ought to verify.
Right here, we verify three issues:
- Every pattern ought to comprise not less than two sources.
- The transient ought to comprise not less than ten distinctive sources in complete.
- These sources should come from not less than 5 distinctive domains.
We will solely apply the checks after Codex has completed getting ready it. Which means a Cease hook is appropriate right here.
We first create the validation script in .codex/hooks/validate_research.py:
import json
import sys
from urllib.parse import urlparse
MIN_PER_TREND = 2
MIN_SOURCES = 10
MIN_DOMAINS = 5
occasion = json.load(sys.stdin)
transient = json.hundreds(occasion["last_assistant_message"])
errors = []
all_urls = set()
for quantity, pattern in enumerate(transient["trends"], 1):
urls = set(pattern["sources"])
all_urls.replace(urls)
if len(urls) < MIN_PER_TREND:
errors.append(f"Pattern {quantity} wants not less than {MIN_PER_TREND} sources.")
domains = {
urlparse(url).netloc
for url in all_urls
}
if len(all_urls) < MIN_SOURCES:
errors.append(f"Add not less than {MIN_SOURCES} distinctive sources.")
if len(domains) < MIN_DOMAINS:
errors.append(f"Use not less than {MIN_DOMAINS} supply domains.")
if errors:
message = "Analysis transient verify failed:n- " + "n- ".be part of(errors)
outcome = {"determination": "block", "purpose": message}
else:
outcome = {}
print(json.dumps(outcome))
When the Cease occasion is emitted, Codex passes in last_assistant_message, which follows the schema we outlined earlier. Our script can then parse this response right into a Python dictionary and iterate over the tendencies and gather their sources in a set.
Subsequent, we use urlparse to extract the area from every distinctive URL. After that, we will apply our checks.
If any verify fails, the script would return a block determination along with the errors:
{
"determination": "block",
"purpose": "Analysis transient verify failed:n- Add not less than 10 distinctive sources."
}
Word that for the Cease occasion, block doesn’t terminate the run; it simply prevents Codex from ending. Codex can use the suggestions to enhance the transient inside the identical run.
Now we have to outline the hook to inform Codex when and easy methods to execute it. We do that in .codex/hooks.json:
{
"hooks": {
"Cease": [
{
"hooks": [
{
"type": "command",
"command": "python3 .codex/hooks/validate_research.py",
"commandWindows": "python .codexhooksvalidate_research.py"
}
]
}
]
}
}
Codex at the moment doesn’t apply matchers to the Cease occasion. So we didn’t outline any within the configuration above.
2.3 Working a Concrete Analysis Job
As a check, I requested Codex to analysis latest tendencies in data-center infrastructure:
{
"subject": "latest tendencies in data-center infrastructure",
"as_of": "2026-08-01",
"lookback_days": 90
}
After inserting these values into our immediate template, we save the rendered immediate to outputs/research_prompt.md.
Earlier than the primary run, you’ll be able to open Codex within the venture listing and use /hooks to evaluate the hook.
On this case, we’ll run the duty in headless mode with exec:
codex --search exec
--model gpt-5.6-sol
--json
--output-schema schemas/research_brief.schema.json
-o outputs/research_brief.json
-
< outputs/research_prompt.md
> outputs/run.jsonl
A few issues price mentioning:
exec: runs Codex non-interactively.--search: offers the agent entry to net search.--model: selects the mannequin used for the run.--output-schema: that is the place we provide our pre-defined schema to constrain the agent output.-o: this implies we save the agent’s response to the goal location.--json: this makes Codex emit its execution occasions as JSONL. We redirect this occasion stream tooutputs/run.jsonl, which provides us a hint of the run.-: tells Codex to learn the immediate from normal enter.<: This operator providesoutputs/research_prompt.mdas that enter.
Throughout my check, I see that Codex first produced three tendencies supported by seven distinctive sources. Every pattern had greater than two sources, however the transient didn’t meet our total requirement of ten.
Our Cease hook labored, as Codex obtained this suggestions:
The transient wants broader corroboration. I’m including not less than three
unbiased, in-window sources whereas preserving the identical three
evidence-supported tendencies.
After one other spherical, Codex lastly produced an up to date transient with 12 distinctive sources from 10 domains.
The ultimate transient recognized three main tendencies: the rise of gigawatt-scale AI campuses, energy entry and allowing as infrastructure constraints, and the shift towards liquid cooling.
The hook ran once more, however this time it allowed Codex to complete. The end result is saved to outputs/research_brief.json.
3. When Hooks Are Helpful
In our case research, we confirmed easy methods to use a Cease hook to validate a accomplished outcome. The identical design course of additionally applies to different lifecycle occasions.
For SessionStart hook, it’s helpful when we have to load context when a session begins. If we have to examine an operation earlier than it occurs, we will use PreToolUse hook. If we need to course of the results of a device name, we will use PostToolUse hook.
When designing a hook, ask your self three questions:
- At which level within the lifecycle ought to it run?
- Below what situations ought to it run at that time?
- What motion ought to it execute?
That is how one can add deterministic logic across the Codex execution.

