Table of Contents generated with DocToc
Shared reference for the gh CLI and gh api / gh api graphql invocations the skills use against the project‘s tracker repository. The skills reference this file for the recipe shape; each inline command in a skill already substitutes the tracker repo slug from the adopting project’s manifest (see ../../<project-config>/project.md).
Placeholder convention used below:
<tracker> — the tracker repository slug from <project manifest>.tracker_repo (for Airflow, <tracker>).<upstream> — the upstream codebase slug from <project manifest>.upstream_repo (for Airflow, <upstream>).<N> — issue or PR number.Every skill's Step 0 pre-flight must verify that gh is authenticated and has collaborator access to <tracker>:
gh auth status # must show logged-in user + scopes gh api repos/<tracker> --jq .name # must return the repo name; 401/403/404 means stop
A non-zero exit on either command is a hard stop — the skill reports the failure and asks the user to gh auth login (or to ask for collaborator access to the tracker) rather than retrying.
gh api repos/<tracker>/collaborators --jq '.[].login'
The authoritative “who is on the security team” list. Every collaborator counts regardless of permission level (read / triage / write / maintain / admin). Roster snapshots maintained in the project manifest files (for Airflow, release-trains.md) are caches of this command's output and can drift between changes.
gh issue view <N> --repo <tracker> \ --json number,title,state,body,labels,milestone,assignees,author
Add --json comments when the skill needs the comment trail, and --json projectItems when it needs to see which project boards the issue sits on.
gh issue create --repo <tracker> \ --title '<title>' \ --body-file <path> \ --label '<label-1>' --label '<label-2>'
Always write the body to a temp file and pass --body-file — shell quoting silently corrupts anything with literal backticks, $(…), or newlines inside a multi-paragraph body.
gh issue edit <N> --repo <tracker> \ --add-label '<label-a>,<label-b>' \ --remove-label '<label-c>'
Apply every add + remove in one call so the change lands as a single audit-trail entry rather than as N separate events.
gh issue edit <N> --repo <tracker> --add-assignee @me # self-assign gh issue edit <N> --repo <tracker> --add-assignee <handle> # named user
gh issue edit <N> --repo <tracker> --body-file <tmpfile>
Write the edited body to a temp file first. The skills that perform “body-field surgery” (updating one ### <field> section without touching the rest) read the full body, replace the targeted section between its header and the next ### heading, and write the result back via --body-file.
gh issue comment <N> --repo <tracker> --body-file <tmpfile>
Before posting, scrub the comment body for bare-name mentions of project maintainers / release managers / security-team members and replace with @-handles. See the per-project mention rule (for Airflow, ../../<project-config>/naming-conventions.md#mentioning-airflow-maintainers-and-security-team-members) for the grep-list of names to check.
gh issue close <N> --repo <tracker> --reason completed # or 'not planned' gh issue reopen <N> --repo <tracker>
gh api 'repos/<tracker>/milestones?state=all&per_page=100' \ --jq '.[] | select(.title == "<target>") | {number, state}'
gh api repos/<tracker>/milestones \ -f title='<target>' \ -f state=open \ -f description='<optional one-line description>'
The create call returns the milestone object including its number — capture that in case the milestone is later closed (see fallback below).
gh issue edit <N> --repo <tracker> --milestone '<title>'
Closed-milestone fallback. gh issue edit --milestone '<title>' fails with '<title>' not found if the milestone is closed. Fall back to the REST API and reference it by number:
gh api repos/<tracker>/issues/<N> -X PATCH -F milestone=<number>
gh label list --repo <tracker> --limit 100 \ --json name,description,color --jq '.[].name'
gh label create '<name>' --repo <tracker> \ --description '<short description>' \ --color '<hex>'
Do not silently create labels without asking the user. Label names are the shared vocabulary of the security team, and new labels should be discussed.
gh pr create --web --repo <upstream> \ --base <base-branch> --head <user>:<branch> \ --title "<neutral title>" \ --body "$(cat <path-to-body>)"
--web is load-bearing. Per the per-project convention (for Airflow, see ../../<project-config>/fix-workflow.md#pr-creation-convention), always open PRs through the browser so the human reviewer can check the title, body, and Gen-AI disclosure before clicking Create.
gh pr edit <N> --repo <upstream> --add-label '<backport-label>'
Safe to run immediately after PR creation; the backport bot acts on the label when the PR merges, not when it is applied.
Forbidden. The public PR body and any follow-up public comment must not reveal the CVE, the security nature, or the private tracker URL. Enforce via the scrub step before writing the PR body — see the per-project scrubbing rule (for Airflow, ../../<project-config>/fix-workflow.md#pr-title--body-scrubbing).
See project-board.md for the board introspection and updateProjectV2ItemFieldValue patterns.
If any state-changing command fails, stop the apply loop, report the failure verbatim, and ask the user how to proceed — do not guess. Most sync-style skills order their apply list so the load-bearing edit (usually the body edit) is first; a failure on a later step leaves the body correct and a subsequent sync run will catch up the rest.