These rules apply to every developer and AI agent opening pull requests in this repository.
Open PRs from branches in PolicyEngine/policyengine-sim-api, not from personal
forks. CI and deployment checks are designed around same-repository branches.
Before creating or sharing a PR:
- Confirm the canonical repository is reachable:
gh repo view PolicyEngine/policyengine-sim-api --json nameWithOwner. - Open a GitHub issue for the work, or verify that an appropriate issue already exists.
- Put
Fixes #ISSUE_NUMBERas the first line of the PR description, using the issue number from the issue created or found in the previous step. - Run formatting and the most relevant tests for the changed surface. If an expected check cannot be run, say so in the PR body.
- Push the current branch to the canonical repository:
make push-pr-branch. - Create the PR as a draft from that same repository:
gh pr create --draft --repo PolicyEngine/policyengine-sim-api --head "$(git branch --show-current)" --base main. - Verify the PR is draft and the head repository is canonical:
gh pr view <PR> --repo PolicyEngine/policyengine-sim-api --json isDraft,headRepositoryOwner,headRepository. - Leave the PR as draft unless a maintainer explicitly asks for it to be marked ready for review.
The PR is valid only if isDraft is true and the head repository is
PolicyEngine/policyengine-sim-api. If you cannot push to the canonical
repository, stop and ask for access. Do not create a fork PR as a fallback. If
you accidentally create one, close it immediately and replace it with a
same-repository draft PR.
Agents must never bypass branch rules, even when their credentials have admin
rights: do not merge with gh pr merge --admin, and do not use GitHub's option
to bypass rules. If a required check or review blocks a merge, report it to a
human instead.
In a stack of pull requests, only the lowest unmerged one runs the full PR
workflow (.github/workflows/pr.yml) and the Modal image smoke. The ones above
it run only the CI complete job, which fails and says so. A stack therefore
uses one set of runners instead of one per layer.
CI completeis the required check. It needs every other job inpr.yml. On a pull request that isn't stacked, or is the lowest unmerged one, it passes only when every job passed. Skipped jobs would otherwise count as passing, so a stack can only merge bottom-up, and nothing merges untested.- When the pull request below merges, GitHub rebases the next one onto
the trunk, and that push starts its full run. If no run starts, push again
(
gh stack rebase, thengh stack push), or close and reopen the pull request. Re-running the old workflow doesn't help: it reuses the old event, which still describes the pull request as higher in the stack. - When you add a job to
pr.yml, add it toCI complete'sneeds. If the job has noneedsof its own, also give it the same stack condition as the other jobs.projects/policyengine-simulation-executor/tests/test_ci_complete_gate.pychecks both.
Do not add [codex], [claude], [copilot], or other agent labels to PR
titles. Use a plain descriptive title.