How the SessionEnd Hook Preserves State and Extracts Patterns in Everything-Claude-Code
The SessionEnd hook serializes the current conversation memory to JSON and runs configured regex patterns against the transcript before persisting both to disk.
The SessionEnd hook is a critical component of the WorldFlowAI/everything-claude-code plugin architecture. It executes automatically when a Claude chat session terminates, ensuring no conversational context is lost and enabling automated pattern extraction from the dialogue. This article examines the implementation details found in scripts/hooks/session-end.js and its supporting files.
State Preservation in the SessionEnd Hook
The primary responsibility of the SessionEnd hook is state persistence. When invoked, it receives the in-memory memory object from the Claude plugin runtime.
The Serialization Process
The hook performs three discrete operations:
- Retrieve the current conversation state from the Claude plugin API
- Serialize the memory object to JSON format
- Write the serialized data atomically to
session-state.jsonin the plugin's data directory
// Conceptual flow based on session-end.js implementation
const memory = await claude.getMemory(); // Fetch live state
const serialized = JSON.stringify(memory, null, 2); // Pretty-printed JSON
await writeFileAtomic('session-state.json', serialized);
Atomic writes prevent state corruption if the process terminates unexpectedly during the write operation. The hook also records file size and timestamp to a debug log for troubleshooting persistence issues.
State Restoration Counterpart
The SessionStart hook (scripts/hooks/session-start.js) performs the inverse operation on subsequent sessions. It locates session-state.json, parses the JSON, and injects the restored memory back into the Claude runtime—allowing the assistant to resume with full conversational context intact.
Pattern Extraction Architecture
Before persisting state, the SessionEnd hook executes its second core function: pattern extraction from the conversation transcript.
Configuration-Driven Regex Matching
Patterns are defined in hooks/hooks.json as an array of regex strings under the session-end.patterns key:
{
"session-end": {
"patterns": [
"(?<task>TODO):\\s*(?<detail>.+)",
"(?<url>https?://[\\w./-]+)",
"(?<decision>DECISION):\\s*(?<rationale>.+)"
]
}
}
Each pattern may include named capture groups (?<name>) that the hook uses to structure extracted data.
Extraction andStorage Pipeline
The hook processes patterns through the following pipeline:
// Simplified representation of the extraction logic
const transcript = memory.getTranscript(); // Full conversation text
const config = loadConfig('hooks/hooks.json');
const results = {};
for (const pattern of config['session-end'].patterns) {
const regex = new RegExp(pattern, 'gmi');
const matches = [...transcript.matchAll(regex)];
matches.forEach(match => {
const groups = match.groups || { default: match[0] };
Object.entries(groups).forEach(([key, value]) => {
results[key] = results[key] || [];
results[key].push(value);
});
});
}
await writeFileAtomic('extracted-patterns.json', JSON.stringify(results, null, 2));
Extracted patterns are written to extracted-patterns.json with a structure mirroring the named capture groups:
{
"task": [
"Refactor the session handling logic",
"Add unit tests for pattern extraction"
],
"url": [
"https://github.com/WorldFlowAI/everything-claude-code"
],
"decision": [
"Use atomic writes for state persistence"
]
}
Hook Execution Flow
The complete SessionEnd hook lifecycle can be visualized as:
Claude session termination
↓
┌─────────────────┐
│ SessionEnd Hook │
│ (session-end.js) │
└─────────────────┘
↓
┌────────────┐
│ Get memory │◄────────────────────┐
│ object │ │
└────────────┘ │
↓ │
┌────────────┐ │
│ Extract │ │
│ patterns │ │
│ from config│ │
└────────────┘ │
↓ │
┌────────────┐ ┌─────────────┐ │
│Write │────►│extracted- │ │
│patterns │ │patterns.json│ │
└────────────┘ └─────────────┘ │
│
┌────────────┐ │
│Serialize │ │
│memory │ │
└────────────┘ │
↓ │
┌────────────┐ ┌─────────────┐ │
│Write state │────►│session-state│──┘
│atomically │ │.json │
└────────────┘ └─────────────┘
↓
Log summary (patterns found, bytes written)
↓
Claude shutdown continues
Manual Invocation for Debugging
Developers can trigger the SessionEnd hook manually to verify state persistence and pattern extraction without closing their Claude session:
node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-end.js" --force
The --force flag bypasses the normal session-termination check, allowing inspection of output files while the session remains active.
Test Coverage
The test suite in tests/hooks/hooks.test.js validates both state preservation and pattern extraction behaviors. Key test scenarios include:
- State round-trip: Verifying that saved state loads identically through
SessionStart - Pattern matching accuracy: Confirming regexes with named groups populate correct output structure
- Atomic write integrity: Simulating crashes mid-write and confirming no corruption occurs
- Empty transcript handling: Ensuring graceful behavior when no patterns match
Summary
- State preservation: The
SessionEndhook inscripts/hooks/session-end.jsserializes the conversationmemoryobject tosession-state.jsonusing atomic writes for crash safety - Pattern extraction: Configured regex patterns from
hooks/hooks.jsonare executed against the full transcript, with named capture groups structuring output toextracted-patterns.json - Complementary hooks:
SessionStartrestores persisted state, creating seamless session-to-session continuity - Observable behavior: Debug logging reports pattern match counts and serialized state size for operational visibility
Frequently Asked Questions
Where does the SessionEnd hook store its output files?
The hook writes to two JSON files in the plugin's data directory: session-state.json containing the serialized memory object, and extracted-patterns.json containing regex match results. These paths are resolved relative to the CLAUDE_PLUGIN_ROOT environment variable.
How do I add custom patterns for the SessionEnd hook to extract?
Edit hooks/hooks.json and add regex strings to the session-end.patterns array. Use named capture groups (?<name>) to control the structure of extracted data in extracted-patterns.json. The patterns are evaluated with the gmi flags (global, multiline, case-insensitive).
What happens if the SessionEnd hook crashes during execution?
Atomic write operations ensure that neither session-state.json nor extracted-patterns.json can be left in a partially-written corrupt state. If the hook fails before completion, the previous valid state files remain untouched, and the next session starts from that last-known-good checkpoint.
Can other hooks consume the patterns extracted by SessionEnd?
Yes. The extracted-patterns.json output serves as input for downstream hooks such as evaluate-session. These hooks can analyze extracted patterns to generate suggestions, trigger automation, or feed analytics pipelines without re-parsing the full conversation transcript.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →