Deutsch

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 in config.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, SubagentStart oder Stop
  • 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:

  • description sind optionale Metadaten auf oberster Ebene für eine hooks.json-Datei. Sie ändern nicht, welche Hooks ausgeführt werden.
  • timeout wird in Sekunden angegeben.
  • Wenn timeout nicht angegeben ist, verwendet Codex für die meisten Hooks 600 Sekunden.
    • SessionEnd und Interrupt verwenden standardmäßig 1 Sekunde und unterstützen bis zu 3 Sekunden.
  • statusMessage ist optional.
  • additionalContextLimit legt fest, wie viel additionalContext ein 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.
  • commandWindows ist eine optionale, ausschließlich für Windows vorgesehene Befehlsüberschreibung. Verwenden Sie in TOML command_windows oder commandWindows.
  • Legen Sie async auf true fest, um einen Befehls-Hook im Hintergrund auszuführen.
  • Handler vom Typ command und mcp_tool werden unterstützt. Handler vom Typ prompt und agent werden geparst, aber übersprungen.
  • Befehle werden mit dem cwd der 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.
  • SessionEnd unterstü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 = false

Verwenden 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_dir wird unter macOS und Linux verwendet.
  • windows_managed_dir wird unter Windows verwendet.
  • Codex verteilt die Skripte in managed_dir nicht; 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 aus requirements.toml und 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_ROOT ist eine Codex-spezifische Erweiterung, die auf das Stammverzeichnis des installierten Plugins verweist.
  • PLUGIN_DATA ist eine Codex-spezifische Erweiterung, die auf das beschreibbare Datenverzeichnis des Plugins verweist.
  • Codex setzt außerdem CLAUDE_PLUGIN_ROOT und CLAUDE_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|Write
  • mcp__filesystem__read_file
  • mcp__filesystem__.*
  • startup|resume|clear|compact
  • manual|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 = 120

Hintergrund-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