Hooks
Hooks
Deterministische Skripte während des Codex-Lebenszyklus ausführen
Hooks sind ein Erweiterungs-Framework für Codex. Mit ihnen können Sie während der agentischen Schleife Skripte oder MCP-Tools ausführen und so unter anderem folgende Funktionen ermöglichen:
- Den Chat an eine benutzerdefinierte Protokollierungs-/Analyse-Engine senden
- Die Prompts Ihres Teams prüfen, um das versehentliche Einfügen von API keys zu verhindern
- Chats zusammenfassen, um automatisch persistente Erinnerungen zu erstellen
- Beim Ende eines Chat-Durchlaufs eine benutzerdefinierte Validierungsprüfung ausführen, um Standards durchzusetzen
- Prompts anpassen, wenn Sie sich in einem bestimmten Verzeichnis befinden
Beachten Sie folgendes Laufzeitverhalten:
- Alle passenden Hooks aus mehreren Dateien werden ausgeführt.
- Mehrere passende Befehls-Hooks für dasselbe Ereignis werden gleichzeitig gestartet, sodass ein Hook den Start eines anderen passenden Hooks nicht verhindern kann.
- Nicht verwaltete Hooks müssen geprüft und als vertrauenswürdig eingestuft werden, bevor sie ausgeführt werden.
Hooks werden an verschiedenen Punkten einer Unterhaltung ausgeführt:
| Zeitpunkt | Hooks |
|---|---|
| Während eines Durchlaufs | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| Wenn Sie einen aktiven Durchlauf unterbrechen | Interrupt (wird für Subagenten nicht ausgeführt) |
| Wenn eine Sitzung oder ein Subagent gestartet wird | SessionStart, SubagentStart |
| Wenn der Haupt-Thread endet | SessionEnd (wird für Subagenten nicht ausgeführt) |
Wo Codex nach Hooks sucht
Codex erkennt Hooks neben aktiven Konfigurationsebenen in einer der folgenden Formen:
hooks.json- eingebettete
[hooks]-Tabellen inconfig.toml
Installierte Plugins können die Lebenszykluskonfiguration auch über ihr Plugin-Manifest
oder eine standardmäßige hooks/hooks.json-Datei bündeln. Die Regeln für die
Plugin-Paketierung finden Sie unter Plugins
erstellen.
In der Praxis sind die vier nützlichsten Speicherorte:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
Wenn mehrere Hook-Quellen vorhanden sind, lädt Codex alle passenden Hooks.
Konfigurationsebenen mit höherer Priorität ersetzen Hooks aus Ebenen mit niedrigerer Priorität nicht.
Wenn eine einzelne Ebene sowohl hooks.json als auch eingebettete [hooks] enthält, führt Codex
sie zusammen und zeigt beim Start eine Warnung an. Verwenden Sie vorzugsweise nur eine Darstellungsform pro Ebene.
Codex kann außerdem Hooks erkennen, die mit aktivierten Plugins gebündelt sind. Mit Plugins gebündelte Hooks werden zusammen mit anderen Hook-Quellen geladen und durchlaufen denselben Prüf- und Vertrauensprozess wie andere nicht verwaltete Hooks.
Projektlokale Hooks werden nur geladen, wenn die .codex/-Ebene des Projekts als vertrauenswürdig eingestuft ist. In
nicht vertrauenswürdigen Projekten lädt Codex weiterhin Benutzer- und System-Hooks aus deren eigenen
aktiven Konfigurationsebenen.
Hooks prüfen und als vertrauenswürdig einstufen
Codex listet konfigurierte Hooks auf, bevor entschieden wird, welche davon ausgeführt werden dürfen. Bevor ein nicht verwalteter Hook ausgeführt werden kann, müssen Sie die genaue Hook-Definition prüfen und als vertrauenswürdig einstufen. Codex speichert die Vertrauensentscheidung für den aktuellen Hash des Hooks. Neue oder geänderte Hooks werden daher zur Prüfung markiert und bis zur Vertrauensfreigabe übersprungen.
Verwenden Sie /hooks in der CLI, um Hook-Quellen zu untersuchen, neue oder geänderte Hooks zu prüfen,
Hooks als vertrauenswürdig einzustufen oder einzelne nicht verwaltete Hooks zu deaktivieren. Wenn Hooks beim
Start geprüft werden müssen, zeigt Codex eine Warnung mit der Aufforderung an, /hooks zu öffnen.
Verwaltete Hooks aus System-, MDM-, Cloud- oder requirements.toml-Quellen werden als
verwaltet gekennzeichnet, gelten gemäß Richtlinie als vertrauenswürdig und können nicht über den Hook-Browser des Benutzers deaktiviert werden.
Für einmalige Automatisierungen, bei denen Hook-Quellen bereits außerhalb von Codex geprüft werden, übergeben Sie
--dangerously-bypass-hook-trust, um aktivierte Hooks für diesen Aufruf ohne
gespeicherte Hook-Vertrauensentscheidung auszuführen.
Konfigurationsstruktur
Hooks sind auf drei Ebenen organisiert:
- Ein Hook-Ereignis wie
PreToolUse,PostToolUse,PreCompact,SubagentStartoderStop - Eine Matcher-Gruppe, die entscheidet, wann dieses Ereignis übereinstimmt
- Ein oder mehrere Hook-Handler, die ausgeführt werden, wenn die Matcher-Gruppe übereinstimmt
{
"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
}
]
}
]
}
}Hinweise:
descriptionsind optionale Metadaten auf oberster Ebene für einehooks.json-Datei. Sie ändern nicht, welche Hooks ausgeführt werden.timeoutwird in Sekunden angegeben.- Wenn
timeoutnicht angegeben ist, verwendet Codex für die meisten Hooks600Sekunden.SessionEndundInterruptverwenden standardmäßig1Sekunde und unterstützen bis zu3Sekunden.
statusMessageist optional.additionalContextLimitlegt fest, wie vieladditionalContextein Befehls-Hook an das Modell senden kann, bevor Codex den vollständigen Text auf dem Datenträger speichert und stattdessen eine kürzere Vorschau sendet. Siehe Große Hook-Ausgaben.commandWindowsist eine optionale, ausschließlich für Windows vorgesehene Befehlsüberschreibung. Verwenden Sie in TOMLcommand_windowsodercommandWindows.- Legen Sie
asyncauftruefest, um einen Befehls-Hook im Hintergrund auszuführen. - Handler vom Typ
commandundmcp_toolwerden unterstützt. Handler vom Typpromptundagentwerden geparst, aber übersprungen. - Befehle werden mit dem
cwdder Sitzung als Arbeitsverzeichnis ausgeführt. - Bei Repository-lokalen Hooks sollten Sie den Pfad vorzugsweise vom Git-Stammverzeichnis aus auflösen, anstatt einen
relativen Pfad wie
.codex/hooks/...zu verwenden. Codex kann aus einem Unterverzeichnis gestartet werden, und ein auf dem Git-Stammverzeichnis basierender Pfad hält den Speicherort des Hooks stabil.
Entsprechendes eingebettetes TOML in 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"MCP-Tool-Hooks
Mit einem MCP-Tool-Hook kann ein Lebenszyklusereignis ein Tool auf einem bereits verbundenen MCP-Server aufrufen. Er sendet strukturierte Argumente direkt an das Tool und verwendet denselben Vertrauensprüfungs- und Ausgabevertrag wie ein Befehls-Hook.
Einen MCP-Tool-Hook konfigurieren
Dieser Hook fordert den MCP-Server scanner auf, jeden Patch zu prüfen, nachdem Codex Dateien schreibt oder
bearbeitet:
{
"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"
}
]
}
]
}
}| Feld | Bedeutung |
|---|---|
type |
Muss mcp_tool sein. |
server |
Erforderlicher Name eines bereits verbundenen MCP-Servers. |
tool |
Erforderlicher Name eines von diesem Server bereitgestellten Tools. |
input |
Optionales JSON-Objekt mit Argumentvorlagen. Standardwert: {}. |
timeout |
Optionales Zeitlimit für die aktive Ausführung in Sekunden. Standardwert: 600. |
statusMessage |
Optionale Meldung, die während der Hook-Ausführung angezeigt wird. |
Argumente aus dem Hook-Ereignis erweitern
Verwenden Sie ${field.nested}, um ein durch Punkte getrenntes Feld aus dem Hook-Ereignis zu lesen. Ein Platzhalter,
der einen vollständigen Wert ausfüllt, behält seinen JSON-Typ. Ein Platzhalter innerhalb einer längeren
Zeichenfolge wird als Text gerendert. Codex erweitert Objekte und Arrays rekursiv.
Für ein Ereignis mit {"tool_input":{"file_path":"src/main.rs","count":3}}
wird diese Argumentvorlage:
{
"path": "${tool_input.file_path}",
"count": "${tool_input.count}",
"message": "Scanning ${tool_input.file_path}"
}zu:
{
"path": "src/main.rs",
"count": 3,
"message": "Scanning src/main.rs"
}Ausführung und Lebenszyklus
- Hooks verwenden eine bestehende MCP-Verbindung. Sie starten Server weder, noch stellen sie die Verbindung erneut her.
- Ein Hook kann einen Vorgang blockieren, wenn das Tool eine blockierende Entscheidung zurückgibt. Fehler, fehlende Server und nicht verfügbare Tools blockieren den Vorgang nicht.
- MCP-Tool-Hooks werden synchron ausgeführt. Sie fordern keine Tool-Genehmigung an und lösen keine weiteren Hooks aus.
- Es gilt das kürzere Zeitlimit des Hooks oder Servers. Die Wartezeit auf eine MCP-Elicitation-Antwort wird nicht auf das Zeitlimit angerechnet.
SessionStart-Hooks können ausgeführt werden, bevor ein MCP-Server bereit ist. In diesem Fall blockieren sie die Sitzung nicht.SessionEndunterstützt keine MCP-Tool-Hooks.
Hooks deaktivieren
Hooks sind standardmäßig aktiviert. Um sie in config.toml zu deaktivieren, legen Sie Folgendes fest:
[features]
hooks = falseVerwenden Sie hooks als kanonischen Feature-Schlüssel. codex_hooks funktioniert weiterhin als
veralteter Alias. Administratoren können Hooks auf dieselbe Weise in
requirements.toml mit [features].hooks = false zwangsweise deaktivieren.
Verwaltete Hooks aus requirements.toml
Unternehmensseitig verwaltete Anforderungen können Hooks auch direkt unter [hooks] definieren.
Dies ist nützlich, wenn Administratoren die Hook-Konfiguration durchsetzen, die eigentlichen
Skripte jedoch über MDM oder ein anderes Geräteverwaltungssystem bereitstellen möchten.
Um verwaltete Hooks auch für Benutzer durchzusetzen, die Hooks lokal deaktiviert haben, fixieren Sie
[features].hooks = true in requirements.toml zusammen mit [hooks]. Um
Benutzer-, Projekt-, Sitzungs- und Plugin-Hooks zu ignorieren, während administrativ
verwaltete Hooks weiterhin zugelassen werden, legen Sie allow_managed_hooks_only = true fest.
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"Hinweise zu verwalteten Hooks:
managed_dirwird unter macOS und Linux verwendet.windows_managed_dirwird unter Windows verwendet.- Codex verteilt die Skripte in
managed_dirnicht; Ihre Unternehmenstools müssen sie separat installieren und aktualisieren. - Befehle verwalteter Hooks sollten absolute Skriptpfade unterhalb des konfigurierten verwalteten Verzeichnisses verwenden.
allow_managed_hooks_only = trueüberspringt Hooks aus Benutzer-, Projekt-, Sitzungs- und Plugin-Quellen, lädt jedoch weiterhin verwaltete Hooks ausrequirements.tomlund anderen verwalteten Konfigurationsebenen.
Mit Plugins gebündelte Hooks
Wenn ein Plugin aktiviert ist, kann Codex Lebenszyklus-Hooks aus diesem Plugin zusammen mit Benutzer-, Projekt- und verwalteten Hooks laden.
Standardmäßig sucht Codex im Plugin-Stammverzeichnis nach hooks/hooks.json. Ein Plugin-Manifest
kann diesen Standardwert mit einem hooks-Eintrag in
.codex-plugin/plugin.json überschreiben. Der Manifesteintrag kann ein mit ./ präfigierter Pfad, ein
Array mit ./ präfigierter Pfade, ein eingebettetes Hooks-Objekt oder ein Array eingebetteter
Hooks-Objekte sein.
{
"name": "repo-policy",
"hooks": "./hooks/hooks.json"
}Hook-Pfade im Manifest werden relativ zum Plugin-Stammverzeichnis aufgelöst und müssen innerhalb
dieses Stammverzeichnisses verbleiben. Wenn ein Manifest hooks definiert, verwendet Codex diese
Manifesteinträge anstelle der standardmäßigen hooks/hooks.json.
Plugin-Hook-Befehle erhalten diese Umgebungsvariablen:
PLUGIN_ROOTist eine Codex-spezifische Erweiterung, die auf das Stammverzeichnis des installierten Plugins verweist.PLUGIN_DATAist eine Codex-spezifische Erweiterung, die auf das beschreibbare Datenverzeichnis des Plugins verweist.- Codex setzt außerdem
CLAUDE_PLUGIN_ROOTundCLAUDE_PLUGIN_DATA, um die Kompatibilität mit bestehenden Plugin-Hooks zu gewährleisten.
Plugin-Hooks verwenden dasselbe Ereignisschema wie andere Hooks. Durch das Installieren oder Aktivieren eines Plugins werden dessen Hooks nicht automatisch als vertrauenswürdig eingestuft; Codex überspringt mit Plugins gebündelte Hooks, bis Sie die aktuelle Hook-Definition geprüft und als vertrauenswürdig eingestuft haben.
Matcher-Muster
Das Feld matcher ist eine Regex-Zeichenfolge, die filtert, wann Hooks ausgelöst werden. Verwenden Sie "*",
"" oder lassen Sie matcher vollständig weg, um jedes Auftreten eines unterstützten
Ereignisses abzugleichen.
Nur einige der aktuellen Codex-Ereignisse berücksichtigen matcher:
| Ereignis | Was matcher filtert |
Hinweise |
|---|---|---|
PermissionRequest |
Toolname | Unterstützt werden unter anderem Bash, apply_patch* und MCP-Toolnamen |
PostToolUse |
Toolname | Siehe Toolabdeckung |
PostCompact |
Auslöser der Komprimierung | Werte sind manual oder auto |
PreCompact |
Auslöser der Komprimierung | Werte sind manual oder auto |
PreToolUse |
Toolname | Siehe Toolabdeckung |
SessionEnd |
Beendigungsgrund | Derzeit nur other |
SessionStart |
Startquelle | Werte sind startup, resume, clear und compact |
SubagentStart |
Subagententyp | Die Werte hängen vom gestarteten Subagenten ab |
SubagentStop |
Subagententyp | Die Werte hängen vom beendeten Subagenten ab |
UserPromptSubmit |
nicht unterstützt | Für dieses Ereignis wird jedes konfigurierte matcher ignoriert |
Stop |
nicht unterstützt | Für dieses Ereignis wird jedes konfigurierte matcher ignoriert |
Interrupt |
nicht unterstützt | Für dieses Ereignis wird jedes konfigurierte matcher ignoriert |
*Für apply_patch können matcher-Werte auch Edit oder Write verwenden.
Beispiele:
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|auto
Tool-Abdeckung
PreToolUse und PostToolUse können mehr als Shell- und MCP-Aufrufe beobachten. Die meisten
lokalen Funktionstools verwenden denselben Hook-Pfad. Daher können Sie den Tool-Namen abgleichen,
die JSON-Argumente untersuchen und den Aufruf bei PreToolUse blockieren oder umschreiben.
| Tool-Pfad | PreToolUse |
PostToolUse |
Hinweise |
|---|---|---|---|
| Shell-Befehle | Ja | Ja | Als Bash abgleichen. |
Vereinheitlichte Ausführung (exec_command) |
Ja | Ja | Als Bash abgleichen. Eine spätere write_stdin-Abfrage kann das PostToolUse des ursprünglichen Befehls liefern, wenn dieser abgeschlossen ist. |
apply_patch |
Ja | Ja | Als apply_patch, Edit oder Write abgleichen. |
| MCP-Tools | Ja | Ja | Den MCP-Tool-Namen abgleichen, beispielsweise mcp__filesystem__read_file. |
| Andere lokale Funktionstools | Ja | Ja | Den Namen des Funktionstools abgleichen, beispielsweise update_plan. spawn_agent stimmt auch mit Agent überein. |
Gehostete Tools wie WebSearch |
Nein | Nein | Diese verwenden nicht den Hook-Pfad für lokale Funktionstools. |
write_stdin dient als Transport für eine bestehende vereinheitlichte Ausführungssitzung. Es führt
PreToolUse nicht erneut aus, wenn es Eingaben sendet oder einen Befehl abfragt, der
PreToolUse bereits durchlaufen hat.
Einige spezialisierte Tool-Pfade können den standardmäßigen Hook-Pfad deaktivieren. Betrachten Sie Tool-Hooks als nützliche Schutzmaßnahme, nicht als vollständige Durchsetzungsgrenze.
Gemeinsame Eingabefelder
Jeder Befehls-Hook erhält ein JSON-Objekt über stdin.
Diese gemeinsamen Felder werden Sie in der Regel verwenden:
| Feld | Typ | Bedeutung |
|---|---|---|
session_id |
string |
ID der aktuellen Codex-Sitzung. Subagenten-Hooks verwenden die ID der übergeordneten Sitzung. |
transcript_path |
string | null |
Pfad zur Sitzungs-Transkriptdatei, sofern vorhanden |
cwd |
string |
Arbeitsverzeichnis der Sitzung |
hook_event_name |
string |
Name des aktuellen Hook-Ereignisses |
model |
string |
Codex-spezifische Erweiterung. Slug des aktiven Modells |
Bei durchlaufbezogenen Hooks ist turn_id in den ereignisspezifischen Tabellen als
Codex-spezifische Erweiterung aufgeführt.
SessionStart, PreToolUse, PermissionRequest, PostToolUse,
UserPromptSubmit, SubagentStart, SubagentStop, Stop und Interrupt enthalten außerdem
permission_mode, das den aktuellen Berechtigungsmodus als default,
acceptEdits, plan, dontAsk oder bypassPermissions beschreibt.
transcript_path verweist der Einfachheit halber auf ein Chat-Transkript, das
Transkriptformat ist jedoch keine stabile Schnittstelle für Hooks und kann sich im Laufe der Zeit ändern.
Das vollständige Übertragungsformat finden Sie unter Schemas.
Gemeinsame Ausgabefelder
SessionStart, PreCompact, PostCompact, UserPromptSubmit,
SubagentStop und Stop unterstützen diese gemeinsamen JSON-Felder. SubagentStart
akzeptiert dieselbe Struktur für systemMessage und Hook-spezifischen Kontext, aber
continue: false beendet den Subagenten nicht:
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}| Feld | Auswirkung |
|---|---|
continue |
Markiert diese Hook-Ausführung bei false als beendet |
stopReason |
Wird als Beendigungsgrund aufgezeichnet |
systemMessage |
Wird in der UI oder im Ereignisstream als Warnung angezeigt |
suppressOutput |
Wird derzeit geparst, ist aber noch nicht implementiert |
Exit 0 ohne Ausgabe gilt als erfolgreich, und Codex fährt fort.
PreToolUse und PermissionRequest unterstützen systemMessage, aber continue,
stopReason und suppressOutput werden für diese Ereignisse derzeit nicht unterstützt.
Wenn ein PreToolUse-Hook eines dieser nicht unterstützten Felder zurückgibt, markiert Codex
diese Hook-Ausführung als fehlgeschlagen, meldet den Fehler und setzt den Tool-Aufruf fort.
PostToolUse unterstützt systemMessage, continue: false und stopReason.
suppressOutput wird geparst, für dieses Ereignis derzeit jedoch nicht unterstützt.
Umfangreiche Hook-Ausgabe
Standardmäßig begrenzt Codex jede für das Modell sichtbare Hook-Ausgabenachricht auf ungefähr
2.500 Token. Gibt ein Hook mehr zurück, speichert Codex den vollständigen Text unter
<temp_dir>/hook_outputs/<session_id>/<uuid>.txt und stellt dem Modell eine
Vorschau aus Anfang und Ende samt Pfad der gespeicherten Datei bereit. Dieses Verhalten wird
Spilling genannt: Codex speichert übergroße Ausgaben auf dem Datenträger und ersetzt sie durch eine
kürzere, für das Modell sichtbare Vorschau. Kann die Datei nicht geschrieben werden, erhält das Modell weiterhin
eine gekürzte Vorschau.
Legen Sie für jeden Befehls-Hook, der additionalContext zurückgibt,
additionalContextLimit im Handler fest, um den ungefähren Token-Schwellenwert anzupassen:
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"additionalContextLimit": 5000
}Lassen Sie additionalContextLimit weg, um den standardmäßigen Schwellenwert von 2500 Token zu verwenden. Verwenden Sie eine
positive Ganzzahl, um einen anderen Schwellenwert auszuwählen, oder 0, um den vollständigen zusätzlichen Kontext des Handlers
direkt an das Modell zu übergeben. Codex wertet jeden passenden Handler unabhängig aus.
Bei Ereignissen, die keinen zusätzlichen Kontext erzeugen können, ignoriert Codex
additionalContextLimit und meldet eine Konfigurationswarnung.
Die Einstellung gilt nur für additionalContext. Tool-Feedback und Fortsetzungs-Prompts
behalten den standardmäßigen Grenzwert bei.
Da übergroße Ausgaben auf den Datenträger geschrieben werden können, sollten Hook-Ausgaben keine Geheimnisse oder anderen vertraulichen Daten enthalten.
Hooks im Hintergrund ausführen
Standardmäßig wartet Codex auf den Abschluss eines Befehls-Hooks, bevor der
Vorgang fortgesetzt wird, der ihn ausgelöst hat. Setzen Sie async auf true, um einen Befehls-Hook im
Hintergrund auszuführen, während Codex fortfährt.
Einen Hintergrund-Hook konfigurieren
Fügen Sie einem Befehlshandler in hooks.json die Option "async": true hinzu:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/post_tool_use.py",
"async": true,
"timeout": 120
}
]
}
]
}
}Legen Sie für einen eingebetteten Hook in config.toml die Option async = true fest:
[[hooks.PostToolUse]]
matcher = "Bash"
[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120Hintergrund-Hooks verwenden dieselben Eingaben, Matcher, Vertrauensprüfungen, Zeitlimits und
dieselbe Verarbeitung großer Ausgaben wie synchrone Befehls-Hooks. Wie
bei anderen Befehls-Hooks wird timeout in Sekunden gemessen und ist standardmäßig auf
600 festgelegt. Interrupt-Hooks verwenden standardmäßig eine Sekunde und maximal drei Sekunden,
auch wenn sie im Hintergrund ausgeführt werden.
Ausführung von Hintergrund-Hooks
Wenn ein Hintergrund-Hook abgeschlossen ist, stellt Codex unterstützte informative Ausgaben am nächsten sicheren Punkt der Unterhaltung bereit:
- Ist ein Durchlauf aktiv, wartet Codex, bis die aktuelle Modellanfrage und die Tool-Aufrufe abgeschlossen sind, und stellt die Ausgabe dann der nächsten Modellanfrage in diesem Durchlauf zur Verfügung.
- Ist kein Durchlauf aktiv, wartet Codex bis zum nächsten Benutzerdurchlauf. Der Abschluss eines Hintergrund-Hooks startet keinen neuen Durchlauf.
Verwenden Sie dieselbe ereignisspezifische JSON-Ausgabe wie bei einem synchronen Hook. Codex fügt
additionalContext zum Kontext des Modells hinzu und zeigt systemMessage als
Warnung an.
Einschränkungen
- Codex führt pro Sitzung bis zu acht Hintergrund-Hooks gleichzeitig aus. Weitere Hooks warten, bis ein laufender Hook abgeschlossen ist.
- Jeder passende Aufruf wird unabhängig ausgeführt, und Hintergrund-Hooks können in einer anderen Reihenfolge abgeschlossen werden, als sie gestartet wurden.
- Beim Ende der Sitzung bricht Codex nicht abgeschlossene Hintergrund-Hooks ab und verwirft noch nicht zugestellte Ausgaben.
SessionEnd-Hooks werden immer synchron ausgeführt.
Hooks
SessionStart
Für dieses Ereignis wird matcher auf source angewendet.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
source |
string |
Wie die Sitzung gestartet wurde: startup, resume, clear oder compact |
Nur-Text in stdout wird als zusätzlicher Entwicklerkontext hinzugefügt.
JSON in stdout unterstützt gemeinsame Ausgabefelder und diese
Hook-spezifische Struktur:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Load the workspace conventions before editing."
}
}Dieser additionalContext-Text wird als zusätzlicher Entwicklerkontext hinzugefügt.
Nachdem Codex eine Stammsitzung komprimiert hat, werden SessionStart-Hooks, die mit
source: "compact" übereinstimmen, vor der nächsten Modellanfrage ausgeführt. Dies gilt auch, wenn
die automatische Komprimierung mitten in einem Durchlauf erfolgt: Codex stellt den zusätzlichen
Kontext des Hooks unmittelbar für die Fortsetzung bereit, statt auf einen
späteren Benutzerdurchlauf zu warten. Gibt der Hook continue: false zurück, beendet Codex den Durchlauf,
ohne eine weitere Modellanfrage zu senden.
SessionEnd
Mit SessionEnd können Sie beim Ende einer Sitzung einen Befehl ausführen, etwa um abschließende
Notizen zu speichern oder Dateien zu bereinigen. Der Hook wird für den Haupt-Thread ausgeführt, wenn Sie eine noch geöffnete
Unterhaltung archivieren oder löschen, wenn Codex ordnungsgemäß beendet wird oder nachdem eine
Unterhaltung 30 Minuten lang inaktiv war und in keinem verbundenen Client geöffnet ist.
Für Subagenten wird er nicht ausgeführt.
Das Wechseln zu einer anderen Unterhaltung oder der Aufruf von thread/unsubscribe beendet
die Sitzung nicht sofort, sodass SessionEnd nicht unmittelbar ausgeführt wird. Der Hook kann
während seiner Ausführung weiterhin das Sitzungstranskript lesen.
matcher filtert für dieses Ereignis reason. Derzeit ist reason immer other.
Sie können matcher weglassen oder other verwenden, um den Hook bei jedem SessionEnd-Ereignis auszuführen.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
reason |
string |
Grund für das Sitzungsende: other |
Ein SessionEnd-Befehl erhält beispielsweise:
{
"session_id": "thr_123",
"transcript_path": "/workspace/.codex/rollout.jsonl",
"cwd": "/workspace",
"hook_event_name": "SessionEnd",
"reason": "other"
}SessionEnd-Hooks werden immer synchron ausgeführt, auch wenn async den Wert true hat. Sie
haben beratenden Charakter, sodass ihre Ausgabe Codex nicht steuert oder den Thread geöffnet hält. Wenn ein
Befehl das Zeitlimit überschreitet oder mit einem Fehler beendet wird, meldet Codex dies als Hook-Fehler.
SubagentStart
Für dieses Ereignis wird matcher auf agent_type angewendet.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
agent_id |
string |
Kennung des Subagenten |
agent_type |
string |
Subagententyp oder -profil |
permission_mode |
string |
Aktueller Berechtigungsmodus |
Nur-Text in stdout wird als zusätzlicher Entwicklerkontext für den Subagenten hinzugefügt.
JSON in stdout unterstützt systemMessage und diese Hook-spezifische Struktur:
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}Dieser additionalContext-Text wird als zusätzlicher Entwicklerkontext für den
Subagenten hinzugefügt. continue: false wird aus Kompatibilitätsgründen geparst, verhindert aber nicht,
dass der Subagent gestartet wird.
PreToolUse
PreToolUse kann Bash, über apply_patch ausgeführte Dateibearbeitungen,
MCP-Tool-Aufrufe und andere lokale Funktionstools abfangen. Unterstützte Pfade und Ausnahmen finden Sie unter
Tool-Abdeckung.
matcher wird auf tool_name und Matcher-Aliasse angewendet. Für Dateibearbeitungen über
apply_patch können matcher-Werte apply_patch, Edit oder Write verwenden; die Hook-Eingabe
meldet weiterhin tool_name: "apply_patch".
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
tool_name |
string |
Kanonischer Hook-Tool-Name, etwa Bash, apply_patch oder ein MCP-Name wie mcp__fs__read |
tool_use_id |
string |
Tool-Aufruf-ID für diesen Aufruf |
tool_input |
JSON value |
Tool-spezifische Eingabe. Bash und apply_patch verwenden tool_input.command. MCP- und andere lokale Funktionstools senden ihre Argumente. |
Nur-Text in stdout wird ignoriert.
JSON in stdout kann systemMessage verwenden. Um einen unterstützten Tool-Aufruf abzulehnen, geben Sie
diese Hook-spezifische Struktur zurück:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}Codex akzeptiert auch diese ältere Blockstruktur:
{
"decision": "block",
"reason": "Destructive command blocked by hook."
}Alternativ können Sie Exit-Code 2 verwenden und den Blockierungsgrund in stderr schreiben.
Um für das Modell sichtbaren Kontext hinzuzufügen, ohne zu blockieren, geben Sie
hookSpecificOutput.additionalContext zurück:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}Um einen unterstützten Tool-Aufruf umzuschreiben, ohne ihn zu blockieren, geben Sie
permissionDecision: "allow" mit updatedInput zurück:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": {
"command": "echo rewritten"
}
}
}Bei Bash-Befehlen und apply_patch muss updatedInput ein command-Feld vom Typ Zeichenfolge
enthalten. Bei MCP- und anderen lokalen Funktionstools ist updatedInput das
Objekt mit den Ersatzargumenten. Geben Sie updatedInput nur zusammen mit
permissionDecision: "allow" zurück; andere updatedInput-Strukturen werden als
Fehler gemeldet.
permissionDecision: "ask", das veraltete decision: "approve", continue: false,
stopReason und suppressOutput werden geparst, aber noch nicht unterstützt. Codex markiert
die Hook-Ausführung als fehlgeschlagen, meldet den Fehler und setzt den Tool-Aufruf fort.
PermissionRequest
PermissionRequest wird ausgeführt, wenn Codex im Begriff ist, eine Genehmigung anzufordern, etwa für eine
Shell-Eskalation oder eine Genehmigung für ein verwaltetes Netzwerk. Der Hook kann die Anfrage zulassen, ablehnen
oder auf eine Entscheidung verzichten und die normale Genehmigungsabfrage fortsetzen lassen.
Er wird nicht für Befehle ausgeführt, die keine Genehmigung benötigen.
matcher wird auf tool_name und Matcher-Aliasse angewendet. Zu den aktuellen kanonischen
Werten gehören Bash, apply_patch und MCP-Tool-Namen wie
mcp__server__tool; apply_patch stimmt auch mit Edit und Write überein.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
tool_name |
string |
Kanonischer Hook-Tool-Name, etwa Bash, apply_patch oder ein MCP-Name wie mcp__fs__read |
tool_input |
JSON value |
Tool-spezifische Eingabe. Bash und apply_patch verwenden tool_input.command, während MCP-Tools alle Argumente senden. |
tool_input.description |
string | null |
Für Menschen lesbarer Genehmigungsgrund, sofern Codex einen hat |
Nur-Text in stdout wird ignoriert.
Einige Tool-Eingaben können eine für Menschen lesbare Beschreibung enthalten. Verlassen Sie sich jedoch nicht bei
jedem Tool auf ein tool_input.description-Feld.
Um die Anfrage zu genehmigen, geben Sie Folgendes zurück:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}Um die Anfrage abzulehnen, geben Sie Folgendes zurück:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}Wenn mehrere passende Hooks Entscheidungen zurückgeben, hat jedes deny Vorrang. Andernfalls lässt ein
allow die Anfrage fortfahren, ohne die Genehmigungsabfrage anzuzeigen. Wenn kein
passender Hook eine Entscheidung trifft, verwendet Codex den normalen Genehmigungsablauf.
Geben Sie für PermissionRequest weder updatedInput noch updatedPermissions oder interrupt zurück;
diese Felder sind für zukünftiges Verhalten reserviert und führen derzeit zu einer geschlossenen Ablehnung.
PostToolUse
PostToolUse wird ausgeführt, nachdem unterstützte Tools eine Ausgabe erzeugt haben, einschließlich Bash,
apply_patch, MCP-Tool-Aufrufen und anderen lokalen Funktionstools. Bei Bash wird der Hook
auch nach Befehlen ausgeführt, die mit einem Status ungleich null beendet werden. Er kann Nebenwirkungen
eines bereits ausgeführten Tools nicht rückgängig machen. Unterstützte Pfade und Ausnahmen finden Sie unter Tool-Abdeckung.
matcher wird auf tool_name und Matcher-Aliasse angewendet. Für Dateibearbeitungen über
apply_patch können matcher-Werte apply_patch, Edit oder Write verwenden; die Hook-Eingabe
meldet weiterhin tool_name: "apply_patch".
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
tool_name |
string |
Kanonischer Hook-Tool-Name, etwa Bash, apply_patch oder ein MCP-Name wie mcp__fs__read |
tool_use_id |
string |
Tool-Aufruf-ID für diesen Aufruf |
tool_input |
JSON value |
Tool-spezifische Eingabe. Bash und apply_patch verwenden tool_input.command. MCP- und andere lokale Funktionstools senden ihre Argumente. |
tool_response |
JSON value |
Tool-spezifische Ausgabe. MCP-Tools senden das Ergebnis des MCP-Aufrufs. Andere lokale Funktionstools senden normalerweise ihre für das Modell bestimmte Ausgabe. |
Nur-Text in stdout wird ignoriert.
JSON in stdout kann systemMessage und diese Hook-spezifische Struktur verwenden:
{
"decision": "block",
"reason": "The Bash output needs review before continuing.",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "The command updated generated files."
}
}Dieser additionalContext-Text wird als zusätzlicher Entwicklerkontext hinzugefügt.
Bei diesem Ereignis macht decision: "block" den abgeschlossenen Bash-Befehl nicht rückgängig.
Stattdessen zeichnet Codex das Feedback auf, ersetzt das Tool-Ergebnis durch dieses
Feedback und setzt das Modell mit der vom Hook bereitgestellten Meldung fort.
Alternativ können Sie Exit-Code 2 verwenden und den Feedbackgrund in stderr schreiben.
Um die normale Verarbeitung des ursprünglichen Tool-Ergebnisses zu beenden, nachdem der Befehl bereits
ausgeführt wurde, geben Sie continue: false zurück. Codex ersetzt das Tool-Ergebnis durch
Ihr Feedback oder Ihren Beendigungstext und setzt den Vorgang von dort aus fort.
updatedMCPToolOutput und suppressOutput werden geparst, aber noch nicht unterstützt.
Codex markiert die Hook-Ausführung als fehlgeschlagen, meldet den Fehler und setzt die normale
Verarbeitung des Tool-Ergebnisses fort.
Tool-Aufrufe aus dem Codemodus
Wenn ein Modell im Codemodus ein Tool über JavaScript aufruft, gelten Hook-Entscheidungen
für diesen verschachtelten Aufruf. PreToolUse kann das Tool vor der Ausführung stoppen oder seine
Eingabe umschreiben. Ein blockierendes PostToolUse kann die Nebenwirkungen des Tools nicht rückgängig machen, aber
verhindern, dass das ursprüngliche Ergebnis das laufende Skript erreicht.
| Hook-Ergebnis | Was der Codemodus sieht |
|---|---|
PreToolUse blockiert |
Das Tool-Promise wird abgelehnt, bevor das Tool ausgeführt wird. |
PreToolUse gibt updatedInput zurück |
Das Tool wird mit der umgeschriebenen Eingabe ausgeführt, und das Promise wird mit diesem Ergebnis aufgelöst. |
PostToolUse gibt decision: "block" zurück oder wird mit Code 2 beendet |
Das Tool wird ausgeführt, anschließend wird das Promise mit dem Hook-Grund abgelehnt. |
PostToolUse gibt continue: false zurück |
Codex verwendet das Hook-Feedback für das für das Modell sichtbare Ergebnis, lehnt das verschachtelte Tool-Promise jedoch nicht ab. |
PreCompact
PreCompact wird ausgeführt, bevor Codex den Chat komprimiert. matcher wird auf
trigger angewendet, dessen Werte manual und auto sind.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
trigger |
string |
Auslöser der Komprimierung: manual oder auto |
Nur-Text in stdout wird ignoriert.
JSON in stdout unterstützt gemeinsame Ausgabefelder. Wenn ein
passender PreCompact-Hook continue: false zurückgibt, beendet Codex den Vorgang vor
der Komprimierung.
PostCompact
PostCompact wird ausgeführt, nachdem Codex den Chat komprimiert hat. matcher wird auf
trigger angewendet, dessen Werte manual und auto sind.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
trigger |
string |
Auslöser der Komprimierung: manual oder auto |
Nur-Text in stdout wird ignoriert.
JSON in stdout unterstützt gemeinsame Ausgabefelder. Wenn ein
passender PostCompact-Hook continue: false zurückgibt, beendet Codex den Vorgang nach
der Komprimierung.
UserPromptSubmit
matcher wird für dieses Ereignis derzeit nicht verwendet.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
prompt |
string |
Benutzer-Prompt, der gleich gesendet wird |
Nur-Text in stdout wird als zusätzlicher Entwicklerkontext hinzugefügt.
JSON in stdout unterstützt gemeinsame Ausgabefelder und
diese Hook-spezifische Struktur:
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}Dieser additionalContext-Text wird als zusätzlicher Entwicklerkontext hinzugefügt.
Um den Prompt zu blockieren, geben Sie Folgendes zurück:
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}Alternativ können Sie Exit-Code 2 verwenden und den Blockierungsgrund in stderr schreiben.
SubagentStop
Für dieses Ereignis wird matcher auf agent_type angewendet.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
agent_id |
string |
Kennung des Subagenten |
agent_type |
string |
Subagententyp oder -profil |
agent_transcript_path |
string | null |
Pfad zur Transkriptdatei des Subagenten, sofern vorhanden |
stop_hook_active |
boolean |
Ob dieser Subagent bereits fortgesetzt wurde |
last_assistant_message |
string | null |
Neueste Assistentennachricht des Subagenten, sofern verfügbar |
SubagentStop erwartet beim Beenden mit 0 JSON in stdout. Nur-Text-Ausgaben sind
für dieses Ereignis ungültig.
JSON in stdout unterstützt gemeinsame Ausgabefelder. Um
Codex aufzufordern, den Subagentenablauf fortzusetzen, geben Sie Folgendes zurück:
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}Alternativ können Sie Exit-Code 2 verwenden und den Fortsetzungsgrund in stderr schreiben.
Wenn ein passender SubagentStop-Hook continue: false zurückgibt, hat dies
Vorrang vor Fortsetzungsentscheidungen anderer passender SubagentStop-Hooks.
Stop
matcher wird für dieses Ereignis derzeit nicht verwendet.
Zusätzliche Felder zu den gemeinsamen Eingabefeldern:
| Feld | Typ | Bedeutung |
|---|---|---|
turn_id |
string |
Codex-spezifische Erweiterung. ID des aktiven Codex-Durchlaufs |
stop_hook_active |
boolean |
Ob dieser Durchlauf bereits durch Stop fortgesetzt wurde |
last_assistant_message |
string | null |
Text der neuesten Assistentennachricht, sofern verfügbar |
Stop erwartet beim Beenden mit 0 JSON in stdout. Nur-Text-Ausgaben sind für
dieses Ereignis ungültig.
JSON in stdout unterstützt gemeinsame Ausgabefelder. Damit
Codex fortfährt, geben Sie Folgendes zurück:
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}Alternativ können Sie Exit-Code 2 verwenden und den Fortsetzungsgrund in stderr schreiben.
Bei diesem Ereignis lehnt decision: "block" den Durchlauf nicht ab. Stattdessen weist es
Codex an, fortzufahren, und erstellt automatisch einen neuen Fortsetzungs-Prompt, der
als neuer Benutzer-Prompt fungiert und Ihr reason als Prompttext verwendet.
Wenn ein passender Stop-Hook continue: false zurückgibt, hat dies Vorrang
vor Fortsetzungsentscheidungen anderer passender Stop-Hooks.
Interrupt
Interrupt wird ausgeführt, wenn Sie einen aktiven Durchlauf im Haupt-Thread unterbrechen. Verwenden Sie den Hook,
um die Unterbrechung aufzuzeichnen oder von einem Hook gestartete Arbeiten zu bereinigen. Er wird weder
für inaktive Threads noch für Subagenten ausgeführt, und jedes konfigurierte matcher wird ignoriert.
Zusätzlich zu den allgemeinen Eingabefeldern enthält das Ereignis
turn_id, die ID des unterbrochenen Durchlaufs, und permission_mode.
Befehls-Hooks haben standardmäßig ein Zeitlimit von einer Sekunde. Konfigurierte Zeitlimits sind
auf eine bis drei Sekunden begrenzt. Die Hook-Ausgabe kann die
Unterbrechung weder verhindern noch den Durchlauf neu starten. Beenden Sie den Prozess mit 0 ohne Ausgabe oder geben Sie JSON mit
einer optionalen Eigenschaft systemMessage zurück, um eine Warnung anzuzeigen. Eine reine Textausgabe ist
für dieses Ereignis ungültig.
{ "systemMessage": "Saved the interrupted turn to the local audit log." }Schemas
Wenn Sie das exakte aktuelle Übertragungsformat benötigen, sehen Sie sich die generierten Schemas im Codex-GitHub-Repository an.
Nur-Text-Aliasse
- string | null