Shared, reusable GitHub Actions workflows for Lennar engineering teams.
The repo is public, so any repo in any org can call these workflows directly — no cross-org setup. The review logic lives here and is maintained once; consuming repos add a tiny caller and nothing else. No secrets are stored here.
Automated, codebase-aware code review powered by OpenAI Codex. It behaves like GitHub Copilot's reviewer — inline diff comments plus a summary — with a few deliberate improvements:
- Zero config. Add one ~20-line caller. No prompt, no stack hints, no install script. The workflow auto-detects your stack (npm/yarn/pnpm, uv/pip, go) and installs deps.
- Codebase-aware. A single stack-agnostic prompt (bundled here) detects the language
and reads your repo's own
AGENTS.md/CLAUDE.md/.agents/rules/for conventions. - Never blocks. The review is always posted as a non-blocking
COMMENT. The model's verdict is shown as advisory text (Verdict: Changes suggested, 2 issues, 1 suggestion), so resolving threads is clean and nothing wedges your merge. - Low noise. It reviews only what changed since its last pass, debounces a burst of
pushes into one review, opens inline threads only for findings at or above a severity
floor (nitpicks go in the body by default), caps inline threads per run, and pauses on
draft or a
codex:pauselabel. See "Reducing thread churn" below. - Consistent comments. Conventional Comments
(
issue/suggestion/nitpick), each with a one-line subject, a required why, and a concrete fix. No emoji. - Maintained centrally. Change the review behavior for every repo by editing the prompt here, not by touching each consumer.
Add CODEX_ACCESS_TOKEN at the org level (one-time, shared by all repos) under
Settings → Secrets and variables → Actions. Use a static credential: an OpenAI API
key (sk-*), an agent-identity JWT, or a personal access token (at-*).
Prefer
CODEX_ACCESS_TOKENfor CI. It has no rotating refresh token, so concurrent PR reviews across repos cannot race it.CODEX_AUTH_JSON(a full~/.codex/auth.json) is a fallback only: its single-use refresh token breaks under concurrent CI runs with "refresh token already used" / 401.
Create .github/workflows/pr-review.yml — this is the entire integration, identical
in every repo:
name: PR Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
pull-requests: write
issues: write
# The reusable workflow manages its own per-PR concurrency and debounce, so a
# caller-level concurrency block is optional. This one cancels superseded caller
# runs early to save minutes on a burst of pushes.
concurrency:
group: codex-pr-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
codex-review:
# Same-repo guard: never runs for fork PRs, keeping credentials away from
# untrusted code. (Don't add workflow_dispatch: an arbitrary PR number
# would bypass this guard.)
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.draft == false
uses: modsy/ci-workflows/.github/workflows/codex-pr-review.yml@main
with:
pr_number: ${{ github.event.pull_request.number }}
secrets:
CODEX_AUTH_JSON: ${{ secrets.CODEX_AUTH_JSON }}That's it. Open a PR and the reviewer comments within a minute or two. Do not add a prompt — it's bundled here and applied to every caller.
- Your caller triggers on
pull_requestand calls this reusable workflow. - The workflow:
- Checks out the PR merge commit (
persist-credentials: false, so the token can't push or fetch). - Fetches PR metadata and any linked issues for context. Codex runs the
git diffitself against the checkout; the diff is not pasted into the prompt. - Decides whether to review. Skips if this exact HEAD was already reviewed, if the
PR is a draft, or if it carries
codex:pause. Otherwise it debounces: it pauses briefly and exits if a newer commit has landed, so a burst of pushes collapses to one review. When a prior review exists, it reviews only the increment since that commit. - Auto-installs dependencies by detecting a root manifest:
package-lock.json→npm ci(and builds workspaces if it's a monorepo),yarn.lock/pnpm-lock.yaml,uv.lock→uv sync,requirements.txt/pyproject.toml→ pip,go.mod→go mod download. Best-effort andcontinue-on-error: if it can't install, the review still runs statically. - Loads the review prompt from this repo (version-locked to the workflow's own commit), never from the PR under review.
- Runs the Codex CLI in an ephemeral sandbox and parses its JSON output.
- Posts a single non-blocking
COMMENTreview. Findings at or above the severity floor open inline threads (capped per run and deduped against prior bot comments); lower-severity, overflow, non-diff, and docs/test-only findings are listed in the body.
- Checks out the PR merge commit (
| Input | Required | Default | Description |
|---|---|---|---|
pr_number |
No | auto | PR to review. Resolved from the triggering event; the caller above passes it explicitly. |
codex_version |
No | 0.142.0 |
Pinned @openai/codex version. |
pre_install_command |
No | "" |
Optional override for dependency setup. Leave empty for auto-detect. Set only for non-standard layouts (e.g. a package nested in a monorepo subdir). |
inline_min_severity |
No | suggestion |
Minimum severity that opens an inline thread (blocking/suggestion/nitpick). Findings below the floor go under "Minor notes" in the body. The default keeps nitpicks out of threads. |
max_inline_comments |
No | 10 |
Cap on inline threads per run. Highest-severity findings stay inline; the rest are listed in the body. |
debounce_seconds |
No | 30 |
Pause at job start, then re-resolve the PR head. If a newer commit landed, the run exits so a burst of pushes collapses to one review. Set 0 to disable. |
Reducing thread churn. The reviewer skips while a PR is a draft or carries the
codex:pause label, and resumes when the PR is marked ready or the label is removed.
Docs/test-only increments post as summary notes with no inline threads. These behaviors
are advisory and never block merge.
Provide one (org-level recommended):
| Secret | When to use |
|---|---|
CODEX_ACCESS_TOKEN |
Preferred. A static credential: OpenAI API key (sk-*), agent-identity JWT, or personal access token (at-*). No rotating refresh token, so concurrent CI runs cannot race it. |
CODEX_AUTH_JSON |
Fallback only. Full ~/.codex/auth.json; its single-use refresh token breaks under concurrent CI runs ("refresh token already used" / 401). |
| Output | Description |
|---|---|
review_url |
URL of the posted PR review. |
There is one prompt for all repos:
.github/codex/prompts/codex-pr-review.md.
- Change it for everyone: edit the prompt here and open a PR.
- Tune it for one repo: document the convention in that repo's
AGENTS.md/CLAUDE.md— the prompt reads them at review time.
You should never need a prompt file in a consuming repo.
| Concern | How it's addressed |
|---|---|
| Secret isolation | Auth secrets are stored per org/repo and passed at call time. Never stored here. |
| Prompt integrity | The prompt is read from this repo at the workflow's own commit, never from the PR — a PR can't change what the credentialed reviewer runs. |
| Fork exfiltration | The caller's same-repo if: guard prevents the workflow (and its secrets) from running on fork PRs. |
| Credential leak via git | persist-credentials: false keeps GITHUB_TOKEN out of git config. |
| Script injection | GitHub context values reach the shell only as environment variables, never interpolated into run: blocks. |
| Sandbox | Codex runs --ephemeral --sandbox workspace-write: no persistent state, writes scoped to the workspace. |
@main tracks the latest. Pin to a commit SHA for full reproducibility:
uses: modsy/ci-workflows/.github/workflows/codex-pr-review.yml@<sha>| Symptom | Cause / fix |
|---|---|
| Review never appears | Confirm CODEX_AUTH_JSON (or CODEX_ACCESS_TOKEN) is set and visible to the repo. The codex-review job's auth step fails fast without it. |
Either CODEX_ACCESS_TOKEN or CODEX_AUTH_JSON secret is required |
No auth secret reached the workflow. Add it at the org or repo level. |
refresh token already used / intermittent 401 |
You are on the CODEX_AUTH_JSON fallback; its single-use refresh token is being raced by concurrent CI runs. Switch to a static CODEX_ACCESS_TOKEN. |
401 from api.openai.com/v1/responses |
An sk-* key lacks api.responses.write, or is out of credits. Use an agent-identity JWT / at-* token as CODEX_ACCESS_TOKEN. |
invalid agent identity JWT format |
CODEX_ACCESS_TOKEN isn't a valid JWT/PAT. Re-mint the token. |
| Review is shallow / misses conventions | Add an AGENTS.md or CLAUDE.md to your repo; the prompt reads them for project rules. |
| Dependencies not installed | Auto-detect is best-effort. For a nested monorepo package, set pre_install_command to your install command. |
| Fork PRs not reviewed | Intentional — the same-repo guard keeps secrets away from fork code. |
A CI-side gate that stops hardcoded secrets (API keys, tokens, private keys,
connection strings) from merging, and optionally flags likely PII/PHI for human
review. It complements, and does not replace, pre-commit hooks: a pre-commit hook is
skipped by --no-verify, IDE commits, and web/API pushes, so this workflow
catches everything that actually reaches the PR.
- Zero config, stack-agnostic. One small caller.
gitleaksruns from a directly-downloaded binary (no marketplace action, no license key that org accounts otherwise need). - Diff-scoped by default. Scans only the commits the PR introduces, so a
pre-existing finding on the base branch does not fail your PR. Set
scan_scope: fullfor a one-time history audit. - Blocks by default, deliberately. Unlike the advisory code reviewer, a
detected secret fails the check (
fail_on_secrets: true). Set it false for report-only mode. Values are redacted in logs and the PR comment. - Advisory PII sweep (opt-in).
scan_pii: trueadds a high-confidence email/SSN/phone regex pass over added lines. It NEVER blocks the merge, regex PII detection is false-positive-prone. True PHI coverage needs a dedicated service and is out of scope for a dependency-free gate. - One comment, upserted. Results post to a single marker-tagged PR comment that updates in place, so pushes do not pile up duplicates.
name: Secret Scan
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
pull-requests: write
jobs:
secret-scan:
if: github.event.pull_request.draft == false
uses: modsy/ci-workflows/.github/workflows/secret-scan.yml@main
with:
scan_scope: "diff" # or "full"
fail_on_secrets: true # false for report-only
# scan_pii: true # advisory email/SSN/phone sweep
# gitleaks_config: ".gitleaks.toml" # repo-specific rules / allowlistNo secret needs to be configured. See examples/secret-scan.yml and
examples/secret-scan-with-fork-guard.yml.
| Input | Default | Purpose |
|---|---|---|
scan_scope |
"diff" |
diff scans the PR's commits; full scans all history on the head. |
fail_on_secrets |
true |
Fail (block) on a secret finding, or report-only when false. |
scan_pii |
false |
Enable the advisory PII sweep. Never blocks regardless of fail_on_secrets. |
gitleaks_config |
"" |
Path to a custom .gitleaks.toml for repo-specific rules or allowlists. |
gitleaks_version |
pinned | gitleaks release to install. Bump deliberately. |
Point gitleaks_config at a .gitleaks.toml in your repo to add rules (e.g.
Django SECRET_KEY, VITE_-prefixed vars, an internal token format) or to
allowlist known test fixtures. Inline gitleaks:allow comments and a
.gitleaksignore file also suppress specific findings.
Maintained by the modsy platform team. Open a PR for changes that benefit consuming teams, and call out any breaking input or behavior change in the description.