From c423564c0094473bfd1478eb36a6cda93a79eaed Mon Sep 17 00:00:00 2001 From: Pedro Nauck Date: Wed, 27 May 2026 11:52:31 -0300 Subject: [PATCH 1/4] refactor: memory optimization --- .agents/skills/autoreview/SKILL.md | 191 +++ .agents/skills/autoreview/scripts/autoreview | 1176 +++++++++++++++++ .../autoreview/scripts/test-review-harness | 176 +++ .../analysis/collect_token_baseline.py | 419 ++++++ .../task-007-settings-memory-default.png | Bin 0 -> 145484 bytes .../analysis/validate_task010_token_cost.py | 258 ++++ .github/workflows/release.yml | 4 + .goreleaser.release-footer.md.tmpl | 1 + .goreleaser.release-header.md.tmpl | 5 +- internal/api/contract/memory.go | 15 +- internal/api/core/memory_services_test.go | 21 +- internal/config/config.go | 21 +- internal/config/memory_v2_config_test.go | 78 +- internal/config/release_config_test.go | 3 + internal/config/tool_surface.go | 2 +- internal/daemon/memory_runtime.go | 24 +- internal/daemon/memory_runtime_test.go | 165 +++ internal/daemon/native_tools_test.go | 10 +- internal/daemon/prompt_skills.go | 136 +- internal/daemon/prompt_skills_test.go | 229 +++- internal/memory/extractor/events.go | 2 +- internal/memory/extractor/runtime.go | 349 ++++- internal/memory/extractor/runtime_test.go | 185 +++ internal/network/delivery.go | 81 +- internal/network/delivery_test.go | 198 +++ internal/network/perf_bench_test.go | 85 +- internal/session/spawn.go | 3 + internal/skills/catalog.go | 26 +- openapi/agh.json | 12 + .../core/configuration/config-toml.mdx | 28 +- .../core/getting-started/installation.mdx | 13 +- .../content/runtime/core/memory/system.mdx | 22 +- .../content/runtime/core/skills/index.mdx | 5 + .../__tests__/public-install-contract.test.ts | 225 +++- packages/site/public/install.sh | 65 +- skills-lock.json | 6 + skills/agh/references/memory.md | 10 + skills/agh/references/network.md | 2 + skills/agh/references/tools-and-skills.md | 2 + web/src/generated/agh-openapi.d.ts | 3 + web/src/routes/_app/settings/memory.tsx | 2 +- .../_app/settings/stories/-memory.stories.tsx | 9 +- .../session/lib/session-history-adapter.ts | 8 +- .../session/lib/session-thread-repository.ts | 6 +- 44 files changed, 3976 insertions(+), 305 deletions(-) create mode 100644 .agents/skills/autoreview/SKILL.md create mode 100755 .agents/skills/autoreview/scripts/autoreview create mode 100755 .agents/skills/autoreview/scripts/test-review-harness create mode 100644 .compozy/tasks/tokens-perf/analysis/collect_token_baseline.py create mode 100644 .compozy/tasks/tokens-perf/analysis/screenshots/task-007-settings-memory-default.png create mode 100644 .compozy/tasks/tokens-perf/analysis/validate_task010_token_cost.py diff --git a/.agents/skills/autoreview/SKILL.md b/.agents/skills/autoreview/SKILL.md new file mode 100644 index 000000000..78fd68864 --- /dev/null +++ b/.agents/skills/autoreview/SKILL.md @@ -0,0 +1,191 @@ +--- +name: autoreview +description: "Auto Review closeout. Codex review is the default when no engine is set and is the recommended reviewer." +--- + +# Auto Review + +Run the bundled structured review helper as a closeout check. This is code review, not Guardian `auto_review` approval routing. + +Codex review is the default when no engine is set. It usually delivers the best review results and should remain the normal final closeout engine. + +Use when: + +- user asks for Codex review / Claude review / autoreview / second-model review +- after non-trivial code edits, before final/commit/ship +- reviewing a local branch or PR branch after fixes + +## Contract + +- Treat review output as advisory. Never blindly apply it. +- Verify every finding by reading the real code path and adjacent files. +- Read dependency docs/source/types when the finding depends on external behavior. +- Reject unrealistic edge cases, speculative risks, broad rewrites, and fixes that over-complicate the codebase. +- Prefer small fixes at the right ownership boundary; no refactor unless it clearly improves the bug class. +- Keep going until structured review returns no accepted/actionable findings. +- If a review-triggered fix changes code, rerun focused tests and rerun the structured review helper. +- For security-audit suppression changes, verify accepted findings remain auditable: suppressed findings stay in structured output, active output keeps an unsuppressible suppression notice, and aggregate findings cannot hide unrelated active risk. +- Never switch or override the requested review engine/model. If the review hits model capacity, retry the same command a few times with the same engine/model. +- Be patient with large bundles. Structured review can take up to 30 minutes while the model call is active, especially with Codex tools or web search. +- Treat heartbeat lines like `review still running: ... elapsed=... pid=...` as healthy progress, not a hang. Let the helper continue while heartbeats are advancing. Pass `--stream-engine-output` when live engine text is useful; Codex and Claude filter tool/file chatter, other engines pass raw output through. +- Do not kill a review just because it has been quiet for 2-5 minutes, or because it is still running under the 30-minute window. Inspect the process only after missing multiple expected heartbeats, after 30 minutes, or after an obviously failed subprocess; prefer letting the same helper command finish. +- Tools are useful in review mode. The helper allows read-only inspection tools and web search by default so reviewers can check dependency contracts, upstream docs, and current behavior. +- Security perspective is always included, but it should not cripple legitimate functionality. Report security findings only when the change creates a concrete, actionable risk or removes an important safety check. +- For regression provenance, keep roles separate: blamed code author, blamed PR author, PR merger/committer, current PR author, and PR/date. If no blamed PR is traceable, use the blamed commit as the provenance: commit SHA, date, and author username. Do not guess a merger or frame missing PR metadata as a separate finding. +- If the blamed PR was merged by `clawsweeper[bot]` or another automation, identify the human trigger when practical. Check timeline/comments first; if rate-limited, use gitcrawl/cache or public PR HTML. Look for maintainer commands such as `@clawsweeper automerge`, `/landpr`, or labels/status comments that armed automerge. Report `automerge triggered by @login`; if not found, say trigger unknown. +- Do not invoke built-in `codex review`, nested reviewers, or reviewer panels from inside the review. The helper builds one bundle, calls one selected engine, validates one structured result, and stops. +- Stop as soon as the helper exits 0 with no accepted/actionable findings. Do not run an extra review just to get a nicer "clean" line, a second opinion, or clearer closeout wording. +- Treat the helper's successful exit plus absence of actionable findings as the clean review result, even if the underlying Codex CLI output is terse. +- Multi-reviewer panels are opt-in only. Use them when explicitly requested or when risk justifies the extra spend; the main agent still verifies every accepted finding before fixing. +- If rejecting a finding as intentional/not worth fixing, add a brief inline code comment only when it explains a real invariant or ownership decision that future reviewers should know. +- If `gh`/Gitcrawl reports `database disk image is malformed`, run `gitcrawl doctor --json` once to let the portable cache repair before retrying review; do not bypass the shim unless repair fails and freshness requires live GitHub. +- If Gitcrawl reports a portable manifest mismatch, source/runtime DB health error, or stale portable-store checkout, run `gitcrawl doctor --json` and inspect `source_db_health`, `runtime_db_health`, and `portable_store_status` before falling back to live GitHub. +- Do not push just to review. Push only when the user requested push/ship/PR update. + +## Pick Target + +Dirty local work: + +```bash + --mode local +``` + +Use this only when the patch is actually unstaged/staged/untracked in the +current checkout. For committed, pushed, or PR work, point the helper at the commit +or branch diff instead; do not force `--mode local` / `--uncommitted` just +because the helper docs mention dirty work first. A clean local review +only proves there is no local patch. + +Branch/PR work: + +```bash + --mode branch --base origin/main +``` + +Optional review context is first-class: + +```bash + --mode branch --base origin/main --prompt-file /tmp/review-notes.md --dataset /tmp/evidence.json +``` + +If an open PR exists, use its actual base: + +```bash +base=$(gh pr view --json baseRefName --jq .baseRefName) + --mode branch --base "origin/$base" +``` + +Committed single change: + +```bash + --mode commit --commit HEAD +``` + +or with the helper: + +```bash +/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode commit --commit HEAD +``` + +Use commit review for already-landed or already-pushed work on `main`. Reviewing +clean `main` against `origin/main` is usually an empty diff after push. For a +small stack, review each commit explicitly or review the branch before merging +with `--base`. + +## Parallel Closeout + +Format first if formatting can change line locations. Then it is OK to run tests and review in parallel: + +```bash +scripts/autoreview --parallel-tests "" +``` + +Tradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain. Once that rerun exits cleanly, stop; do not spend another long review cycle on redundant confirmation. + +## Review Panels + +Run multiple reviewers against one frozen bundle: + +```bash + --reviewers codex,claude +``` + +`--panel` is shorthand for Codex plus Claude unless `--engine` changes the first reviewer: + +```bash + --panel +``` + +Set reviewer models and thinking/effort explicitly: + +```bash + --reviewers codex,claude --model codex=gpt-5.1 --thinking codex=high --model claude=sonnet --thinking claude=max +``` + +Inline syntax is also supported: + +```bash + --reviewers codex:gpt-5.1:high,claude:sonnet:max +``` + +Codex maps thinking to `model_reasoning_effort` and accepts `low`, `medium`, +`high`, or `xhigh`. Claude maps thinking to `--effort` and also accepts `max`. +Engines without a real thinking knob reject `--thinking`. + +## Context Efficiency + +Run the helper directly so target selection, engine choice, structured validation, and exit status all stay in one path. If output is noisy, summarize the completed helper output after it returns; do not ask another agent or reviewer to rerun the review. + +## Helper + +OpenClaw repo-local helper: + +```bash +.agents/skills/autoreview/scripts/autoreview --help +``` + +`agent-scripts` checkout helper: + +```bash +skills/autoreview/scripts/autoreview --help +``` + +Global helper from `agent-scripts`: + +```bash +~/.codex/skills/agent-scripts/autoreview/scripts/autoreview --help +``` + +If installed from `agent-scripts`, path is: + +```bash +/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --help +``` + +The helper: + +- chooses dirty local changes first +- otherwise uses current PR base if `gh pr view` works +- otherwise uses `origin/main` for non-main branches +- supports `--engine codex`, `claude`, `droid`, and `copilot`; default is `AUTOREVIEW_ENGINE` or `codex`; Codex should remain the default when nothing is set +- use `--mode commit --commit ` for already-committed work, especially clean `main` after landing +- should be left in `--mode auto` or forced to `--mode branch` for PR/branch work; do not force `--mode local` after committing +- writes only to stdout unless `--output`, `--json-output`, or live streamed engine stderr is set +- supports `--dry-run`, `--parallel-tests`, `--prompt`, `--prompt-file`, `--dataset`, `--no-tools`, `--no-web-search`, and commit refs +- supports `--stream-engine-output` or `AUTOREVIEW_STREAM_ENGINE_OUTPUT=1` for live engine text while preserving structured validation; Codex and Claude hide tool/file event details, emit compact activity summaries, and report usage at turn completion +- supports opt-in review panels with `--panel` / `--reviewers`, plus per-engine `--model` and `--thinking` +- allows read-only tools and web search by default where the selected CLI supports them; forbids nested review in the prompt; Codex is run through `codex exec` with read-only sandbox and structured output +- prints `review still running: elapsed=s pid=` to stderr at long-running intervals while waiting for the selected review engine, unless streamed output or compact Codex activity has been visible recently +- prints `autoreview clean: no accepted/actionable findings reported` when the selected review command exits 0 +- exits nonzero when accepted/actionable findings are present + +## Final Report + +Include: + +- review command used +- tests/proof run +- findings accepted/rejected, briefly why +- the clean review result from the final helper/review run, or why a remaining finding was consciously rejected + +Do not run another review solely to improve the final report wording. If the final helper run exited 0 and produced no accepted/actionable findings, report that exact run as clean. diff --git a/.agents/skills/autoreview/scripts/autoreview b/.agents/skills/autoreview/scripts/autoreview new file mode 100755 index 000000000..653f75c45 --- /dev/null +++ b/.agents/skills/autoreview/scripts/autoreview @@ -0,0 +1,1176 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import concurrent.futures +import copy +import json +import os +import queue +import subprocess +import sys +import tempfile +import textwrap +import threading +import time +from pathlib import Path +from typing import Any, Callable + + +ENGINES = ("codex", "claude", "droid", "copilot") +THINKING_LEVELS_BY_ENGINE = { + "codex": {"low", "medium", "high", "xhigh"}, + "claude": {"low", "medium", "high", "xhigh", "max"}, + "droid": set(), + "copilot": set(), +} + + +SCHEMA: dict[str, Any] = { + "type": "object", + "additionalProperties": False, + "required": [ + "findings", + "overall_correctness", + "overall_explanation", + "overall_confidence", + ], + "properties": { + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": False, + "required": [ + "title", + "body", + "priority", + "confidence", + "category", + "code_location", + ], + "properties": { + "title": {"type": "string", "minLength": 1, "maxLength": 140}, + "body": {"type": "string", "minLength": 1, "maxLength": 2000}, + "priority": {"type": "string", "enum": ["P0", "P1", "P2", "P3"]}, + "confidence": {"type": "number", "minimum": 0, "maximum": 1}, + "category": { + "type": "string", + "enum": ["bug", "security", "regression", "test_gap", "maintainability"], + }, + "code_location": { + "type": "object", + "additionalProperties": False, + "required": ["file_path", "line"], + "properties": { + "file_path": {"type": "string", "minLength": 1}, + "line": {"type": "integer", "minimum": 1}, + }, + }, + }, + }, + }, + "overall_correctness": { + "type": "string", + "enum": ["patch is correct", "patch is incorrect"], + }, + "overall_explanation": {"type": "string", "minLength": 1, "maxLength": 3000}, + "overall_confidence": {"type": "number", "minimum": 0, "maximum": 1}, + }, +} + + +def run(args: list[str], cwd: Path, *, input_text: str | None = None, check: bool = True) -> subprocess.CompletedProcess[str]: + result = subprocess.run( + args, + cwd=cwd, + input=input_text, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if check and result.returncode != 0: + cmd = " ".join(args) + raise SystemExit(f"command failed ({result.returncode}): {cmd}\n{result.stderr or result.stdout}") + return result + + +def run_with_heartbeat( + args: list[str], + cwd: Path, + *, + input_text: str | None = None, + label: str, + heartbeat_seconds: int = 60, + stream_output: bool = False, + stream_display: Callable[[str, str], str | None] | None = None, +) -> subprocess.CompletedProcess[str]: + if stream_output: + return run_with_stream( + args, + cwd, + input_text=input_text, + label=label, + heartbeat_seconds=heartbeat_seconds, + stream_display=stream_display, + ) + started = time.monotonic() + proc = subprocess.Popen( + args, + cwd=cwd, + stdin=subprocess.PIPE if input_text is not None else None, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + first_communicate = True + while True: + try: + stdout, stderr = proc.communicate( + input=input_text if first_communicate else None, + timeout=heartbeat_seconds, + ) + return subprocess.CompletedProcess(args, int(proc.returncode or 0), stdout, stderr) + except subprocess.TimeoutExpired: + first_communicate = False + elapsed = int(time.monotonic() - started) + print(f"review still running: {label} elapsed={elapsed}s pid={proc.pid}", file=sys.stderr, flush=True) + + +def run_with_stream( + args: list[str], + cwd: Path, + *, + input_text: str | None, + label: str, + heartbeat_seconds: int, + stream_display: Callable[[str, str], str | None] | None, +) -> subprocess.CompletedProcess[str]: + started = time.monotonic() + proc = subprocess.Popen( + args, + cwd=cwd, + stdin=subprocess.PIPE if input_text is not None else None, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1, + ) + events: queue.Queue[tuple[str, str | None]] = queue.Queue() + stdout_parts: list[str] = [] + stderr_parts: list[str] = [] + + def read_stream(name: str, stream: Any) -> None: + try: + for line in iter(stream.readline, ""): + events.put((name, line)) + finally: + events.put((name, None)) + + def write_stdin() -> None: + if proc.stdin is None or input_text is None: + return + try: + proc.stdin.write(input_text) + proc.stdin.close() + except BrokenPipeError: + return + + threads = [ + threading.Thread(target=read_stream, args=("stdout", proc.stdout), daemon=True), + threading.Thread(target=read_stream, args=("stderr", proc.stderr), daemon=True), + ] + for thread in threads: + thread.start() + stdin_thread = threading.Thread(target=write_stdin, daemon=True) + stdin_thread.start() + + open_streams = 2 + while open_streams: + try: + name, line = events.get(timeout=heartbeat_seconds) + except queue.Empty: + elapsed = int(time.monotonic() - started) + print(f"review still running: {label} elapsed={elapsed}s pid={proc.pid}", file=sys.stderr, flush=True) + continue + if line is None: + open_streams -= 1 + continue + if name == "stdout": + stdout_parts.append(line) + else: + stderr_parts.append(line) + display = stream_display(name, line) if stream_display else line + if display: + target = sys.stdout if name == "stdout" else sys.stderr + target.write(display) + target.flush() + + for thread in threads: + thread.join() + stdin_thread.join(timeout=1) + returncode = proc.wait() + return subprocess.CompletedProcess(args, returncode, "".join(stdout_parts), "".join(stderr_parts)) + + +def git(repo: Path, *args: str, check: bool = True) -> str: + return run(["git", *args], repo, check=check).stdout + + +def repo_root() -> Path: + result = subprocess.run( + ["git", "rev-parse", "--show-toplevel"], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if result.returncode != 0: + raise SystemExit("autoreview must run inside a git repository") + return Path(result.stdout.strip()).resolve() + + +def current_branch(repo: Path) -> str: + return git(repo, "branch", "--show-current", check=False).strip() or "detached" + + +def is_dirty(repo: Path) -> bool: + return bool(git(repo, "status", "--porcelain").strip()) + + +def choose_target(repo: Path, mode: str, base_ref: str | None) -> tuple[str, str | None]: + branch = current_branch(repo) + if mode == "local" or (mode == "auto" and is_dirty(repo)): + return "local", None + if mode == "commit": + return "commit", None + if mode == "branch" or (mode == "auto" and branch != "main"): + return "branch", base_ref or detect_pr_base(repo) or "origin/main" + raise SystemExit("no review target: clean main checkout and no forced mode") + + +def detect_pr_base(repo: Path) -> str | None: + if not shutil_which("gh"): + return None + result = run(["gh", "pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"], repo, check=False) + base = result.stdout.strip() + return f"origin/{base}" if result.returncode == 0 and base else None + + +def shutil_which(name: str) -> str | None: + for part in os.environ.get("PATH", "").split(os.pathsep): + candidate = Path(part) / name + if candidate.exists() and os.access(candidate, os.X_OK): + return str(candidate) + return None + + +def bounded(text: str, limit: int = 180_000) -> str: + if len(text) <= limit: + return text + return text[:limit] + f"\n\n[truncated at {limit} characters]\n" + + +def bounded_field(text: str, limit: int) -> str: + if len(text) <= limit: + return text + suffix = "\n\n[truncated]" + return text[: max(0, limit - len(suffix))] + suffix + + +def read_text(path: Path, limit: int = 40_000) -> str: + try: + data = path.read_bytes() + except OSError as exc: + return f"[unreadable: {exc}]" + if b"\0" in data: + return "[binary file omitted]" + text = data.decode("utf-8", errors="replace") + return bounded(text, limit) + + +def local_bundle(repo: Path) -> str: + parts = [ + "# Git Status", + git(repo, "status", "--short"), + "# Staged Diff", + git(repo, "diff", "--cached", "--stat"), + bounded(git(repo, "diff", "--cached", "--patch", "--find-renames")), + "# Unstaged Diff", + git(repo, "diff", "--stat"), + bounded(git(repo, "diff", "--patch", "--find-renames")), + ] + untracked = [line for line in git(repo, "ls-files", "--others", "--exclude-standard").splitlines() if line] + if untracked: + parts.append("# Untracked Files") + for rel in untracked: + path = repo / rel + parts.append(f"## {rel}\n{read_text(path)}") + return "\n\n".join(parts) + + +def branch_bundle(repo: Path, base_ref: str) -> str: + git(repo, "fetch", "origin", "--quiet", check=False) + return "\n\n".join( + [ + "# Branch Diff", + f"base: {base_ref}", + git(repo, "diff", "--stat", f"{base_ref}...HEAD"), + bounded(git(repo, "diff", "--patch", "--find-renames", f"{base_ref}...HEAD")), + ] + ) + + +def commit_bundle(repo: Path, commit_ref: str) -> str: + return "\n\n".join( + [ + "# Commit Diff", + f"commit: {commit_ref}", + git(repo, "show", "--stat", "--format=fuller", commit_ref), + bounded(git(repo, "show", "--patch", "--find-renames", "--format=fuller", commit_ref)), + ] + ) + + +def review_paths(repo: Path, target: str, target_ref: str | None, commit_ref: str) -> set[str]: + names: set[str] = set() + if target == "local": + sources = [ + git(repo, "diff", "--name-only", "--cached"), + git(repo, "diff", "--name-only"), + git(repo, "ls-files", "--others", "--exclude-standard"), + ] + elif target == "branch": + assert target_ref + sources = [git(repo, "diff", "--name-only", f"{target_ref}...HEAD")] + else: + sources = [git(repo, "show", "--name-only", "--format=", commit_ref)] + for source in sources: + for line in source.splitlines(): + path = line.strip() + if path: + names.add(path) + return names + + +def load_extra_prompt(args: argparse.Namespace) -> str: + chunks: list[str] = [] + for value in args.prompt or []: + chunks.append(value) + for path in args.prompt_file or []: + chunks.append(Path(path).read_text()) + return "\n\n".join(chunks) + + +def load_datasets(args: argparse.Namespace) -> str: + chunks: list[str] = [] + for spec in args.dataset or []: + path = Path(spec) + if path.is_dir(): + raise SystemExit(f"--dataset must be a file, got directory: {path}") + chunks.append(f"# Dataset: {path}\n{read_text(path)}") + return "\n\n".join(chunks) + + +def build_prompt(repo: Path, target: str, target_ref: str | None, bundle: str, extra_prompt: str, datasets: str) -> str: + target_line = f"{target} {target_ref}" if target_ref else target + return textwrap.dedent( + f""" + You are a senior code reviewer. Review the provided git change bundle only. + + Hard rules: + - Return exactly one JSON object and nothing else. Do not wrap it in Markdown. + - The JSON object must match this schema exactly: + {json.dumps(SCHEMA, indent=2)} + - Do not modify files. + - Do not invoke nested reviewers or review tools. + - Forbidden nested review commands include: codex review, autoreview, claude review, oracle review. + - You may use read-only tools and web search to inspect files, dependency contracts, upstream docs, current behavior, and security implications. + - Shell commands, if available, must be read-only inspection commands. Do not run tests, formatters, package installs, generators, network mutation commands, git mutation commands, or commands that write files. + - Report only actionable defects introduced or exposed by this change. + - Prefer high-signal findings over style feedback. + - Include security findings: injection, secret leaks, authz/authn bypass, path traversal, unsafe deserialization, unsafe filesystem or shell use, privacy leaks, and credential handling. + - Do not reject legitimate functionality merely because it touches shell, filesystem, network, auth, or sensitive data. Report a security finding only when the patch creates a concrete exploitable risk, removes an important safety check, or lacks validation at a trust boundary. + - For each finding, use the smallest file/line location that demonstrates the issue. + - If there are no actionable findings, return an empty findings array and mark the patch correct. + + Review target: {target_line} + Repository: {repo} + + {extra_prompt} + + {datasets} + + # Change Bundle + {bundle} + """ + ).strip() + + +def write_json_temp(data: dict[str, Any]) -> Path: + handle = tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) + with handle: + json.dump(data, handle) + return Path(handle.name) + + +def run_codex(args: argparse.Namespace, repo: Path, prompt: str) -> str: + if not args.tools: + raise SystemExit("--no-tools is not supported by the Codex engine; use --engine claude --no-tools for a no-tools run") + schema_path = write_json_temp(SCHEMA) + output_path = Path(tempfile.NamedTemporaryFile("w", suffix=".json", delete=False).name) + cmd = [args.codex_bin, "--ask-for-approval", "never"] + if args.web_search: + cmd.append("--search") + if args.model: + cmd.extend(["--model", args.model]) + if args.thinking: + cmd.extend(["-c", f'model_reasoning_effort="{args.thinking}"']) + cmd.append("exec") + if args.stream_engine_output: + cmd.append("--json") + cmd.extend( + [ + "--ephemeral", + "-C", + str(repo), + "-s", + "read-only", + "--output-schema", + str(schema_path), + "--output-last-message", + str(output_path), + "-", + ] + ) + result = run_with_heartbeat( + cmd, + repo, + input_text=prompt, + label="codex", + stream_output=args.stream_engine_output, + stream_display=CodexStreamDisplay() if args.stream_engine_output else None, + ) + try: + output = output_path.read_text() + finally: + schema_path.unlink(missing_ok=True) + output_path.unlink(missing_ok=True) + if result.returncode != 0: + raise SystemExit(f"codex engine failed ({result.returncode})\n{result.stderr or result.stdout}") + return output or result.stdout + + +def run_claude(args: argparse.Namespace, repo: Path, prompt: str) -> str: + cmd = [ + args.claude_bin, + "--print", + "--no-session-persistence", + "--output-format", + "stream-json" if args.stream_engine_output else "json", + "--json-schema", + json.dumps(SCHEMA), + ] + if args.tools: + cmd.extend(["--allowedTools", claude_allowed_tools(args)]) + else: + cmd.extend(["--tools", ""]) + if args.stream_engine_output: + cmd.append("--verbose") + if args.model: + cmd.extend(["--model", args.model]) + if args.thinking: + cmd.extend(["--effort", args.thinking]) + result = run_with_heartbeat( + cmd, + repo, + input_text=prompt, + label="claude", + stream_output=args.stream_engine_output, + stream_display=ClaudeStreamDisplay() if args.stream_engine_output else None, + ) + if result.returncode != 0: + raise SystemExit(f"claude engine failed ({result.returncode})\n{result.stderr or result.stdout}") + return result.stdout + + +def run_droid(args: argparse.Namespace, repo: Path, prompt: str) -> str: + if args.thinking: + raise SystemExit("--thinking is not supported by the droid engine") + prompt_path = Path(tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False).name) + prompt_path.write_text(prompt) + cmd = [ + args.droid_bin, + "exec", + "--cwd", + str(repo), + "--output-format", + "json", + "-f", + str(prompt_path), + ] + if args.model: + cmd.extend(["--model", args.model]) + if not args.tools: + cmd.extend(["--disabled-tools", "*"]) + result = run_with_heartbeat(cmd, repo, label="droid", stream_output=args.stream_engine_output) + prompt_path.unlink(missing_ok=True) + if result.returncode != 0: + raise SystemExit(f"droid engine failed ({result.returncode})\n{result.stderr or result.stdout}") + return result.stdout + + +def run_copilot(args: argparse.Namespace, repo: Path, prompt: str) -> str: + if args.thinking: + raise SystemExit("--thinking is not supported by the copilot engine") + if not args.tools: + raise SystemExit("--no-tools is not supported by the copilot engine; copilot requires a read-only file view tool to load the review bundle without exposing it in argv") + with tempfile.TemporaryDirectory(prefix="autoreview-copilot.") as tempdir: + prompt_path = Path(tempdir) / "prompt.txt" + prompt_path.write_text(prompt) + os.chmod(prompt_path, 0o600) + cmd = [ + args.copilot_bin, + "-C", + tempdir, + "-p", + "Read ./prompt.txt and follow it exactly. Return only the requested JSON object.", + "--output-format", + "json", + "--stream", + "on" if args.stream_engine_output else "off", + "--no-ask-user", + "--disable-builtin-mcps", + ] + if args.model: + cmd.extend(["--model", args.model]) + cmd.extend( + [ + "--available-tools=read_agent,rg,view,web_fetch", + "--allow-tool=read_agent", + "--allow-tool=rg", + "--allow-tool=view", + "--allow-tool=web_fetch", + ] + ) + if args.web_search: + cmd.append("--allow-all-urls") + result = run_with_heartbeat(cmd, Path(tempdir), label="copilot", stream_output=args.stream_engine_output) + if result.returncode != 0: + raise SystemExit(f"copilot engine failed ({result.returncode})\n{result.stderr or result.stdout}") + return result.stdout + + +class CodexStreamDisplay: + def __init__(self, *, activity_seconds: int = 20) -> None: + self.activity_seconds = activity_seconds + self.hidden_events = 0 + self.last_visible = time.monotonic() + + def __call__(self, name: str, line: str) -> str | None: + if name != "stdout": + return line + try: + event = json.loads(line) + except json.JSONDecodeError: + return self.visible(line) + event_type = event.get("type") + if event_type == "thread.started": + return self.visible(f"codex thread: {event.get('thread_id', '')}\n") + if event_type == "turn.started": + return self.visible("codex turn started\n") + if event_type == "turn.completed": + usage = event.get("usage") + message = format_codex_usage(usage) + "\n" if isinstance(usage, dict) else "codex turn completed\n" + return self.visible(self.flush_hidden() + message) + item = event.get("item") + if isinstance(item, dict) and item.get("type") == "agent_message" and isinstance(item.get("text"), str): + return self.visible(self.flush_hidden() + item["text"].rstrip() + "\n") + return self.hidden_activity() + + def hidden_activity(self) -> str | None: + self.hidden_events += 1 + if time.monotonic() - self.last_visible < self.activity_seconds: + return None + return self.visible(self.flush_hidden()) + + def flush_hidden(self) -> str: + if not self.hidden_events: + return "" + count = self.hidden_events + self.hidden_events = 0 + return f"codex activity: {count} hidden tool/status events\n" + + def visible(self, text: str) -> str: + self.last_visible = time.monotonic() + return text + + +class ClaudeStreamDisplay: + def __init__(self, *, activity_seconds: int = 20) -> None: + self.activity_seconds = activity_seconds + self.hidden_events = 0 + self.last_visible = time.monotonic() + self.started = False + + def __call__(self, name: str, line: str) -> str | None: + if name != "stdout": + return line + try: + event = json.loads(line) + except json.JSONDecodeError: + return self.visible(line) + event_type = event.get("type") + if event_type == "system" and not self.started: + self.started = True + return self.visible("claude turn started\n") + if event_type == "assistant": + return self.assistant_message(event) + if event_type == "result": + return self.visible(self.flush_hidden() + self.result_summary(event)) + return self.hidden_activity() + + def assistant_message(self, event: dict[str, Any]) -> str | None: + message = event.get("message") + if not isinstance(message, dict): + return self.hidden_activity() + chunks: list[str] = [] + for item in message.get("content", []): + if not isinstance(item, dict): + continue + if item.get("type") == "text" and isinstance(item.get("text"), str): + chunks.append(item["text"].rstrip()) + if chunks: + return self.visible(self.flush_hidden() + "\n".join(chunks) + "\n") + return self.hidden_activity() + + def result_summary(self, event: dict[str, Any]) -> str: + usage = event.get("usage") + fields: list[str] = [] + if isinstance(usage, dict): + for key in ( + "input_tokens", + "cache_read_input_tokens", + "cache_creation_input_tokens", + "output_tokens", + ): + value = usage.get(key) + if isinstance(value, int): + fields.append(f"{key}={value}") + cost = event.get("total_cost_usd") + if isinstance(cost, (int, float)) and not isinstance(cost, bool): + fields.append(f"cost_usd={cost:.6f}") + return "claude usage: " + " ".join(fields) + "\n" if fields else "claude turn completed\n" + + def hidden_activity(self) -> str | None: + self.hidden_events += 1 + if time.monotonic() - self.last_visible < self.activity_seconds: + return None + return self.visible(self.flush_hidden()) + + def flush_hidden(self) -> str: + if not self.hidden_events: + return "" + count = self.hidden_events + self.hidden_events = 0 + return f"claude activity: {count} hidden tool/status events\n" + + def visible(self, text: str) -> str: + self.last_visible = time.monotonic() + return text + + +def format_codex_usage(usage: dict[str, Any]) -> str: + fields = [ + "input_tokens", + "cached_input_tokens", + "output_tokens", + "reasoning_output_tokens", + ] + parts = [f"{field}={usage[field]}" for field in fields if isinstance(usage.get(field), int)] + return "codex usage: " + " ".join(parts) if parts else "codex usage: unavailable" + + +def claude_allowed_tools(args: argparse.Namespace) -> str: + tools = [tool.strip() for tool in args.claude_allowed_tools.split(",") if tool.strip()] + if not args.web_search: + tools = [tool for tool in tools if tool not in {"WebSearch", "WebFetch"}] + return ",".join(tools) + + +def extract_json(text: str) -> dict[str, Any]: + stripped = text.strip() + if not stripped: + raise SystemExit("review engine returned empty output") + try: + parsed = json.loads(stripped) + except json.JSONDecodeError as exc: + fenced_report = parse_json_candidate(stripped) + if isinstance(fenced_report, dict) and "findings" in fenced_report: + return fenced_report + jsonl_report = extract_json_from_jsonl(stripped) + if jsonl_report: + return jsonl_report + raise SystemExit(f"review engine returned non-JSON output: {exc}\n{stripped[:2000]}") + if isinstance(parsed, dict) and "findings" in parsed: + return parsed + if isinstance(parsed, dict) and isinstance(parsed.get("structured_output"), dict): + return parsed["structured_output"] + if isinstance(parsed, dict) and isinstance(parsed.get("result"), str): + result_json = parse_json_candidate(parsed["result"]) + if isinstance(result_json, dict) and "findings" in result_json: + return result_json + raise SystemExit(f"review engine result was not structured JSON:\n{parsed['result'][:2000]}") + jsonl_report = extract_json_from_jsonl(stripped) + if jsonl_report: + return jsonl_report + raise SystemExit(f"review engine returned unexpected JSON shape:\n{json.dumps(parsed)[:2000]}") + + +def extract_json_from_jsonl(text: str) -> dict[str, Any] | None: + candidates: list[str | dict[str, Any]] = [] + for line in text.splitlines(): + line = line.strip() + if not line: + continue + try: + event = json.loads(line) + except json.JSONDecodeError: + continue + if not isinstance(event, dict): + continue + part = event.get("part") + if isinstance(part, dict) and isinstance(part.get("text"), str): + candidates.append(part["text"]) + data = event.get("data") + if isinstance(data, dict) and isinstance(data.get("content"), str): + candidates.append(data["content"]) + if isinstance(event.get("result"), str): + candidates.append(event["result"]) + if isinstance(event.get("structured_output"), dict): + candidates.append(event["structured_output"]) + for candidate in reversed(candidates): + if isinstance(candidate, dict): + if "findings" in candidate: + return candidate + continue + parsed = parse_json_candidate(candidate) + if isinstance(parsed, dict) and "findings" in parsed: + return parsed + return None + + +def parse_json_candidate(text: str) -> Any | None: + stripped = text.strip() + if stripped.startswith("```"): + lines = stripped.splitlines() + if lines and lines[0].startswith("```") and lines[-1].strip() == "```": + stripped = "\n".join(lines[1:-1]).strip() + try: + parsed = json.loads(stripped) + except json.JSONDecodeError: + return None + if isinstance(parsed, str) and parsed != text: + nested = parse_json_candidate(parsed) + return nested if nested is not None else parsed + return parsed + + +def validate_report(report: dict[str, Any], repo: Path, changed_paths: set[str], required: list[str]) -> None: + allowed_top = {"findings", "overall_correctness", "overall_explanation", "overall_confidence"} + extra_top = set(report) - allowed_top + if extra_top: + raise SystemExit(f"review JSON has unexpected top-level keys: {sorted(extra_top)}") + for key in SCHEMA["required"]: + if key not in report: + raise SystemExit(f"review JSON missing required key: {key}") + if not isinstance(report["findings"], list): + raise SystemExit("review JSON findings must be an array") + if report.get("overall_correctness") not in {"patch is correct", "patch is incorrect"}: + raise SystemExit(f"review JSON has invalid overall_correctness: {report.get('overall_correctness')}") + if not isinstance(report.get("overall_explanation"), str) or not report["overall_explanation"]: + raise SystemExit("review JSON overall_explanation must be a non-empty string") + if len(report["overall_explanation"]) > 3000: + raise SystemExit("review JSON overall_explanation is too long") + if not number_in_range(report.get("overall_confidence")): + raise SystemExit("review JSON overall_confidence must be numeric") + finding_text = "" + kept_findings: list[dict[str, Any]] = [] + ignored_findings: list[tuple[int, dict[str, Any], str, int]] = [] + for index, finding in enumerate(report["findings"]): + if not isinstance(finding, dict): + raise SystemExit(f"finding {index} must be an object") + allowed_finding = {"title", "body", "priority", "confidence", "category", "code_location"} + extra_finding = set(finding) - allowed_finding + if extra_finding: + raise SystemExit(f"finding {index} has unexpected keys: {sorted(extra_finding)}") + for key in allowed_finding: + if key not in finding: + raise SystemExit(f"finding {index} missing required key: {key}") + title = finding.get("title") + if not isinstance(title, str) or not title or len(title) > 140: + raise SystemExit(f"finding {index} has invalid title") + body = finding.get("body") + if not isinstance(body, str) or not body or len(body) > 2000: + raise SystemExit(f"finding {index} has invalid body") + priority = finding.get("priority") + if priority not in {"P0", "P1", "P2", "P3"}: + raise SystemExit(f"finding {index} has invalid priority: {priority}") + if not number_in_range(finding.get("confidence")): + raise SystemExit(f"finding {index} has invalid confidence") + category = finding.get("category") + if category not in {"bug", "security", "regression", "test_gap", "maintainability"}: + raise SystemExit(f"finding {index} has invalid category: {category}") + location = finding.get("code_location") + if not isinstance(location, dict): + raise SystemExit(f"finding {index} missing code_location") + rel = str(location.get("file_path", "")).strip() + line = location.get("line") + if not rel or not isinstance(line, int) or line < 1: + raise SystemExit(f"finding {index} has invalid location: {location}") + if Path(rel).is_absolute() or ".." in Path(rel).parts: + raise SystemExit(f"finding {index} uses invalid file path: {rel}") + if rel not in changed_paths: + ignored_findings.append((index, finding, rel, line)) + continue + kept_findings.append(finding) + finding_text += "\n" + json.dumps(finding, sort_keys=True) + if ignored_findings: + for index, finding, rel, line in ignored_findings: + title = finding.get("title", "") + print( + f"autoreview ignored out-of-scope finding {index}: {title} ({rel}:{line})", + file=sys.stderr, + ) + print(bounded_field(str(finding.get("body", "")), 500), file=sys.stderr) + report["findings"] = kept_findings + if not kept_findings and report["overall_correctness"] == "patch is incorrect": + note = f"Ignored {len(ignored_findings)} out-of-scope finding(s) outside the reviewed change." + explanation = report["overall_explanation"].rstrip() + report["overall_correctness"] = "patch is correct" + report["overall_explanation"] = bounded_field(f"{explanation}\n\n{note}", 3000) + haystack = finding_text.lower() + for needle in required: + if needle.lower() not in haystack: + raise SystemExit(f"required finding text not found: {needle}") + + +def number_in_range(value: Any) -> bool: + return isinstance(value, (int, float)) and not isinstance(value, bool) and 0 <= value <= 1 + + +def print_report(report: dict[str, Any], *, label: str = "autoreview") -> None: + findings = report["findings"] + if findings: + print(f"{label} findings: {len(findings)}") + elif report["overall_correctness"] == "patch is incorrect": + print(f"{label} verdict: patch is incorrect without discrete findings") + else: + print(f"{label} clean: no accepted/actionable findings reported") + for finding in findings: + loc = finding["code_location"] + print(f"[{finding['priority']}] {finding['title']}") + print(f"{loc['file_path']}:{loc['line']}") + print(f"{finding['body']}") + print() + print(f"overall: {report['overall_correctness']} ({report['overall_confidence']})") + print(report["overall_explanation"]) + + +def start_parallel_tests(command: str, repo: Path) -> tuple[subprocess.Popen, float]: + print(f"tests: {command}") + return subprocess.Popen(command, cwd=repo, shell=True), time.time() + + +def finish_parallel_tests(proc: subprocess.Popen, started: float) -> int: + proc.wait() + print(f"tests exit: {proc.returncode} after {int(time.time() - started)}s") + return int(proc.returncode or 0) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Bundle-driven AI code review.") + parser.add_argument("--mode", choices=["auto", "local", "branch", "commit"], default="auto") + parser.add_argument("--base") + parser.add_argument("--commit", default="HEAD") + parser.add_argument("--engine", choices=ENGINES, default=os.environ.get("AUTOREVIEW_ENGINE", "codex")) + parser.add_argument("--reviewers", help="Comma-separated review panel, e.g. codex,claude or codex:gpt-5:high.") + parser.add_argument("--panel", action="store_true", help="Run a Codex/Claude review panel unless --engine changes the first reviewer.") + parser.add_argument("--model", action="append", help="Model for all reviewers or engine=model. Repeatable.") + parser.add_argument("--thinking", action="append", help="Thinking/effort for all reviewers or engine=level. Repeatable. Codex: low, medium, high, xhigh. Claude: low, medium, high, xhigh, max.") + parser.add_argument("--allow-partial-panel", action="store_true", help="Continue panel output when one reviewer fails.") + parser.add_argument("--codex-bin", default=os.environ.get("CODEX_BIN", "codex")) + parser.add_argument("--claude-bin", default=os.environ.get("CLAUDE_BIN", "claude")) + parser.add_argument("--droid-bin", default=os.environ.get("DROID_BIN", "droid")) + parser.add_argument("--copilot-bin", default=os.environ.get("COPILOT_BIN", "copilot")) + parser.add_argument("--no-tools", dest="tools", action="store_false", default=True, help="Disable tools for engines that support it. Codex and copilot reject no-tools review.") + parser.add_argument("--no-web-search", dest="web_search", action="store_false", default=True) + parser.add_argument( + "--claude-allowed-tools", + default=os.environ.get( + "AUTOREVIEW_CLAUDE_TOOLS", + "Read,Grep,Glob,WebSearch,WebFetch", + ), + ) + parser.add_argument("--prompt", action="append", help="Additional review instruction text.") + parser.add_argument("--prompt-file", action="append", help="Additional review instruction file.") + parser.add_argument("--dataset", action="append", help="Extra evidence file to include in the review bundle.") + parser.add_argument("--output", help="Write human output to a file as well as stdout.") + parser.add_argument("--json-output", help="Write validated structured review JSON.") + parser.add_argument( + "--stream-engine-output", + action="store_true", + default=os.environ.get("AUTOREVIEW_STREAM_ENGINE_OUTPUT") == "1", + help="Stream review engine output while preserving buffered output for validation. Codex output is filtered to hide tool/file chatter.", + ) + parser.add_argument("--parallel-tests", help="Run a test command concurrently with review; failure fails the helper.") + parser.add_argument("--require-finding", action="append", default=[], help="Require finding text to contain this substring.") + parser.add_argument("--expect-findings", action="store_true", help="Treat findings as success; for harness acceptance tests.") + parser.add_argument("--dry-run", action="store_true") + args = parser.parse_args() + if args.engine not in ENGINES: + raise SystemExit(f"invalid --engine/AUTOREVIEW_ENGINE: {args.engine}") + return args + + +def run_engine(args: argparse.Namespace, repo: Path, prompt: str) -> str: + if args.engine == "codex": + return run_codex(args, repo, prompt) + if args.engine == "claude": + return run_claude(args, repo, prompt) + if args.engine == "droid": + return run_droid(args, repo, prompt) + if args.engine == "copilot": + return run_copilot(args, repo, prompt) + raise SystemExit(f"unsupported engine: {args.engine}") + + +def parse_keyed_options(values: list[str] | None, option: str) -> tuple[str | None, dict[str, str]]: + global_value: str | None = None + per_engine: dict[str, str] = {} + for raw in values or []: + value = raw.strip() + if not value: + raise SystemExit(f"--{option} cannot be empty") + if "=" in value: + engine, engine_value = value.split("=", 1) + engine = engine.strip() + engine_value = engine_value.strip() + if engine not in ENGINES: + raise SystemExit(f"--{option} uses unknown engine: {engine}") + if not engine_value: + raise SystemExit(f"--{option} for {engine} cannot be empty") + if engine in per_engine: + raise SystemExit(f"--{option} specified more than once for {engine}") + per_engine[engine] = engine_value + else: + if global_value is not None: + raise SystemExit(f"--{option} global value specified more than once") + global_value = value + return global_value, per_engine + + +def parse_reviewer_token(token: str) -> tuple[str, str | None, str | None]: + parts = [part.strip() for part in token.split(":")] + if len(parts) > 3 or not parts[0]: + raise SystemExit(f"invalid reviewer spec: {token}") + engine = parts[0] + if engine not in ENGINES: + raise SystemExit(f"unknown reviewer engine: {engine}") + model = parts[1] if len(parts) >= 2 and parts[1] else None + thinking = parts[2] if len(parts) == 3 and parts[2] else None + return engine, model, thinking + + +def reviewer_args(args: argparse.Namespace) -> list[argparse.Namespace]: + global_model, model_by_engine = parse_keyed_options(args.model, "model") + global_thinking, thinking_by_engine = parse_keyed_options(args.thinking, "thinking") + reviewers: list[tuple[str, str | None, str | None]] = [] + if args.reviewers: + tokens = [token.strip() for token in args.reviewers.split(",") if token.strip()] + if len(tokens) == 1 and tokens[0] == "all": + tokens = list(ENGINES) + reviewers = [parse_reviewer_token(token) for token in tokens] + elif args.panel: + engines = [args.engine] + for engine in ("codex", "claude"): + if engine not in engines: + engines.append(engine) + reviewers = [(engine, None, None) for engine in engines] + else: + reviewers = [(args.engine, None, None)] + + seen: set[str] = set() + result: list[argparse.Namespace] = [] + for engine, inline_model, inline_thinking in reviewers: + if engine in seen: + raise SystemExit(f"reviewer specified more than once: {engine}") + seen.add(engine) + model = inline_model or model_by_engine.get(engine) or global_model + thinking = inline_thinking or thinking_by_engine.get(engine) or global_thinking + if thinking and thinking not in THINKING_LEVELS_BY_ENGINE[engine]: + valid = ", ".join(sorted(THINKING_LEVELS_BY_ENGINE[engine])) or "none" + raise SystemExit(f"invalid thinking level for {engine}: {thinking} (valid: {valid})") + clone = copy.copy(args) + clone.engine = engine + clone.model = model + clone.thinking = thinking + result.append(clone) + return result + + +def reviewer_label(args: argparse.Namespace) -> str: + parts = [args.engine] + if args.model: + parts.append(f"model={args.model}") + if args.thinking: + parts.append(f"thinking={args.thinking}") + return " ".join(parts) + + +def run_reviewer(args: argparse.Namespace, repo: Path, prompt: str, changed_paths: set[str], required: list[str]) -> dict[str, Any]: + raw = run_engine(args, repo, prompt) + report = extract_json(raw) + validate_report(report, repo, changed_paths, required) + return report + + +def merge_panel_reports(reports: list[tuple[str, dict[str, Any]]]) -> dict[str, Any]: + findings: list[dict[str, Any]] = [] + seen: set[tuple[str, int, str, str]] = set() + for label, report in reports: + for finding in report["findings"]: + location = finding["code_location"] + key = ( + location["file_path"], + location["line"], + finding["category"], + " ".join(finding["title"].lower().split()), + ) + if key in seen: + continue + seen.add(key) + merged = copy.deepcopy(finding) + merged["body"] = bounded_field(f"Reviewer: {label}\n\n{merged['body']}", 2000) + findings.append(merged) + incorrect = bool(findings) or any(report["overall_correctness"] == "patch is incorrect" for _, report in reports) + summary = ", ".join(f"{label}: {len(report['findings'])} finding(s)" for label, report in reports) + return { + "findings": findings, + "overall_correctness": "patch is incorrect" if incorrect else "patch is correct", + "overall_explanation": f"Panel review complete. {summary}.", + "overall_confidence": max((report["overall_confidence"] for _, report in reports), default=0.5), + } + + +def run_panel(args: argparse.Namespace, reviewers: list[argparse.Namespace], repo: Path, prompt: str, changed_paths: set[str]) -> dict[str, Any]: + reports: list[tuple[str, dict[str, Any]]] = [] + failures: list[str] = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=len(reviewers)) as executor: + future_by_label = { + executor.submit(run_reviewer, reviewer, repo, prompt, changed_paths, []): reviewer_label(reviewer) + for reviewer in reviewers + } + for future in concurrent.futures.as_completed(future_by_label): + label = future_by_label[future] + try: + reports.append((label, future.result())) + except SystemExit as exc: + failures.append(f"{label}: {exc}") + except Exception as exc: + failures.append(f"{label}: {exc}") + if failures and not args.allow_partial_panel: + raise SystemExit("autoreview panel failed\n" + "\n".join(failures)) + if failures: + for failure in failures: + print(f"panel reviewer failed: {failure}") + if not reports: + raise SystemExit("autoreview panel produced no reports") + reports.sort(key=lambda item: item[0]) + report = merge_panel_reports(reports) + validate_report(report, repo, changed_paths, args.require_finding) + return report + + +def main() -> int: + args = parse_args() + reviewers = reviewer_args(args) + repo = repo_root() + target, target_ref = choose_target(repo, args.mode, args.base) + print(f"autoreview target: {target}") + print(f"branch: {current_branch(repo)}") + if len(reviewers) == 1 and not args.reviewers and not args.panel: + print(f"engine: {reviewers[0].engine}") + if reviewers[0].model: + print(f"model: {reviewers[0].model}") + if reviewers[0].thinking: + print(f"thinking: {reviewers[0].thinking}") + else: + print(f"reviewers: {', '.join(reviewer_label(reviewer) for reviewer in reviewers)}") + print(f"tools: {'on' if args.tools else 'off'}") + print(f"web_search: {'on' if args.web_search else 'off'}") + display_ref = args.commit if target == "commit" else target_ref + if display_ref: + print(f"ref: {display_ref}") + if args.dry_run: + return 0 + + if target == "local": + bundle = local_bundle(repo) + elif target == "branch": + assert target_ref + bundle = branch_bundle(repo, target_ref) + else: + bundle = commit_bundle(repo, args.commit) + target_ref = args.commit + prompt = build_prompt(repo, target, target_ref, bundle, load_extra_prompt(args), load_datasets(args)) + changed_paths = review_paths(repo, target, target_ref, args.commit) + print(f"bundle: {len(prompt)} chars") + + tests_proc: tuple[subprocess.Popen, float] | None = None + if args.parallel_tests: + tests_proc = start_parallel_tests(args.parallel_tests, repo) + try: + if len(reviewers) == 1: + report = run_reviewer(reviewers[0], repo, prompt, changed_paths, args.require_finding) + label = "autoreview" + else: + report = run_panel(args, reviewers, repo, prompt, changed_paths) + label = "autoreview panel" + if args.json_output: + Path(args.json_output).write_text(json.dumps(report, indent=2) + "\n") + + if args.output: + original_stdout = sys.stdout + with Path(args.output).open("w") as handle: + sys.stdout = Tee(original_stdout, handle) + print_report(report, label=label) + sys.stdout = original_stdout + else: + print_report(report, label=label) + finally: + tests_status = finish_parallel_tests(*tests_proc) if tests_proc else 0 + + has_findings = bool(report["findings"]) + overall_incorrect = report["overall_correctness"] == "patch is incorrect" + if tests_status != 0: + return 1 + if args.expect_findings: + return 0 if has_findings else 1 + return 1 if has_findings or overall_incorrect else 0 + + +class Tee: + def __init__(self, *streams: Any) -> None: + self.streams = streams + + def write(self, data: str) -> None: + for stream in self.streams: + stream.write(data) + + def flush(self) -> None: + for stream in self.streams: + stream.flush() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.agents/skills/autoreview/scripts/test-review-harness b/.agents/skills/autoreview/scripts/test-review-harness new file mode 100755 index 000000000..58105bc55 --- /dev/null +++ b/.agents/skills/autoreview/scripts/test-review-harness @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: test-review-harness [--fixture malicious|benign] [--engine codex|claude|droid|copilot]... + +Creates a temporary git repo with either a deliberately unsafe patch or a +security-sensitive-but-safe patch, then verifies each selected engine through +autoreview. +Default engines: codex, claude. +EOF +} + +engines=() +fixture=malicious +while [[ $# -gt 0 ]]; do + case "$1" in + --fixture) + fixture=${2:-} + shift 2 + ;; + --engine) + engines+=("${2:-}") + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage >&2 + exit 2 + ;; + esac +done + +case "$fixture" in + malicious|benign) ;; + *) + usage >&2 + exit 2 + ;; +esac + +if [[ ${#engines[@]} -eq 0 ]]; then + engines=(codex claude) +fi + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +repo=$(mktemp -d "${TMPDIR:-/tmp}/autoreview-fixture.XXXXXX") +trap 'rm -rf "$repo"' EXIT + +cd "$repo" +git init --quiet +git config user.name "Review Fixture" +git config user.email "review-fixture@example.com" + +if [[ "$fixture" == malicious ]]; then + cat > app.js <<'EOF' +export function uploadPath(name) { + return `uploads/${name.replaceAll("/", "")}`; +} + +export function publicUser(user) { + return { id: user.id, name: user.name }; +} +EOF +else + cat > app.js <<'EOF' +import path from "node:path"; + +const uploadsRoot = path.resolve("uploads"); + +function safeChildPath(root, name) { + if (name.includes("/") || name.includes("\\") || name.includes("\0")) { + throw new Error("invalid child name"); + } + const resolved = path.resolve(root, name); + if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root"); + return resolved; +} + +export function uploadPath(name) { + return safeChildPath(uploadsRoot, name); +} + +export function publicUser(user) { + return { id: user.id, name: user.name }; +} +EOF +fi + +git add app.js +git commit --quiet -m "initial safe version" + +if [[ "$fixture" == malicious ]]; then + cat > app.js <<'EOF' +import { execSync } from "node:child_process"; + +export function uploadPath(name) { + return `uploads/${name}`; +} + +export function deleteUpload(name) { + return execSync(`rm -rf uploads/${name}`); +} + +export function publicUser(user) { + return { id: user.id, name: user.name, password: user.password }; +} +EOF +else + cat > app.js <<'EOF' +import { execFile } from "node:child_process"; +import path from "node:path"; +import { promisify } from "node:util"; + +const uploadsRoot = path.resolve("uploads"); +const reposRoot = path.resolve("repos"); +const execFileAsync = promisify(execFile); + +function safeChildPath(root, name) { + if (name.includes("/") || name.includes("\\") || name.includes("\0")) { + throw new Error("invalid child name"); + } + const resolved = path.resolve(root, name); + if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root"); + return resolved; +} + +function repoChildPath(root, name) { + if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error("invalid repo name"); + return safeChildPath(root, name); +} + +export function uploadPath(name) { + return safeChildPath(uploadsRoot, name); +} + +export async function repoStatus(repoName) { + const { stdout } = await execFileAsync("git", ["status", "--short"], { + cwd: repoChildPath(reposRoot, repoName), + encoding: "utf8", + maxBuffer: 16 * 1024 * 1024, + }); + return stdout; +} + +export function publicUser(user) { + return { id: user.id, name: user.name }; +} + +export function accountSettingsForOwner(user, requesterId) { + if (String(requesterId) !== String(user.id)) throw new Error("forbidden"); + return { id: user.id, hasPassword: Boolean(user.passwordHash) }; +} +EOF +fi + +for engine in "${engines[@]}"; do + echo "== $engine ==" + if [[ "$fixture" == malicious ]]; then + "$script_dir/autoreview" \ + --mode local \ + --engine "$engine" \ + --prompt "This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch." \ + --require-finding "command" \ + --expect-findings + else + "$script_dir/autoreview" \ + --mode local \ + --engine "$engine" \ + --prompt "Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff." + fi +done diff --git a/.compozy/tasks/tokens-perf/analysis/collect_token_baseline.py b/.compozy/tasks/tokens-perf/analysis/collect_token_baseline.py new file mode 100644 index 000000000..101414a25 --- /dev/null +++ b/.compozy/tasks/tokens-perf/analysis/collect_token_baseline.py @@ -0,0 +1,419 @@ +#!/usr/bin/env python3 +"""Read-only token baseline collector for the tokens-perf incident. + +The script intentionally reads only: +- Claude Code JSONL transcripts from one project directory. +- AGH SQLite/crash-bundle observability files. + +It does not inspect provider auth/config/secret paths. +""" + +from __future__ import annotations + +import argparse +import json +import sqlite3 +from collections import Counter, defaultdict +from dataclasses import dataclass, field +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + + +TOKEN_FIELDS = ( + "input_tokens", + "cache_creation_input_tokens", + "cache_read_input_tokens", + "output_tokens", +) + + +def parse_time(value: str | None) -> datetime | None: + if not value: + return None + text = value.strip() + if text.endswith("Z"): + text = text[:-1] + "+00:00" + try: + parsed = datetime.fromisoformat(text) + except ValueError: + return None + if parsed.tzinfo is None: + return parsed.replace(tzinfo=timezone.utc) + return parsed.astimezone(timezone.utc) + + +def iso_utc(value: datetime | None) -> str | None: + if value is None: + return None + return value.astimezone(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z") + + +def minute_bucket(value: datetime | None) -> str: + if value is None: + return "unknown" + rounded = value.astimezone(timezone.utc).replace(second=0, microsecond=0) + return iso_utc(rounded) or "unknown" + + +def text_from_content(value: Any, max_chars: int = 80_000) -> str: + parts: list[str] = [] + + def walk(node: Any) -> None: + if sum(len(part) for part in parts) >= max_chars: + return + if isinstance(node, str): + parts.append(node[:max_chars]) + return + if isinstance(node, list): + for item in node: + walk(item) + return + if isinstance(node, dict): + for key in ("text", "content", "input"): + if key in node: + walk(node[key]) + return + + walk(value) + text = "\n".join(parts) + if len(text) > max_chars: + return text[:max_chars] + return text + + +@dataclass +class TranscriptStats: + path: Path + first_timestamp: datetime | None = None + first_user_text: str = "" + raw_assistant_usage_rows: int = 0 + deduped_assistant_calls: int = 0 + usage: Counter[str] = field(default_factory=Counter) + + def classify(self) -> str: + lowered = self.first_user_text.lower() + if "extractor candidate prompt v1" in lowered and "what_not_to_save v1" in lowered: + return "memory_extractor" + if " dict[str, Any]: + seen: set[tuple[str, str, str]] = set() + totals: Counter[str] = Counter() + by_class: dict[str, Counter[str]] = defaultdict(Counter) + session_starts_by_class: Counter[str] = Counter() + calls_by_minute: Counter[str] = Counter() + cache_read_by_minute: Counter[str] = Counter() + top_files: list[dict[str, Any]] = [] + transcript_count = 0 + raw_rows = 0 + deduped_calls = 0 + + for path in sorted(project_dir.glob("*.jsonl")): + transcript_count += 1 + stats = TranscriptStats(path=path) + + with path.open("r", encoding="utf-8", errors="replace") as handle: + for line_no, line in enumerate(handle, 1): + try: + row = json.loads(line) + except json.JSONDecodeError: + continue + + timestamp = parse_time(row.get("timestamp")) + if timestamp and (stats.first_timestamp is None or timestamp < stats.first_timestamp): + stats.first_timestamp = timestamp + + row_type = row.get("type") + message = row.get("message") if isinstance(row.get("message"), dict) else {} + + if row_type == "user" and not stats.first_user_text: + content = message.get("content", row.get("content")) + stats.first_user_text = text_from_content(content) + + if row_type != "assistant": + continue + + usage = message.get("usage") if isinstance(message.get("usage"), dict) else None + if not usage: + continue + + stats.raw_assistant_usage_rows += 1 + raw_rows += 1 + + request_id = str(row.get("requestId") or row.get("request_id") or "") + message_id = str(message.get("id") or row.get("uuid") or f"line-{line_no}") + dedupe_key = (path.name, request_id, message_id) + if dedupe_key in seen: + continue + seen.add(dedupe_key) + + stats.deduped_assistant_calls += 1 + deduped_calls += 1 + + for field_name in TOKEN_FIELDS: + value = usage.get(field_name) or 0 + if isinstance(value, (int, float)): + stats.usage[field_name] += int(value) + totals[field_name] += int(value) + + bucket = minute_bucket(timestamp) + calls_by_minute[bucket] += 1 + cache_read_by_minute[bucket] += int(usage.get("cache_read_input_tokens") or 0) + + cls = stats.classify() + if stats.first_timestamp and in_window(stats.first_timestamp, start, end): + session_starts_by_class[cls] += 1 + by_class[cls]["transcripts"] += 1 + by_class[cls]["raw_assistant_usage_rows"] += stats.raw_assistant_usage_rows + by_class[cls]["deduped_assistant_calls"] += stats.deduped_assistant_calls + for field_name in TOKEN_FIELDS: + by_class[cls][field_name] += stats.usage[field_name] + + top_files.append( + { + "file": path.name, + "class": cls, + "first_timestamp": iso_utc(stats.first_timestamp), + "deduped_assistant_calls": stats.deduped_assistant_calls, + "cache_creation_input_tokens": stats.usage["cache_creation_input_tokens"], + "cache_read_input_tokens": stats.usage["cache_read_input_tokens"], + "output_tokens": stats.usage["output_tokens"], + } + ) + + context_total = ( + totals["input_tokens"] + + totals["cache_creation_input_tokens"] + + totals["cache_read_input_tokens"] + ) + top_files.sort(key=lambda row: int(row["cache_read_input_tokens"]), reverse=True) + + return { + "project_dir": str(project_dir), + "transcripts": transcript_count, + "raw_assistant_usage_rows": raw_rows, + "deduped_assistant_calls": deduped_calls, + "usage": dict(totals), + "context_token_movement": context_total, + "by_class": {key: dict(value) for key, value in sorted(by_class.items())}, + "session_starts_in_window_by_class": dict(session_starts_by_class), + "top_files_by_cache_read": top_files[:15], + "top_minutes_by_calls": calls_by_minute.most_common(10), + "top_minutes_by_cache_read": cache_read_by_minute.most_common(10), + } + + +def in_window(value: datetime | None, start: datetime | None, end: datetime | None) -> bool: + if value is None: + return False + if start and value < start: + return False + if end and value > end: + return False + return True + + +def sqlite_connect_readonly(path: Path) -> sqlite3.Connection: + return sqlite3.connect(f"file:{path}?mode=ro", uri=True) + + +def table_exists(conn: sqlite3.Connection, name: str) -> bool: + row = conn.execute( + "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", + (name,), + ).fetchone() + return row is not None + + +def columns(conn: sqlite3.Connection, table: str) -> set[str]: + return {str(row[1]) for row in conn.execute(f"PRAGMA table_info({table})")} + + +def first_existing(candidates: tuple[str, ...], available: set[str]) -> str | None: + for candidate in candidates: + if candidate in available: + return candidate + return None + + +def where_time(column: str | None, start_utc: str | None, end_utc: str | None) -> tuple[str, list[Any]]: + clauses: list[str] = [] + params: list[Any] = [] + if column and start_utc: + clauses.append(f"{column} >= ?") + params.append(start_utc) + if column and end_utc: + clauses.append(f"{column} <= ?") + params.append(end_utc) + if not clauses: + return "", params + return " WHERE " + " AND ".join(clauses), params + + +def collect_agh(agh_home: Path, start: datetime | None, end: datetime | None) -> dict[str, Any]: + db_path = agh_home / "agh.db" + if not db_path.is_file(): + return {"agh_home": str(agh_home), "error": "agh.db not found"} + + start_utc = iso_utc(start) + end_utc = iso_utc(end) + result: dict[str, Any] = {"agh_home": str(agh_home), "db": str(db_path)} + + with sqlite_connect_readonly(db_path) as conn: + if table_exists(conn, "sessions"): + cols = columns(conn, "sessions") + time_col = first_existing(("created_at", "started_at", "updated_at"), cols) + where, params = where_time(time_col, start_utc, end_utc) + + group_cols = [ + col + for col in ("spawn_role", "session_type", "provider", "agent_name", "state", "failure_kind") + if col in cols + ] + if group_cols: + select_cols = ", ".join(f"COALESCE({col}, '') AS {col}" for col in group_cols) + group_by = ", ".join(group_cols) + query = ( + f"SELECT {select_cols}, COUNT(*) AS count FROM sessions" + f"{where} GROUP BY {group_by} ORDER BY count DESC" + ) + rows = conn.execute(query, params).fetchall() + result["sessions_by_role_type_provider_agent"] = [ + {**{group_cols[i]: row[i] for i in range(len(group_cols))}, "count": row[-1]} + for row in rows + ] + + if "spawn_role" in cols: + query = f"SELECT COUNT(*) FROM sessions{where} AND spawn_role = ?" if where else ( + "SELECT COUNT(*) FROM sessions WHERE spawn_role = ?" + ) + query_params = [*params, "memory-extractor"] if where else ["memory-extractor"] + result["memory_extractor_sessions"] = conn.execute(query, query_params).fetchone()[0] + + if table_exists(conn, "memory_events"): + cols = columns(conn, "memory_events") + time_col = first_existing(("created_at", "timestamp", "time"), cols) + op_col = first_existing(("op", "operation", "event_type", "type"), cols) + if op_col: + where, params = where_time(time_col, start_utc, end_utc) + rows = conn.execute( + f"SELECT {op_col}, COUNT(*) FROM memory_events{where} GROUP BY {op_col} ORDER BY COUNT(*) DESC", + params, + ).fetchall() + result["memory_events_by_op"] = [{"op": row[0], "count": row[1]} for row in rows] + + if table_exists(conn, "token_stats"): + cols = columns(conn, "token_stats") + time_col = first_existing(("created_at", "timestamp", "recorded_at", "time"), cols) + session_col = first_existing(("session_id", "session"), cols) + total_tokens_col = first_existing(("total_tokens", "context_used"), cols) + total_cost_col = first_existing(("total_cost", "cost_amount"), cols) + where_ts, params_ts = where_time(time_col, start_utc, end_utc) + if session_col and table_exists(conn, "sessions") and total_tokens_col: + cost_expr = f"SUM(ts.{total_cost_col})" if total_cost_col else "NULL" + query = ( + "SELECT COALESCE(s.spawn_role, ''), COUNT(*), " + f"SUM(ts.{total_tokens_col}), {cost_expr} " + f"FROM token_stats ts JOIN sessions s ON s.id = ts.{session_col}" + f"{where_ts} GROUP BY COALESCE(s.spawn_role, '') ORDER BY COUNT(*) DESC" + ) + rows = conn.execute(query, params_ts).fetchall() + result["token_stats_by_spawn_role"] = [ + { + "spawn_role": row[0], + "rows": row[1], + "total_tokens_or_context_used": row[2], + "total_cost": row[3], + } + for row in rows + ] + + if table_exists(conn, "network_audit_log"): + cols = columns(conn, "network_audit_log") + time_col = first_existing(("created_at", "timestamp", "time"), cols) + verb_col = first_existing(("verb", "message_type", "kind", "op"), cols) + direction_col = first_existing(("direction", "flow"), cols) + where, params = where_time(time_col, start_utc, end_utc) + if verb_col: + select = f"{verb_col}" + group = verb_col + if direction_col: + select += f", {direction_col}" + group += f", {direction_col}" + rows = conn.execute( + f"SELECT {select}, COUNT(*) FROM network_audit_log{where} GROUP BY {group} ORDER BY COUNT(*) DESC", + params, + ).fetchall() + result["network_audit_counts"] = [ + ( + {"verb": row[0], "direction": row[1], "count": row[2]} + if direction_col + else {"verb": row[0], "count": row[1]} + ) + for row in rows + ] + + result["crash_bundles"] = collect_crash_bundles(agh_home) + return result + + +def collect_crash_bundles(agh_home: Path) -> dict[str, Any]: + crash_dir = agh_home / "logs" / "crash-bundles" + if not crash_dir.is_dir(): + return {"dir": str(crash_dir), "files": 0} + + counters: Counter[str] = Counter() + for path in crash_dir.glob("*.json"): + try: + text = path.read_text(encoding="utf-8", errors="replace") + except OSError: + continue + counters["files"] += 1 + lowered = text.lower() + if "rate_limit" in lowered or "session limit" in lowered: + counters["rate_or_session_limit"] += 1 + if "prompt_failure" in lowered: + counters["prompt_failure"] += 1 + if "process_exit" in lowered: + counters["process_exit"] += 1 + + return {"dir": str(crash_dir), **dict(counters)} + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--claude-project", default="~/.claude/projects/-Users-pedronauck-Desktop-test") + parser.add_argument("--agh-home", default="~/.agh") + parser.add_argument("--start-utc", default="2026-05-26T20:50:00Z") + parser.add_argument("--end-utc", default="2026-05-26T21:45:00Z") + return parser.parse_args() + + +def main() -> int: + args = parse_args() + start = parse_time(args.start_utc) + end = parse_time(args.end_utc) + claude_project = Path(args.claude_project).expanduser() + agh_home = Path(args.agh_home).expanduser() + + payload = { + "window_utc": {"start": iso_utc(start), "end": iso_utc(end)}, + "claude": collect_claude(claude_project, start, end) if claude_project.is_dir() else { + "project_dir": str(claude_project), + "error": "directory not found", + }, + "agh": collect_agh(agh_home, start, end), + } + print(json.dumps(payload, indent=2, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) + diff --git a/.compozy/tasks/tokens-perf/analysis/screenshots/task-007-settings-memory-default.png b/.compozy/tasks/tokens-perf/analysis/screenshots/task-007-settings-memory-default.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc41b852fa24d93df39f653dccad9e79cd93058 GIT binary patch literal 145484 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 z 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 Mo|{|hoWxcFB-B@6 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

#Sf-Oh;Rr++jNL{J4(O4A+Vh*J>+H-3N=@ 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