Back to Skills

hook-intercept-block

verified

This skill should be used when implementing slash commands that execute without Claude API calls. Use when: adding a new /bumper-* command, understanding why commands return "block" responses, debugging UserPromptSubmit hooks, or learning the pattern for instant command execution. Keywords: UserPromptSubmit, block decision, hook response, slash command implementation.

View on GitHub

Marketplace

claude-bumper-lanes

kylesnowschwartz/claude-bumper-lanes

Plugin

claude-bumper-lanes

Repository

kylesnowschwartz/claude-bumper-lanes
26stars

bumper-lanes-plugin/skills/hook-intercept-block/SKILL.md

Last Verified

January 21, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/kylesnowschwartz/claude-bumper-lanes/blob/main/bumper-lanes-plugin/skills/hook-intercept-block/SKILL.md -a claude-code --skill hook-intercept-block

Installation paths:

Claude
.claude/skills/hook-intercept-block/
Powered by add-skill CLI

Instructions

# Hook-Intercept-Block Pattern

Pattern for implementing slash commands that execute entirely in the hook handler,
bypassing the Claude API call entirely.

## Why Use This Pattern

- **No API cost**: Commands execute in Go, no Claude API call
- **Faster**: Direct execution vs markdown parsing + API round trip
- **Deterministic**: No model variance - same input, same output

## How It Works

```
User types: /bumper-reset
    ↓
UserPromptSubmit hook fires
    ↓
prompt_handler.go matches regex: ^/(?:claude-bumper-lanes:)?bumper-reset\s*$
    ↓
handleReset() executes Go logic
    ↓
Returns JSON to stdout: {"decision":"block","reason":"Baseline reset. Score: 0/400"}
    ↓
Claude Code shows "reason" to user, skips API call
```

## The Confusing Naming

Claude Code's hook response API uses counterintuitive terminology:

| Response | What It Actually Means |
|----------|----------------------|
| `decision: "block"` | "I handled this, don't call Claude API" (NOT "blocked/rejected") |
| `decision: "continue"` | "Let it through to Claude API" |
| `reason: "..."` | Message shown to user (only with "block") |

**Key insight**: `block` = "handled and done", not "rejected". The command succeeded.

## Implementation Components

1. **Hook config** (`hooks.json`): Routes UserPromptSubmit to handler binary
2. **Handler** (`internal/hooks/prompt_handler.go`): Regex matching + dispatch
3. **Command stubs** (`commands/*.md`): MUST exist for `/help` discovery (body ignored)

## Adding a New Command

### Step 1: Add Regex Pattern

In `prompt_handler.go`:

```go
var newCmdPattern = regexp.MustCompile(`^/(?:claude-bumper-lanes:)?bumper-foo\s*(.*)$`)
```

The `(?:claude-bumper-lanes:)?` makes the plugin namespace optional.

### Step 2: Add Dispatch

In `HandlePrompt()`:

```go
if m := newCmdPattern.FindStringSubmatch(prompt); m != nil {
    return handleFoo(sessionID, strings.TrimSpace(m[1]))
}
```

### Step 3: Implement Handler

Use the helper functions for DRY session management:

```go
fun

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
4117 chars