#!/usr/bin/env python3 """PreCompact hook — block Claude Code's built-in auto-compact. Only active in projects that have opted in (AirContext/ exists). Otherwise Claude's default auto-compact behaviour is preserved untouched. Manual `/compact` is always allowed; auto-triggered compaction is rejected so AirContext's rule-driven compactor is the only thing that mutates the chain. """ from __future__ import annotations import json import os import sys from pathlib import Path def main() -> int: raw = sys.stdin.read() or "{}" try: payload = json.loads(raw) except json.JSONDecodeError: payload = {} cwd = payload.get("cwd") or os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd() if not (Path(cwd) / "AirContext").exists(): return 0 # project hasn't opted in; let Claude do whatever it wants trigger = payload.get("trigger") or payload.get("compact_trigger") if trigger == "auto": print(json.dumps({ "decision": "block", "reason": ( "AirContext: auto-compact disabled by user policy. " "Custom rule-driven compaction handles this out-of-band." ) })) return 0 return 0 # manual /compact passes through if __name__ == "__main__": sys.exit(main())