| |
| """Load project wiki context at session start.""" |
|
|
| import json |
| import os |
| import subprocess |
| import sys |
| from pathlib import Path |
|
|
|
|
| def project_root() -> Path: |
| env_root = os.environ.get("CLAUDE_PROJECT_DIR") |
| if env_root: |
| return Path(env_root) |
|
|
| try: |
| output = subprocess.check_output( |
| ["git", "rev-parse", "--show-toplevel"], |
| stderr=subprocess.DEVNULL, |
| text=True, |
| ).strip() |
| if output: |
| return Path(output) |
| except Exception: |
| pass |
|
|
| return Path.cwd() |
|
|
|
|
| VALID_POLICIES = {"require_approval", "auto", "open"} |
|
|
|
|
| def resolve_write_policy(root: Path) -> str: |
| """Resolve the active write policy. Fail closed: default to require_approval. |
| |
| Resolution order: |
| 1. A valid `write_policy` enum value. |
| 2. Legacy `require_human_approval` boolean (true -> require_approval, |
| false -> open). |
| 3. require_approval (fail-closed: missing/unreadable/invalid config). |
| """ |
| try: |
| config = json.loads((root / "wiki.config.json").read_text(encoding="utf-8")) |
| if isinstance(config, dict): |
| policy = config.get("write_policy") |
| if policy in VALID_POLICIES: |
| return policy |
| if "require_human_approval" in config: |
| return "require_approval" if config.get("require_human_approval") else "open" |
| except Exception: |
| pass |
|
|
| return "require_approval" |
|
|
|
|
| def write_policy_text(policy: str) -> str: |
| if policy == "open": |
| return ( |
| "Wiki write policy (wiki.config.json): human approval NOT required " |
| "(open). When you find durable knowledge, you may write the wiki page " |
| "directly without waiting for approval — still update wiki/index.md, " |
| 'append to wiki/log.md, and output a wiki evaluation marker (e.g. "Wiki ' |
| 'suggestion") so the Stop hook passes.' |
| ) |
| if policy == "auto": |
| return ( |
| "Wiki write policy (wiki.config.json): auto. NOTE: the deterministic " |
| "PreToolUse gate is Claude-only; Codex does not enforce it, so apply " |
| "these rules by self-discipline. You may write a wiki page directly " |
| "only when its resulting frontmatter confidence is `high`, and you must " |
| "then disclose the diff. If the resulting confidence would be `medium`, " |
| "`low`, or missing — or for any delete or wrong-location write — do not " |
| 'write; propose it with the "Wiki suggestion" format instead. Still ' |
| "update wiki/index.md, append to wiki/log.md, and emit a wiki evaluation " |
| "marker." |
| ) |
| return ( |
| "Wiki write policy (wiki.config.json): human approval REQUIRED. " |
| 'Propose updates with the "Wiki suggestion" format and wait for ' |
| "explicit approval before creating, updating, or deleting any wiki page." |
| ) |
|
|
|
|
| def emit_context(text: str) -> None: |
| print( |
| json.dumps( |
| { |
| "hookSpecificOutput": { |
| "hookEventName": "SessionStart", |
| "additionalContext": text, |
| } |
| } |
| ) |
| ) |
|
|
|
|
| def git_output(root: Path, args: list[str]) -> str: |
| try: |
| return subprocess.check_output( |
| ["git", "-C", str(root), *args], |
| stderr=subprocess.DEVNULL, |
| text=True, |
| ).rstrip() |
| except Exception: |
| return "" |
|
|
|
|
| def main() -> None: |
| mode = sys.argv[1] if len(sys.argv) > 1 else "" |
| root = project_root() |
|
|
| if mode == "wiki-index": |
| index_path = root / "wiki" / "index.md" |
| if not index_path.is_file(): |
| print("{}") |
| return |
| emit_context( |
| "Project wiki index:\n\n" |
| f"{index_path.read_text(encoding='utf-8')}\n\n" |
| "Codex wiki review rule: every substantial final response must " |
| "evaluate whether the conversation produced durable project " |
| "knowledge. If yes, include a visible `Wiki suggestion`. If no, " |
| "do not add a visible no-op marker; keep the transcript clean.\n\n" |
| f"{write_policy_text(resolve_write_policy(root))}" |
| ) |
| return |
|
|
| if mode == "git-context": |
| status = git_output(root, ["status", "-s"]) |
| latest_commit = git_output(root, ["log", "-1", "--format=%h %s (%cr)"]) |
| emit_context(f"Git status:\n{status}\n\nLatest commit:\n{latest_commit}\n") |
| return |
|
|
| print("{}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|