SuperAPI AI Directory

setup-repo-guards

Deployment & operations

View repository

Updated 10-15 15:12

About this skill

setup-repo-guards

Introduce the organization-standard set of CI guards into the target repository. The following 4 items are introduced, and in the order Step 1 → 4, each Step is finalized via PR → all CI pass → review thread resolve → squash merge before proceeding to the next.

  1. ai-review (wrapper for the PR auto-review workflow)
  2. AGENTS.md (collection of review perspectives read by AI review)
  3. Aggregation job for CI required checks (ci-complete etc.)
  4. branch protection ruleset and repository additional guards (GitHub API only, no commit required)

Reason for keeping this order: the dependencies — "the aggregation job to be included in the required checks must exist first" and "AGENTS.md is referenced from the PR's base commit, so it takes effect from the next PR after merging" — are naturally satisfied in this order.

Usage

setup-repo-guards Fandhe-AI/my-repo public
setup-repo-guards Fandhe-AI/repo-a public Fandhe-AI/repo-b private
  • 1st argument: target repository name (owner/repo)
  • 2nd argument: visibility (public / private). Used to branch the runner policy (public uses ubuntu hosted, private uses self-hosted. Only the review job of ai-review is an exception using a dedicated self-hosted runner)
  • When applying in bulk to multiple repositories, list the repository and visibility pairs. Process them sequentially in each repository's session (or parallel agent)

Prerequisites

  • gh The CLI is installed and authenticated with admin privileges for the target repository (check withcommand -v gh && gh auth status )
  • jq is installed (command -v jq )
  • Have reference permission to Fandhe-AI/actions (the provider of the reusable workflow)
  • The target repository is already cloned and CLAUDE.md and existing workflows can be read

Flow

Step 1: Introduction of ai-review (only if not yet introduced)

.github/workflows/ai-review.yml Add as a wrapper and reference the reusable workflow of Fandhe-AI/actions with the mutable tag ai-review.yml を mutable tag @latest (usage-side convention of Fandhe-AI/actions. Sincelatest automatically follows main, no reference update work is needed. Do not use commit SHA pinning or@main ). The old codex-review.yml has already been deleted from Fandhe-AI/actions, so do not use it for new introductions.

  • If .github/workflows/ai-review.yml already exists, skip this Step
  • If the old .github/workflows/codex-review.yml remains,codex-review.yml@latest cannot be resolved and the review is in a non-working state. Following the "Migration from codex-review" procedure in Fandhe-AI/actions' ai-review/README.md(input name mapping table and required check name replacement order), replace it

Create the wrapper by copying the single-provider template as-is (default is provider: codex, job ID codex):

