mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 01:37:05 +00:00
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
195 lines
6.3 KiB
Markdown
195 lines
6.3 KiB
Markdown
# Hook Input/Output Schemas
|
|
|
|
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. 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
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Bash",
|
|
"tool_input": {
|
|
"command": "git commit -m 'feat: add player health system'",
|
|
"description": "Commit changes with message",
|
|
"timeout": 120000
|
|
}
|
|
}
|
|
```
|
|
|
|
The PowerShell tool sends the same shape with `"tool_name": "PowerShell"`, so a
|
|
matcher of `Bash|PowerShell` covers both.
|
|
|
|
### PreToolUse: Write
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Write",
|
|
"tool_input": {
|
|
"file_path": "src/gameplay/health.gd",
|
|
"content": "extends Node\n..."
|
|
}
|
|
}
|
|
```
|
|
|
|
### PreToolUse: Edit
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Edit",
|
|
"tool_input": {
|
|
"file_path": "src/gameplay/health.gd",
|
|
"old_string": "var health = 100",
|
|
"new_string": "var health: int = 100"
|
|
}
|
|
}
|
|
```
|
|
|
|
### PreToolUse: Read
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Read",
|
|
"tool_input": {
|
|
"file_path": "src/gameplay/health.gd"
|
|
}
|
|
}
|
|
```
|
|
|
|
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** — 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
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Write",
|
|
"tool_input": {
|
|
"file_path": "assets/data/enemy_stats.json",
|
|
"content": "{\"goblin\": {\"health\": 50}}"
|
|
},
|
|
"tool_response": {
|
|
"filePath": "assets/data/enemy_stats.json",
|
|
"type": "create"
|
|
}
|
|
}
|
|
```
|
|
|
|
### PostToolUse: Edit
|
|
|
|
```json
|
|
{
|
|
"tool_name": "Edit",
|
|
"tool_input": {
|
|
"file_path": "assets/data/enemy_stats.json",
|
|
"old_string": "\"health\": 50",
|
|
"new_string": "\"health\": 75"
|
|
},
|
|
"tool_response": { "filePath": "assets/data/enemy_stats.json" }
|
|
}
|
|
```
|
|
|
|
## SubagentStart
|
|
|
|
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`). The
|
|
agent's name is in `agent_type` — there is no `agent_name` field.
|
|
|
|
```json
|
|
{
|
|
"agent_id": "agent-abc123",
|
|
"agent_type": "game-designer"
|
|
}
|
|
```
|
|
|
|
## SessionStart
|
|
|
|
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 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 **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 |
|
|
|-----------|---------|
|
|
| 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
|
|
|
|
- Hooks receive JSON on **stdin** (pipe). Use `INPUT=$(cat)` to capture.
|
|
- Parse with `jq` if available, fall back to `grep` for cross-platform compatibility.
|
|
- On Windows, `grep -P` (Perl regex) is often unavailable. Use `grep -E` (POSIX extended) instead.
|
|
- Path separators may be `\` on Windows. Normalize with `sed 's|\\|/|g'` when comparing paths.
|