Hook
Hook
Chạy các tập lệnh có tính xác định trong suốt vòng đời Codex
Hook là một khung mở rộng dành cho Codex. Chúng cho phép bạn chạy tập lệnh hoặc công cụ MCP trong vòng lặp tác nhân, hỗ trợ các tính năng như:
- Gửi cuộc trò chuyện đến một công cụ ghi nhật ký/phân tích tùy chỉnh
- Quét prompt của nhóm để ngăn việc vô tình dán API key
- Tóm tắt cuộc trò chuyện để tự động tạo bộ nhớ lâu dài
- Chạy bước kiểm tra xác thực tùy chỉnh khi một lượt trò chuyện dừng lại nhằm thực thi các tiêu chuẩn
- Tùy chỉnh prompt khi ở trong một thư mục nhất định
Hành vi trong thời gian chạy cần lưu ý:
- Tất cả hook khớp từ nhiều tệp đều chạy.
- Nhiều hook lệnh khớp với cùng một sự kiện được khởi chạy đồng thời, vì vậy một hook không thể ngăn một hook khớp khác bắt đầu.
- Bạn phải xem xét và tin cậy các hook không được quản lý trước khi chúng chạy.
Hook chạy tại các thời điểm khác nhau trong cuộc trò chuyện:
| Thời điểm | Hook |
|---|---|
| Trong một lượt | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| Khi bạn ngắt một lượt đang hoạt động | Interrupt (không chạy cho tác nhân phụ) |
| Khi một phiên hoặc tác nhân phụ bắt đầu | SessionStart, SubagentStart |
| Khi luồng chính kết thúc | SessionEnd (không chạy cho tác nhân phụ) |
Nơi Codex tìm hook
Codex phát hiện hook bên cạnh các lớp cấu hình đang hoạt động ở một trong hai dạng sau:
hooks.json- các bảng
[hooks]nội tuyến bên trongconfig.toml
Plugin đã cài đặt cũng có thể đóng gói cấu hình vòng đời thông qua manifest của plugin
hoặc tệp hooks/hooks.json mặc định. Xem Xây dựng
plugin để biết các quy tắc
đóng gói plugin.
Trong thực tế, bốn vị trí hữu ích nhất là:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
Nếu có nhiều hơn một nguồn hook, Codex sẽ tải tất cả hook khớp.
Các lớp cấu hình có độ ưu tiên cao hơn không thay thế hook ở lớp có độ ưu tiên thấp hơn.
Nếu một lớp chứa cả hooks.json và [hooks] nội tuyến, Codex
sẽ hợp nhất chúng và cảnh báo khi khởi động. Mỗi lớp nên chỉ dùng một cách biểu diễn.
Codex cũng có thể phát hiện hook được đóng gói cùng các plugin đã bật. Hook đi kèm plugin được tải cùng các nguồn hook khác và sử dụng cùng quy trình xem xét độ tin cậy như các hook không được quản lý khác.
Hook cục bộ của dự án chỉ được tải khi lớp .codex/ của dự án được tin cậy. Trong
các dự án không được tin cậy, Codex vẫn tải hook người dùng và hệ thống từ các
lớp cấu hình đang hoạt động tương ứng.
Xem xét và tin cậy hook
Codex liệt kê các hook đã cấu hình trước khi quyết định hook nào có thể chạy. Trước khi một hook không được quản lý có thể chạy, Codex yêu cầu bạn xem xét và tin cậy chính xác định nghĩa hook đó. Codex ghi nhận độ tin cậy dựa trên hàm băm hiện tại của hook, vì vậy hook mới hoặc đã thay đổi sẽ được đánh dấu để xem xét và bị bỏ qua cho đến khi được tin cậy.
Dùng /hooks trong CLI để kiểm tra nguồn hook, xem xét hook mới hoặc đã thay đổi,
tin cậy hook hoặc vô hiệu hóa từng hook không được quản lý. Nếu có hook cần xem xét khi
khởi động, Codex sẽ in cảnh báo yêu cầu bạn mở /hooks.
Hook được quản lý từ nguồn hệ thống, MDM, đám mây hoặc requirements.toml được đánh dấu
là được quản lý, được chính sách tin cậy và không thể bị vô hiệu hóa trong trình duyệt hook của người dùng.
Đối với tác vụ tự động hóa dùng một lần đã kiểm tra nguồn hook bên ngoài Codex, hãy truyền
--dangerously-bypass-hook-trust để chạy các hook đã bật mà không yêu cầu
độ tin cậy hook được lưu cho lần gọi đó.
Cấu trúc cấu hình
Hook được tổ chức thành ba cấp:
- Một sự kiện hook như
PreToolUse,PostToolUse,PreCompact,SubagentStarthoặcStop - Một nhóm bộ so khớp quyết định thời điểm sự kiện đó khớp
- Một hoặc nhiều trình xử lý hook chạy khi nhóm bộ so khớp khớp
{
"description": "Optional lifecycle hooks for this workspace.",
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"statusMessage": "Loading session notes",
"additionalContextLimit": 5000
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_end.py",
"timeout": 3
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py\"",
"statusMessage": "Checking Bash command"
}
]
}
],
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",
"statusMessage": "Checking approval request"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py\"",
"statusMessage": "Reviewing Bash output"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/user_prompt_submit_data_flywheel.py\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/stop_continue.py\"",
"timeout": 30
}
]
}
]
}
}Lưu ý:
descriptionlà siêu dữ liệu cấp cao nhất không bắt buộc cho tệphooks.json. Thuộc tính này không thay đổi những hook nào sẽ chạy.timeoutđược tính bằng giây.- Nếu bỏ qua
timeout, Codex sử dụng600giây cho hầu hết các hook.SessionEndvàInterruptmặc định sử dụng1giây và hỗ trợ tối đa3giây.
statusMessagelà không bắt buộc.additionalContextLimitđặt lượngadditionalContextmà một hook lệnh có thể gửi đến mô hình trước khi Codex lưu toàn bộ văn bản vào ổ đĩa và thay vào đó gửi một bản xem trước ngắn hơn. Xem Đầu ra hook lớn.commandWindowslà tùy chọn ghi đè lệnh không bắt buộc, chỉ dành cho Windows. Trong TOML, hãy dùngcommand_windowshoặccommandWindows.- Đặt
asyncthànhtrueđể chạy hook lệnh trong nền. - Các trình xử lý
commandvàmcp_toolđược hỗ trợ. Các trình xử lýpromptvàagentđược phân tích cú pháp nhưng bị bỏ qua. - Các lệnh chạy với
cwdcủa phiên làm thư mục làm việc. - Đối với các hook cục bộ của repo, nên phân giải đường dẫn từ thư mục gốc git thay vì sử dụng
đường dẫn tương đối như
.codex/hooks/.... Codex có thể được khởi động từ một thư mục con, và đường dẫn dựa trên thư mục gốc git giúp vị trí của hook luôn ổn định.
TOML nội tuyến tương đương trong config.toml:
[[hooks.SessionStart]]
matcher = "^compact$"
[[hooks.SessionStart.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/session_start.py"'
additionalContextLimit = 5000
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30
statusMessage = "Checking Bash command"
[[hooks.PostToolUse]]
matcher = "^Bash$"
[[hooks.PostToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py"'
timeout = 30
statusMessage = "Reviewing Bash output"Hook công cụ MCP
Hook công cụ MCP cho phép một sự kiện vòng đời gọi công cụ trên một máy chủ MCP đã kết nối. Hook gửi trực tiếp các đối số có cấu trúc đến công cụ và dùng cùng quy trình xem xét độ tin cậy cũng như hợp đồng đầu ra như hook lệnh.
Cấu hình hook công cụ MCP
Hook này yêu cầu máy chủ MCP scanner quét từng bản vá sau khi Codex ghi hoặc
chỉnh sửa tệp:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "mcp_tool",
"server": "scanner",
"tool": "scan_patch",
"input": { "patch": "${tool_input.command}" },
"timeout": 30,
"statusMessage": "Scanning edited files"
}
]
}
]
}
}| Trường | Ý nghĩa |
|---|---|
type |
Phải là mcp_tool. |
server |
Tên bắt buộc của một máy chủ MCP đã kết nối. |
tool |
Tên bắt buộc của một công cụ do máy chủ đó cung cấp. |
input |
Đối tượng JSON không bắt buộc chứa mẫu đối số. Mặc định là {}. |
timeout |
Thời gian chờ thực thi đang hoạt động không bắt buộc, tính bằng giây. Mặc định là 600. |
statusMessage |
Thông báo không bắt buộc hiển thị trong khi hook chạy. |
Mở rộng đối số từ sự kiện hook
Dùng ${field.nested} để đọc một trường phân cấp bằng dấu chấm từ sự kiện hook. Placeholder
chiếm toàn bộ một giá trị sẽ giữ nguyên kiểu JSON. Placeholder nằm trong một chuỗi
lớn hơn sẽ được kết xuất dưới dạng văn bản. Codex mở rộng đệ quy các đối tượng và mảng.
Với sự kiện chứa {"tool_input":{"file_path":"src/main.rs","count":3}},
mẫu đối số này:
{
"path": "${tool_input.file_path}",
"count": "${tool_input.count}",
"message": "Scanning ${tool_input.file_path}"
}sẽ trở thành:
{
"path": "src/main.rs",
"count": 3,
"message": "Scanning src/main.rs"
}Thực thi và vòng đời
- Hook dùng kết nối MCP hiện có. Hook không khởi động hoặc kết nối lại máy chủ.
- Hook có thể chặn một thao tác khi công cụ trả về quyết định chặn. Lỗi, máy chủ bị thiếu và công cụ không khả dụng không chặn thao tác.
- Hook công cụ MCP chạy đồng bộ. Hook không yêu cầu phê duyệt công cụ hoặc kích hoạt hook khác.
- Thời gian chờ ngắn hơn giữa hook và máy chủ sẽ được áp dụng. Thời gian chờ phản hồi gợi ý từ MCP không được tính vào thời gian chờ.
- Hook
SessionStartcó thể chạy trước khi máy chủ MCP sẵn sàng. Nếu điều đó xảy ra, chúng không chặn phiên. SessionEndkhông hỗ trợ hook công cụ MCP.
Tắt hook
Hook được bật theo mặc định. Để tắt chúng trong config.toml, hãy đặt:
[features]
hooks = falseDùng hooks làm khóa tính năng chuẩn. codex_hooks vẫn hoạt động như một
bí danh không còn được khuyến nghị. Quản trị viên có thể buộc tắt hook theo cùng cách trong
requirements.toml bằng [features].hooks = false.
Hook được quản lý từ requirements.toml
Các yêu cầu do doanh nghiệp quản lý cũng có thể định nghĩa hook nội tuyến bên dưới [hooks].
Điều này hữu ích khi quản trị viên muốn thực thi cấu hình hook trong khi
phân phối các tập lệnh thực tế qua MDM hoặc một hệ thống quản lý thiết bị khác.
Để thực thi hook được quản lý ngay cả với người dùng đã tắt hook cục bộ, hãy ghim
[features].hooks = true trong requirements.toml cùng với [hooks]. Để bỏ qua
hook người dùng, dự án, phiên và plugin nhưng vẫn cho phép hook do quản trị viên
quản lý, hãy đặt allow_managed_hooks_only = true.
allow_managed_hooks_only = true
[features]
hooks = true
[hooks]
managed_dir = "/enterprise/hooks"
windows_managed_dir = 'C:\enterprise\hooks'
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 /enterprise/hooks/pre_tool_use_policy.py"
command_windows = 'py -3 C:\enterprise\hooks\pre_tool_use_policy.py'
timeout = 30
statusMessage = "Checking managed Bash command"Lưu ý về hook được quản lý:
managed_dirđược dùng trên macOS và Linux.windows_managed_dirđược dùng trên Windows.- Codex không phân phối các tập lệnh trong
managed_dir; công cụ doanh nghiệp của bạn phải cài đặt và cập nhật chúng riêng. - Lệnh hook được quản lý nên dùng đường dẫn tập lệnh tuyệt đối bên dưới thư mục được quản lý đã cấu hình.
allow_managed_hooks_only = truebỏ qua hook từ nguồn người dùng, dự án, phiên và plugin, nhưng vẫn tải hook được quản lý từrequirements.tomlvà các lớp cấu hình được quản lý khác.
Hook đi kèm plugin
Khi một plugin được bật, Codex có thể tải hook vòng đời từ plugin đó cùng với hook người dùng, dự án và được quản lý.
Theo mặc định, Codex tìm hooks/hooks.json bên trong thư mục gốc plugin. Manifest của plugin
có thể ghi đè giá trị mặc định đó bằng một mục hooks trong
.codex-plugin/plugin.json. Mục manifest có thể là một đường dẫn có tiền tố ./,
mảng đường dẫn có tiền tố ./, đối tượng hook nội tuyến hoặc mảng
đối tượng hook nội tuyến.
{
"name": "repo-policy",
"hooks": "./hooks/hooks.json"
}Đường dẫn hook trong manifest được phân giải tương đối với thư mục gốc plugin và phải nằm
trong thư mục gốc đó. Nếu manifest định nghĩa hooks, Codex dùng các mục
manifest đó thay cho hooks/hooks.json mặc định.
Lệnh hook plugin nhận các biến môi trường sau:
PLUGIN_ROOTlà phần mở rộng riêng của Codex trỏ đến thư mục gốc của plugin đã cài đặt.PLUGIN_DATAlà phần mở rộng riêng của Codex trỏ đến thư mục dữ liệu có thể ghi của plugin.- Codex cũng đặt
CLAUDE_PLUGIN_ROOTvàCLAUDE_PLUGIN_DATAđể tương thích với các hook plugin hiện có.
Hook plugin dùng cùng lược đồ sự kiện như các hook khác. Việc cài đặt hoặc bật plugin không tự động đặt hook của plugin là đáng tin cậy; Codex bỏ qua hook đi kèm plugin cho đến khi bạn xem xét và tin cậy định nghĩa hook hiện tại.
Mẫu bộ so khớp
Trường matcher là một chuỗi biểu thức chính quy lọc thời điểm hook kích hoạt. Dùng "*",
"" hoặc bỏ qua hoàn toàn matcher để khớp mọi lần xuất hiện của một sự kiện
được hỗ trợ.
Chỉ một số sự kiện Codex hiện tại tuân theo matcher:
| Sự kiện | Nội dung được matcher lọc |
Ghi chú |
|---|---|---|
PermissionRequest |
tên công cụ | Phạm vi hỗ trợ bao gồm Bash, apply_patch* và tên công cụ MCP |
PostToolUse |
tên công cụ | Xem Phạm vi công cụ |
PostCompact |
tác nhân kích hoạt nén ngữ cảnh | Các giá trị là manual hoặc auto |
PreCompact |
tác nhân kích hoạt nén ngữ cảnh | Các giá trị là manual hoặc auto |
PreToolUse |
tên công cụ | Xem Phạm vi công cụ |
SessionEnd |
lý do kết thúc | Hiện chỉ có other |
SessionStart |
nguồn bắt đầu | Các giá trị là startup, resume, clear và compact |
SubagentStart |
loại tác nhân phụ | Các giá trị phụ thuộc vào tác nhân phụ được khởi động |
SubagentStop |
loại tác nhân phụ | Các giá trị phụ thuộc vào tác nhân phụ dừng hoạt động |
UserPromptSubmit |
không được hỗ trợ | Mọi matcher đã cấu hình đều bị bỏ qua cho sự kiện này |
Stop |
không được hỗ trợ | Mọi matcher đã cấu hình đều bị bỏ qua cho sự kiện này |
Interrupt |
không được hỗ trợ | Mọi matcher đã cấu hình đều bị bỏ qua cho sự kiện này |
*Đối với apply_patch, các giá trị matcher cũng có thể dùng Edit hoặc Write.
Ví dụ:
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|auto
Phạm vi hỗ trợ công cụ
PreToolUse và PostToolUse có thể quan sát nhiều thứ hơn lệnh shell và lệnh gọi MCP. Hầu hết
công cụ hàm cục bộ dùng cùng đường dẫn hook, vì vậy bạn có thể khớp tên công cụ,
kiểm tra các đối số JSON và, đối với PreToolUse, chặn hoặc viết lại lệnh gọi.
| Đường dẫn công cụ | PreToolUse |
PostToolUse |
Lưu ý |
|---|---|---|---|
| Lệnh shell | Có | Có | Khớp dưới dạng Bash. |
Thực thi hợp nhất (exec_command) |
Có | Có | Khớp dưới dạng Bash. Một lần thăm dò write_stdin sau đó có thể chuyển PostToolUse của lệnh gốc khi lệnh đó hoàn tất. |
apply_patch |
Có | Có | Khớp dưới dạng apply_patch, Edit hoặc Write. |
| Công cụ MCP | Có | Có | Khớp tên công cụ MCP, chẳng hạn mcp__filesystem__read_file. |
| Công cụ hàm cục bộ khác | Có | Có | Khớp tên công cụ hàm, chẳng hạn update_plan. spawn_agent cũng khớp Agent. |
Công cụ được lưu trữ, như WebSearch |
Không | Không | Các công cụ này không dùng đường dẫn hook công cụ hàm cục bộ. |
write_stdin là phương tiện truyền tải cho một phiên thực thi hợp nhất hiện có. Nó không chạy
lại PreToolUse khi gửi đầu vào hoặc thăm dò một lệnh đã vượt qua
PreToolUse.
Một số đường dẫn công cụ chuyên biệt có thể chọn không dùng đường dẫn hook mặc định. Hãy coi hook công cụ là một biện pháp bảo vệ hữu ích, không phải ranh giới thực thi toàn diện.
Các trường đầu vào chung
Mỗi hook lệnh nhận một đối tượng JSON trên stdin.
Đây là các trường dùng chung mà bạn thường sử dụng:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
session_id |
string |
ID phiên Codex hiện tại. Hook tác nhân phụ dùng ID phiên cha. |
transcript_path |
string | null |
Đường dẫn đến tệp bản chép lời của phiên, nếu có |
cwd |
string |
Thư mục làm việc của phiên |
hook_event_name |
string |
Tên sự kiện hook hiện tại |
model |
string |
Phần mở rộng riêng của Codex. Slug mô hình đang hoạt động |
Hook trong phạm vi lượt liệt kê turn_id dưới dạng phần mở rộng riêng của Codex trong
các bảng dành riêng cho sự kiện.
SessionStart, PreToolUse, PermissionRequest, PostToolUse,
UserPromptSubmit, SubagentStart, SubagentStop, Stop và Interrupt cũng bao gồm
permission_mode, mô tả chế độ quyền hiện tại là default,
acceptEdits, plan, dontAsk hoặc bypassPermissions.
transcript_path trỏ đến bản chép lời cuộc trò chuyện để thuận tiện, nhưng
định dạng bản chép lời không phải là giao diện ổn định cho hook và có thể thay đổi theo thời gian.
Nếu bạn cần định dạng truyền tải đầy đủ, hãy xem Lược đồ.
Các trường đầu ra chung
SessionStart, PreCompact, PostCompact, UserPromptSubmit,
SubagentStop và Stop hỗ trợ các trường JSON dùng chung sau. SubagentStart
chấp nhận cùng cấu trúc cho systemMessage và ngữ cảnh riêng của hook, nhưng
continue: false không dừng tác nhân phụ:
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}| Trường | Tác dụng |
|---|---|
continue |
Nếu là false, đánh dấu lần chạy hook đó là đã dừng |
stopReason |
Được ghi lại làm lý do dừng |
systemMessage |
Được hiển thị dưới dạng cảnh báo trong UI hoặc luồng sự kiện |
suppressOutput |
Hiện được phân tích cú pháp nhưng chưa triển khai |
Thoát với 0 mà không có đầu ra được coi là thành công và Codex tiếp tục.
PreToolUse và PermissionRequest hỗ trợ systemMessage, nhưng continue,
stopReason và suppressOutput hiện không được hỗ trợ cho các sự kiện đó.
Nếu một hook PreToolUse trả về một trong các trường không được hỗ trợ này, Codex đánh dấu
lần chạy hook đó là thất bại, báo lỗi và tiếp tục lệnh gọi công cụ.
PostToolUse hỗ trợ systemMessage, continue: false và stopReason.
suppressOutput được phân tích cú pháp nhưng hiện không được hỗ trợ cho sự kiện đó.
Đầu ra hook lớn
Theo mặc định, Codex giới hạn mỗi thông báo đầu ra hook mà mô hình nhìn thấy ở khoảng
2.500 token. Nếu hook trả về nhiều hơn, Codex lưu toàn bộ văn bản bên dưới
<temp_dir>/hook_outputs/<session_id>/<uuid>.txt và cung cấp cho mô hình bản
xem trước gồm phần đầu và cuối cùng với đường dẫn tệp đã lưu. Hành vi này được gọi là
spilling: Codex lưu đầu ra quá lớn vào đĩa và thay thế bằng một bản
xem trước ngắn hơn mà mô hình có thể thấy. Nếu không thể ghi tệp, mô hình vẫn
nhận được bản xem trước đã cắt ngắn.
Với mọi hook lệnh trả về additionalContext, hãy đặt
additionalContextLimit trên trình xử lý để tùy chỉnh ngưỡng token
xấp xỉ:
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"additionalContextLimit": 5000
}Bỏ qua additionalContextLimit để dùng ngưỡng mặc định 2500 token. Dùng một
số nguyên dương để chọn ngưỡng khác hoặc 0 để chuyển toàn bộ ngữ cảnh bổ sung
của trình xử lý trực tiếp đến mô hình. Codex đánh giá độc lập từng
trình xử lý khớp. Với các sự kiện không thể tạo ngữ cảnh bổ sung,
Codex bỏ qua additionalContextLimit và báo cảnh báo cấu hình.
Cài đặt này chỉ áp dụng cho additionalContext. Phản hồi công cụ và prompt tiếp tục
vẫn dùng giới hạn mặc định.
Vì đầu ra quá lớn có thể được ghi vào đĩa, hãy tránh trả về bí mật hoặc dữ liệu nhạy cảm khác trong đầu ra hook.
Chạy hook trong nền
Theo mặc định, Codex đợi hook lệnh hoàn tất trước khi tiếp tục
thao tác đã kích hoạt hook đó. Đặt async thành true để chạy hook lệnh trong
nền trong khi Codex tiếp tục.
Cấu hình hook nền
Thêm "async": true vào trình xử lý lệnh trong hooks.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/post_tool_use.py",
"async": true,
"timeout": 120
}
]
}
]
}
}Với hook nội tuyến trong config.toml, hãy đặt async = true:
[[hooks.PostToolUse]]
matcher = "Bash"
[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120Các hook chạy nền sử dụng cùng dữ liệu đầu vào, matcher, quy trình xét duyệt độ tin cậy, thời gian chờ và
cơ chế xử lý đầu ra lớn như các hook lệnh đồng bộ. Tương tự
các hook lệnh khác, timeout được tính bằng giây và mặc định là
600. Các hook Interrupt sử dụng giá trị mặc định là một giây và tối đa là ba giây,
kể cả khi chạy trong nền.
Cách hook nền chạy
Khi một hook nền hoàn tất, Codex chuyển đầu ra thông tin được hỗ trợ ở thời điểm an toàn tiếp theo trong cuộc trò chuyện:
- Nếu một lượt đang hoạt động, Codex đợi yêu cầu mô hình và các lệnh gọi công cụ hiện tại hoàn tất, sau đó cung cấp đầu ra cho yêu cầu mô hình tiếp theo trong lượt đó.
- Nếu không có lượt nào đang hoạt động, Codex đợi đến lượt người dùng tiếp theo. Việc hoàn tất một hook nền không bắt đầu lượt mới.
Dùng cùng đầu ra JSON dành riêng cho sự kiện như hook đồng bộ. Codex thêm
additionalContext vào ngữ cảnh của mô hình và hiển thị systemMessage dưới dạng
cảnh báo.
Giới hạn
- Codex chạy đồng thời tối đa tám hook nền cho mỗi phiên. Hook bổ sung sẽ đợi cho đến khi một hook đang chạy hoàn tất.
- Mỗi lần gọi khớp chạy độc lập và hook nền có thể hoàn tất theo thứ tự khác với lúc bắt đầu.
- Khi phiên kết thúc, Codex hủy các hook nền chưa hoàn tất và loại bỏ đầu ra chưa được chuyển.
- Hook
SessionEndluôn chạy đồng bộ.
Hook
SessionStart
matcher được áp dụng cho source đối với sự kiện này.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
source |
string |
Cách phiên bắt đầu: startup, resume, clear hoặc compact |
Văn bản thuần trên stdout được thêm làm ngữ cảnh nhà phát triển bổ sung.
JSON trên stdout hỗ trợ Các trường đầu ra chung và
cấu trúc dành riêng cho hook này:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Load the workspace conventions before editing."
}
}Văn bản additionalContext đó được thêm làm ngữ cảnh nhà phát triển bổ sung.
Sau khi Codex nén một phiên gốc, các hook SessionStart khớp với
source: "compact" sẽ chạy trước yêu cầu mô hình tiếp theo. Điều này cũng áp dụng khi
quá trình nén tự động diễn ra giữa một lượt: Codex chuyển ngữ cảnh bổ sung của hook
đến ngay lần tiếp tục, thay vì chờ một
lượt người dùng sau đó. Nếu hook trả về continue: false, Codex kết thúc lượt
mà không gửi yêu cầu mô hình khác.
SessionEnd
SessionEnd cho phép bạn chạy lệnh khi một phiên kết thúc, chẳng hạn lưu ghi chú cuối cùng
hoặc dọn dẹp tệp. Hook chạy cho luồng chính khi bạn lưu trữ hoặc
xóa một cuộc trò chuyện vẫn đang mở, khi Codex đóng bình thường hoặc sau khi
một cuộc trò chuyện không hoạt động và không được mở trong bất kỳ ứng dụng kết nối nào trong 30
phút. Hook không chạy cho tác nhân phụ.
Việc chuyển khỏi cuộc trò chuyện hoặc gọi thread/unsubscribe không kết thúc
phiên ngay lập tức, vì vậy thao tác đó không chạy SessionEnd ngay. Hook của bạn vẫn có thể
đọc bản chép lời phiên trong khi chạy.
matcher lọc reason cho sự kiện này. Hiện tại, reason luôn là other.
Bạn có thể bỏ qua matcher hoặc dùng other để chạy trên mọi sự kiện SessionEnd.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
reason |
string |
Lý do phiên kết thúc: other |
Ví dụ, một lệnh SessionEnd nhận:
{
"session_id": "thr_123",
"transcript_path": "/workspace/.codex/rollout.jsonl",
"cwd": "/workspace",
"hook_event_name": "SessionEnd",
"reason": "other"
}Hook SessionEnd luôn chạy đồng bộ, ngay cả khi async là true. Chúng
mang tính tư vấn nên đầu ra sẽ không định hướng Codex hoặc giữ luồng mở. Nếu
một lệnh hết thời gian chờ hoặc thoát với lỗi, Codex báo đó là lỗi hook.
SubagentStart
matcher được áp dụng cho agent_type đối với sự kiện này.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
agent_id |
string |
Mã định danh của tác nhân phụ |
agent_type |
string |
Loại hoặc hồ sơ tác nhân phụ |
permission_mode |
string |
Chế độ quyền hiện tại |
Văn bản thuần trên stdout được thêm làm ngữ cảnh nhà phát triển bổ sung cho tác nhân phụ.
JSON trên stdout hỗ trợ systemMessage và cấu trúc dành riêng cho hook này:
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}Văn bản additionalContext đó được thêm làm ngữ cảnh nhà phát triển bổ sung cho
tác nhân phụ. continue: false được phân tích cú pháp để đảm bảo tính tương thích, nhưng không ngăn
tác nhân phụ bắt đầu.
PreToolUse
PreToolUse có thể chặn giữa Bash, thao tác chỉnh sửa tệp thực hiện qua apply_patch,
lệnh gọi công cụ MCP và các công cụ hàm cục bộ khác. Xem Phạm vi
hỗ trợ công cụ để biết các đường dẫn được hỗ trợ và ngoại lệ.
matcher được áp dụng cho tool_name và các bí danh của bộ so khớp. Đối với thao tác chỉnh sửa tệp qua
apply_patch, giá trị matcher có thể dùng apply_patch, Edit hoặc Write; đầu vào hook
vẫn báo tool_name: "apply_patch".
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
tool_name |
string |
Tên công cụ hook chuẩn, chẳng hạn Bash, apply_patch hoặc tên MCP như mcp__fs__read |
tool_use_id |
string |
ID lệnh gọi công cụ cho lần gọi này |
tool_input |
JSON value |
Đầu vào dành riêng cho công cụ. Bash và apply_patch dùng tool_input.command. MCP và các công cụ hàm cục bộ khác gửi đối số của chúng. |
Văn bản thuần trên stdout bị bỏ qua.
JSON trên stdout có thể dùng systemMessage. Để từ chối một lệnh gọi công cụ được hỗ trợ, hãy trả về
cấu trúc dành riêng cho hook này:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}Codex cũng chấp nhận cấu trúc khối cũ hơn này:
{
"decision": "block",
"reason": "Destructive command blocked by hook."
}Bạn cũng có thể dùng mã thoát 2 và ghi lý do chặn vào stderr.
Để thêm ngữ cảnh mà mô hình nhìn thấy mà không chặn, hãy trả về
hookSpecificOutput.additionalContext:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}Để viết lại một lệnh gọi công cụ được hỗ trợ mà không chặn, hãy trả về
permissionDecision: "allow" cùng với updatedInput:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": {
"command": "echo rewritten"
}
}
}Đối với lệnh Bash và apply_patch, updatedInput phải bao gồm trường chuỗi
command. Đối với MCP và các công cụ hàm cục bộ khác, updatedInput là
đối tượng đối số thay thế. Chỉ trả về updatedInput cùng với
permissionDecision: "allow"; các cấu trúc updatedInput khác sẽ bị báo là
lỗi.
permissionDecision: "ask", decision: "approve" cũ, continue: false,
stopReason và suppressOutput được phân tích cú pháp nhưng chưa được hỗ trợ. Codex đánh dấu
lần chạy hook là thất bại, báo lỗi và tiếp tục lệnh gọi công cụ.
PermissionRequest
PermissionRequest chạy khi Codex sắp yêu cầu phê duyệt, chẳng hạn như
nâng cấp quyền shell hoặc phê duyệt mạng được quản lý. Hook có thể cho phép yêu cầu, từ chối
yêu cầu hoặc không đưa ra quyết định để lời nhắc phê duyệt thông thường tiếp tục.
Hook không chạy cho các lệnh không cần phê duyệt.
matcher được áp dụng cho tool_name và các bí danh của bộ so khớp. Các giá trị chuẩn hiện tại
bao gồm Bash, apply_patch và tên công cụ MCP như
mcp__server__tool; apply_patch cũng khớp Edit và Write.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
tool_name |
string |
Tên công cụ hook chuẩn, chẳng hạn Bash, apply_patch hoặc tên MCP như mcp__fs__read |
tool_input |
JSON value |
Đầu vào dành riêng cho công cụ. Bash và apply_patch dùng tool_input.command, còn công cụ MCP gửi tất cả đối số. |
tool_input.description |
string | null |
Lý do phê duyệt mà con người có thể đọc, khi Codex có lý do đó |
Văn bản thuần trên stdout bị bỏ qua.
Một số đầu vào công cụ có thể bao gồm mô tả mà con người có thể đọc, nhưng đừng phụ thuộc vào
trường tool_input.description cho mọi công cụ.
Để phê duyệt yêu cầu, hãy trả về:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}Để từ chối yêu cầu, hãy trả về:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}Nếu nhiều hook khớp trả về quyết định, bất kỳ deny nào cũng được ưu tiên. Nếu không, một
allow cho phép yêu cầu tiếp tục mà không hiển thị lời nhắc phê duyệt. Nếu không có
hook khớp nào đưa ra quyết định, Codex dùng luồng phê duyệt thông thường.
Không trả về updatedInput, updatedPermissions hoặc interrupt cho
PermissionRequest; các trường này được dành cho hành vi trong tương lai và hiện sẽ từ chối
để bảo đảm an toàn.
PostToolUse
PostToolUse chạy sau khi công cụ được hỗ trợ tạo đầu ra, bao gồm Bash,
apply_patch, lệnh gọi công cụ MCP và các công cụ hàm cục bộ khác. Đối với Bash, hook
cũng chạy sau các lệnh thoát với trạng thái khác không. Hook không thể hoàn tác tác dụng phụ
của một công cụ đã chạy. Xem Phạm vi hỗ trợ công cụ để biết
các đường dẫn được hỗ trợ và ngoại lệ.
matcher được áp dụng cho tool_name và các bí danh của bộ so khớp. Đối với thao tác chỉnh sửa tệp qua
apply_patch, giá trị matcher có thể dùng apply_patch, Edit hoặc Write; đầu vào hook
vẫn báo tool_name: "apply_patch".
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
tool_name |
string |
Tên công cụ hook chuẩn, chẳng hạn Bash, apply_patch hoặc tên MCP như mcp__fs__read |
tool_use_id |
string |
ID lệnh gọi công cụ cho lần gọi này |
tool_input |
JSON value |
Đầu vào dành riêng cho công cụ. Bash và apply_patch dùng tool_input.command. MCP và các công cụ hàm cục bộ khác gửi đối số của chúng. |
tool_response |
JSON value |
Đầu ra dành riêng cho công cụ. Công cụ MCP gửi kết quả lệnh gọi MCP. Các công cụ hàm cục bộ khác thường gửi đầu ra dành cho mô hình. |
Văn bản thuần trên stdout bị bỏ qua.
JSON trên stdout có thể dùng systemMessage và cấu trúc dành riêng cho hook này:
{
"decision": "block",
"reason": "The Bash output needs review before continuing.",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "The command updated generated files."
}
}Văn bản additionalContext đó được thêm làm ngữ cảnh nhà phát triển bổ sung.
Đối với sự kiện này, decision: "block" không hoàn tác lệnh Bash đã hoàn tất.
Thay vào đó, Codex ghi lại phản hồi, thay thế kết quả công cụ bằng phản hồi đó
và tiếp tục mô hình từ thông báo do hook cung cấp.
Bạn cũng có thể dùng mã thoát 2 và ghi lý do phản hồi vào stderr.
Để dừng quá trình xử lý bình thường đối với kết quả công cụ gốc sau khi lệnh
đã chạy, hãy trả về continue: false. Codex sẽ thay thế kết quả công cụ bằng
phản hồi hoặc văn bản dừng của bạn rồi tiếp tục từ đó.
updatedMCPToolOutput và suppressOutput được phân tích cú pháp nhưng chưa được hỗ trợ.
Codex đánh dấu lần chạy hook là thất bại, báo lỗi và tiếp tục xử lý
kết quả công cụ theo cách thông thường.
Lệnh gọi công cụ từ chế độ mã
Khi mô hình dùng chế độ mã để gọi công cụ từ JavaScript, quyết định của hook được áp dụng
cho lệnh gọi lồng nhau đó. PreToolUse có thể dừng công cụ trước khi chạy hoặc viết lại
đầu vào của công cụ. Một PostToolUse chặn không thể hoàn tác tác dụng phụ của công cụ, nhưng có thể
ngăn kết quả gốc đến được tập lệnh đang chạy.
| Kết quả hook | Nội dung chế độ mã nhận được |
|---|---|
PreToolUse chặn |
Promise của công cụ bị từ chối trước khi công cụ chạy. |
PreToolUse trả về updatedInput |
Công cụ chạy với đầu vào đã viết lại và promise được phân giải bằng kết quả đó. |
PostToolUse trả về decision: "block" hoặc thoát với mã 2 |
Công cụ chạy, sau đó promise bị từ chối với lý do của hook. |
PostToolUse trả về continue: false |
Codex dùng phản hồi của hook làm kết quả mà mô hình nhìn thấy, nhưng không từ chối promise công cụ lồng nhau. |
PreCompact
PreCompact chạy trước khi Codex nén cuộc trò chuyện. matcher được áp dụng
cho trigger, có các giá trị là manual và auto.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
trigger |
string |
Yếu tố kích hoạt nén: manual hoặc auto |
Văn bản thuần trên stdout bị bỏ qua.
JSON trên stdout hỗ trợ Các trường đầu ra chung. Nếu một
hook PreCompact khớp trả về continue: false, Codex dừng trước khi
nén.
PostCompact
PostCompact chạy sau khi Codex nén cuộc trò chuyện. matcher được áp dụng
cho trigger, có các giá trị là manual và auto.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
trigger |
string |
Yếu tố kích hoạt nén: manual hoặc auto |
Văn bản thuần trên stdout bị bỏ qua.
JSON trên stdout hỗ trợ Các trường đầu ra chung. Nếu một
hook PostCompact khớp trả về continue: false, Codex dừng sau khi
nén.
UserPromptSubmit
matcher hiện không được dùng cho sự kiện này.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
prompt |
string |
Prompt người dùng sắp được gửi |
Văn bản thuần trên stdout được thêm làm ngữ cảnh nhà phát triển bổ sung.
JSON trên stdout hỗ trợ Các trường đầu ra chung và
cấu trúc dành riêng cho hook này:
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}Văn bản additionalContext đó được thêm làm ngữ cảnh nhà phát triển bổ sung.
Để chặn prompt, hãy trả về:
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}Bạn cũng có thể dùng mã thoát 2 và ghi lý do chặn vào stderr.
SubagentStop
matcher được áp dụng cho agent_type đối với sự kiện này.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
agent_id |
string |
Mã định danh của tác nhân phụ |
agent_type |
string |
Loại hoặc hồ sơ tác nhân phụ |
agent_transcript_path |
string | null |
Đường dẫn đến tệp bản chép lời của tác nhân phụ, nếu có |
stop_hook_active |
boolean |
Tác nhân phụ này đã được tiếp tục hay chưa |
last_assistant_message |
string | null |
Thông báo mới nhất của trợ lý tác nhân phụ, nếu có |
SubagentStop yêu cầu JSON trên stdout khi thoát với 0. Đầu ra văn bản thuần
không hợp lệ cho sự kiện này.
JSON trên stdout hỗ trợ Các trường đầu ra chung. Để yêu cầu
Codex tiếp tục luồng tác nhân phụ, hãy trả về:
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}Bạn cũng có thể dùng mã thoát 2 và ghi lý do tiếp tục vào stderr.
Nếu bất kỳ hook SubagentStop khớp nào trả về continue: false, quyết định đó được
ưu tiên hơn quyết định tiếp tục từ các hook SubagentStop khớp
khác.
Stop
matcher hiện không được dùng cho sự kiện này.
Các trường bổ sung ngoài Các trường đầu vào chung:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
turn_id |
string |
Phần mở rộng riêng của Codex. ID lượt Codex đang hoạt động |
stop_hook_active |
boolean |
Lượt này đã được Stop tiếp tục hay chưa |
last_assistant_message |
string | null |
Văn bản thông báo mới nhất của trợ lý, nếu có |
Stop yêu cầu JSON trên stdout khi thoát với 0. Đầu ra văn bản thuần không hợp lệ
cho sự kiện này.
JSON trên stdout hỗ trợ Các trường đầu ra chung. Để Codex
tiếp tục chạy, hãy trả về:
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}Bạn cũng có thể dùng mã thoát 2 và ghi lý do tiếp tục vào stderr.
Đối với sự kiện này, decision: "block" không từ chối lượt. Thay vào đó, trường này yêu cầu
Codex tiếp tục và tự động tạo một prompt tiếp tục mới hoạt động
như một prompt người dùng mới, dùng reason của bạn làm văn bản prompt đó.
Nếu bất kỳ hook Stop khớp nào trả về continue: false, quyết định đó được ưu tiên
hơn quyết định tiếp tục từ các hook Stop khớp khác.
Ngắt
Interrupt chạy khi bạn ngắt một lượt đang hoạt động trên luồng chính. Hãy dùng hook này
để ghi lại lần ngắt hoặc dọn dẹp công việc do một hook khởi tạo. Hook này không chạy
cho các luồng không hoạt động hoặc tác nhân phụ, và mọi matcher đã cấu hình đều bị bỏ qua.
Ngoài Các trường đầu vào chung, sự kiện còn bao gồm
turn_id, id của lượt bị ngắt và permission_mode.
Các hook lệnh mặc định có thời gian chờ một giây. Thời gian chờ đã cấu hình được
giới hạn từ một đến ba giây. Đầu ra của hook không thể ngăn việc
ngắt hoặc khởi động lại lượt. Thoát với 0 mà không có đầu ra, hoặc trả về JSON có
systemMessage không bắt buộc để hiển thị cảnh báo. Đầu ra văn bản thuần không hợp lệ
cho sự kiện này.
{ "systemMessage": "Saved the interrupted turn to the local audit log." }Lược đồ
Nếu bạn cần định dạng truyền tải chính xác hiện tại, hãy xem các lược đồ được tạo trong kho lưu trữ GitHub của Codex.
Bí danh văn bản thuần
- string | null