Custom Hooks
Hook support varies by platform and by event:
SessionStarthook ships on Claude Code, Cursor, OpenCode, Gemini CLI, Qoder, CodeBuddy, Copilot, Droid (and Codex withcodex_hooks = truein~/.codex/config.toml). Kiro’s Agent Hooks are user-configured — Trellis does not install any out of the box.PreToolUse(sub-agent context injection) ships on Claude Code, Cursor, OpenCode, CodeBuddy, Droid. The other hook-capable platforms rely on a pull-based prelude inside each sub-agent instead.UserPromptSubmit(workflow-state nudge) ships on the same platforms asSessionStart.- Kilo, Antigravity, Windsurf have no hook primitive at all; behavior is delivered via workflow files + skills.
Hook types
| Hook | Trigger | Purpose |
|---|---|---|
SessionStart | A new session starts | Load context, initialize environment |
UserPromptSubmit | User submits a prompt | Nudge the AI toward the current task state |
PreToolUse | Before a tool invocation | Intercept, modify parameters, inject context |
PostToolUse | After a tool invocation | Log activity, trigger follow-up actions |
settings.json or hooks.json referencing Python scripts). OpenCode uses JS plugins (factory functions in .opencode/plugins/) with the same event semantics. The rest of the hook-capable platforms (Codex, Gemini, Qoder, Copilot) run a session-start.py only — no PreToolUse — and configure it via a platform-native config file.
settings.json configuration (Claude Code)
Configure hooks in .claude/settings.json:
- Each event type is an array of
{ matcher, hooks }blocks. matcher: pattern to match ("startup"matches session start,"Task"matches Task tool calls,"*"matches everything).hooks: array of commands that run when matched, in order.$CLAUDE_PROJECT_DIR: expanded by Claude Code to the project root.timeout: seconds; if exceeded, the hook is skipped.
Shipped hooks
session-start.py: context loading
Trigger: SessionStart.
What it does:
- Reads
.trellis/.developerfor developer identity. - Reads
.trellis/workflow.mdfor the workflow contract. - Reads
.trellis/workspace/{name}/index.mdfor session history. - Reads
git logfor recent commits. - Reads active tasks.
inject-workflow-state.py: workflow-state nudge
Trigger: UserPromptSubmit.
What it does: when a task is active, appends a short breadcrumb to the user message so the AI is reminded of the current task’s phase (planning / in_progress / finishing). Parsed from .trellis/workflow.md.
inject-subagent-context.py: spec injection engine
Trigger: PreToolUse, matching Task tool calls.
What it does (see §4.3 for details):
- Intercepts Task tool calls.
- Reads the JSONL matching the
subagent_type(implement.jsonl,check.jsonl,research.jsonl). - Reads all files referenced in the JSONL.
- Assembles the sub-agent prompt (specs + requirements + original instructions).
- Each sub-agent receives its full context at launch; there is no resume.
- Only
trellis-*sub-agents are hooked; custom sub-agents must opt in by editing this file or using their own injection.
Writing a custom hook
Hooks receive JSON input on stdin and emit JSON results on stdout. Input format (PreToolUse example):Example: an auto-test hook
.claude/hooks/auto-test.py:
settings.json: