Imported from zmihai/.github (
AGENTS.md). Install upstream withnpx skills add zmihai/.github. Copyright stays with the author.
AGENTS.md
This file provides guidance to AI agents when working with code in this repository.
This is the single source of truth for AI-agent guidance. Tool-specific files such as
CLAUDE.mdlink here rather than duplicating content — please keep all guidance in this file and update it in the same commit as any related code change.
Project Overview
This is .github — an organization-level repository of reusable GitHub Actions
workflows, composite actions, and starter workflow templates. Its centerpiece is a
Gemini-CLI-powered automation that reviews pull requests, runs a security pass, and
conditionally squash-merges them. There is no application to build here; everything in this
repo is consumed by other repositories via pinned references.
Because changes here drive automation that runs in other repositories, correctness and security matter far more than style. A bad change can mis-merge or block PRs org-wide.
The only executable code in-repo is the Python test suite under tests/, which validates
the workflow templates and language-support matrix (run with pytest). Do not run
builds — there is no app build.
Repository Layout
.github/
workflows/
reusable-gemini-guard.yml # trigger policy + PR-head ref resolution (shared gate)
reusable-gemini-dispatch.yml # entry point: guard, then fan out on the command
gemini-review.yml # code-review pass + security pass (2 Gemini calls)
gemini-merge.yml # classify failures, optionally remediate, squash-merge
reusable-ci.yml # language dispatcher → ci-{npm,python,php,java}.yml
ci-npm.yml / ci-python.yml / ci-php.yml / ci-java.yml # per-language CI
reusable-security-scan.yml # dependency audit + optional CodeQL
commands/
pr-review.toml # the review prompt
pr-merge.toml # the review-and-merge prompt (encodes merge policy)
copilot-instructions.md # review guidance for AI reviewers of THIS repo
actions/
setup-node-env/ setup-python-env/ setup-php-env/ setup-java-env/ # composite actions
workflow-templates/ # starter workflows (ci, security-scan) + *.properties.json
tests/ # pytest suite validating templates + language support
docs/ARCHITECTURE.md # deep-dive on every workflow/action (see below)
GEMINI.md # links to AGENTS.md (single source of truth)
README.md / QUICKSTART.md / CONTRIBUTING.md / examples/
Architecture Overview / Workflow Catalog
The full per-workflow, per-action, per-input catalog lives in docs/ARCHITECTURE.md — read it before changing any workflow, prompt, composite action, or template. The summary below is enough for orientation.
Reusable Workflows & Composite Actions (what each does)
Gemini automation (reusable-gemini-dispatch.yml → gemini-review.yml /
gemini-merge.yml, driven by .github/commands/*.toml):
- Guard (
reusable-gemini-guard.yml) is the single source of truth for the trigger policy. It allows only non-forkpull_requestevents, opened/reopened issues, and@gemini-cli-prefixed comments from anOWNER/MEMBER/COLLABORATORhuman user; it derives the command (review,review-and-merge,merge,fallthrough,unsupported-fork), resolves the PR head ref (via the API forissue_commentevents, whose payload has no PR head SHA), and computesis_forkfailing closed (fork PRs are unsupported and never receive secrets). Dependabot PRs map toreview-and-merge. Downstream callers run it as their first job — before any job that checks out code or receives secrets — gate CI onproceed/is_pr/is_fork, and feedresolved_refto their CI/scan/dispatch calls. Dispatch calls it internally too, so caller-side and dispatch-side gates cannot drift.- Inputs:
ref(optional override). Outputs:proceed,command,request,additional_context,resolved_ref,is_fork,is_pr,issue_number.
- Inputs:
- Dispatch runs the guard, then (for allowed events) posts the acknowledgement
comment and fans out to review/merge.
- Inputs:
projects(optional JSON string, default[]),ref(optional). - Secrets (all optional, forwarded explicitly to review/merge —
secrets: inheritonly works between same-owner workflows):GEMINI_API_KEY,GOOGLE_API_KEY,APP_PRIVATE_KEY. A distinct identity for PR updates comes from the GitHub App path (vars.APP_ID+APP_PRIVATE_KEY); otherwise the default token is used. - Callers must grant at least
contents: write,pull-requests: write,issues: write,id-token: write— the caller's token caps what called reusable workflows can do, and GitHub validates nestedpermissions:requests against it.security-events: write+actions: readare needed only when CodeQL is enabled (reusable-security-scanwithscan-code: true).
- Inputs:
- Review runs two separate Gemini invocations in one job: a code-review pass
(code-review extension, GitHub MCP
v0.27.0) and a security pass (security extension, GitHub MCPv0.18.0,/security:analyze-github-pr). They must stay separate — loading both extensions in one invocation causes tool-registration collisions. Their outputs are folded into onereview_summary. - Merge classifies each CI/security failure, may apply+push a low-risk remediation to the PR's source branch, then squash-merges — subject to the merge policy below. A post-run gate verifies the run left a durable outcome (actually merged, or actually submitted a new decisive review), comparing against a pre-run snapshot of review IDs.
- Repo-vars consulted:
APP_ID/APP_PRIVATE_KEY(GitHub App identity),GEMINI_*_MODEL/GEMINI_MODEL,GEMINI_CLI_VERSION,GEMINI_DEBUG,UPLOAD_ARTIFACTS, and the GCP/Vertex vars (GOOGLE_CLOUD_*,GCP_WIF_PROVIDER,SERVICE_ACCOUNT_EMAIL,GOOGLE_GENAI_USE_*).
reusable-ci.yml — dispatches on language (javascript/python/php/java) to a
per-language sub-workflow; exposes a single outcome output. Key inputs: language,
language-version, working-directory, extensions (PHP extensions / Java apt
packages), run-lint/run-test/run-build, build-before-test (JS), ref. Optional
CUSTOM_TOKEN secret (JS private packages).
reusable-security-scan.yml — dependency audit per language (npm audit,
pip-audit, composer audit --locked, Trivy for Java) plus optional CodeQL
(scan-code). Runs independently of CI and against untrusted refs, so it never builds the
project. Exposes an outcome output.
Composite actions (actions/<name>@vX.Y.Z) — setup-node-env, setup-python-env,
setup-php-env, setup-java-env: set up the toolchain with caching and best-effort
dependency install. setup-java-env auto-detects Maven/Gradle and outputs build-tool;
its dependency cache is an explicit actions/cache with a restore-keys prefix fallback
(not setup-java's built-in cache, which has none), so build-file changes restore the
closest previous cache instead of downloading everything cold.
How Downstream Repos Consume These
Downstream repos reference this repo by pinned release tag:
# Reusable workflow (note the doubled .github/.github path)
uses: zmihai/.github/.github/workflows/reusable-ci.yml@vX.Y.Z
# Composite action
uses: zmihai/.github/actions/setup-node-env@vX.Y.Z
To wire up the Gemini automation, a downstream repo runs reusable-gemini-guard.yml as
its first job, then reusable-ci.yml and reusable-security-scan.yml per project (gated
on the guard's proceed/is_pr/is_fork and checking out the guard's resolved_ref),
aggregates their outcomes into a projects JSON array (working-directory, language,
language-version, ci-outcome, scan-outcome per project), and passes it to the Gemini
workflows with an explicit secrets: map (inherit does not cross owners). workflow-templates/gemini.yml is the canonical caller
(trigger set including pull_request: synchronize, per-PR concurrency group, and the
minimum permissions grant); see also README.md / QUICKSTART.md / examples/.
Operational practice: merge serialization is per PR, via the caller template's
concurrency group; the merge workflow deliberately has no group of its own. (A former
repo-wide merge group let queued merge runs be silently evicted — Actions keeps only one
pending run per group — leaving simultaneous Dependabot PRs reviewed but unmerged.)
Merges of different PRs may race; the losing merge fails visibly, and Dependabot
auto-rebases when the base moves, triggering a fresh run.
Versioning & Release
- The repo is released as semver tags. All in-repo
@vX.Y.Zreferences (README, templates, and thezmihai/.github/...refs inside the workflows) point at that same tag. - A release is not just a tag. Cutting a new version requires sweeping every in-repo
@vX.Y.Zreference to the new tag — the per-language CI workflows and the security-scan workflow reference the composite actions aszmihai/.github/actions/...@vX.Y.Z, and the README/templates contain many@vX.Y.Zexamples. Bump them all in the release commit, then tag. - Workflow templates are served from the default branch, not a tag — edits to
workflow-templates/take effect immediately without a release. (Theuses:lines inside the templates still carry a pinned tag that must be bumped on release.) - Nested third-party actions are pinned by commit SHA with a
# ratchet:comment naming the version. Keep that pattern; don't replace SHAs with floating tags.
AI-Agent / Automation Conventions & Gotchas
These are durable rules, several learned the hard way. Verify against the current source before relying on them.
Remotes & branching:
git fetchand reconcile against upstream before committing. Dependabot churn makes stale local copies costly to rebase later.- If a branch's upstream shows
[gone], it was almost certainly squash-merged — switch tomasterand delete the dead branch.
Gemini / merge automation:
gemini-flash-latestis a deliberate, capable choice (resolves to Flash 3.5). Do not treat it as weak or propose "upgrading" it. Model selection isGEMINI_*_MODEL→GEMINI_MODEL→gemini-flash-latest.- Keep
GEMINI_DEBUGfalse/unset. Debug-on emits multi-MB stderr that exceeds GitHub Actions' template object-size limit and fails the job. For observability useUPLOAD_ARTIFACTS=true(uploadsstdout.log/stderr.log/telemetry.log) — note that MCP tool calls appear only intelemetry.log, notstdout.log. GEMINI_CLI_VERSIONdefaults to a pinned0.46.0, not floatinglatest— newer CLI releases tightened env/MCP permissions and need prompt/action updates first.tools.coremust list the MCP tools by theirmcp_github_*FQNs for the GitHub MCP tools to reach the model (it acts as a global allowlist that also filters MCP tools).- The security pass needs UNSCOPED
run_shell_commandinsettings.tools.core— it runsgit diffetc. A scoped allowlist (cat/echo/grep/…) makes every git command "denied by policy" and fails the step. - Merge mechanism: merge via the MCP
merge_pull_requesttool, falling back togh pr merge <n> --squash(token from env). Nevercurlwith a token in argv (it leaks into telemetry), and never push/merge to the default branch — remediation fixes go to the PR's source branch (head_ref). - Merge safety policy: classify each failure related vs unrelated/pre-existing (when in doubt → related); related failures must pass or be remediated, unrelated pre-existing failures (including security) do not block; any 🔴 Critical / 🟠 High review or security finding → REQUEST_CHANGES (block, never auto-merge). A "remediate-then-merge everything" variant was tried and rolled back because it merged an unfixed Critical — do not re-enable a posture that auto-merges past a Critical without a confirm-fix-on-remote guard.
Gemini prompt-authoring & sandbox conventions:
- GitHub MCP Tool Naming: Use the exact
mcp_github_*-prefixed tool names in prompt templates (e.g.,mcp_github_pull_request_review_write). Bare names are wrong. - Parsing JSON Arrays with
jq: Inject JSON-array variables (likePROJECTS) into.gemini-context.jsonwithjq --argjsoninstead of--arg(which stringifies it and breaks array-typed schemas). - Custom /commands must be installed, with non-colliding names: the CLI treats an unresolved
/commandas literal prompt text (no error), and run-gemini-cli copies its own bundled commands (including agemini-review.toml) into.gemini/commands/right before the CLI runs, overwriting same-named files. Hence theinstall-gemini-commandscomposite action and thepr-review/pr-mergenames. @{file}includes silently drop gitignored paths: the Gemini CLI's at-file include filters through.gitignore/.geminiignore(verified in 0.46.0) — an ignored file vanishes from the prompt with no error. That's why the prompt context file lives at the repo root as.gemini-context.json(several consumer repos gitignore.gemini/) and why the Prepare-prompt-context steps guard it withgit check-ignore. Never move it back under.gemini/.- YOLO Mode Tool Policy: To allow unrestricted shell execution in YOLO mode, specify
"run_shell_command"with no arguments (specifying an argument like"run_shell_command(echo)"restricts execution only to that command).
Permissions in reusable workflows:
- GitHub validates every nested job's
permissions:request against the caller's grant at startup, regardless ofif:conditions. A conditionally-skipped job with apermissions:block exceeding the documented caller baseline startup-fails every least-privilege caller — even though the job would never run. Jobs whose permissions exceed the baseline for an opt-in feature (e.g. CodeQL) must carry no job-levelpermissions:block; document the runtime needs instead and have opt-in callers grant them.
Reusable security scan & dependency auditing rules:
- No Build on Untrusted PRs: Workflows or steps triggered on untrusted PR refs (such as dependency scans) must never build the project, run installer scripts, or trigger build hooks (e.g., running
pip install .on a customsetup.py/pyproject.tomlor compiling Java projects during audit jobs). This prevents untrusted PRs from executing arbitrary code on our runners. - Static Lockfile/Manifest Auditing: Perform dependency audits on static, pre-existing lockfiles or generate them using strictly read-only, non-resolving commands (such as
uv export --frozen --no-emit-project --no-hashes). - Conditional Tool Installation: Install auxiliary scanning tools (such as
uv) conditionally inside workflows (e.g., only ifuv.lockis present in the working directory). Do not install them unconditionally to avoid unnecessary package-download runtime, dependency overhead, and supply-chain security surface area to repositories that do not use them.
Inline PR review & comment management via gh CLI:
- When requested to check inline PR review comments or reply to them, use the GitHub REST API via the
ghCLI for direct and accurate interaction:- Fetch all inline comments:
gh api repos/{owner}/{repo}/pulls/{pull_number}/comments - Reply to an inline comment thread:
(Note: Use single quotes for inner strings in PowerShell to avoid escaping issues).gh api --method POST -H "Accept: application/vnd.github+json" \ /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies \ -f body="Your reply text"
- Fetch all inline comments:
Reviewing PRs against this repo (see .github/copilot-instructions.md):
- Be comprehensive on the first pass; prioritize correctness/security over style.
- Respect intentional patterns: SHA-pinned actions with
# ratchet:comments and deliberately quoted workflow expressions are intentional — do not flag them. - Review merge-automation changes against the related/unrelated policy, not an "all checks must pass" assumption. The durable-outcome gate intentionally fails closed and detects this run's outcome by snapshotting review IDs (not timestamps).
Key Files Reference
.github/workflows/reusable-gemini-guard.yml— shared trigger policy + ref/fork resolution..github/workflows/reusable-gemini-dispatch.yml— entry point / command router..github/workflows/gemini-review.yml— code-review + security passes; buildsreview_summary..github/workflows/gemini-merge.yml— merge policy execution + durable-outcome gate..github/commands/pr-merge.toml— the prompt encoding the merge/remediation policy..github/commands/pr-review.toml— the review prompt (severity levels, comment format)..github/workflows/reusable-ci.yml+ci-{npm,python,php,java}.yml— reusable CI..github/workflows/reusable-security-scan.yml— dependency audits + CodeQL.actions/setup-{node,python,php,java}-env/action.yml— composite setup actions.workflow-templates/— starter workflows +*.properties.jsonauto-suggestion patterns.tests/— pytest suite validating templates and language support.GEMINI.md— links toAGENTS.mdas the single source of truth..github/copilot-instructions.md— review guidance for AI reviewers of this repo.README.md/QUICKSTART.md— downstream consumption examples and full input/secret docs.docs/ARCHITECTURE.md— the full deep-dive catalog.
