Session Start to Stop
How OrchestKit manages the full session lifecycle -- from environment setup and context loading through metrics, compaction, and fire-and-forget cleanup.
The Session Lifecycle
A Claude Code session is bookended by startup and shutdown. OrchestKit hooks at every boundary to load context, track metrics, coordinate with other instances, and clean up when you leave -- all without blocking your workflow.
Setup (first run)
|
v
SessionStart -----> UserPromptSubmit (repeated) -----> Stop
| | |
| load context | inject memory, | fire-and-forget:
| check consent | detect patterns | 29 background hooks
| enrich PR status | track satisfaction |
| prefill guard | v
v v SessionEnd
|
| coordination cleanup
| metrics summary
| pattern sync push
v
(done)Setup Hooks (9 hooks)
Setup hooks run when the plugin is installed or during maintenance windows. They are registered under the Setup event in hooks.json.
| Hook | Purpose | Runs Once? |
|---|---|---|
setup/unified-dispatcher | Fire-and-forget launcher for background setup tasks | No |
setup/setup-check | Validate plugin installation integrity | Yes |
setup/first-run-setup | Create .claude/ directories, initialize config files | Yes |
setup/setup-maintenance | Periodic cleanup of stale files and caches | No |
setup/setup-repair | Self-heal corrupted configuration files | No |
setup/monorepo-detector | Detect monorepo structure and set workspace context | Yes |
Hooks marked "Runs Once" use the "once": true flag in hooks.json, so they execute only on the first invocation per session.
SessionStart Hooks (5 hooks)
When a new session begins, these hooks fire in order:
Unified Dispatcher (fire-and-forget)
Spawns a detached background process that runs startup tasks in parallel without blocking the session:
- pattern-sync-pull -- Pull learned patterns from previous sessions
- coordination-init -- Register this instance for multi-instance coordination
- decision-sync-pull -- Pull decision history
- dependency-version-check -- Check for outdated dependencies
Session Context Loader
Loads session state using Context Protocol 2.0. Reads from:
.claude/context/session/state.json-- Previous session state.claude/context/identity.json-- Project identity configuration.claude/context/knowledge/index.json-- Knowledge index.claude/context/session/compaction-manifest.json-- Key decisions and files touched from the last compacted session
If an AGENT_TYPE environment variable is set (e.g., from --from-pr or agent dispatch), the loader also reads agent-specific configuration from .claude/agents/{agent-type}.md.
// The compaction manifest bridges sessions across compactions
const manifest = JSON.parse(readFileSync(compactionManifest, 'utf-8'));
process.env.ORCHESTKIT_LAST_SESSION = manifest.sessionId;
process.env.ORCHESTKIT_LAST_DECISIONS = JSON.stringify(manifest.keyDecisions);Analytics Consent Check
Verifies that analytics tracking has user consent before enabling telemetry hooks.
PR Status Enricher
When a session is started with claude --from-pr 123, this hook enriches the context with PR status, review comments, and CI check results.
Prefill Guard
Scans skills for deprecated patterns (response prefilling, output_format parameter) that are unsupported on Opus 4.6+. If detected, it emits a warning with migration guidance:
Opus 4.6 deprecation: 3 skill(s) reference deprecated patterns.
Migration: use structured outputs instead of prefilling;
use output_config.format instead of output_format.SessionEnd Hooks (4 hooks)
When the session formally ends (after Stop hooks have dispatched), these hooks run synchronously:
| Hook | Purpose |
|---|---|
lifecycle/coordination-cleanup | Unregisters the instance from the coordination database, updates heartbeat status to "stopping", removes .instance_env |
lifecycle/session-metrics-summary | Reads session metrics (tool call counts, error counts) and logs a summary |
lifecycle/session-cleanup | Removes temporary files created during the session |
lifecycle/pattern-sync-push | Pushes newly learned patterns to persistent storage |
Coordination Cleanup in Detail
Multi-instance coordination uses a SQLite database at .claude/coordination/.claude.db and heartbeat files at .claude/coordination/heartbeats/{instance-id}.json. The cleanup hook:
- Loads the instance ID from
.claude/.instance_env - Updates the heartbeat file status to
"stopping" - Unregisters the instance from the coordination database (releases all locks)
- Deletes the
.instance_envfile
function updateHeartbeatStatus(projectDir: string, instanceId: string): void {
const heartbeatFile = `${heartbeatsDir}/${instanceId}.json`;
const content = JSON.parse(readFileSync(heartbeatFile, 'utf-8'));
content.status = 'stopping';
writeFileSync(heartbeatFile, JSON.stringify(content, null, 2));
}PreCompact Hook (1 hook)
When: The context window is about to be compacted (conversation history truncated to fit within token limits).
The lifecycle/pre-compact-saver hook preserves critical context that would otherwise be lost during compaction:
- Key decisions made during the session
- List of files touched
- Current task status and dependencies
- Open problems and blockers
This data is written to .claude/context/session/compaction-manifest.json and is loaded by the session context loader on the next session start.
The Fire-and-Forget Pattern
The most important architectural pattern in OrchestKit's lifecycle hooks is fire-and-forget. When the user types /exit, they should not wait 10+ seconds for 29 cleanup hooks to finish. Instead:
User types /exit
|
v
stop-fire-and-forget.mjs called (stdin: hook input)
|
v
Writes work payload to .claude/hooks/pending/stop-{uuid}.json
|
v
Spawns detached background-worker.mjs (child.unref())
|
v
Returns immediately: {"continue": true, "suppressOutput": true}
|
v
Session exits instantly (~50ms)
|
v
Background worker picks up the payload and runs 29 hooks in parallelThe 29 Stop Hooks
These hooks run in the background after the session has already exited:
Core Session (6):
auto-save-context-- Save conversation context for next sessionsession-patterns-- Extract and persist patterns from the sessionissue-work-summary-- Summarize work done on GitHub issuescalibration-persist-- Save calibration metricssession-profile-aggregator-- Aggregate session profile datasession-end-tracking-- Final session telemetry
Memory Sync (2):
graph-queue-sync-- Flush pending graph memory operationsworkflow-preference-learner-- Learn workflow preferences from session behavior
Instance Management (3):
multi-instance-cleanup-- Clean up multi-instance coordination statecleanup-instance-- Remove instance registrationtask-completion-check-- Verify all tasks completed or properly handed off
Analysis (3):
context-compressor-- Compress session context for storageauto-remember-continuity-- Automatically store important decisions for session continuitysecurity-scan-aggregator-- Aggregate security findings from the session
Skill Validation (12):
coverage-check,evidence-collector,coverage-threshold-gate,cross-instance-test-validator,di-pattern-enforcer,duplicate-code-detector,eval-metrics-collector,migration-validator,review-summary-generator,security-summary,test-pattern-validator,test-runner
Heavy Analysis (1):
full-test-suite-- Run comprehensive test validation
Background Worker Safeguards
The background worker (bin/background-worker.mjs) includes several safety mechanisms:
- 5-minute timeout -- Self-terminates via
setTimeoutto prevent hangs - Orphan cleanup -- Removes temp files in
.claude/hooks/pending/older than 10 minutes - Parallel execution -- All 29 hooks run via
Promise.allSettled(failures don't block others) - Debug logging -- Writes to
.claude/logs/hooks/background-worker.log
Multi-Instance Coordination
When multiple Claude Code sessions run on the same project (e.g., one per terminal tab), hooks coordinate through:
- Instance registration -- Each session registers with a unique instance ID at startup
- Heartbeat files -- Periodic heartbeat updates at
.claude/coordination/heartbeats/ - File locks -- The
multi-instance-lockPreToolUse hook writes locks atomically (temp file +renameSync) to prevent concurrent writes to the same file - Quality gates -- The
multi-instance-quality-gatechecks if another instance is already working on the same area
SEC-001 -- SQL Injection Prevention: Instance IDs are validated against /^[a-zA-Z0-9_\-.:]+$/ before any shell-exec SQLite operations. Invalid IDs are silently rejected.
SEC-003 -- Atomic File Writes: Lock files are written to a temp path (locks.json.{pid}.tmp) then renamed atomically, preventing TOCTOU race conditions.
Unified Dispatchers
OrchestKit uses 6 unified dispatchers across the lifecycle. Each is a single hooks.json entry that fans out to multiple internal hooks:
| Dispatcher | Event | Internal Hooks | Execution |
|---|---|---|---|
lifecycle/unified-dispatcher | SessionStart | 7 | Fire-and-forget |
posttool/unified-dispatcher | PostToolUse | 7 | Fire-and-forget |
stop-fire-and-forget.mjs | Stop | 29 | Detached background worker |
subagent-stop/unified-dispatcher | SubagentStop | varies | Fire-and-forget |
notification/unified-dispatcher | Notification | varies | Fire-and-forget |
setup/unified-dispatcher | Setup | varies | Fire-and-forget |
The fire-and-forget pattern is used exclusively for non-blocking operations: analytics, network I/O, and cleanup tasks that can fail silently without impacting the user's workflow.
Hook Architecture
How OrchestKit's 86-hook system works: bundles, dispatchers, execution modes, and the stop pipeline.
Security Gates and File Guards
How OrchestKit blocks dangerous commands, protects sensitive files, and auto-approves safe operations -- the defense-in-depth hooks that run before every tool use.
Last updated on