A small Codex UserPromptSubmit hook that automatically gives Codex CLI conversations a useful title as soon as the user submits a prompt.
Validated with Codex CLI 0.151.0 on 2026-09-05.
It deliberately does not edit state_*.sqlite, rollout JSONL files, or other Codex state files directly. Thread inspection and renaming go through Codex app-server APIs.
On each UserPromptSubmit event the hook launcher exits quickly after starting a detached worker, before the main agent turn needs to finish. The worker then checks whether the thread still needs a title. For an eligible thread it:
- Reads the thread through
thread/read. - Requires
thread.source == "cli", so Desktop/app-server/exec threads are ignored. - Uses the persisted thread preview when available, otherwise the
UserPromptSubmit.prompttext so naming can start before app-server preview persistence catches up. - Treats Codex's automatic initial 36-character preview-derived name as provisional, while preserving any other existing name as an explicit/manual name. Manual
/renamestill wins. - Generates a short title with an ephemeral
codex execchild. - Reads the thread again before writing: a manual rename performed during generation is preserved, while a Codex provisional name that appears during the race is replaceable.
- Sets the final title through
thread/name/setand records a small processed marker so later turns do not rename the thread again.
The Codex hook itself is synchronous but intentionally tiny: it only starts a detached background worker and returns immediately. This works with Codex builds that currently skip async hooks. The background worker does the app-server lookup and title generation. If generation fails, it uses a conservative local fallback based on the first request. Operational errors never block the Codex turn and are retried on a later UserPromptSubmit event.
- No direct SQLite writes.
- No direct rollout/transcript edits.
- Only threads whose app-server source is
cliare auto-named. - Explicit/manual names are never overwritten; only Codex's known provisional initial preview-derived name is replaceable.
- A second name check closes both the manual-rename race and the Codex-initial-name race.
- The hook forwards at most 6000 prompt characters to its detached worker, avoiding the old empty-preview retry without putting an unbounded prompt in the worker environment.
- A per-session lock prevents duplicate concurrent
UserPromptSubmitworkers. - The title-generation child sets
CODEX_AUTO_TITLE_CHILD=1so its ownUserPromptSubmithook exits immediately and cannot recurse. - Logs contain session IDs and status/error classes, but not prompt text or generated titles.
- A recent Codex CLI with Hooks support.
codex app-serversupport forthread/readandthread/name/set.- No Codex async-hook support is required; the hook launcher detaches its own worker.
- Python 3.10+.
- The same Codex authentication/model-provider configuration that your normal CLI uses.
From this directory:
python .\install.pyThe installer:
- copies
auto_thread_title.pyto~/.codex/hooks/auto-thread-title/; - removes this hook's legacy
Stopregistration if present, then merges one short synchronousUserPromptSubmitlauncher into~/.codex/hooks.json; the launcher immediately detaches the real worker; - makes a timestamped backup before changing an existing
hooks.json; - preserves all unrelated hooks.
Restart Codex after installation. If Codex asks you to review/trust the newly discovered hook, open /hooks and approve it after reviewing the command.
Uninstall only this hook:
python .\install.py --uninstallUninstall preserves the hook's state/log directory so it does not accidentally erase diagnostics.
All settings are optional environment variables inherited by Codex:
| Variable | Default | Purpose |
|---|---|---|
CODEX_AUTO_TITLE_MODEL |
current turn model | Override the model used to generate titles |
CODEX_AUTO_TITLE_PROVIDER |
thread model provider | Override the model provider |
CODEX_AUTO_TITLE_MAX_CHARS |
64 |
Maximum title length; clamped to 24-120 |
CODEX_AUTO_TITLE_GENERATION_TIMEOUT |
90 |
Child generation timeout in seconds; clamped to 15-300 |
CODEX_AUTO_TITLE_CODEX |
codex on PATH |
Explicit Codex executable |
CODEX_AUTO_TITLE_STATE_DIR |
~/.codex/auto-thread-title |
State/log directory |
Processed markers live under processed/, locks under locks/, and operational events in events.jsonl.
Conceptually the installer adds this group to hooks.UserPromptSubmit (the real command contains absolute paths):
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "python /path/to/auto_thread_title.py",
"commandWindows": "python.exe C:\\path\\to\\auto_thread_title.py",
"timeout": 10,
"statusMessage": "Starting CLI auto-title worker..."
}
]
}
]
}
}UserPromptSubmit fires as soon as the user submits a prompt, so a resumed unnamed thread can be titled without waiting for the main agent turn to finish. The launcher detaches a worker and forwards a bounded copy of the hook's text prompt. The worker still asks app-server for authoritative session source, preview, and current name, but can use the hook prompt while thread.preview is temporarily empty. This avoids losing the naming race to Codex's own provisional initial title.