Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ common:ci --disk_cache=
# Shared config for the main Bazel CI workflow.
common:ci-bazel --config=ci
common:ci-bazel --build_metadata=TAG_workflow=bazel
# Keep code-mode integration cases out of ordinary Bazel legs. The
# Windows-cross config below re-enables them after generating its Windows V8
# snapshot on the Windows runner. Also skip the ConPTY Ctrl-C integration test
# until Windows Bazel CI can reliably interrupt foreground processes.
common:ci-bazel --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=suite::code_mode::,tests::windows_tests::conpty_ctrl_c_interrupts_powershell_foreground_child

# Shared config for Bazel-backed Rust linting.
build:clippy --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect
Expand All @@ -117,7 +122,6 @@ build:clippy --@rules_rust//rust/settings:clippy.toml=//codex-rs:clippy.toml
build:clippy --@rules_rust//rust/settings:clippy_flag=-Dwarnings
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::await_holding_invalid_type
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::await_holding_lock
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::disallowed_methods
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::expect_used
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::identity_op
build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_clamp
Expand Down Expand Up @@ -161,9 +165,6 @@ build:argument-comment-lint --@rules_rust//rust/toolchain/channel=nightly
common:ci-windows --config=ci-bazel
common:ci-windows --build_metadata=TAG_os=windows
common:ci-windows --repo_contents_cache=D:/a/.cache/bazel-repo-contents-cache
# The hidden dynamic-tool callback currently times out on Windows, and ConPTY
# cannot reliably interrupt foreground processes on Windows Bazel runners.
common:ci-windows --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=suite::code_mode::code_mode_can_call_hidden_dynamic_tools,tests::windows_tests::conpty_ctrl_c_interrupts_powershell_foreground_child

# We prefer to run the build actions entirely remotely so we can dial up the concurrency.
# We have platform-specific tests, so we want to execute the tests on all platforms using the strongest sandboxing available on each platform.
Expand All @@ -174,6 +175,24 @@ common:ci-linux --config=ci-bazel
common:ci-linux --build_metadata=TAG_os=linux
common:ci-linux --platforms=//:rbe

# GitLab Bazel CI uses the same hermetic Linux target as GitHub CI, but the
# managed Bazel runner injects its BuildBuddy auth through the runner home
# `.bazelrc` instead of requiring the repo to carry endpoint or secret flags.
common:ci-gitlab --config=ci-bazel
common:ci-gitlab --build_metadata=ROLE=GITLAB_CI
common:ci-gitlab --build_metadata=VISIBILITY=INTERNAL
common:ci-gitlab --build_metadata=TAG_ci_provider=gitlab

# Managed Bazel runners with injected BuildBuddy auth use the remote Linux
# platform. The local fallback keeps the same GNU/Linux ABI on the runner host.
common:ci-gitlab-linux --config=ci-gitlab
common:ci-gitlab-linux --build_metadata=TAG_os=linux
common:ci-gitlab-linux --platforms=//:rbe

common:ci-gitlab-local-linux --config=ci-gitlab
common:ci-gitlab-local-linux --build_metadata=TAG_os=linux
common:ci-gitlab-local-linux --platforms=//:local_linux

# On mac, we can run all the build actions remotely but test actions locally.
common:ci-macos --config=ci-bazel
common:ci-macos --build_metadata=TAG_os=macos
Expand All @@ -189,11 +208,13 @@ common:ci-windows-cross --strategy=TestRunner=local
# V8 embeds IsolateData offsets in snapshot builtins; Windows snapshots must be
# generated by a Windows mksnapshot binary rather than the Linux RBE host tool.
common:ci-windows-cross --strategy=V8Mksnapshot=local
common:ci-windows-cross --local_test_jobs=8
common:ci-windows-cross --local_test_jobs=4
common:ci-windows-cross --test_env=RUST_TEST_THREADS=1
# Native Windows CI still covers the PowerShell parser-process tests. The
# cross-built gnullvm binaries currently hang in those tests when run on the
# Windows runner. This replaces the Windows skip list, so retain its exclusions.
# Windows runner. Keep V8-backed code-mode tests enabled except for the hidden
# dynamic-tool callback test, which currently times out on Windows. This config
# replaces the base skip list, so repeat the exact ConPTY Ctrl-C test exclusion.
common:ci-windows-cross --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=command_safety::powershell_parser::tests::,suite::code_mode::code_mode_can_call_hidden_dynamic_tools,tests::windows_tests::conpty_ctrl_c_interrupts_powershell_foreground_child
common:ci-windows-cross --platforms=//:windows_x86_64_gnullvm
common:ci-windows-cross --extra_execution_platforms=//:rbe,//:windows_x86_64_msvc
Expand Down
1 change: 0 additions & 1 deletion .codex/environments/environment.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
version = 1
name = "codex"

