Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ Flag skill guidance that implies automatic delegation, recommends parallel write

When auditing target skills or plugin-repo docs that mention OpenAI Codex Hooks, keep hooks conceptually separate from marketplace and install-surface guidance. Hooks are Codex runtime lifecycle scripts; plugins may bundle lifecycle config, but hooks are not themselves a plugin install surface.

Flag hooks guidance that uses deprecated `features.codex_hooks` wording instead of canonical `features.hooks`, implies hooks are disabled by default, implies project-local hooks load without a trusted `.codex/` layer, treats `PreToolUse` or `PostToolUse` as complete enforcement for every tool path, omits non-managed hook trust review, or confuses Codex Hooks with git pre-commit hooks or repo-maintenance hook scripts.
Flag hooks guidance that uses deprecated `features.codex_hooks` wording instead of canonical `features.hooks`, refers to removed or legacy plugin-hook gates such as `features.plugin_hooks`, implies hooks are disabled by default, implies project-local hooks load without a trusted `.codex/` layer, treats `PreToolUse` or `PostToolUse` as complete enforcement for every tool path, omits non-managed hook trust review, or confuses Codex Hooks with git pre-commit hooks or repo-maintenance hook scripts.
32 changes: 26 additions & 6 deletions plugins/codex-utilities/docs/thread-title-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ The current hook listens for `SessionStart` with the `startup` matcher and runs:
sh ${PLUGIN_ROOT}/hooks/capture-session-start.sh
```

This command path is intentionally provisional. The live Codex hook docs do not
document `${PLUGIN_ROOT}` expansion for plugin-bundled hook commands, and the
Comment on lines +22 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct the PLUGIN_ROOT hook guidance

In the next hook-test workflow, this note sends maintainers down a stale path: the current OpenAI Hooks docs now explicitly document PLUGIN_ROOT for plugin-bundled hooks as pointing to the installed plugin root, so the ${PLUGIN_ROOT}/hooks/... command is not undocumented/provisional for this reason. Leaving this contradiction in the audit notes can block or misdirect testing of the bundled hook based on an upstream-doc premise that is no longer true.

Useful? React with 👍 / 👎.

managed-hook guidance recommends absolute script paths for managed hooks. Before
enabling `rename` mode, confirm how Codex resolves plugin-relative hook commands
in an installed plugin cache.

The script appends stdin to:

```text
Expand Down Expand Up @@ -98,14 +104,28 @@ visible inside the new thread than the direct App Server hook route.

## Next Test

Before testing, confirm the active Codex config uses the current feature keys:
`features.hooks = true` and the stable plugin feature. Removed keys such as
`features.plugin_hooks` are not required and should not appear in operator
guidance.

An installed `codex-utilities@socket` 6.16.0 probe did not expose or run the
plugin-bundled `SessionStart` hook in the Codex GUI settings or in
`codex exec --dangerously-bypass-hook-trust`. Current Codex docs say
plugin-bundled hooks load alongside other hook sources and do not document a
`SessionStart` exclusion, so treat that result as a product behavior mismatch or
loading-order limitation until confirmed upstream. A user-level or project-local
hook is the better live test surface for the thread-title flow.

1. Install or refresh the Socket marketplace plugin locally.
2. Trust the `codex-utilities` `SessionStart` hook.
3. Start a new thread in a known working directory with the default `capture`
2. Confirm the hook source is visible in Codex hook settings or `/hooks`.
3. Trust the `codex-utilities` `SessionStart` hook if it appears.
4. Start a new thread in a known working directory with the default `capture`
mode.
4. Compare the captured `session_id` with the new thread id.
5. Repeat with `CODEX_UTILITIES_THREAD_TITLE_MODE=dry-run` and inspect
5. Compare the captured `session_id` with the new thread id.
6. Repeat with `CODEX_UTILITIES_THREAD_TITLE_MODE=dry-run` and inspect
`thread-title-decisions.jsonl`.
6. Only after that identity is confirmed, repeat with
7. Only after that identity is confirmed, repeat with
`CODEX_UTILITIES_THREAD_TITLE_MODE=rename`.
7. Keep the model-mediated prefix route as a comparison path if direct App
8. Keep the model-mediated prefix route as a comparison path if direct App
Server renaming loses too much of Codex's generated-title quality.
19 changes: 18 additions & 1 deletion plugins/codex-utilities/scripts/session-start-hook.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import fs from "node:fs";
import net from "node:net";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";

const pluginRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");

const payloadText = await readStdin();
const payload = parsePayload(payloadText);
Expand Down Expand Up @@ -92,11 +95,25 @@ function readConfig() {
maxPrefixLength,
mode,
payloadLogPath: path.join(dataDir, "session-start.jsonl"),
pluginVersion: readPluginVersion(pluginRoot),
socketPath,
timeoutMs,
};
}

function readPluginVersion(pluginRoot) {
const manifestPath = path.join(pluginRoot, ".codex-plugin", "plugin.json");
try {
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
if (typeof manifest.version === "string" && manifest.version.trim()) {
return manifest.version.trim();
}
} catch {
return "unknown";
}
return "unknown";
}

function modeFromEnv(rawMode) {
const mode = (rawMode ?? "capture").trim().toLowerCase();
if (["capture", "dry-run", "rename"].includes(mode)) {
Expand Down Expand Up @@ -139,7 +156,7 @@ async function setThreadName({ socketPath, threadId, name, timeoutMs }) {
clientInfo: {
name: "codex_utilities_hook",
title: "Codex Utilities Hook",
version: "6.15.4",
version: config.pluginVersion,
},
capabilities: {
experimentalApi: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ hooks = false
```

`codex_hooks` still works as a deprecated alias, but skill and repo guidance
should use `features.hooks`.
should use `features.hooks`. Do not use older plugin-gating keys such as
`features.plugin_hooks`; current Codex releases expose plugin support through
the stable plugin feature and hook support through `features.hooks`.

Codex discovers hooks next to active config layers in either `hooks.json` or inline `[hooks]` tables in `config.toml`. The most common locations are:

Expand Down Expand Up @@ -86,6 +88,7 @@ Good hook guidance names the lifecycle event, the matcher scope, the script loca
When auditing hooks guidance, flag wording that:

- uses deprecated `features.codex_hooks` wording instead of canonical `features.hooks`
- refers to removed or legacy plugin-hook gates such as `features.plugin_hooks`
- implies hooks are disabled by default
- implies project-local hooks load in untrusted projects
- says higher-precedence config layers replace lower-precedence hooks
Expand Down