mkdir -p .github/workflows
gh api -H 'Accept: application/vnd.github.raw' \
  repos/Fandhe-AI/actions/contents/ai-review/templates/ai-review.single.yml \
  > .github/workflows/ai-review.yml
  • For writing style and application conditions (fork PR rejection, runners without sudo, etc.), see Fandhe-AI/actions' ai-review/README.md と ai-review/docs/runner-exception.md, refer to and align with the wrapper of existing onboarding repositories (fandhe-frontend, etc.)
  • runner policy: CI jobs use ubuntu hosted for public, self-hosted for private. The ai-review review job (runner. codex's default is self-hosted's codex label) is the only exception for a dedicated runner. preflight / post_feedback(post-feedback-runner) does not touch credentials and by default automatically switches according to visibility (public is ubuntu-latest、private は self-hosted), so explicit specification is unnecessary
  • Credentials: CODEX_HOME_DIR is already set as an org-level Actions variable (visibility: all), so do not set it in the repository. gh api orgs/Fandhe-AI/actions/variables --jq '.variables[].name' to confirm its existence, and if it is absent (other org, etc.), ai-review/README.mdfollow "Setup" procedure step 3 to set it in the repository
  • update-external daily sync PR (chore/skills-update-* / chore/submodule-update-*), specify skip-branch-prefixes: chore/skills-update-,chore/submodule-update- . There is an accepted residual risk that a principal able to push can bypass the gate via the branch name, so do not specify it in repositories that have third-party write collaborators (ai-review/README.md「skip-branch-prefixes 's accepted residual risk")
  • collaborators-only(for events by actors with less than write, make preflight fail) use the default true as is
  • While credentials are unavailable, the review job becomes skipped , and the workflow as a whole appears successful. In the onboarding PR, always confirm at the job level that review was executed (see "Verification" below)

Step 2: Add AGENTS.md (the collection of AI review perspectives)

ai-review は AGENTS.md of the PR's base commit as repository-specific review criteria. Create it newly in Japanese at the repository root (if one already exists, do not weaken the criteria; append the missing perspectives).

Write the three mandatory perspectives by alwaysconcrete items specific to the target repository(do not reuse descriptions for another repository):

  1. Security perspective: secret leakage, injection, dependency auditing, least privilege, etc., in line with the repository's actual state
  2. Architecture and design consistency perspective: CLAUDE.md, responsibility boundaries in design documents, consistency with conventions
  3. Reusability and assetization perspective: separation of generic implementations, avoiding hardcoding, ease of repurposing, documentation readiness

In addition:

  • CLAUDE.md / .claude/rules/ / organize repository-specific perspectives extracted from design documents
  • Assign severity categories P0 (merge block) / P1 (strongly recommended) / P2 (suggestion), anddo not contradict the definition of P1 with the actual behavior of the CI gate (due to ai-review's block-priorities default P0,P1 , the review job fails even for P1)
  • Custom prompt (.github/ai-review/prompts/review.md) already exists, avoid double management: use the role division where the source of truth for perspectives is AGENTS.md and the source of truth for enforcement (completion judgment, mechanical promotion) is review.md, and make only the minimal addition of reading AGENTS.md in review.md. If it is left at the old path .github/codex/prompts/review.md , .github/ai-review/prompts/review.md (or prompt-path to specify the old path explicitly)
  • Reference examples: AGENTS.md in fandhe-backend / fandhe-frontend / Fandhe-AI/actions / agent-cli-skills
  • Note: The new standard takes effect from thenext PR after the merge(base reference specification)

Step 3: Set up an aggregate job for required CI checks

For workflows with multiple jobs, add an aggregate job (ci-complete , etc.): List all jobs in needs: , addif: always() , and checktoJSON(needs) with jq.

  • Strictly adhere to fail-closed: skipped Allowif: only for theexplicit listof "conditional jobs (jobs with ", and accept only success for other jobs (accepting skipped for all is flagged as fail-open with a P1 finding in AI review). If there is a change detection gate, accept skipped only in "situations where skipping is correct" based on the gate output
  • Add permissions: {} to the aggregate job, and write a comment saying "when adding a job, it must be added to needs"
  • If you are using a reusable workflow (lint-docs, etc.) from Fandhe-AI/actions, you can consolidate to a single check by bumping the reference to a SHA that includes the aggregate job (lint-docs / lint-docs-complete , etc.)
  • YAML の name: に # or ": ", always quote it (if unquoted, the API-reported name is truncated partway, making it unstable as a required check name)

Step 4: branch protection / repository settings (GitHub API only, no commit required)

  • Merge settings (gh api -X PATCH repos/...): squash only (merge commit / rebase prohibited), automatically delete branch after merge, allow auto-merge, squash title = PR_TITLE / body = PR_BODY
  • ruleset main-protection(target: branch、~DEFAULT_BRANCH, enforcement: active, bypass_actors empty):
    • deletion prohibited / non_fast_forward (force push prohibited)
    • pull_request: required_approving_review_count 0 (AI operation with no human approver. The review gate is ensured by ai-review's required checks) · required_review_thread_resolution true · allowed_merge_methods ["squash"]
    • required_status_checks(strict false is mandatory. If set to true, each time one PR is merged, the base of other open PRs becomes stale, and parallel runs of implement-issue-tree will not converge. strict is a freshness control, not a control for non-bypassability, so even with false, the client-side auto-merge G0 passes. If .claude/rules/ruleset-policy.md exists in the execution environment, follow its details): the required set changes depending on whether autoMerge is used (see "Notes on selecting required checks" below). If not used, [<aggregate job>, (always-on checks from other workflows that cannot be aggregated), ai-review's 3 checks] , the minimal set; if used, all contexts reported to the PR HEAD. ai-review's 3 checks start with the job ID <job> / preflight・<job> / review・<job> / post_feedback(if the template default, codex / preflight etc. In a multi-model configuration, the aggregation gate included with the template ai-review-gate may be just one). When registering individual jobs, preflight must always be included: in actor determination etc., preflight fails, subsequent ones become skipped, and skipped satisfies the required check (ai-review-gate は reviewer の preflight failing also causes itself to fail, so when registering with a single gate, there is no need to add individual preflight )
    • When using auto-merge (implement-issue-tree's autoMerge: true), bind the originating App's integration_id to each entry of required_status_checks (if unbound, G0 declines with issuer-unbound ). After updating the ruleset with PUT, always run the 3-axis sweep in "Verification" below(PUT は required_status_checks.parameters is replaced entirely, so the binding may be lost. When applying in bulk to multiple repos, run it on all repos)
  • Notes on selecting required checks (important pitfalls):
    • From the check runs of the most recent PR, select only checks that are "always reported". Do not include checks that may not run due to a workflow-level paths filter (merging will be blocked forever). skipped at the job level is acceptable
    • When not using autoMerge: do not make external apps such as Cursor Bugbot required.
    • autoMerge: trueWhen using (implement-issue-tree): the above exclusions do not apply. implement-issue-tree autoMerge G0 uses as its pass condition that "among the check-runs / commit statuses on the PR HEAD, there are 0 contexts not included in required_status_checks" (skills/implement-issue-tree/references/automerge-design.md G0 (d)/(f)/(g)). If you remove an external app from required, that context is detected by G0 (f) as a "non-required context" and it declines with server-enforcement-missing , so auto-merge structurally does not hold. args.externalChecks Include the contexts of external Apps declared inpreflight / review / post_feedback) and all jobs of the ai-review workflow (all contexts reported to the PR HEAD in required, and bind the required entries for external Apps with the originating App's ID (for rulesets, integration_id). Since commit statuses cannot have an App binding (integration_id), external providers that only publish commit-status-only checks that cannot be bound cannot be used together with autoMerge (a consequence of G0 (g)). To reconcile with the constraint that checks which may not run due to a paths filter cannot be made required, use an implementation pattern where conditions are moved to the workflow's on.pull_request.paths not at the job level if: and the check-run itself is always reported (skipped is acceptable) (example: Fandhe-AI/fandhe-frontend の musl-smoke.yml / image-size.yml the "Detect relevant changes" step. The same repo's .claude/rules/ci.md「ci-complete aggregation job and ruleset required checks" section [Issue #2325] also adopts the operation of not removing external checks from required).
    • When merging a PR that changes check names, replace the ruleset with the new check names via PUT before merging (If the old names remain, it stays "Expected" and BLOCKED even if all CI passes). For the PUT, take the JSON from GET and send it with only required_status_checks replaced
  • Additional guards: secret scanning + push protection / Dependabot alerts + automated security fixes / (if public) private vulnerability reporting / if tags are used, a tag ruleset (deletion, non_fast_forward) / make the default GITHUB_TOKEN permission read (after confirming that permissions: is explicit in all workflows)/ Set Actions' permission to create and approve PRs to false unless automated PR operations (such as update-external) exist / (if private) disable forking / disable unused wiki and projects
  • Record items that hit plan limits (403/422) as "user action required" and continue with the others

Verification

Confirm completion of each Step with the following:

repo="Fandhe-AI/<REPO>"
# Step 1: wrapper の存在と @latest 参照(@main・旧 codex-review.yml が残っていないこと)
grep -n "uses: Fandhe-AI/actions" .github/workflows/ai-review.yml
test ! -e .github/workflows/codex-review.yml && echo "旧 wrapper なし"
# Step 1: 直近 run でジョブ単位に review が実行されたこと(skipped は「workflow 成功」に見える)
# head_branch は検証対象の PR(導入 PR 等)の head ブランチ名
run_id=$(gh run list --repo "${repo}" --workflow "AI PR review" --event pull_request --branch "${head_branch}" --limit 1 --json databaseId --jq '.[0].databaseId')
gh run view "${run_id}" --repo "${repo}" --json jobs --jq '.jobs[] | {name, status, conclusion}'
# Step 2: AGENTS.md の存在と P0/P1/P2 定義
grep -n "P0\|P1\|P2" AGENTS.md | head
# Step 3: 直近 PR の check runs で集約ジョブが報告されること
gh pr checks "$(gh pr list --repo "${repo}" --state merged --limit 1 --json number --jq '.[0].number')" --repo "${repo}"
# Step 4: ruleset とマージ設定
gh api "repos/${repo}/rulesets" --jq '.[] | {id, name, enforcement}'
gh api "repos/${repo}" --jq '{allow_squash_merge, allow_merge_commit, allow_rebase_merge, delete_branch_on_merge, allow_auto_merge}'

# Step 4-a: 一括更新後の 3 軸スイープ(strict / bypass_actors / integration_id 残存)
# PUT した ruleset 単体ではなく branch target の全 ruleset を掃く(org 継承は source_type でルーティング)。
# コマンド全文・判定表は実行環境に .claude/rules/ruleset-policy.md があれば「一括更新後の検証」節を参照。
# 無ければ下記 Step 4-a/4-b のコマンド・判定表をそのまま用いる
org="${repo%%/*}"
gh api "repos/${repo}/rulesets" \
  --jq '.[] | select(.target == "branch") | [(.id|tostring), .name, (.source_type // "unknown")] | @tsv' |
while IFS=$'\t' read -r id name src; do
  case "${src}" in
    Repository)   path="repos/${repo}/rulesets/${id}" ;;
    Organization) path="orgs/${org}/rulesets/${id}" ;;
    *)            echo "UNKNOWN source_type: ${name} (${src}) — 手動確認"; continue ;;
  esac
  gh api "${path}" --jq '{
    name: .name, enforcement: .enforcement, bypass: (.bypass_actors | length),
    strict: ([.rules[]? | select(.type=="required_status_checks") | .parameters.strict_required_status_checks_policy] | first),
    total:   ([.rules[]? | select(.type=="required_status_checks") | .parameters.required_status_checks[]?] | length),
    unbound: [.rules[]? | select(.type=="required_status_checks") | .parameters.required_status_checks[]? | select(.integration_id == null) | .context]
  }'
done

# Step 4-b: classic branch protection を別枠で掃く(defaultBranchRef 解決・@uri エンコード・HTTP status 分岐)
db=$(gh repo view "${repo}" --json defaultBranchRef --jq '.defaultBranchRef.name')
db_enc=$(printf '%s' "${db}" | jq -sRr '@uri')
code=$(gh api -i "repos/${repo}/branches/${db_enc}/protection" 2>/dev/null | awk 'NR==1{print $2}')
case "${code}" in
  200) gh api "repos/${repo}/branches/${db_enc}/protection" --jq \
         '{strict: (.required_status_checks.strict // "none"), unbound: [.required_status_checks.checks[]? | select(.app_id == null) | .context]}' ;;
  404) echo "classic BP なし(${db})" ;;
  *)   echo "判定不能 (HTTP ${code:-?}) — Administration: read 権限を確認。green と扱わない" ;;
