chore: add ClawHub autoreview skill (#2294)

This commit is contained in:
Patrick Erichsen
2026-05-18 10:53:23 -07:00
committed by GitHub
parent ba587040b0
commit f9072e53e1
4 changed files with 742 additions and 0 deletions
+196
View File
@@ -0,0 +1,196 @@
---
name: autoreview
description: "Use when ClawHub needs Codex review, autoreview, second-model review, or a final advisory review gate before commit, PR update, ship, or maintainer handoff."
---
# Autoreview
Run Codex's built-in code review as a closeout check. This is code review
(`codex review`), not Guardian `auto_review` approval routing.
Codex native review mode performs best and is recommended. Non-Codex reviewers
are fallback or second-opinion paths that receive a generated diff prompt, not
the full Codex review-mode runtime.
Use when:
- the user asks for Codex review, autoreview, or second-model review
- after non-trivial code edits, before final/commit/ship
- reviewing a local branch or PR branch after fixes
- closing out ClawHub maintainer work that touched source, tests, Convex, UI,
CLI packages, or workflows
## 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 the selected review path returns no accepted/actionable
findings.
- If a review-triggered fix changes code, rerun focused tests and rerun the
review helper.
- Default to Codex review. If Codex is unavailable or exits with an error, the
helper can fall back to `claude -p`, `pi -p`, `opencode run`, `droid exec`, or
`copilot`.
- Stop as soon as the review command/helper exits 0 with no
accepted/actionable findings. Do not run an extra direct `codex review` just
to get a nicer clean line, a second opinion, or clearer closeout wording.
- 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
future reviewers should know.
- Do not push just to review. Push only when the user requested push/ship/PR
update.
## ClawHub Proof Routing
Pick the smallest proof that matches the touched surface:
| Touched surface | Usual proof |
| --- | --- |
| Formatting/lint/static repo health | `bun run ci:static` |
| Unit-tested source behavior | focused `bunx vitest run ...`, then `bun run ci:unit` when PR-ready |
| Convex code | read `convex/_generated/ai/guidelines.md` first; run focused tests and the deploy/typecheck path that covers the change |
| Packages/CLI/mod tool | `bun run ci:packages` or the package-specific `verify` script |
| Runtime/build/package surface | `bun run ci:types-build`, `bun run ci:e2e-http`, or the matching broader gate |
| UI behavior | use `clawhub-ui-proof` with `proof:ui`; publish proof before final PR comments when needed |
| Linux/CI-parity validation | use `crabbox`, normally through the repo scripts |
For Convex query or schema work, apply the repo's Convex rules: prefer indexes
over `.filter()` scans, use cursor-based backfills for data shape changes, and
verify with the repo's Convex/typecheck path before claiming deploy safety.
## Pick Target
Dirty local work:
```bash
codex review --uncommitted
```
Use this only when the patch is actually unstaged/staged/untracked in the
current checkout. For committed, pushed, or PR work, point Codex at the commit
or branch diff instead. A clean `--uncommitted` review only proves there is no
local patch.
Branch/PR work:
```bash
git fetch origin
codex review --base origin/main
```
If an open PR exists, use its actual base:
```bash
base=$(gh pr view --json baseRefName --jq .baseRefName)
codex review --base "origin/$base"
```
Do not pass a prompt with `--base`. Some Codex CLI versions reject
`codex review --base <ref> -` with `--base <BRANCH> cannot be used with
[PROMPT]`. If that happens, rerun plain `codex review --base <ref>` and report
that prompt injection was skipped.
Committed single change:
```bash
codex review --commit HEAD
```
or with the helper:
```bash
.agents/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
.agents/skills/autoreview/scripts/autoreview --parallel-tests "bun run ci:static"
```
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.
## Context Efficiency
Codex review is usually noisy. Default to a subagent filter when subagents are
available. Ask it to run the review and return only:
- actionable findings it accepts
- findings it rejects, with one-line reason
- exact files/tests to rerun
Run inline only for tiny changes or when subagents are unavailable.
## Helper
Bundled helper:
```bash
.agents/skills/autoreview/scripts/autoreview --help
```
The helper:
- chooses dirty `--uncommitted` first
- otherwise uses current PR base if `gh pr view` works
- otherwise uses `origin/main` for non-main branches
- auto-runs `bun run ci:static` in parallel when the repo has `package.json`,
`bun.lock`, `node_modules`, and a `ci:static` script; disable with
`AUTOREVIEW_AUTO_TESTS=0`
- use `--mode commit --commit <ref>` 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
- supports `--reviewer codex|claude|pi|opencode|droid|copilot|auto`; `auto`
means Codex first
- supports `--fallback-reviewer auto|claude|pi|opencode|droid|copilot|none`
- falls back only when Codex is unavailable or exits nonzero without findings,
not when Codex reports findings
- writes only to stdout unless `--output` or `AUTOREVIEW_OUTPUT` is set
- supports `--dry-run`, `--parallel-tests`, and commit refs
- runs nested review with `--dangerously-bypass-approvals-and-sandbox --sandbox
danger-full-access` by default; use `--no-yolo` or `AUTOREVIEW_YOLO=0` to opt
out
- prints `autoreview clean: no accepted/actionable findings reported` when the
selected review command exits 0 and no accepted/actionable findings are
reported
## 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 Codex review solely to improve final wording. If the final
helper run exited 0 and produced no accepted/actionable findings, report that
exact run as clean.
## PR / CI Closeout
- Prefer direct run/job APIs after CI starts: `gh run view <run-id> --json jobs`;
use PR rollup only for final mergeability.
- After rebase, compare `origin/main..HEAD`; drop CI-fix commits already
upstream before pushing.
- Update the PR body once near the final head unless proof labels are missing
or stale enough to block CI.
+543
View File
@@ -0,0 +1,543 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: autoreview [options]
Options:
--mode auto|local|branch|commit
Target selection. Default: auto.
--base REF
Base ref for branch review. Default: PR base or origin/main.
--commit REF
Commit ref for commit review. Default: HEAD.
--reviewer codex|claude|pi|opencode|droid|copilot|auto
Review engine. Default: Codex with configured fallback on error.
--fallback-reviewer auto|claude|pi|opencode|droid|copilot|none
Fallback when Codex is unavailable or exits nonzero without findings.
--codex-bin PATH
Codex binary. Default: codex.
--claude-bin PATH
Claude binary. Default: claude.
--pi-bin PATH
Pi binary. Default: pi.
--opencode-bin PATH
OpenCode binary. Default: opencode.
--droid-bin PATH
Droid binary. Default: droid.
--copilot-bin PATH
GitHub Copilot binary. Default: copilot.
--full-access
Keep yolo/full-access mode enabled. Default.
--no-yolo
Run nested Codex review with normal sandbox/approval prompts.
--output FILE
Also save output to file.
--parallel-tests CMD
Run review and test command concurrently. Pass "" to disable auto-tests.
Default: bun run ci:static when package.json, bun.lock, node_modules, and
a ci:static script are present.
--dry-run
Print selected commands, do not run.
-h, --help
Show help.
Modes:
local codex review --uncommitted
branch codex review --base <ref>
commit codex review --commit <ref>
auto dirty tree -> local, else PR/current branch -> branch
EOF
}
mode=auto
base_ref=
commit_ref=HEAD
reviewer=${AUTOREVIEW_REVIEWER:-${CODEX_REVIEW_REVIEWER:-auto}}
fallback_reviewer=${AUTOREVIEW_FALLBACK_REVIEWER:-${CODEX_REVIEW_FALLBACK_REVIEWER:-auto}}
codex_bin=${CODEX_BIN:-codex}
claude_bin=${CLAUDE_BIN:-claude}
pi_bin=${PI_BIN:-pi}
opencode_bin=${OPENCODE_BIN:-opencode}
droid_bin=${DROID_BIN:-droid}
copilot_bin=${COPILOT_BIN:-copilot}
yolo=${AUTOREVIEW_YOLO:-${CODEX_REVIEW_YOLO:-1}}
output=${AUTOREVIEW_OUTPUT:-${CODEX_REVIEW_OUTPUT:-}}
parallel_tests=
parallel_tests_set=false
parallel_tests_auto=false
dry_run=false
while [[ $# -gt 0 ]]; do
case "$1" in
--mode) mode=${2:-}; shift 2 ;;
--base) base_ref=${2:-}; shift 2 ;;
--commit) commit_ref=${2:-}; shift 2 ;;
--reviewer) reviewer=${2:-}; shift 2 ;;
--fallback-reviewer) fallback_reviewer=${2:-}; shift 2 ;;
--codex-bin) codex_bin=${2:-}; shift 2 ;;
--claude-bin) claude_bin=${2:-}; shift 2 ;;
--pi-bin) pi_bin=${2:-}; shift 2 ;;
--opencode-bin) opencode_bin=${2:-}; shift 2 ;;
--droid-bin) droid_bin=${2:-}; shift 2 ;;
--copilot-bin) copilot_bin=${2:-}; shift 2 ;;
--full-access) yolo=1; shift ;;
--no-yolo) yolo=0; shift ;;
--output) output=${2:-}; shift 2 ;;
--parallel-tests) parallel_tests=${2:-}; parallel_tests_set=true; shift 2 ;;
--dry-run) dry_run=true; shift ;;
-h|--help) usage; exit 0 ;;
*) usage >&2; exit 2 ;;
esac
done
case "$mode" in
auto|local|branch|commit) ;;
*) echo "invalid --mode: $mode" >&2; exit 2 ;;
esac
case "$reviewer" in
auto|codex|claude|pi|opencode|droid|copilot) ;;
*) echo "invalid --reviewer: $reviewer" >&2; exit 2 ;;
esac
case "$fallback_reviewer" in
auto|claude|pi|opencode|droid|copilot|none) ;;
*) echo "invalid --fallback-reviewer: $fallback_reviewer" >&2; exit 2 ;;
esac
repo_root=$(git rev-parse --show-toplevel)
current_branch=$(git branch --show-current 2>/dev/null || true)
dirty=false
if [[ -n "$(git status --porcelain)" ]]; then
dirty=true
fi
codex_args=()
case "$yolo" in
0|false|False|FALSE|no|No|NO|off|Off|OFF) ;;
*) codex_args+=(--dangerously-bypass-approvals-and-sandbox --sandbox danger-full-access) ;;
esac
has_package_script() {
local script_name=$1
command -v node >/dev/null 2>&1 || return 1
node -e '
const { readFileSync } = require("node:fs");
const pkg = JSON.parse(readFileSync(process.argv[1], "utf8"));
process.exit(pkg.scripts?.[process.argv[2]] ? 0 : 1);
' "$repo_root/package.json" "$script_name" >/dev/null 2>&1
}
auto_tests_disabled() {
case "${AUTOREVIEW_AUTO_TESTS:-${CODEX_REVIEW_AUTO_TESTS:-1}}" in
0|false|False|FALSE|no|No|NO|off|Off|OFF) return 0 ;;
*) return 1 ;;
esac
}
pr_url=
if [[ -z "$base_ref" && "$mode" != local ]] && command -v gh >/dev/null 2>&1; then
if pr_lines=$(gh pr view --json baseRefName,url --jq '[.baseRefName, .url] | @tsv' 2>/dev/null); then
base_name=${pr_lines%%$'\t'*}
pr_url=${pr_lines#*$'\t'}
if [[ -n "$base_name" ]]; then
base_ref="origin/$base_name"
fi
fi
fi
if [[ -z "$base_ref" ]]; then
base_ref=origin/main
fi
review_kind=
if [[ "$mode" == local || ( "$mode" == auto && "$dirty" == true ) ]]; then
review_kind=local
elif [[ "$mode" == commit ]]; then
review_kind=commit
elif [[ "$mode" == branch || ( "$mode" == auto && -n "$current_branch" && "$current_branch" != "main" ) ]]; then
review_kind=branch
else
echo "no review target: clean main checkout and no forced mode" >&2
exit 1
fi
if [[ "$review_kind" == local ]]; then
review_cmd=("$codex_bin" "${codex_args[@]}" review --uncommitted)
elif [[ "$review_kind" == commit ]]; then
review_cmd=("$codex_bin" "${codex_args[@]}" review --commit "$commit_ref")
else
review_cmd=("$codex_bin" "${codex_args[@]}" review --base "$base_ref")
fi
if [[ "$parallel_tests_set" == false && -z "$parallel_tests" ]] && ! auto_tests_disabled; then
if [[ -f "$repo_root/package.json" && -f "$repo_root/bun.lock" && -d "$repo_root/node_modules" ]] &&
command -v bun >/dev/null 2>&1 && has_package_script ci:static; then
printf -v quoted_repo_root '%q' "$repo_root"
parallel_tests="cd $quoted_repo_root && bun run ci:static"
parallel_tests_auto=true
fi
fi
printf 'autoreview target: %s\n' "$review_kind"
printf 'branch: %s\n' "${current_branch:-detached}"
if [[ -n "$pr_url" ]]; then
printf 'pr: %s\n' "$pr_url"
fi
if [[ "$reviewer" == auto ]]; then
printf 'reviewer: codex\n'
else
printf 'reviewer: %s\n' "$reviewer"
fi
if [[ "$reviewer" == auto || "$reviewer" == codex ]]; then
printf 'review:'
printf ' %q' "${review_cmd[@]}"
printf '\n'
else
printf 'review: %s prompt review\n' "$reviewer"
fi
if [[ -n "$parallel_tests" ]]; then
printf 'tests: %s' "$parallel_tests"
if [[ "$parallel_tests_auto" == true ]]; then
printf ' (auto)'
fi
printf '\n'
fi
if [[ "$review_kind" == branch ]]; then
printf 'fetch: git fetch origin --quiet\n'
fi
if [[ -n "$output" ]]; then
printf 'output: %s\n' "$output"
fi
if [[ "$dry_run" == true ]]; then
exit 0
fi
if [[ "$review_kind" == branch ]]; then
git fetch origin --quiet || {
echo "warning: git fetch origin failed; reviewing with existing refs" >&2
}
fi
review_output=$output
review_output_is_temp=false
prompt_file=
if [[ -z "$review_output" ]]; then
review_output=$(mktemp)
review_output_is_temp=true
fi
mkdir -p "$(dirname "$review_output")"
: > "$review_output"
cleanup() {
if [[ "${review_output_is_temp:-false}" == true && -n "${review_output:-}" ]]; then
rm -f "$review_output"
fi
if [[ -n "${prompt_file:-}" ]]; then
rm -f "$prompt_file"
fi
}
trap cleanup EXIT
diff_for_review() {
case "$review_kind" in
local)
git -C "$repo_root" diff --stat
git -C "$repo_root" diff --cached --stat
git -C "$repo_root" diff --find-renames
git -C "$repo_root" diff --cached --find-renames
while IFS= read -r untracked_file; do
[[ -n "$untracked_file" ]] || continue
git -C "$repo_root" diff --no-index -- /dev/null "$untracked_file" || true
done < <(git -C "$repo_root" ls-files --others --exclude-standard)
;;
commit)
git -C "$repo_root" show --find-renames --stat --format=fuller "$commit_ref"
git -C "$repo_root" show --find-renames --format=medium "$commit_ref"
;;
branch)
git -C "$repo_root" diff --find-renames --stat "$base_ref"...HEAD
git -C "$repo_root" diff --find-renames "$base_ref"...HEAD
;;
esac
}
build_prompt_file() {
prompt_file=$(mktemp)
{
cat <<'EOF'
You are reviewing a ClawHub diff.
Return only accepted/actionable findings. Verify claims against the diff and
reject speculative, low-value, or overbroad rewrites.
Use this format for findings:
[P1] Short title
File: path:line
Why: one sentence
Fix: one sentence
If no accepted/actionable findings, output exactly:
autoreview clean: no accepted/actionable findings reported
Diff:
EOF
diff_for_review
} > "$prompt_file"
}
review_output_has_clean_marker() {
local path=$1
grep -Eq '^[^[:alnum:]]*autoreview clean: no accepted/actionable findings reported[[:space:]]*$' "$path"
}
review_output_has_findings() {
grep -Eq '\[P[0-3]\]' "$review_output"
}
review_output_empty() {
[[ ! -s "$review_output" ]] || ! grep -q '[^[:space:]]' "$review_output"
}
review_output_used_prompt_reviewer() {
grep -Eq '^fallback: (claude -p|pi -p|opencode run|droid exec|copilot)$' "$review_output"
}
run_codex_review() {
if ! command -v "$codex_bin" >/dev/null 2>&1; then
echo "codex reviewer unavailable: $codex_bin" >&2
return 127
fi
"${review_cmd[@]}" 2>&1 | tee "$review_output"
}
run_prompt_reviewer() {
local selected=$1
local status=0
local prompt_bytes=0
local copilot_prompt=
build_prompt_file
case "$selected" in
claude)
command -v "$claude_bin" >/dev/null 2>&1 || {
echo "fallback reviewer unavailable: $claude_bin" >&2
return 127
}
printf 'fallback: claude -p\n' | tee -a "$review_output"
"$claude_bin" --tools "" --no-session-persistence -p < "$prompt_file" 2>&1 | tee -a "$review_output"
status=${PIPESTATUS[0]}
;;
pi)
command -v "$pi_bin" >/dev/null 2>&1 || {
echo "fallback reviewer unavailable: $pi_bin" >&2
return 127
}
printf 'fallback: pi -p\n' | tee -a "$review_output"
"$pi_bin" --no-tools --no-session -p < "$prompt_file" 2>&1 | tee -a "$review_output"
status=${PIPESTATUS[0]}
;;
opencode)
command -v "$opencode_bin" >/dev/null 2>&1 || {
echo "fallback reviewer unavailable: $opencode_bin" >&2
return 127
}
printf 'fallback: opencode run\n' | tee -a "$review_output"
"$opencode_bin" run --pure --dir "$repo_root" "Review the attached prompt file. Do not modify files." --file "$prompt_file" 2>&1 | tee -a "$review_output"
status=${PIPESTATUS[0]}
;;
droid)
command -v "$droid_bin" >/dev/null 2>&1 || {
echo "fallback reviewer unavailable: $droid_bin" >&2
return 127
}
printf 'fallback: droid exec\n' | tee -a "$review_output"
"$droid_bin" exec --cwd "$repo_root" -f "$prompt_file" 2>&1 | tee -a "$review_output"
status=${PIPESTATUS[0]}
;;
copilot)
command -v "$copilot_bin" >/dev/null 2>&1 || {
echo "fallback reviewer unavailable: $copilot_bin" >&2
return 127
}
printf 'fallback: copilot\n' | tee -a "$review_output"
prompt_bytes=$(wc -c < "$prompt_file" | tr -d '[:space:]')
if (( prompt_bytes > 120000 )); then
echo "copilot reviewer unavailable: generated prompt is too large" | tee -a "$review_output"
status=1
else
copilot_prompt=$(< "$prompt_file")
"$copilot_bin" -C "$repo_root" --available-tools=none --stream off --output-format text --silent -p "$copilot_prompt" 2>&1 | tee -a "$review_output"
status=${PIPESTATUS[0]}
fi
;;
*)
echo "unsupported prompt reviewer: $selected" >&2
status=2
;;
esac
rm -f "$prompt_file"
prompt_file=
return "$status"
}
fallback_reviewer_is_available() {
local selected=$1
case "$selected" in
claude) command -v "$claude_bin" >/dev/null 2>&1 ;;
pi) command -v "$pi_bin" >/dev/null 2>&1 ;;
opencode) command -v "$opencode_bin" >/dev/null 2>&1 ;;
droid) command -v "$droid_bin" >/dev/null 2>&1 ;;
copilot) command -v "$copilot_bin" >/dev/null 2>&1 ;;
*) return 1 ;;
esac
}
run_selected_review() {
local selected=$1
case "$selected" in
codex) run_codex_review ;;
claude|pi|opencode|droid|copilot) run_prompt_reviewer "$selected" ;;
*) echo "unsupported reviewer: $selected" >&2; return 2 ;;
esac
}
run_auto_fallback_review() {
local selected
if [[ "$fallback_reviewer" != auto ]]; then
run_selected_review "$fallback_reviewer"
return $?
fi
for selected in claude pi opencode droid copilot; do
if fallback_reviewer_is_available "$selected"; then
run_selected_review "$selected"
return $?
fi
done
echo "fallback reviewer unavailable: no configured fallback CLI found" >&2
return 127
}
run_auto_review() {
local status=0
run_selected_review codex
status=$?
if [[ "$status" == 0 ]]; then
return 0
fi
if (( status > 128 && status < 192 )); then
return "$status"
fi
if review_output_has_findings; then
return "$status"
fi
if [[ "$fallback_reviewer" == none ]]; then
return "$status"
fi
if [[ "$fallback_reviewer" == auto ]]; then
printf 'autoreview warning: codex exited %s; trying configured fallback reviewers\n' "$status" >&2
else
printf 'autoreview warning: codex exited %s; falling back to %s\n' "$status" "$fallback_reviewer" >&2
fi
run_auto_fallback_review
}
elapsed_since() {
local started_at=$1
local finished_at
finished_at=$(date +%s)
printf '%s\n' "$((finished_at - started_at))"
}
format_elapsed() {
local seconds=$1
if (( seconds < 60 )); then
printf '%ss\n' "$seconds"
else
printf '%sm%ss\n' "$((seconds / 60))" "$((seconds % 60))"
fi
}
report_clean_review_or_fail() {
local elapsed_text
elapsed_text=$(format_elapsed "${review_elapsed_seconds:-0}")
if review_output_has_findings; then
printf 'autoreview complete after %s\n' "$elapsed_text"
printf 'autoreview findings: accepted/actionable findings reported\n'
return 1
fi
if review_output_empty; then
printf 'autoreview complete after %s; no output\n' "$elapsed_text"
return 1
fi
if review_output_used_prompt_reviewer && ! review_output_has_clean_marker "$review_output"; then
printf 'autoreview complete after %s\n' "$elapsed_text"
printf 'autoreview findings: prompt reviewer did not emit clean marker\n'
return 1
fi
printf 'autoreview complete after %s\n' "$elapsed_text"
printf 'autoreview clean: no accepted/actionable findings reported\n'
}
if [[ -z "$parallel_tests" ]]; then
review_started_at=$(date +%s)
set +e
if [[ "$reviewer" == auto ]]; then
run_auto_review
else
run_selected_review "$reviewer"
fi
review_status=$?
review_elapsed_seconds=$(elapsed_since "$review_started_at")
set -e
if [[ "$review_status" == 0 ]]; then
report_clean_review_or_fail
exit $?
fi
exit "$review_status"
fi
review_status_file=$(mktemp)
review_elapsed_file=$(mktemp)
tests_status_file=$(mktemp)
(
set +e
review_started_at=$(date +%s)
if [[ "$reviewer" == auto ]]; then
run_auto_review
else
run_selected_review "$reviewer"
fi
status=$?
elapsed=$(elapsed_since "$review_started_at")
printf '%s\n' "$status" > "$review_status_file"
printf '%s\n' "$elapsed" > "$review_elapsed_file"
) &
review_pid=$!
(
set +e
bash -lc "$parallel_tests"
status=$?
printf '%s\n' "$status" > "$tests_status_file"
) &
tests_pid=$!
wait "$review_pid" || true
wait "$tests_pid" || true
review_status=$(cat "$review_status_file")
review_elapsed_seconds=$(cat "$review_elapsed_file")
tests_status=$(cat "$tests_status_file")
rm -f "$review_status_file" "$review_elapsed_file" "$tests_status_file"
printf 'autoreview exit: %s\n' "$review_status"
printf 'tests exit: %s\n' "$tests_status"
if [[ "$review_status" != 0 || "$tests_status" != 0 ]]; then
exit 1
fi
report_clean_review_or_fail
+2
View File
@@ -49,6 +49,8 @@ skills-lock.json
!.agents/skills/clawhub-pr-maintainer/**
!.agents/skills/clawhub-moderation/
!.agents/skills/clawhub-moderation/**
!.agents/skills/autoreview/
!.agents/skills/autoreview/**
skills/*
.codex/*
!.codex/environments/
+1
View File
@@ -48,6 +48,7 @@
- Commit messages: Conventional Commits (`feat:`, `fix:`, `chore:`, `docs:`…).
- Keep changes scoped; avoid repo-wide search/replace.
- Before commit/PR handoff, run `bun run ci:static` so formatting, linting, audit/peer checks, and dead-code export checks match the CI `static` job. For faster inner loops, targeted `bun run format:check -- <files>` / `bun run lint` are fine, but do not treat them as the final pre-push gate.
- Before commit/PR handoff for non-trivial code changes, use `$autoreview` until no accepted/actionable findings remain, unless equivalent manual review already happened, the change is trivial/docs-only, or the user opts out.
- Before opening a PR for source or test changes, run the targeted tests for the touched behavior and `bun run ci:unit` (`VITE_CONVEX_URL=https://example.invalid bun run coverage`) unless the change is docs/config-only or the user explicitly asks to rely on CI. For runtime, build, or package changes, also run the matching broader gate when it covers the touched surface: `bun run ci:types-build`, `bun run ci:packages`, `bun run ci:e2e-http`, or `bun run ci:playwright-smoke`.
- PRs: include summary + test commands run. Add screenshots for UI changes.
- Before merging any PR, verify TypeScript cleanly with `bunx tsc -p packages/schema/tsconfig.json --noEmit` and `bunx tsc -p packages/clawhub/tsconfig.json --noEmit`; if Convex code changed, also run the repo typecheck path used by deploy so `bunx convex deploy` will not fail on `tsc`.