Skip to content

Commit e7116de

Browse files
committed
🤖 ci: add Codex PR loop tooling and readiness wrapper
Bring over mux pull-request skill and supporting scripts into this Go repo, then adapt them for coder-k8s workflows. - add PR skill at .mux/skills/pull-requests/SKILL.md - add Codex/PR scripts under scripts/ - add scripts/wait_pr_ready.sh wrapper for one-command Codex+CI waiting - add project AGENTS.md guidance (non-TypeScript sections adapted for Go) - add codex-comments job to .github/workflows/ci.yaml Validation: - bash -n scripts/*.sh - actionlint .github/workflows/ci.yaml - make verify-vendor - make test - make build --- _Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: `$0.82`_ <!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.82 -->
1 parent 68aaf00 commit e7116de

10 files changed

Lines changed: 1097 additions & 0 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ jobs:
6666
advanced-security: false
6767
inputs: .github/workflows
6868

69+
codex-comments:
70+
name: Codex Comments
71+
if: github.event_name == 'pull_request'
72+
runs-on: ubuntu-latest
73+
permissions:
74+
contents: read
75+
pull-requests: read
76+
steps:
77+
- name: Checkout
78+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
79+
with:
80+
fetch-depth: 0
81+
persist-credentials: false
82+
83+
- name: Check unresolved Codex comments
84+
env:
85+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
86+
run: ./scripts/check_codex_comments.sh ${{ github.event.pull_request.number }}
87+
6988
publish-main:
7089
name: Publish GHCR :main
7190
needs: [test, lint-actions]

.mux/skills/pull-requests/SKILL.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
name: pull-requests
3+
description: Guidelines for creating and managing Pull Requests in this repo
4+
---
5+
6+
# Pull Request Guidelines
7+
8+
## Attribution Footer
9+
10+
Public work (issues/PRs/commits) must use 🤖 in the title and include this footer in the body:
11+
12+
```md
13+
---
14+
15+
_Generated with `mux` • Model: `<modelString>` • Thinking: `<thinkingLevel>` • Cost: `$<costs>`_
16+
17+
<!-- mux-attribution: model=<modelString> thinking=<thinkingLevel> costs=<costs> -->
18+
```
19+
20+
Always check `$MUX_MODEL_STRING`, `$MUX_THINKING_LEVEL`, and `$MUX_COSTS_USD` via bash before creating or updating PRs—include them in the footer if set.
21+
22+
## Lifecycle Rules
23+
24+
- Before submitting a PR, ensure the branch name reflects the work and the base branch is correct.
25+
- PRs are always squash-merged into `main`.
26+
- Often, work begins from another PR's merged state; rebase onto `main` before submitting a new PR.
27+
- Reuse existing PRs; never close or recreate without instruction.
28+
- Force-push minor PR updates; otherwise add a new commit to preserve the change timeline.
29+
- If a PR is already open for your change, keep it up to date with the latest commits; don't leave it stale.
30+
- Never enable auto-merge or merge into `main` yourself. The user must explicitly merge PRs.
31+
32+
## CI & Validation
33+
34+
- After pushing, you may use `./scripts/wait_pr_checks.sh <pr_number>` to wait for CI to pass.
35+
- Use `wait_pr_checks` only when there's no more useful work to do.
36+
- Waiting for PR checks can take 10+ minutes, so prefer local validation first (for this repo: `make verify-vendor`, `make test`, `make build`) to catch issues early.
37+
- If asked to fix an issue in CI, first replicate it locally, get it to pass locally, then use `wait_pr_checks` to wait for CI to pass.
38+
39+
## Status Decoding
40+
41+
| Field | Value | Meaning |
42+
| ------------------ | ------------- | ------------------- |
43+
| `mergeable` | `MERGEABLE` | Clean, no conflicts |
44+
| `mergeable` | `CONFLICTING` | Needs resolution |
45+
| `mergeStateStatus` | `CLEAN` | Ready to merge |
46+
| `mergeStateStatus` | `BLOCKED` | Waiting for CI |
47+
| `mergeStateStatus` | `BEHIND` | Needs rebase |
48+
| `mergeStateStatus` | `DIRTY` | Has conflicts |
49+
50+
If behind: `git fetch origin && git rebase origin/main && git push --force-with-lease`.
51+
52+
## Codex Review Workflow
53+
54+
When posting multi-line comments with `gh` (e.g., `@codex review`), **do not** rely on `\n` escapes inside quoted `--body` strings (they will be sent as literal text). Prefer `--body-file -` with a heredoc to preserve real newlines:
55+
56+
```bash
57+
gh pr comment <pr_number> --body-file - <<'EOF'
58+
@codex review
59+
60+
<message>
61+
EOF
62+
```
63+
64+
### Handling Codex Comments
65+
66+
Use these scripts to check, resolve, and wait on Codex review comments:
67+
68+
- `./scripts/check_codex_comments.sh <pr_number>` — Lists unresolved Codex comments (both regular comments and review threads). Outputs thread IDs needed for resolution.
69+
- `./scripts/resolve_pr_comment.sh <thread_id>` — Resolves a review thread by its ID (e.g., `PRRT_abc123`).
70+
- `./scripts/wait_pr_codex.sh <pr_number>` — Waits for Codex to respond to the latest `@codex review` request. When the PR looks good, Codex leaves an explicit approval comment (e.g., it will say `Didn't find any major issues`).
71+
72+
- `./scripts/wait_pr_ready.sh <pr_number>` — Convenience wrapper that runs Codex waiting first and CI checks second. Use it when you are done coding and want to block until the PR is ready or actionable feedback appears.
73+
74+
When Codex leaves review comments, you **must** address them before the PR can merge:
75+
76+
1. Push your fixes
77+
2. Resolve each review thread: `./scripts/resolve_pr_comment.sh <thread_id>`
78+
3. Comment `@codex review` to re-request review
79+
4. Run `./scripts/wait_pr_codex.sh <pr_number>` to wait for the next Codex response (either new comments to address, or an explicit approval comment)
80+
81+
### Required Loop Discipline
82+
83+
After a PR is open, stay in a review loop until completion:
84+
85+
1. Run local validation and push fixes.
86+
2. Request review with `@codex review`.
87+
3. Run `./scripts/wait_pr_codex.sh <pr_number>` and wait for Codex to respond.
88+
4. If Codex leaves comments, address them, resolve each thread, push, and repeat from step 2.
89+
5. Once Codex explicitly approves, run `./scripts/wait_pr_checks.sh <pr_number>` and wait for required checks.
90+
91+
Only stop the loop early if a reviewer is clearly misunderstanding the change intent and further edits would be counterproductive. In that case, leave a clarifying PR comment and pause for human direction.
92+
93+
## PR Title Conventions
94+
95+
- Title prefixes: `perf|refactor|fix|feat|ci|tests|bench`
96+
- Example: `🤖 fix: handle workspace rename edge cases`
97+
- Use `tests:` for test-only changes (test helpers, flaky test fixes, storybook)
98+
- Use `ci:` for CI config changes
99+
100+
## PR Bodies
101+
102+
### Structure
103+
104+
PR bodies should generally follow this structure; omit sections that are N/A or trivially inferable for the change.
105+
106+
- Summary
107+
- Single-paragraph executive summary of the change
108+
- Background
109+
- The "why" behind the change
110+
- What problem this solves
111+
- Relevant commits, issues, or PRs that capture more context
112+
- Implementation
113+
- Validation
114+
- Steps taken to prove the change works as intended
115+
- Avoid boilerplate like `ran tests`; include this section only for novel, change-specific steps
116+
- Do not include steps implied by passing PR checks
117+
- Risks
118+
- PRs that touch intricate logic must include an assessment of regression risk
119+
- Explain regression risk in terms of severity and affected product areas
120+
121+
## Upkeep
122+
123+
Once the code is pushed to the remote (even if not yet a Pull Request), do your best to commit
124+
and push all changes before responding to ensure its visible to the user. Commits on the working branch
125+
are for yourself to understand the change, they do not have to follow repository conventions as the
126+
PR body and title become the commit subject and body respectively.
127+
128+
Whenever generating a compaction summary, include whether or not a Pull Request was opened
129+
and the general state of the remote (e.g. CI checks, known reviews, divergence).

AGENTS.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
title: AGENTS.md
3+
description: Agent instructions for AI assistants working on the coder-k8s codebase
4+
---
5+
6+
**Prime directive:** keep edits minimal and token-efficient—say only what conveys actionable signal.
7+
8+
## Project Snapshot
9+
10+
- `coder-k8s` is a Go Kubernetes controller/operator for the `CoderControlPlane` API.
11+
- Core code lives in `main.go`, `api/`, and `internal/controller/`.
12+
- **Before creating or updating any PR, commit, or public issue, you MUST read the `pull-requests` skill** (`.mux/skills/pull-requests/SKILL.md`) and follow its attribution and workflow rules.
13+
14+
## Repo Reference
15+
16+
- Entrypoint: `main.go`
17+
- API definitions: `api/v1alpha1/`
18+
- Controller logic: `internal/controller/`
19+
- Build/test automation: `Makefile`
20+
- Code generation: `hack/update-codegen.sh`
21+
22+
## Documentation Rules
23+
24+
- Prefer code, tests, and inline comments over ad-hoc docs.
25+
- Do not add new root-level documentation files unless explicitly requested.
26+
27+
### Code Comments
28+
29+
- Leave rationale in code comments when delivering a user request.
30+
- Prefer comments that explain the "why" behind the change.
31+
- Explain the "what" when code is opaque or surprising.
32+
33+
## Tooling & Commands
34+
35+
- Use Go modules with vendored dependencies (`-mod=vendor`).
36+
- Makefile is the source of truth for routine tasks.
37+
- Primary targets: `make vendor`, `make verify-vendor`, `make test`, `make build`, `make codegen`.
38+
- Validate locally before relying on CI whenever practical.
39+
- **Codex reviews:** if a PR has Codex review comments, address + resolve them, then re-request review by commenting `@codex review` on the PR. Repeat until `./scripts/check_codex_comments.sh <pr_number>` reports none.
40+
41+
- For a one-command wait flow after requesting review, use `./scripts/wait_pr_ready.sh <pr_number>`.
42+
43+
## Codex PR Review Loop (Required)
44+
45+
Once a PR exists, stay in the review loop until the PR is truly ready:
46+
47+
1. Push your latest fixes.
48+
2. Run local validation (`make verify-vendor`, `make test`, `make build`).
49+
3. Request AI review with `@codex review`.
50+
4. Run `./scripts/wait_pr_codex.sh <pr_number>` and wait for Codex to respond.
51+
5. If Codex leaves review comments/threads:
52+
- Address the feedback in code.
53+
- Resolve each thread with `./scripts/resolve_pr_comment.sh <thread_id>`.
54+
- Push and repeat from step 2.
55+
6. After explicit Codex approval, run `./scripts/wait_pr_checks.sh <pr_number>` and wait for CI checks to finish.
56+
57+
Only stop looping before approval if the reviewer is clearly misunderstanding the intended change and further churn would be counterproductive. In that case, leave a clarifying PR comment and wait for human direction.
58+
59+
## Refactoring & Runtime Etiquette
60+
61+
- Use `git mv` to retain history when moving files.
62+
63+
## Self-Healing & Crash Resilience
64+
65+
- Prefer self-healing behavior for corrupted persisted data where possible.
66+
- Never let one malformed value permanently block core workflows; sanitize or skip invalid entries when safe.
67+
- Startup-time initialization should fail gracefully whenever possible.
68+
69+
## Bug-Fixing Mindset
70+
71+
- Avoid timing-based coordination when deterministic signals exist.
72+
- When asked to reduce LoC, simplify production logic—not comments, docs, or tests.
73+
74+
## Logging
75+
76+
- Use structured logging patterns from `controller-runtime` (key/value fields) and keep logs actionable.
77+
78+
## Tool: status_set
79+
80+
- Set the status URL to the Pull Request once opened.
81+
82+
## GitHub
83+
84+
- Prefer the `gh` CLI over manual web/curl flows when reading or writing GitHub data.

scripts/check_codex_comments.sh

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
if [ $# -eq 0 ]; then
5+
echo "Usage: $0 <pr_number>"
6+
exit 1
7+
fi
8+
9+
PR_NUMBER=$1
10+
BOT_LOGIN_GRAPHQL="chatgpt-codex-connector"
11+
12+
echo "Checking for unresolved Codex comments in PR #${PR_NUMBER}..."
13+
14+
# Use GraphQL to get all comments (including minimized status)
15+
# shellcheck disable=SC2016 # Single quotes are intentional - this is a GraphQL query, not shell expansion
16+
GRAPHQL_QUERY='query($owner: String!, $repo: String!, $pr: Int!) {
17+
repository(owner: $owner, name: $repo) {
18+
pullRequest(number: $pr) {
19+
comments(first: 100) {
20+
nodes {
21+
id
22+
author { login }
23+
body
24+
createdAt
25+
isMinimized
26+
}
27+
}
28+
reviewThreads(first: 100) {
29+
nodes {
30+
id
31+
isResolved
32+
comments(first: 1) {
33+
nodes {
34+
id
35+
author { login }
36+
body
37+
createdAt
38+
path
39+
line
40+
}
41+
}
42+
}
43+
}
44+
}
45+
}
46+
}'
47+
48+
REPO_INFO=$(gh repo view --json owner,name --jq '{owner: .owner.login, name: .name}')
49+
OWNER=$(echo "$REPO_INFO" | jq -r '.owner')
50+
REPO=$(echo "$REPO_INFO" | jq -r '.name')
51+
52+
# Depot runners sometimes hit transient network timeouts to api.github.com.
53+
# Retry the GraphQL request a few times before failing the required check.
54+
MAX_ATTEMPTS=5
55+
BACKOFF_SECS=2
56+
57+
for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do
58+
if RESULT=$(gh api graphql \
59+
-f query="$GRAPHQL_QUERY" \
60+
-F owner="$OWNER" \
61+
-F repo="$REPO" \
62+
-F pr="$PR_NUMBER"); then
63+
break
64+
fi
65+
66+
if [ "$attempt" -eq "$MAX_ATTEMPTS" ]; then
67+
echo "❌ GraphQL query failed after ${MAX_ATTEMPTS} attempts"
68+
exit 1
69+
fi
70+
71+
echo "⚠️ GraphQL query failed (attempt ${attempt}/${MAX_ATTEMPTS}); retrying in ${BACKOFF_SECS}s..."
72+
sleep "$BACKOFF_SECS"
73+
BACKOFF_SECS=$((BACKOFF_SECS * 2))
74+
done
75+
76+
# Filter regular comments from bot that aren't minimized, excluding:
77+
# - "Didn't find any major issues" (no issues found)
78+
# - "usage limits have been reached" (rate limit error, not a real review)
79+
REGULAR_COMMENTS=$(echo "$RESULT" | jq "[.data.repository.pullRequest.comments.nodes[] | select(.author.login == \"${BOT_LOGIN_GRAPHQL}\" and .isMinimized == false and (.body | test(\"Didn't find any major issues|usage limits have been reached\") | not))]")
80+
REGULAR_COUNT=$(echo "$REGULAR_COMMENTS" | jq 'length')
81+
82+
# Filter unresolved review threads from bot
83+
UNRESOLVED_THREADS=$(echo "$RESULT" | jq "[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false and .comments.nodes[0].author.login == \"${BOT_LOGIN_GRAPHQL}\")]")
84+
UNRESOLVED_COUNT=$(echo "$UNRESOLVED_THREADS" | jq 'length')
85+
86+
TOTAL_UNRESOLVED=$((REGULAR_COUNT + UNRESOLVED_COUNT))
87+
88+
echo "Found ${REGULAR_COUNT} unminimized regular comment(s) from bot"
89+
echo "Found ${UNRESOLVED_COUNT} unresolved review thread(s) from bot"
90+
91+
if [ $TOTAL_UNRESOLVED -gt 0 ]; then
92+
echo ""
93+
echo "❌ Found ${TOTAL_UNRESOLVED} unresolved comment(s) from Codex in PR #${PR_NUMBER}"
94+
echo ""
95+
echo "Codex comments:"
96+
97+
if [ "$REGULAR_COUNT" -gt 0 ]; then
98+
echo "$REGULAR_COMMENTS" | jq -r '.[] | " - [\(.createdAt)]\n\(.body)\n"'
99+
fi
100+
101+
if [ "$UNRESOLVED_COUNT" -gt 0 ]; then
102+
echo "$UNRESOLVED_THREADS" | jq -r '.[] | " - [\(.comments.nodes[0].createdAt)] thread=\(.id) \(.comments.nodes[0].path // "comment"):\(.comments.nodes[0].line // "")\n\(.comments.nodes[0].body)\n"'
103+
echo ""
104+
echo "Resolve review threads with: ./scripts/resolve_pr_comment.sh <thread_id>"
105+
fi
106+
107+
echo ""
108+
echo "Please address or resolve all Codex comments before merging."
109+
exit 1
110+
else
111+
echo "✅ No unresolved Codex comments found"
112+
exit 0
113+
fi

0 commit comments

Comments
 (0)