esac

As a final check, after rollout, run one small PR and observe that ai-review runs, required checks are reported, only squash merge is allowed, and thread resolution is actually enforced.

Completion report

Report in a table the PR number for each Step, the perspective structure of AGENTS.md, the final list of required checks in the ruleset, and items that could not be applied (with reasons).

Common failures

Problem Workaround
Allowing all skipped aggregate jobs is flagged as fail-open by AI review as a P1 issue Step 3: Limit skipped allowances to an explicit list of conditional jobs
A check-name-change PR is BLOCKED even if all CI passes (the ruleset still waits for the old name as "Expected") Step 4: Replace the ruleset with the new check names via PUT before merging
Unquoted name: の # and everything after it is truncated, making the API-reported name unstable Step 3: name に # If it contains ": ", quoting is required
Making a check from a workflow with a paths filter required permanently blocks merges Step 4: Make only checks that are always reported required
AI review detected mixing up reference files (inclusion of an AGENTS.md for a different repository) Step 2: Tailor it to specific items unique to the target repository
AI review pointed out a contradiction between the P1 definition in AGENTS.md and the actual CI gate behavior (fails even for P1) Step 2: Do not make the P1 definition contradict the actual gate behavior
Making GITHUB_TOKEN read breaks workflows that implicitly depend on write Step 4: Apply after confirming that permissions are explicit in all workflows
After PUTting the ruleset integration_id binding is dropped and auto-merge silently stops (looking only at strict and bypass makes it appear all green) Step 4-a: After PUT, run a 3-axis sweep (select(.integration_id==null))
Old ruleset / classic BP omissions leave unbound and strict=true remaining Step 4-a/4-b: Enumerate and sweep all branch rulesets, and for classic BP defaultBranchRef resolve + check separately in a status branch
When writing the G0 contract for auto-merge in AGENTS.md, list strict as a requirement; a contract stronger than the implementation becomes the basis for a P0 in AI review Step 2: If writing the G0 contract, explicitly state that strict is an "intentional non-requirement" (if .claude/rules/ruleset-policy.md exists in the execution environment, reference it)
In autoMerge operation, if external apps, post_feedback, etc. are removed from required, G0 (f) declines with server-enforcement-missing and auto-merge silently stops permanently Step 4: When using autoMerge, list all contexts of the PR HEAD as required (including all jobs of external apps and ai-review)
Old codex-review.yml Introducing a new wrapper, or leaving the old one in place (it has been deleted from Fandhe-AI/actions and the workflow cannot be resolved) Step 1: ai-review/templates/ai-review.single.yml Introduce from , and replace the old wrapper via "migration from codex-review"
ai-review の preflight Remove from required, and satisfy the required checks while review remains skipped due to actor determination failure Step 4: <job> / preflight Always include in required
Even though review is skipped due to unset credentials, treat onboarding as complete by seeing the overall workflow success Verification: gh run view --json jobs check per-job execution of review with

Notes

  • Create commits in Japanese Conventional Commits format, and follow the target repository's commit conventions and footer usage.--no-verify is not used
  • Quote shell variables in the "${var}" format
  • If an AI review point is valid, respond with a fix (do not paper over it by weakening tests/gates or skipping). Reply to the thread with what was done, resolve it, and then merge
  • Propose creating an Issue to the user for out-of-scope findings (do not file it on your own)
  • This skill requires GitHub operations over the network (ruleset PUT, workflow distribution). Run the relevant commands with the sandbox disabled on a per-command basis. It cannot be executed in an environment where network blocking cannot be lifted