# TODO(anp) make it optional to specify this field
[setup]
script = ""

Expand Down
41 changes: 6 additions & 35 deletions .codex/skills/babysit-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Accept any of the following:
3. Inspect the `actions` list in the JSON response.
4. If `diagnose_ci_failure` is present, inspect failed run logs and classify the failure.
5. If the failure is likely caused by the current branch, patch code locally, commit, and push. Do not patch random flaky tests, CI infrastructure, dependency outages, runner issues, or other failures that are unrelated to the branch.
6. If `process_review_comment` is present, inspect surfaced published review items and decide whether to address them.
7. If a review item is actionable and correct, patch code locally, commit, push, and then resolve the associated review thread only when allowed by the GitHub state mutation policy below.
6. If `process_review_comment` is present, inspect surfaced review items and decide whether to address them.
7. If a review item is actionable and correct, patch code locally, commit, push, and then mark the associated review thread/comment as resolved once the fix is on GitHub.
8. Do not post replies to human-authored review comments/threads unless the user explicitly confirms the exact response. If a human review item is non-actionable, already addressed, or not valid, surface the item and recommended response to the user instead of replying on GitHub.
9. If the failure is likely flaky/unrelated and `retry_failed_checks` is present, rerun failed jobs with `--retry-failed-now`.
10. If both actionable review feedback and `retry_failed_checks` are present, prioritize review feedback first; a new commit will retrigger CI, so avoid rerunning flaky checks on the old SHA unless you intentionally defer the review change.
Expand Down Expand Up @@ -92,52 +92,23 @@ The watcher surfaces review items from:
- Inline review comments
- Review submissions (COMMENT / APPROVED / CHANGES_REQUESTED)

Only act on published feedback. Ignore review submissions in GitHub's `PENDING` state and inline
comments attached to those pending reviews. Do not mark pending review feedback as seen; it should
be eligible to surface after the reviewer submits the review.

It intentionally surfaces Codex reviewer bot feedback (for example comments/reviews from `chatgpt-codex-connector[bot]`) in addition to human reviewer feedback. Most unrelated bot noise should still be ignored.
For safety, the watcher only auto-surfaces trusted human review authors (for example repo OWNER/MEMBER/COLLABORATOR, plus the authenticated operator) and approved review bots such as Codex.
On a fresh watcher state file, existing unaddressed published review feedback may be surfaced immediately (not only comments that arrive after monitoring starts). This is intentional so already-open review comments are not missed.
On a fresh watcher state file, existing pending review feedback may be surfaced immediately (not only comments that arrive after monitoring starts). This is intentional so already-open review comments are not missed.

When you agree with a comment and it is actionable:

1. Patch code locally.
2. Commit with `codex: address PR review feedback (#<n>)`.
3. Push to the PR head branch.
4. After the push succeeds, resolve the associated GitHub review thread only when allowed by the GitHub state mutation policy below.
4. After the push succeeds, mark the associated GitHub review thread/comment as resolved.
5. Resume watching on the new SHA immediately (do not stop after reporting the push).
6. If monitoring was running in `--watch` mode, restart `--watch` immediately after the push in the same turn; do not wait for the user to ask again.

Do not post replies to human-authored GitHub review comments/threads automatically. If you disagree with a human comment, believe it is non-actionable/already addressed, or need to answer a question, report the item to the user with a suggested response and wait for explicit confirmation before posting anything on GitHub. If the user approves a response, prefix it with `[codex]` so it is clear the response is automated and not from the human user.
If the watcher later surfaces your own approved reply because the authenticated operator is treated as a trusted review author, treat that self-authored item as already handled and do not reply again.
If a code review comment/thread is already marked as resolved in GitHub, treat it as non-actionable and safely ignore it unless new unresolved follow-up feedback appears.

