Type: output actions produce hookSpecificOutput with these fields:
hookEventName: Always set to "SessionStart"additionalContext: Set from themessagefield of the action
Example:
SessionStart:
- actions:
- type: output
message: "Welcome message"Output:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Welcome message"
}
}Type: command actions must output valid JSON with the following structure:
{
"continue": boolean,
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "string (optional)"
},
"systemMessage": "string (optional)"
}When the command outputs non-JSON text:
- Parse as
additionalContext(raw text) - Set
hookEventNameto "SessionStart" - Set
continueto true
Example:
# Command outputs: "Project initialized"
# Result:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Project initialized"
},
"continue": true
}When the command outputs invalid JSON:
- Log error to stderr as a warning
- Return fallback JSON with
continue: trueandhookEventName: "SessionStart" - No
additionalContextorsystemMessageprovided
When the command exits with non-zero code:
- Log error to stderr as a warning
- Return fallback JSON with
continue: trueandhookEventName: "SessionStart" - No
additionalContextorsystemMessageprovided
When the command outputs empty string (requirement 3.7):
- Treat as success
- Return
continue: trueandhookEventName: "SessionStart" - No
additionalContextprovided - Rationale: Validation-type CLI tools (fmt, linter, pre-commit) exit 0 with no output when everything is OK. In this case, we should allow the session to proceed.
When multiple actions execute in sequence:
continue: Last value wins (early return on false)hookEventName: Set once by first action (always "SessionStart")additionalContextandsystemMessage: Concatenated with newline separator
SessionStart hooks always exit with code 0, even when:
- Command actions fail or return non-zero exit codes
- JSON parsing errors occur
- Invalid/unsupported fields are detected in command output
This ensures Claude Code always receives a response and can handle the result appropriately based on the continue field in the returned JSON.
Errors are logged to stderr as warnings, but cchook continues to output JSON and exits successfully. This ensures Claude Code always receives a response.
When a command outputs empty string with exit code 0, this is treated as successful validation (requirement 1.6, not an error condition). No warning is logged.
When a command outputs empty string with non-zero exit code:
- Treat as command failure
- Return fallback JSON with
continue: true - Log warning to stderr
The continue field in the response indicates whether the session should proceed:
continue: true: Session continues normallycontinue: false: Session is blocked/halted (if supported by Claude Code)
Commands that exit with code 0 and empty output are treated as successful validation:
- No error message is generated
continue: trueis returned- This supports the common pattern of validation tools that output nothing when validation passes
All SessionStart hook responses follow this JSON structure:
{
"continue": boolean,
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "string or omitted"
},
"systemMessage": "string or omitted"
}- Try to parse as JSON
- If valid JSON with expected structure, use as-is
- If valid JSON with unexpected structure, merge fields
- If invalid JSON, parse as additionalContext
- Process non-JSON output as additionalContext
- Handle empty output according to requirement 1.6