Explanatory Output Style — Educational Insights Hook
Educational Insights Hook
SessionStart hook that injects educational context about implementation choices and codebase patterns. Recreates the deprecated Explanatory output style as a plugin, enriching every response with structured ★ Insight blocks.
💡 Educational🎓 Insights🔧 SessionStart Hook📖 Implementation Choices
📚 What is this & why does it exist?
Explanatory Output Style is a SessionStart hook that automatically injects system-level instructions telling Claude to accompany every code response with educational ★ Insight blocks. Each block contains 2–3 points explaining why a particular implementation choice was made, what patterns are being used, and what trade-offs exist. This recreates the deprecated built-in “Explanatory” output style as a standalone, customizable plugin.
💡 Real-world analogy
Think of a cooking show where the chef doesn’t just follow the recipe — they pause to explain why they sear the meat before braising, why they use kosher salt instead of table salt, and what would happen if you skipped the resting step. The Explanatory Output Style plugin turns Claude into that teaching chef: it still writes the code, but now every response includes brief “behind-the-scenes” annotations so you learn the craft while you ship the product.
Architecture
The plugin uses a single SessionStart hook to inject educational instructions into the system prompt at the beginning of each session. The shell script reads a markdown instruction file and returns it as additional context that shapes Claude’s output behavior for the entire session.
flowchart LR
subgraph Trigger["Session Lifecycle"]
A["User starts session"] --> B["SessionStart event fires"]
end
subgraph Hook["Hook Execution"]
B --> C["hooks-handlers/session-start.sh"]
C --> D["Read instruction template"]
D --> E["Inject Insight format rules"]
end
subgraph Output["Claude Responds"]
E --> F["Code + Insight blocks"]
F --> G["2-3 educational points per block"]
F --> H["Implementation rationale"]
F --> I["Pattern identification"]
end
Insight Block Format
Every code response from Claude is enriched with structured insight blocks that follow a consistent format:
★ Insight — Pattern Name
Each insight block opens with a star icon and a descriptive heading identifying the pattern or concept being explained.
- Point 1: Why this approach was chosen over alternatives
- Point 2: What underlying pattern or principle is at work
- Point 3: Trade-offs and when you might choose differently
Insight Placement Rules
Insights appear after the relevant code block, never interrupting the flow of implementation.
- Placed immediately after the code they annotate
- Limited to 2–3 points to avoid information overload
- Focus on non-obvious decisions, not boilerplate
★ Insight — Builder Pattern
• We use a builder here instead of a constructor with 7 parameters because
it makes the call site self-documenting and allows optional fields.
• The builder validates required fields in build() rather than at each
setter call — this is the "fail-fast at assembly" pattern.
Hook Implementation
SessionStart Hook
The hook fires once at the beginning of each Claude Code session. It executes a shell script that outputs additional system instructions.
| Property | Value |
|---|---|
| Event | SessionStart |
| Type | command |
| Handler | hooks-handlers/session-start.sh |
| Output | Appended to system prompt as additional instructions |
| Frequency | Once per session |
#!/bin/bash
# hooks-handlers/session-start.sh
# Reads the explanatory instruction template and outputs it
# so Claude includes ★ Insight blocks in responses
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cat "${SCRIPT_DIR}/../instructions/explanatory-prompt.md"
Data Flow
sequenceDiagram
participant User as Developer
participant CC as Claude Code CLI
participant Hook as session-start.sh
participant Template as explanatory-prompt.md
participant Claude as Claude LLM
User->>CC: Start new session
CC->>Hook: Fire SessionStart event
Hook->>Template: Read instruction file
Template-->>Hook: Insight format rules
Hook-->>CC: Return injected instructions
CC->>Claude: System prompt + insight instructions
User->>Claude: Ask a coding question
Claude-->>User: Code response + Insight block
Note over Claude,User: Each insight has 2-3 educational points
User->>Claude: Follow-up question
Claude-->>User: Updated code + new Insight block
Key Components
| Component | File | Role |
|---|---|---|
session-start.sh | hooks-handlers/session-start.sh | Shell hook that fires on SessionStart and injects instructions |
explanatory-prompt.md | instructions/explanatory-prompt.md | Markdown template defining ★ Insight format and rules |
plugin.json | .claude-plugin/plugin.json | Plugin manifest declaring the SessionStart hook |
README.md | README.md | Plugin documentation and usage guide |
Interactions
| Module | Interface | Data Exchanged |
|---|---|---|
| Claude Code CLI | Hook registration | SessionStart event triggers shell script execution |
| Claude LLM | System prompt injection | Insight format rules appended to system instructions |
| Developer | Enriched responses | Code + ★ Insight blocks with implementation rationale |
| Other plugins | Compatible | Does not conflict with other SessionStart hooks |
Configuration Reference
| Parameter | Default | Description |
|---|---|---|
hooks.SessionStart[0].type | command | Execution type — shell command |
hooks.SessionStart[0].command | hooks-handlers/session-start.sh | Path to the shell script handler |
| Insight points per block | 2–3 | Number of educational points per ★ Insight |
| Insight scope | Non-obvious decisions | Only annotate choices that wouldn’t be apparent to a mid-level developer |
| Insight placement | After code block | Insights appear after the code they describe |
Directory Map
Source tree for Explanatory Output Style
explanatory-output-style/
├── .claude-plugin/plugin.json ← Role: Plugin manifest
├── README.md ← Role: Plugin documentation
├── hooks-handlers/
│ └── session-start.sh ← Role: SessionStart hook handler
└── instructions/
└── explanatory-prompt.md ← Role: ★ Insight format template
Usage Examples
Example Enriched Response
When a developer asks Claude to implement a caching layer, the response includes both the code and educational annotations:
class LRUCache<K, V> {
private map = new Map<K, V>();
constructor(private maxSize: number) {}
get(key: K): V | undefined {
const val = this.map.get(key);
if (val !== undefined) {
this.map.delete(key);
this.map.set(key, val);
}
return val;
}
}
★ Insight — Map Ordering for LRU
• JavaScript Maps maintain insertion order, so delete-then-set moves an entry to the “newest” position — giving O(1) LRU behavior without a separate doubly-linked list.
• The trade-off: Map iteration order is guaranteed in ES2015+, but this trick won’t work with plain objects where key order is implementation-dependent.