## GitHub State Mutation Policy

You can read any PR state you need for monitoring. Writes must comply with this policy.

You can push PRs to update the code under review or to force CI re-runs as described above.

You can resolve review comment threads from the human who requested babysitting or from the Codex
review bot. When resolving, leave a comment prefixed with `[from Codex]: ` and explain what changes
you made and which commit includes them. Don't touch review threads if other humans other than the
user who requested babysitting have participated.

Before making any changes, fetch the PR state yourself instead of relying on the PR watcher script's
output.

Unless explicitly asked, do not:

* comment on other humans' review threads, communicate with the user in chat instead
* resolve review threads from humans other than the user
* interact with humans other than the user
* mark PRs as drafts or ready for review
* close or reopen PRs

In general, never act on GitHub in ways that would make it hard to tell whether you or the user did
something visible to other humans. When in doubt, ask the user for clarification in chat.

## Git Safety Rules

- Work only on the PR head branch.
Expand All @@ -162,10 +133,10 @@ Use this loop in a live Codex session:
3. First check whether the PR is now merged or otherwise closed; if so, report that terminal state and stop polling immediately.
4. Check CI summary, new review items, and mergeability/conflict status.
5. Diagnose CI failures and classify branch-related vs flaky/unrelated. If the overall run is still pending but `failed_jobs` already includes a failed job, fetch that job's logs and diagnose immediately instead of waiting for the whole workflow run to finish. Patch only when the failure is branch-related.
6. For each surfaced review item from another author, patch/commit/push if it is actionable, then resolve it only when allowed by the GitHub state mutation policy above. If it is non-actionable, already addressed, or requires a written answer, surface it to the user with a suggested response instead of posting automatically. If a later snapshot surfaces your own approved reply, treat it as informational and continue without responding again.
6. For each surfaced review item from another author, patch/commit/push and then resolve it if it is actionable. If it is non-actionable, already addressed, or requires a written answer, surface it to the user with a suggested response instead of posting automatically. If a later snapshot surfaces your own approved reply, treat it as informational and continue without responding again.
7. Process actionable review comments before flaky reruns when both are present; if a review fix requires a commit, push it and skip rerunning failed checks on the old SHA.
8. Retry failed checks only when `retry_failed_checks` is present and you are not about to replace the current SHA with a review/CI fix commit. Do not make code changes for unrelated flakes or infrastructure failures just to get CI green.
9. If you pushed a commit, resolved an eligible review thread, or triggered a rerun, report the action briefly and continue polling (do not stop). If a human review comment needs a written GitHub response, stop and ask for confirmation before posting.
9. If you pushed a commit, resolved a review thread, or triggered a rerun, report the action briefly and continue polling (do not stop). If a human review comment needs a written GitHub response, stop and ask for confirmation before posting.
10. After a review-fix push, proactively restart continuous monitoring (`--watch`) in the same turn unless a strict stop condition has already been reached.
11. If everything is passing, mergeable, not blocked on required review approval, and there are no unaddressed review items, report that the PR is currently ready to merge but keep the watcher running so new review comments are surfaced quickly while the PR remains open.
12. If blocked on a user-help-required issue (infra outage, exhausted flaky retries, unclear reviewer request, permissions), report the blocker and stop.
Expand Down
2 changes: 1 addition & 1 deletion .codex/skills/babysit-pr/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface:
display_name: "PR Babysitter"
short_description: "Watch PR review comments, CI, and merge conflicts"
default_prompt: "Babysit the current PR: monitor published reviewer comments, CI, and merge-conflict status (prefer the watcher’s --watch mode for live monitoring); ignore unpublished comments in pending GitHub reviews; surface new published review feedback before acting on CI or mergeability work, fix valid issues, push updates, and rerun flaky failures up to 3 times. Do not post replies to human-authored review comments unless the user explicitly confirms the exact response. Do not patch unrelated flaky tests, CI infrastructure, dependency outages, runner issues, or other failures that are not caused by the branch. Keep exactly one watcher session active for the PR (do not leave duplicate --watch terminals running). If you pause monitoring to patch review/CI feedback, restart --watch yourself immediately after the push in the same turn. If a watcher is still running and no strict stop condition has been reached, the task is still in progress: keep consuming watcher output and sending progress updates instead of ending the turn. Do not treat a green + mergeable PR as a terminal stop while it is still open; continue polling autonomously after any push/rerun so newly posted review comments are surfaced until a strict terminal stop condition is reached or the user interrupts."
default_prompt: "Babysit the current PR: monitor reviewer comments, CI, and merge-conflict status (prefer the watcher’s --watch mode for live monitoring); surface new review feedback before acting on CI or mergeability work, fix valid issues, push updates, and rerun flaky failures up to 3 times. Do not post replies to human-authored review comments unless the user explicitly confirms the exact response. Do not patch unrelated flaky tests, CI infrastructure, dependency outages, runner issues, or other failures that are not caused by the branch. Keep exactly one watcher session active for the PR (do not leave duplicate --watch terminals running). If you pause monitoring to patch review/CI feedback, restart --watch yourself immediately after the push in the same turn. If a watcher is still running and no strict stop condition has been reached, the task is still in progress: keep consuming watcher output and sending progress updates instead of ending the turn. Do not treat a green + mergeable PR as a terminal stop while it is still open; continue polling autonomously after any push/rerun so newly posted review comments are surfaced until a strict terminal stop condition is reached or the user interrupts."
3 changes: 0 additions & 3 deletions .codex/skills/babysit-pr/references/github-api-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ Reruns only failed jobs (and dependencies) for a workflow run.
- Review submissions:
- `gh api repos/{owner}/{repo}/pulls/<pr_number>/reviews?per_page=100`

