Release 1.1.2 — the default path works end to end

Fix release for 1.1.1: the minimal path end to end, engine commands that
run on Godot, Unity and Unreal, hook warnings you can see, and verdicts
that say when they could not check. Details in CHANGELOG.md; upgrade
steps in UPGRADING.md (v1.1.1 → v1.1.2).

Fixes #67
Fixes #131

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WuJn2FdynEybfL5KC697nJ
This commit is contained in:
Donchitos
2026-09-29 21:32:19 +10:00
co-authored by Claude Opus 5.5
parent 7ed2c3e9c4
commit b21fa0f7f2
383 changed files with 22888 additions and 10618 deletions
@@ -1,10 +1,17 @@
# Hook Input/Output Schemas
This documents the JSON payloads each Claude Code hook receives on stdin for every event type.
This documents the JSON payloads each Claude Code hook receives on stdin for every
event type, and how a hook's output reaches the user and Claude. Every payload
also carries the common fields `session_id`, `transcript_path`, `cwd` and
`hook_event_name`; the examples below show the event-specific ones. The full
reference is the Claude Code hooks documentation (https://code.claude.com/docs/en/hooks).
## PreToolUse
Fired before a tool is executed. Can **allow** (exit 0) or **block** (exit 2).
Fired before a tool is executed. Exit 2 **blocks** the call. Exit 0 lets it
continue through the normal permission flow — it does not approve it, and the
user can still be asked. To warn without blocking, exit 0 and print hook JSON —
see [Output](#output-warnings-someone-sees) below.
### PreToolUse: Bash
@@ -19,6 +26,9 @@ Fired before a tool is executed. Can **allow** (exit 0) or **block** (exit 2).
}
```
The PowerShell tool sends the same shape with `"tool_name": "PowerShell"`, so a
matcher of `Bash|PowerShell` covers both.
### PreToolUse: Write
```json
@@ -55,9 +65,18 @@ Fired before a tool is executed. Can **allow** (exit 0) or **block** (exit 2).
}
```
In real payloads a file tool's `file_path` is absolute, with the platform's own
separators — backslashes on Windows. Strip the project root first, then match
from the start of what is left (`assets/data/`). A segment such as
`/assets/data/` matched anywhere also fires on a parent folder of the same name
and on files outside the project, such as the user's own `~/.claude/skills/`.
`validate-assets.sh` shows the stripping.
## PostToolUse
Fired after a tool completes. **Cannot block** (exit code ignored for blocking). Stderr messages are shown as warnings.
Fired after a tool completes. **Cannot block** — the tool already ran. Exit 2
shows stderr to Claude, so it can fix what it just wrote. stderr on exit 0 goes to
the debug log only, so an advisory warning must be hook JSON on stdout.
### PostToolUse: Write
@@ -68,7 +87,10 @@ Fired after a tool completes. **Cannot block** (exit code ignored for blocking).
"file_path": "assets/data/enemy_stats.json",
"content": "{\"goblin\": {\"health\": 50}}"
},
"tool_output": "File written successfully"
"tool_response": {
"filePath": "assets/data/enemy_stats.json",
"type": "create"
}
}
```
@@ -82,7 +104,7 @@ Fired after a tool completes. **Cannot block** (exit code ignored for blocking).
"old_string": "\"health\": 50",
"new_string": "\"health\": 75"
},
"tool_output": "File edited successfully"
"tool_response": { "filePath": "assets/data/enemy_stats.json" }
}
```
@@ -90,35 +112,79 @@ Fired after a tool completes. **Cannot block** (exit code ignored for blocking).
Fired when a subagent is spawned via the `Agent` tool (named `Task` before
Claude Code 2.1.63; `Task` still works as an alias in permission rules and
`tools:` frontmatter, but the hook payload's `tool_name` is now `Agent`).
`tools:` frontmatter, but the hook payload's `tool_name` is now `Agent`). The
agent's name is in `agent_type` — there is no `agent_name` field.
```json
{
"agent_name": "game-designer",
"model": "sonnet",
"description": "Design the combat healing mechanic"
"agent_id": "agent-abc123",
"agent_type": "game-designer"
}
```
## SessionStart
Fired when a Claude Code session begins. **No stdin input** — the hook just runs and its stdout is shown to Claude as context.
Fired when a session starts, resumes, is cleared with `/clear`, or is compacted.
Stdin carries `source`: `startup`, `resume`, `clear`, `compact` or `fork`. Plain stdout is
added to Claude's context — this is the event that restores context after a
compaction.
## PreCompact
Fired before context window compression. **No stdin input** — the hook runs to save state before compression occurs.
Fired before context compaction. Stdin carries `trigger` (`manual` or `auto`).
**Its output does not reach Claude**: stdout goes to the debug log and
`systemMessage` is discarded. Exit 2 blocks the compaction.
## Stop
Fired when the Claude Code session ends. **No stdin input** — the hook runs for cleanup and logging.
Fired **every time Claude finishes a response**, not once when the session ends.
Stdin carries the common fields plus `stop_hook_active` and
`last_assistant_message`. Exit 2 keeps Claude working instead of stopping.
## Output: warnings someone sees
A hook that warns but must not block exits 0 — and **on exit 0, stderr reaches
no one**. Print a JSON object on stdout instead:
```json
{
"systemMessage": "Shown to the user",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Given to Claude next to the tool result"
}
}
```
- stdout must hold **only** that object.
- `hookEventName` is required inside `hookSpecificOutput`.
- **Leave out `permissionDecision`** unless you mean it: on PreToolUse, `"allow"`
skips the user's permission prompt.
CCGS hooks use `hook_warn` from `.claude/hooks/yaml-helper.sh`, which builds this
object and escapes the message without needing `jq`:
```bash
. .claude/hooks/yaml-helper.sh
hook_warn PostToolUse "Asset names must be lowercase: $FILE_PATH"
exit 0
```
## Exit Code Reference
| Exit Code | Meaning | Applicable Events |
|-----------|---------|-------------------|
| 0 | Allow / Success | All events |
| 2 | Block (stderr shown to Claude) | PreToolUse only |
| Other | Treated as error, tool proceeds | All events |
| Exit Code | Meaning |
|-----------|---------|
| 0 | Success. A JSON object on stdout is read as hook output; other stdout goes to the debug log, except on UserPromptSubmit, UserPromptExpansion, SessionStart and PostModelSwitch, where it is added to Claude's context. stderr goes to the debug log only. |
| 2 | Blocks on PreToolUse (Claude sees stderr as the reason), UserPromptSubmit (the prompt is erased), UserPromptExpansion, Stop, SubagentStop (the subagent keeps working) and PreCompact. On PostToolUse it shows stderr to Claude — the tool already ran. On SessionStart, SubagentStart, PostCompact and PostModelSwitch it shows stderr to the user only. On Notification it is ignored. The full per-event table is in the Claude Code hooks documentation. |
| Other | Non-blocking error; the action proceeds. |
**Output is capped at 10,000 characters (observed; the Claude Code hooks documentation does not state it).**
Plain stdout, and each of `additionalContext`, `systemMessage` and
`initialUserMessage`, is measured on its own. Past the cap Claude Code saves
the text to a file and passes a path
plus a 2,000-character preview, and nothing tells Claude to read the file. Keep
what Claude must see inside the cap — `session-start.sh` caps its checkpoint
preview for this reason.
## Notes