github-private-projects
Skill0 starsChanged 7 days agoMITView on GitHub
Use when connecting a machine to GitHub and creating or managing private repos.
- Reads credentials
- Commits and pushes
In this repository6 other files it gives its agents.
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 5 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 60
Create a classic token at https://github.com/settings/tokens with:
- Very specific: line 77
No OS keyring available (containers, some headless Linux, locked keychain)?
- Very specific: line 110
Read access passing but push failing is almost always a scope/role problem, not a credential problem: check gh api repos/<owner>/<repo> …
- Distinctive: line 153
Default branch (for a repo created empty or from a template):
- Very specific: line 166
Read the response before assuming what your plan allows.
- Distinctive: line 170
Do not claim protection is on because a command exited 0 — re-read the endpoint.
- Very specific: line 220
Before a transfer, check on the target: name collision (gh api orgs/<org>/repos --paginate --jq '.[].name'), and what the transfer may drop …
- Very specific: line 239
Check the files a private repo can afford to be sloppy about: .env*, deploy scripts, CI logs, test fixtures with real data, screenshots.
- Distinctive: line 241
Check commit author emails and any internal URLs in code, docs and the repo description.
- Distinctive: line 242
Check the licence actually permits publication.
- Distinctive: line 245
If anything is found, rotate the credential first.
- Very specific: line 252
Never put a token in a command line, a remote URL (https://user:token@...) or a commit — it lands in shell history, .git/config, or the log.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
GitHub private projects
When to Use
- A machine, container or agent account has never talked to GitHub.
- Creating a private repository, personally or in an organisation.
- Granting or revoking access, changing visibility, transferring, archiving or deleting one.
ghworks butgit pushstill prompts, or the reverse.
Public-repo work (issues, PR review, releases) is covered by the bundled github skill; this
one is about standing a private project up correctly and keeping it private.
0. Preflight — find out what already exists
git --version
gh --version 2>/dev/null || echo "gh not installed"
gh auth status 2>/dev/null || echo "gh not authenticated"
git config --global credential.helper 2>/dev/null || echo "no git credential helper"Three independent stores are in play and they are not the same thing:
| Store | Used by | Where it lives |
gh token | gh commands and gh api | ~/.config/gh/hosts.yml (macOS/Linux), %APPDATA%\GitHub CLI\hosts.yml (Windows) |
| git credential helper | git clone/push over HTTPS | OS keyring, ~/.git-credentials, or Windows Credential Manager |
| SSH key | git over git@github.com: | ~/.ssh/, %USERPROFILE%\.ssh |
Authenticating gh does not by itself fix git push. Bridge them with
gh auth setup-git, which registers gh as git's credential helper for github.com.
1. Authenticate
Pick one path; all three end at the same verification step.
A. Device flow (interactive machine)
gh auth login --hostname github.com --git-protocol https --web
gh auth setup-gitB. Personal access token (headless, containers, CI-like setup)
Create a classic token at https://github.com/settings/tokens with:
| Scope | Needed for |
repo | private repo read/write, creating personal private repos |
workflow | adding or editing .github/workflows/* |
read:org | listing org repos, team membership |
admin:org | creating repos in an org you administer, team management |
delete_repo | only if you will delete repositories |
Then, reading the token from a file or stdin — never as an argument:
gh auth login --with-token < /path/to/token.txt
# or: printf '%s' "$GH_TOKEN" | gh auth login --with-tokenNo OS keyring available (containers, some headless Linux, locked keychain)? Add
--insecure-storage; the token then lands in hosts.yml (mode 600) instead of failing.
Fine-grained tokens work too, but must include Administration: read and write (account or
org level) or repo creation returns 403; an org must also permit fine-grained tokens.
C. SSH
ssh-keygen -t ed25519 -C "<label-for-this-machine>" -f ~/.ssh/id_ed25519
gh ssh-key add ~/.ssh/id_ed25519.pub --title "<label-for-this-machine>"
ssh -T git@github.com # exits 1, prints "successfully authenticated" — the exit code is not the testThe text is the test; ssh -T always exits non-zero on GitHub.
Verify (all paths)
gh auth status
gh api user --jq '.login'gh auth status prints the scopes it holds. A fine-grained token shows no scope line at all —
that is normal, not a failure. Then prove git transport itself, with prompting disabled:
GIT_TERMINAL_PROMPT=0 git ls-remote https://github.com/<owner>/<repo>.git$env:GIT_TERMINAL_PROMPT="0"; git ls-remote https://github.com/<owner>/<repo>.gitRead access passing but push failing is almost always a scope/role problem, not a credential
problem: check gh api repos/<owner>/<repo> --jq '.permissions'.
2. Create a private repository
# personal, empty, with a README, cloned next to you
gh repo create <name> --private --add-readme --clone
# organisation
gh repo create <org>/<name> --private --description "<one line>"
# from a directory that already has commits
gh repo create <owner>/<name> --private --source . --remote origin --pushUseful flags: --gitignore <template>, --license mit, --template <owner>/<repo>.
Names are case-insensitive on GitHub even where your filesystem is not, may not contain
spaces, and must be unique within the owner.
--push with no commits fails — commit first (git add -A && git commit -m "init").
Verify creation
gh repo view <owner>/<name> --json nameWithOwner,visibility,isPrivate,defaultBranchRef,urlAssert "visibility":"PRIVATE" and "isPrivate":true. Visibility is the one property
where a successful command does not imply the requested state: org policy can override what
you asked for, so read it back.
3. Configure it
gh repo edit <owner>/<name> \
--description "<one line>" --homepage "<url>" \
--add-topic <topic> --add-topic <topic> \
--enable-issues --enable-wiki --enable-projects \
--delete-branch-on-merge \
--allow-squash-merge --allow-merge-commit false --allow-rebase-mergeDefault branch (for a repo created empty or from a template):
gh repo edit <owner>/<name> --default-branch <branch>Branch protection / rulesets
gh api repos/<owner>/<repo>/branches/<branch>/protection
gh api repos/<owner>/<repo>/rulesetsRead the response before assuming what your plan allows. Branch protection on private repositories has historically been plan-dependent (Pro/Team/Enterprise on personal accounts, org plans vary). A 403 that names a plan limitation means "not included", not "misconfigured": either upgrade, rely on rulesets if they are available to you, or enforce the rule in CI. Do not claim protection is on because a command exited 0 — re-read the endpoint.
Actions
gh api repos/<owner>/<repo>/actions/permissions
gh api -X PUT repos/<owner>/<repo>/actions/permissions -F enabled=true -f allowed_actions=allallowed_actions is all, local_only or selected. If workflows must be restricted, set
selected and then configure actions/permissions/selected-actions; setting the value
without that call leaves an empty allowlist and every action fails to resolve.
Secrets and variables
gh secret set <NAME> --body "$VALUE"
gh secret set <NAME> --env-file .env.production # many at once
gh secret list
gh variable set <NAME> --body "<value>"Secret values are write-only: gh secret list shows names and timestamps, never values.
Verification is "the name appears", plus a workflow run that consumes it.
4. Access
gh api repos/<owner>/<repo>/collaborators --jq '.[].login'
gh api -X PUT repos/<owner>/<repo>/collaborators/<user> -f permission=push
gh api -X DELETE repos/<owner>/<repo>/collaborators/<user>
# team (organisations)
gh api -X PUT orgs/<org>/teams/<team>/repos/<org>/<repo> -f permission=pushPermissions: pull, triage, push, maintain, admin. For an org repo, confirm your own
standing first — gh api orgs/<org>/memberships/<you> --jq '.role' must be admin to create
repos or change team access.
5. Retire, move, or expose
gh repo rename <new-name> # old URLs redirect, clones keep working
gh repo archive <owner>/<name> --yes # read-only, keeps history and issues
gh repo archive <owner>/<name> --yes --unarchive
gh api -X POST repos/<owner>/<repo>/transfer -f new_owner=<org>
gh repo delete <owner>/<name> --yes # requires the delete_repo scopeBefore a transfer, check on the target: name collision
(gh api orgs/<org>/repos --paginate --jq '.[].name'), and what the transfer may drop —
Actions secrets, environments, branch protection, webhooks, packages and Pages settings do
not all travel. Record them first. The transfer API's response echoes the pre-transfer
owner; that is normal, so verify with gh repo view <new-owner>/<repo>.
The local clone's path and remote must be updated separately — see
git-repo-workspace-layout, "Moving a repo between owners".
Before switching a private repo to public
Irreversible in practice: forks cannot be recalled and the history is world-readable.
- Scan all history, not HEAD. Either run
gitleaks/trufflehogin Docker over the clone, or list every blob and grep it:git rev-list --all --objects | awk '{print $1}' | git cat-file --batch \ | grep -aiE '(ghp_|gho_|github_pat_|sk-|AKIA|BEGIN [A-Z ]*PRIVATE KEY|password[=:])' - Check the files a private repo can afford to be sloppy about:
.env*, deploy scripts, CI logs, test fixtures with real data, screenshots. - Check commit author emails and any internal URLs in code, docs and the repo description.
- Check the licence actually permits publication.
gh repo edit <owner>/<repo> --visibility public --accept-visibility-change-consequences
If anything is found, rotate the credential first. Removing it from history afterwards does not un-leak it, and the repo may already be cached or forked.
Pitfalls
gh auth login --with-tokenreads the token from stdin.--with-token "$TOKEN"treats the value as a filename and fails with a confusing parse error.- Never put a token in a command line, a remote URL (
https://user:token@...) or a commit — it lands in shell history,.git/config, or the log. Prefer the credential helper or SSH. gh auth setup-gitis a separate step. Skip it andgit pushprompts whileghworks.- On Windows the default credential helper (
manager) stores in Windows Credential Manager, which is preferable tostore(~/.git-credentials, plaintext). Check withgit config --global credential.helperbefore changing anything. - Org repos behind SAML SSO return 403 "Resource protected by organization SAML enforcement" until the token is authorised for that org in GitHub's settings — no re-login fixes it.
gh repo createrun inside an existing repository without--sourcecreates an unrelated empty repo; with--source .it pushes what is there, including anything staged by accident.- Private-repo Actions minutes are metered against your plan's included quota; public-repo minutes are not. A workflow added to a private repo can therefore start costing money.
- Deleting a repo does not delete a local clone, CI caches, or forks made while it was public.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

