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
6 changes: 6 additions & 0 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ agent-strace explain # plain-English summary

Codex sends one JSON object to each command hook on stdin. agent-strace records the common Codex fields (`session_id`, `turn_id`, `tool_use_id`, `tool_name`, `tool_input`, `tool_response`, `prompt`, and `last_assistant_message`) into the same `.agent-traces/` session store used by Claude Code.

If Codex does not list the hooks after you create the file:

- Use the root `~/.codex/hooks.json` file for user-level hooks, or `<repo>/.codex/hooks.json` for project-level hooks. `~/.codex/hooks/hooks.json` is for plugin-bundled hooks and is not the normal user config path.
- Check `~/.codex/config.toml` and remove `[features].hooks = false` if present. Hooks are enabled by default unless a user, system, or admin config layer disables them.
- Reload Codex or press refresh in the Hooks view. Non-managed command hooks must be reviewed and trusted before they run.

### Gemini CLI hooks

`agent-strace setup --cli gemini` writes a Gemini CLI extension:
Expand Down
2 changes: 1 addition & 1 deletion src/agent_trace/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""agent-trace: strace for AI agents."""

__version__ = "0.79.0"
__version__ = "0.79.1"
8 changes: 8 additions & 0 deletions src/agent_trace/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,14 @@ def cmd_setup(args: argparse.Namespace) -> None:
sys.stderr.write(f"Add this to {path} for {name}:\n\n")
sys.stdout.write(json.dumps(config, indent=2) + "\n")

if cli in ("codex", "all"):
sys.stderr.write(
"\nCodex hook checklist:\n"
"- Put the JSON at ~/.codex/hooks.json or <repo>/.codex/hooks.json, not ~/.codex/hooks/hooks.json.\n"
"- In ~/.codex/config.toml, remove [features].hooks = false if present.\n"
"- Reload Codex, then review and trust command hooks in the Hooks UI or /hooks.\n"
)

if cli == "gemini":
sys.stdout.write(json.dumps(_gemini_hooks_config(args), indent=2) + "\n")
if cli == "cursor":
Expand Down
7 changes: 6 additions & 1 deletion tests/test_codex_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,11 @@ def test_setup_cli_codex_outputs_hooks_json(self):
cmd_setup(args)

config = json.loads(out.getvalue())
self.assertIn("~/.codex/hooks.json", err.getvalue())
err_text = err.getvalue()
self.assertIn("~/.codex/hooks.json", err_text)
self.assertIn("Codex hook checklist", err_text)
self.assertIn("~/.codex/hooks/hooks.json", err_text)
self.assertIn("[features].hooks = false", err_text)
self.assertIn("SessionStart", config["hooks"])
self.assertEqual(
config["hooks"]["PreToolUse"][0]["hooks"][0]["command"],
Expand Down Expand Up @@ -201,6 +205,7 @@ def test_setup_cli_all_outputs_claude_and_codex_sections(self):
self.assertIn("agent-strace hook --provider codex user-prompt", text)
self.assertIn("~/.claude/settings.json", err.getvalue())
self.assertIn("~/.codex/hooks.json", err.getvalue())
self.assertIn("Codex hook checklist", err.getvalue())


if __name__ == "__main__":
Expand Down
Loading