
Python CLI that creates GitHub repos with safe defaults — branch protection, Dependabot, secret scanning, and pre-flight security scanning — applied automatically.
Create GitHub repositories with safe defaults applied automatically. Replaces the five-minute post-creation settings checklist with a single command.
gh-safe-repo create <owner/repo>
Branch protection, immutable tags, Dependabot, restricted Actions permissions, and secret scanning with push protection — all configured before you write your first line of code.
Status: gh-safe-repo is undergoing heavy development. It works well for the core use case — creating a new repo with secure defaults — but the CLI options are still being polished to better match user expectations. Expect breaking changes until releases and CI/CD are nailed down. ✌️
GitHub's defaults are optimised for discoverability and flexibility, not security: every new repo ships with no branch protection, no Dependabot, and Actions that have write access to the repo and can approve their own pull requests.
gh-safe-repo fixes all of that in one shot, showing you a plan first:
--public when you want the world to see it--local / --from), your working tree and git history are scanned locally before anything reaches GitHubhas_wiki = false in config)Everything is configurable. See Safe defaults in full for the exact settings and Configuration for how to change them.
gh CLI authenticated (gh auth login), or GITHUB_TOKEN set in your environmentuv for installation from sourcePushing code with --local or --from additionally needs your normal git credentials for GitHub — see Working from local or existing code.
git clone https://github.com/AriESQ/gh-safe-repo
cd gh-safe-repo
uv tool install .
gh-safe-repo --help
This installs gh-safe-repo into uv's tool environment and adds it to your PATH.
To run it without installing:
uv sync # creates .venv
./gh-safe-repo create <owner/repo>
1. Preview. --dry-run makes zero API calls — nothing is created:
$ gh-safe-repo create AriESQ/demo-repo --dry-run
Configuring AriESQ/demo-repo...
Planned Changes
Type Category Setting Value / Note
------ ----------------- -------------------------------------- ----------------------------------------------------------------
ADD repo repository AriESQ/demo-repo
DELETE file readme README.md
UPDATE actions allowed_actions 'all' → 'selected'
UPDATE actions verified_allowed False → True
UPDATE actions sha_pinning_required False → True
UPDATE actions default_workflow_permissions 'write' → 'read'
UPDATE actions can_approve_pull_request_reviews True → False
SKIP branch_protection branch_protection Branch protection requires a public repo or paid GitHub plan
SKIP security dependabot_alerts Requires a public repo or paid GitHub plan
SKIP security secret_scanning Requires a public repo or paid GitHub plan
SKIP security dependabot_security_updates Requires a public repo or paid GitHub plan
SKIP security private_vulnerability_reporting Requires a public repo or paid GitHub plan
SKIP security enable_dependency_graph Requires a public repo or paid GitHub plan
SKIP security enable_secret_scanning_push_protection Requires a public repo or paid GitHub plan
SKIP tag_protection tag_protection Tag protection rulesets require a public repo or paid GitHub plan
7 change(s) to apply, 8 skipped
Dry run — no changes made.
The SKIP rows above are a free-plan private repo: those features need a public repo or a paid plan. Nothing fails silently — see GitHub plan limitations.
2. Apply. Same command without --dry-run. You get the same plan, then a confirmation prompt (--yes skips it):
gh-safe-repo create AriESQ/demo-repo
3. Start working. On success you get the repo URL and ready-to-paste remote commands:
╭─ Done ───────────────────────────────────────────────────╮
│ Repository created successfully! │
│ https://github.com/AriESQ/demo-repo │
│ │
│ Add remote to existing repo: │
│ SSH : git remote add origin [email protected]:AriESQ/… │
│ HTTPS: git remote add origin https://github.com/… │
│ │
│ Clone fresh: │
│ SSH : git clone [email protected]:AriESQ/demo-repo.git │
│ HTTPS: git clone https://github.com/AriESQ/demo-… │
╰──────────────────────────────────────────────────────────╯
Remotes are listed with your preferred protocol first (gh config get -h github.com git_protocol).
gh-safe-repo create <owner/repo> # private (default)
gh-safe-repo create <owner/repo> --public # public — branch and tag protection apply
A plain create initializes the repo so a default branch exists (branch protection needs one), then deletes the auto-generated README.md so you start clean. Set auto_init = true in config to keep it.
gh-safe-repo create <owner/repo> --local ~/projects/myapp
Scans the directory for secrets first, creates the repo, pushes all branches and tags, then wires up origin and upstream tracking in your original directory so git push works immediately. An existing origin pointing somewhere else is left alone; a warning and the success banner tell you the exact git push -u origin <branch>:<branch> to run instead. See Working from local or existing code.
gh-safe-repo create <owner/repo> --from <owner/source>
gh-safe-repo create <owner/pub> --from <owner/priv> --public # the riskiest move — scanned thoroughly
Clones the source with full history, scans it, and mirrors it into a fresh repo with safe defaults. If you abort at the scan, no code ever reaches the new repo.
gh-safe-repo fix <owner/repo> --dry-run # what's out of compliance?
gh-safe-repo fix <owner/repo> # apply the missing defaults
gh-safe-repo fix <owner/repo> --yes # no prompt, for scripts