# Trigger

Declaring a `triggers` field in a skill's SKILL.md automates hook script and settings.json registration.

## When to Use

- When adding auto-activation conditions to a skill
- When converting existing manual hooks to declarative skill style
- Use with "trigger compile", "trigger list", "hook auto register"

## Schema

Add a `triggers` array to the SKILL.md frontmatter. **triggers must be placed after description:**

```yaml
---
name: cleanup
description: ...
triggers:
  - event: Stop                    # hook event
    action: suggest                # suggest | block | inject
    message: "Run /cleanup run"    # message to pass to Claude
  - event: PostToolUse
    matcher: Bash                  # tool name (regex supported)
    pattern: "git commit"          # pattern to match in command
    action: suggest
    message: "Commit complete. Check commit guidelines."
---
```

### Field Reference

| Field | Required | Description |
|-------|----------|-------------|
| `event` | Y | Hook event: `PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `SessionEnd`, `UserPromptSubmit` |
| `action` | Y | `suggest` (output marker, exit 0), `block` (block execution, exit 1), `inject` (systemMessage JSON, Stop only) |
| `matcher` | optional | Tool name filter. Used only with PreToolUse/PostToolUse. Omit to match all tools |
| `pattern` | optional | Matching pattern in command (regex). Used only with PostToolUse/PreToolUse |
| `message` | Y | Message to pass to Claude. May include skill/topic invocation instructions |
| `exit_code_filter` | optional | Filter by success (0) / failure (non-0) in PostToolUse. Omit to match all exit codes |

### action Types

| action | Behavior | exit code | Supported events |
|--------|----------|-----------|-----------------|
| `suggest` | Output `<skill-trigger>` marker. Claude decides whether to act | 0 | all |
| `block` | Block execution + output reason | 1 | PreToolUse |
| `inject` | Force inject as systemMessage JSON | JSON | Stop only |

## Compilation Procedure

```bash
/skill-kit trigger compile
```

### 1. Skill Scan

Collect `triggers` fields from all SKILL.md files:

```bash
for skill_dir in ~/.claude/skills/*/; do
  skill_file="$skill_dir/SKILL.md"
  [[ -f "$skill_file" ]] || continue

  # extract triggers from frontmatter
  triggers=$(sed -n '/^---$/,/^---$/p' "$skill_file" | grep -A 100 'triggers:')
  [[ -n "$triggers" ]] && echo "$skill_dir: $triggers"
done
```

### 2. Group by Event

Group triggers with the same event into a single dispatcher script:

```
PostToolUse triggers:
  - commit-check: pattern="git commit", action=suggest
  - code-reviewer: pattern="git commit", exit_code_filter=0, action=suggest

Stop triggers:
  - cleanup: action=inject, message="/cleanup run"
  - fix-plan: action=suggest, message="/ralph fix-plan cleanup"
```

### 3. Generate dispatcher Script

Create `~/.claude/hooks/trigger-{event}.sh` files:

```bash
#!/bin/bash
# AUTO-GENERATED by skill-kit trigger compiler
# DO NOT EDIT — regenerate with: /skill-kit trigger compile
# Generated: 2026-03-27T15:00:00

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
EXIT_CODE="${EXIT_CODE:-0}"

### cleanup (Stop, inject) ###
jq -n '{
  "decision": "block",
  "reason": "Run cleanup before session end",
  "systemMessage": "Please run /cleanup run. This is a cleanup task before session end."
}'
```

PostToolUse dispatcher example:

```bash
#!/bin/bash
# AUTO-GENERATED by skill-kit trigger compiler

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
EXIT_CODE="${EXIT_CODE:-0}"

### commit-check (PostToolUse, Bash, pattern: git commit) ###
if [[ "$TOOL_NAME" == "Bash" ]] && echo "$COMMAND" | grep -qE "git commit"; then
  echo "<skill-trigger name=\"commit-check\">"
  echo "Commit complete. Check commit guidelines."
  echo "Please call the Skill(\"commit-check\") tool."
  echo "</skill-trigger>"
fi

### code-reviewer (PostToolUse, Bash, pattern: git commit, exit_code: 0) ###
if [[ "$TOOL_NAME" == "Bash" ]] && echo "$COMMAND" | grep -qE "git commit" && [[ "$EXIT_CODE" == "0" ]]; then
  echo "<skill-trigger name=\"code-reviewer\">"
  echo "Commit succeeded. Run code review."
  echo "</skill-trigger>"
fi
```

### 4. Register in settings.json

Preserve existing hooks while adding/updating only the trigger-dispatcher:

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [{
          "type": "command",
          "command": "~/.claude/hooks/trigger-Stop.sh",
          "timeout": 10
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "~/.claude/hooks/trigger-PostToolUse.sh",
          "timeout": 10
        }]
      }
    ]
  }
}
```

**Existing Hook Preservation Rules:**
- Only overwrite hooks with the `trigger-` prefix
- Never touch other hooks (block_dangerous.sh, etc.)

### 5. Verify

```bash
# Check generated script syntax
bash -n ~/.claude/hooks/trigger-*.sh

# Check settings.json parsing
jq . ~/.claude/settings.json > /dev/null

# Print trigger list
/skill-kit trigger list
```

## Sub-commands

| Command | Behavior |
|---------|----------|
| `compile` | Scan all skills → generate dispatcher → register in settings.json |
| `list` | Print currently registered trigger list |
| `remove <skill>` | Remove a specific skill's triggers from the dispatcher |
| `dry-run` | Preview only the scripts that would be generated (no files created) |

## Example: Adding a Trigger to the cleanup Skill

**Before (manual):**
1. Add trigger keywords to cleanup/SKILL.md description
2. Write a separate script in ~/.claude/hooks/
3. Manually register in ~/.claude/settings.json

**After (declarative):**
1. Add triggers to cleanup/SKILL.md:
```yaml
triggers:
  - event: Stop
    action: inject
    message: "Please run /cleanup run."
```
2. Run `/skill-kit trigger compile` → done

## Notes

- `trigger-*.sh` files are auto-generated. Do not edit directly (compile will overwrite them)
- `inject` action can only be used with the Stop event (systemMessage JSON)
- Does not conflict with existing manual hooks (block_dangerous.sh, etc.)
- Always recommended to run `dry-run` before compile
- `inject` action fires **once per session only** (to prevent infinite loops). Managed via `~/.claude/data/trigger-stop-{skill}` flag files
