opening-prs — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited opening-prs (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A flowing graph that turns the imperative "create branch, push files, open a PR, poll mergeable_state" workflow into a structural DAG. The "NEVER push directly to main" rule is encoded as a validate= gate that physically can't be skipped.
from opening_prs import open_pr
result = open_pr(
repo="owner/repo",
branch_name="feat/cool-thing",
title="Add cool thing",
body="## Summary\n\n...",
files=[
("src/cool.py", "<file content>"),
("docs/cool.md", "<file content>"),
],
base="main", # default; protected names are also rejected
)
print(result["pr_url"]) # https://github.com/.../pull/N
print(result["mergeable_state"]) # clean | dirty | unstable | behind | blockedThe gh pr create workflow (or hand-rolled API calls) has five steps in prose form:
mergeable_state until GitHub finishes computing itEach step has known failure modes:
main — the diagnosed pattern thatmotivated github-procedures §6 in the first place.
mergeable_state: null immediately aftercreation. Need to poll. "Wait a few seconds and check" is prose, not a procedure — so it gets skipped under context pressure.
This skill encodes both as flowing primitives:
determine_branch ──▶ guard ──▶ get_base_head ──▶ create_branch
│ │
│ ▼
│ push_files
│ │
│ ▼
│ create_pr
│ / \
│ ▼ ▼
│ wait_mergeable present_pr [terminal]
│
└─ validate=must_not_be_base_branch{"main", "master", "trunk", "production", "prod"} — case-insensitive — and the configured base itself. The body of create_branch` never fires for a protected name. No GitHub API call happens for an invalid branch name.
consumes the retry budget while GitHub computes the merge result. unknown and null keep polling; settled states (clean, dirty, unstable, behind, blocked) stop. Exhaustion is soft: the PR is still presented with the last observed state.
Requires GH_TOKEN (or GITHUB_TOKEN) in the environment. Classic PAT or fine-grained PAT with repo scope.
import os
os.environ["GH_TOKEN"] = "ghp_..." # or load from a .env fileThe skill sends User-Agent: opening-prs on every API call. (GitHub returns 401 "Bad credentials" without a UA, regardless of token validity. Common trap.)
{
"pr_url": "https://github.com/owner/repo/pull/N",
"pr_number": 42,
"pr_state": "open",
"branch": "feat/cool-thing",
"base": "main",
"head_sha": "abc123...",
"mergeable_state": "clean",
"files_pushed": ["src/cool.py", "docs/cool.md"],
"detached_failures": [],
}Raises RuntimeError only if the main DAG fails (validate, branch creation, file push, or PR creation). Mergeable polling exhaustion is a soft failure — the PR exists, the field just isn't computed yet.
open_pr(
...,
mergeable_poll_retries=8, # default 8
mergeable_poll_base_ms=2000, # default 2s
mergeable_poll_max_ms=8000, # default 8s (cap on exponential backoff)
)with base64 encoding — slow above ~10 files). Use git push if you have the CLI.
commit per file via the contents API.
manipulation. Out of scope; use a different tool.
flowing — the DAG runner this skill is built onclosing-issues — the symmetric "close + synthesize" flowaccessing-github-repos skill for byte-layer GitHub access patterns~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.