fix(codex): keep session-start hook quiet

This commit is contained in:
Boden Fuller
2026-04-23 23:12:41 -04:00
parent 22fbfa2253
commit cd0d4b9555
5 changed files with 37 additions and 13 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ AgentOps turns session output into durable environment state. The automation pat
| Mode | Start path | Closeout path | What is automatic | | Mode | Start path | Closeout path | What is automatic |
|------|------------|---------------|-------------------| |------|------------|---------------|-------------------|
| Hook-capable runtime | SessionStart hook or `ao inject` | SessionEnd/Stop hooks or `ao forge transcript` + `ao flywheel close-loop` | Startup retrieval, transcript forging, pool maintenance when hooks are installed | | Hook-capable runtime | SessionStart hook or `ao inject` | SessionEnd/Stop hooks or `ao forge transcript` + `ao flywheel close-loop` | Startup retrieval, transcript forging, pool maintenance when hooks are installed |
| Codex native hooks (v0.115.0+) | Native `SessionStart` hook via `scripts/install-codex-plugin.sh` | Native `Stop` hook plus explicit `ao codex stop` when transcript-driven closeout is needed | Startup retrieval, prompt/tool guardrails, and turn-scope close-loop are automatic; `SessionEnd` remains explicit because Codex has no native `SessionEnd` event today | | Codex native hooks (v0.115.0+) | Quiet native `SessionStart` hook via `scripts/install-codex-plugin.sh` | Native `Stop` hook plus explicit `ao codex stop` when transcript-driven closeout is needed | Silent startup maintenance, prompt/tool guardrails, and turn-scope close-loop are automatic; context retrieval stays explicit through `ao codex start` / `ao codex ensure-start` to avoid noisy hook injection |
| Codex hookless fallback (pre-v0.115.0) | `ao codex start` | `ao codex stop` | Startup context assembly, transcript discovery fallback, citation capture, and close-loop status through explicit commands | | Codex hookless fallback (pre-v0.115.0) | `ao codex start` | `ao codex stop` | Startup context assembly, transcript discovery fallback, citation capture, and close-loop status through explicit commands |
| Manual fallback | `ao inject` / `ao lookup` | `ao forge transcript` + `ao flywheel close-loop` | Nothing hidden; operator runs the lifecycle directly | | Manual fallback | `ao inject` / `ao lookup` | `ao forge transcript` + `ao flywheel close-loop` | Nothing hidden; operator runs the lifecycle directly |
+1 -1
View File
@@ -109,7 +109,7 @@ SessionEnd would normally run.
| Mode | Start | Closeout | Notes | | Mode | Start | Closeout | Notes |
|------|-------|----------|-------| |------|-------|----------|-------|
| Hook-capable | Natural language, `/session-start`, or startup hooks | Natural language, `/session-end`, or session-end hooks | Best fit for Claude/OpenCode when hooks are installed; `CLAUDE.md` is the startup surface and hooks stage state silently | | Hook-capable | Natural language, `/session-start`, or startup hooks | Natural language, `/session-end`, or session-end hooks | Best fit for Claude/OpenCode when hooks are installed; `CLAUDE.md` is the startup surface and hooks stage state silently |
| Codex native hooks (v0.115.0+) | Same startup path as hook-capable — native hooks installed by `scripts/install-codex-plugin.sh` | Native `Stop` hook for turn-scope close-loop; explicit `ao codex stop` / `ao codex ensure-stop` for transcript-driven closeout | Native `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, and `PermissionRequest`; no native `SessionEnd` event today | | Codex native hooks (v0.115.0+) | Quiet native `SessionStart` maintenance plus explicit `ao codex start` / `ao codex ensure-start` when context retrieval is needed | Native `Stop` hook for turn-scope close-loop; explicit `ao codex stop` / `ao codex ensure-stop` for transcript-driven closeout | Native `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, and `PermissionRequest`; startup hooks stay quiet and no native `SessionEnd` event exists today |
| Codex hookless fallback (pre-v0.115.0) | `ao factory start --goal "<goal>"`, `ao codex start`, or skill-driven `ao codex ensure-start` | `ao codex stop` or skill-driven `ao codex ensure-stop` | No startup/session-end hook surface under `~/.codex`; lifecycle is explicit, and closeout owns the same curation hygiene as SessionEnd | | Codex hookless fallback (pre-v0.115.0) | `ao factory start --goal "<goal>"`, `ao codex start`, or skill-driven `ao codex ensure-start` | `ao codex stop` or skill-driven `ao codex ensure-stop` | No startup/session-end hook surface under `~/.codex`; lifecycle is explicit, and closeout owns the same curation hygiene as SessionEnd |
| Dream overnight run | `ao overnight setup --apply` then `ao overnight start --goal "<goal>"` | `ao overnight report --from <dir>` | Private local overnight mode. Dream bootstraps config and scheduler assistance, while the host OS still owns actual scheduling semantics | | Dream overnight run | `ao overnight setup --apply` then `ao overnight start --goal "<goal>"` | `ao overnight report --from <dir>` | Private local overnight mode. Dream bootstraps config and scheduler assistance, while the host OS still owns actual scheduling semantics |
| Manual fallback | `ao inject`, `ao lookup` | `ao forge transcript`, `ao flywheel close-loop` | Lowest-level portable path | | Manual fallback | `ao inject`, `ao lookup` | `ao forge transcript`, `ao flywheel close-loop` | Lowest-level portable path |
-5
View File
@@ -9,11 +9,6 @@
"type": "command", "type": "command",
"command": "bash ${AGENTOPS_PLUGIN_ROOT:-~/.codex/plugins/cache/agentops}/hooks/session-start.sh", "command": "bash ${AGENTOPS_PLUGIN_ROOT:-~/.codex/plugins/cache/agentops}/hooks/session-start.sh",
"timeout": 10 "timeout": 10
},
{
"type": "command",
"command": "bash ${AGENTOPS_PLUGIN_ROOT:-~/.codex/plugins/cache/agentops}/hooks/ao-inject.sh",
"timeout": 10
} }
] ]
} }
+31 -2
View File
@@ -170,10 +170,13 @@ rg -q '^codex_hooks = true$' "$CODEX_HOME/config.toml" || fail "config.toml miss
[[ -f "$CODEX_HOME/hooks.json" ]] || fail "Missing ~/.codex/hooks.json after native install" [[ -f "$CODEX_HOME/hooks.json" ]] || fail "Missing ~/.codex/hooks.json after native install"
jq -e '.hooks | type == "object" and length == 5' "$CODEX_HOME/hooks.json" >/dev/null \ jq -e '.hooks | type == "object" and length == 5' "$CODEX_HOME/hooks.json" >/dev/null \
|| fail "Expected 5 native Codex hook events in ~/.codex/hooks.json" || fail "Expected 5 native Codex hook events in ~/.codex/hooks.json"
jq -e '[.hooks | to_entries[] | .value[] | .hooks[]] | length == 8' "$CODEX_HOME/hooks.json" >/dev/null \ jq -e '[.hooks | to_entries[] | .value[] | .hooks[]] | length == 7' "$CODEX_HOME/hooks.json" >/dev/null \
|| fail "Expected 8 native Codex hook handlers in ~/.codex/hooks.json" || fail "Expected 7 native Codex hook handlers in ~/.codex/hooks.json"
jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("session-start\\.sh$"))' "$CODEX_HOME/hooks.json" >/dev/null \ jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("session-start\\.sh$"))' "$CODEX_HOME/hooks.json" >/dev/null \
|| fail "Missing session-start.sh handler in ~/.codex/hooks.json" || fail "Missing session-start.sh handler in ~/.codex/hooks.json"
if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("ao-inject\\.sh$"))' "$CODEX_HOME/hooks.json" >/dev/null; then
fail "Codex SessionStart should not install noisy ao-inject.sh"
fi
rg -q '"install_mode": "native-plugin"' "$CODEX_HOME/.agentops-codex-install.json" \ rg -q '"install_mode": "native-plugin"' "$CODEX_HOME/.agentops-codex-install.json" \
|| fail "install metadata missing native-plugin mode" || fail "install metadata missing native-plugin mode"
rg -q '"hook_runtime": "codex-native-hooks"' "$CODEX_HOME/.agentops-codex-install.json" \ rg -q '"hook_runtime": "codex-native-hooks"' "$CODEX_HOME/.agentops-codex-install.json" \
@@ -187,6 +190,29 @@ info "Verifying --codex-home installs hooks into the target Codex home"
EXPLICIT_HOME_ROOT="/tmp/codex-native-plugin-explicit-${timestamp}" EXPLICIT_HOME_ROOT="/tmp/codex-native-plugin-explicit-${timestamp}"
EXPLICIT_CODEX_HOME="${EXPLICIT_HOME_ROOT}/explicit/.codex" EXPLICIT_CODEX_HOME="${EXPLICIT_HOME_ROOT}/explicit/.codex"
REAL_HOME_ROOT="${EXPLICIT_HOME_ROOT}/real-home" REAL_HOME_ROOT="${EXPLICIT_HOME_ROOT}/real-home"
mkdir -p "$EXPLICIT_CODEX_HOME"
cat > "$EXPLICIT_CODEX_HOME/hooks.json" <<'EOF'
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash /old/agentops/hooks/session-start.sh",
"timeout": 10
},
{
"type": "command",
"command": "bash /old/agentops/hooks/ao-inject.sh",
"timeout": 10
}
]
}
]
}
}
EOF
HOME="$REAL_HOME_ROOT" bash "$INSTALL_SCRIPT" \ HOME="$REAL_HOME_ROOT" bash "$INSTALL_SCRIPT" \
--repo-root "$REPO_ROOT" \ --repo-root "$REPO_ROOT" \
--codex-home "$EXPLICIT_CODEX_HOME" \ --codex-home "$EXPLICIT_CODEX_HOME" \
@@ -194,6 +220,9 @@ HOME="$REAL_HOME_ROOT" bash "$INSTALL_SCRIPT" \
--update-command "test-local" >/dev/null --update-command "test-local" >/dev/null
[[ -f "$EXPLICIT_CODEX_HOME/hooks.json" ]] || fail "install-codex-plugin.sh did not create hooks.json under --codex-home" [[ -f "$EXPLICIT_CODEX_HOME/hooks.json" ]] || fail "install-codex-plugin.sh did not create hooks.json under --codex-home"
[[ ! -f "$REAL_HOME_ROOT/.codex/hooks.json" ]] || fail "install-codex-plugin.sh leaked hooks.json into \$HOME instead of --codex-home" [[ ! -f "$REAL_HOME_ROOT/.codex/hooks.json" ]] || fail "install-codex-plugin.sh leaked hooks.json into \$HOME instead of --codex-home"
if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("ao-inject\\.sh$"))' "$EXPLICIT_CODEX_HOME/hooks.json" >/dev/null; then
fail "install-codex-plugin.sh left stale ao-inject.sh in existing Codex hooks"
fi
info "Checking Codex entrypoint files for runtime-agnostic instructions" info "Checking Codex entrypoint files for runtime-agnostic instructions"
entrypoint_files=() entrypoint_files=()
+4 -4
View File
@@ -57,17 +57,17 @@ if [[ -f "$CODEX_HOOKS_JSON" ]]; then
&& pass "hooks/codex-hooks.json is valid JSON" || fail "hooks/codex-hooks.json is invalid JSON" && pass "hooks/codex-hooks.json is valid JSON" || fail "hooks/codex-hooks.json is invalid JSON"
jq -e '.hooks | type == "object" and length == 5' "$CODEX_HOOKS_JSON" >/dev/null 2>&1 \ jq -e '.hooks | type == "object" and length == 5' "$CODEX_HOOKS_JSON" >/dev/null 2>&1 \
&& pass "codex hook bundle defines 5 native hook events" || fail "codex hook bundle event map is unexpectedly small" && pass "codex hook bundle defines 5 native hook events" || fail "codex hook bundle event map is unexpectedly small"
jq -e '[.hooks | to_entries[] | .value[] | .hooks[]] | length == 8' "$CODEX_HOOKS_JSON" >/dev/null 2>&1 \ jq -e '[.hooks | to_entries[] | .value[] | .hooks[]] | length == 7' "$CODEX_HOOKS_JSON" >/dev/null 2>&1 \
&& pass "codex hook bundle defines 8 native hook handlers" || fail "codex hook bundle handler count drifted" && pass "codex hook bundle defines 7 native hook handlers" || fail "codex hook bundle handler count drifted"
if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("session-start\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("session-start\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then
pass "codex hook bundle includes session-start.sh" pass "codex hook bundle includes session-start.sh"
else else
fail "codex hook bundle missing session-start.sh" fail "codex hook bundle missing session-start.sh"
fi fi
if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("ao-inject\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then if jq -e '.hooks.SessionStart[]?.hooks[] | select(.command | test("ao-inject\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then
pass "codex hook bundle includes ao-inject.sh" fail "codex SessionStart must not include ao-inject.sh"
else else
fail "codex hook bundle missing ao-inject.sh" pass "codex SessionStart omits noisy ao-inject.sh"
fi fi
if jq -e '.hooks.Stop[]?.hooks[] | select(.command | test("ao-flywheel-close\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then if jq -e '.hooks.Stop[]?.hooks[] | select(.command | test("ao-flywheel-close\\.sh$"))' "$CODEX_HOOKS_JSON" >/dev/null 2>&1; then
pass "codex hook bundle includes ao-flywheel-close.sh" pass "codex hook bundle includes ao-flywheel-close.sh"