#!/usr/bin/env python3 """SessionStart hook: compose prompts/session-start/*.md into one additionalContext block. Fires on startup/resume/clear, and on 'compact' (matcher includes it) so the composed context survives a context-compaction pass, not just the first turn. Prompt files live under prompts//*.md; only the session-start event is implemented today (SessionEnd cannot inject context — ADR-028). Files are concatenated in filename sort order (e.g. 10-orchestration.md) with no added separator between them, so a single prompt file present alone reproduces the exact bytes it contributes. """ import glob import json import os import sys PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SESSION_START_DIR = os.path.join(PLUGIN_ROOT, "prompts", "session-start") # Deterministic injected-context budget, in lines. Below WARN_LINE_BUDGET, # inject normally. Between the two, still inject but warn on stderr. Above # REFUSE_LINE_BUDGET, refuse to inject anything and warn on stderr instead. WARN_LINE_BUDGET = 120 REFUSE_LINE_BUDGET = 240 def prompt_files(session_start_dir=None): if session_start_dir is None: session_start_dir = SESSION_START_DIR return sorted(glob.glob(os.path.join(session_start_dir, "*.md"))) def compose(paths): """Concatenate prompt file contents in order with no added separators.""" parts = [] for path in paths: with open(path) as f: parts.append(f.read()) return "".join(parts) def main(): paths = prompt_files() if not paths: return context = compose(paths) line_count = len(context.splitlines()) if line_count > REFUSE_LINE_BUDGET: print( f"os-context: session-start prompt budget exceeded " f"({line_count} lines > {REFUSE_LINE_BUDGET}) — refusing to inject.", file=sys.stderr, ) return if line_count > WARN_LINE_BUDGET: print( f"os-context: session-start prompt budget exceeded " f"({line_count} lines > {WARN_LINE_BUDGET}) — injecting anyway.", file=sys.stderr, ) print(json.dumps({ "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": context, } })) if __name__ == "__main__": sys.exit(main())