Use each inline comment's `pull_request_review_id` to find its parent review. Ignore parent reviews
whose `state` is `PENDING`, along with their inline comments, until the review is submitted.

## JSON fields consumed by the watcher

### `gh pr view`
Expand Down
28 changes: 3 additions & 25 deletions .codex/skills/babysit-pr/scripts/gh_pr_watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,14 +452,11 @@ def normalize_issue_comments(items):
return out


def normalize_review_comments(items, review_states):
def normalize_review_comments(items):
out = []
for item in items:
if not isinstance(item, dict):
continue
review_id = str(item.get("pull_request_review_id") or "")
if review_states.get(review_id) == "PENDING":
continue
line = item.get("line")
if line is None:
line = item.get("original_line")
Expand All @@ -484,8 +481,6 @@ def normalize_reviews(items):
for item in items:
if not isinstance(item, dict):
continue
if str(item.get("state") or "").upper() == "PENDING":
continue
out.append(
{
"kind": "review",
Expand Down Expand Up @@ -539,33 +534,16 @@ def fetch_new_review_items(pr, state, fresh_state, authenticated_login=None):
review_payload = gh_api_list_paginated(endpoints["review"], repo=repo)

issue_items = normalize_issue_comments(issue_payload)
review_states = {
str(item.get("id")): str(item.get("state") or "").upper()
for item in review_payload
if isinstance(item, dict) and item.get("id") not in (None, "")
}
pending_review_ids = {
review_id for review_id, review_state in review_states.items() if review_state == "PENDING"
}
pending_review_comment_ids = {
str(item.get("id"))
for item in review_comment_payload
if isinstance(item, dict)
and item.get("id") not in (None, "")
and str(item.get("pull_request_review_id") or "") in pending_review_ids
}
review_comment_items = normalize_review_comments(review_comment_payload, review_states)
review_comment_items = normalize_review_comments(review_comment_payload)
review_items = normalize_reviews(review_payload)
all_items = issue_items + review_comment_items + review_items

seen_issue = {str(x) for x in state.get("seen_issue_comment_ids") or []}
seen_review_comment = {str(x) for x in state.get("seen_review_comment_ids") or []}
seen_review = {str(x) for x in state.get("seen_review_ids") or []}
seen_review_comment.difference_update(pending_review_comment_ids)
seen_review.difference_update(pending_review_ids)

# On a brand-new state file, surface existing review activity instead of
# silently treating it as seen. This avoids missing already-published review
# silently treating it as seen. This avoids missing already-pending review
# feedback when monitoring starts after comments were posted.

new_items = []
Expand Down
Loading
Loading