github-repository · git:20261002.4d31436 · 2026-10-02 · sha256 79c9edfd25004650
github-repository git:20261002.4d31436A
Immutable. This exact content never changes and is served at /api/v1/blob/79c9edfd25004650.
---
name: github-repository
description: "Configure GitHub topics, descriptions, merge policy, and security settings with gh."
license: MIT
metadata:
kind: task
author: Médéric HURIER (Fmind)
source: github.com/fmind/dot/tree/main/skills/github-repository
created: "2026-06-23"
updated: "2026-10-02"
---
# GitHub Repository
Derive a repository's description, homepage, and topics from its codebase and apply the requested fields with `gh repo edit`. For a new solo-maintained repository or an explicitly requested settings pass, use the baseline below; a metadata-only request does not include merge policy, sidebar features, or security settings.
## Workflow
Use [gh](../gh/SKILL.md) for account selection, bounded API calls, and request serialization when needed.
1. **Extract metadata** from the codebase:
- Project metadata: Python `pyproject.toml` (`[project]` name, description, and URLs).
- `README.md`: the first paragraphs give a one-line description under ~140 characters.
- Homepage: use the configured, verified canonical site; do not infer a live Pages site merely from the repository name.
- Topics: 3 to 6 lowercase tags for language, frameworks, tools, or domain (`agent`, `python`, `cli`); letters, numbers, and hyphens only, 50 characters max, 20 per repository.
1. **Inspect the current state** so the edit stays idempotent; stop when there is no GitHub remote or `gh` is not authenticated. Resolve repository identity through `gh`; never print raw remote URLs, which can contain credentials:
```bash
gh auth status
gh repo view --json nameWithOwner,visibility,isInOrganization,description,homepageUrl,repositoryTopics,deleteBranchOnMerge,squashMergeAllowed,mergeCommitAllowed,rebaseMergeAllowed,hasIssuesEnabled,hasProjectsEnabled,hasWikiEnabled,hasDiscussionsEnabled
```
1. **Build one scoped edit**: for metadata-only work, include only the requested metadata flags and topic changes. Use the complete baseline below only when repository settings are in scope, preserving an existing team's policy and active wiki/projects/discussions unless their removal was requested. Add the desired topics, remove obsolete topics only when replacing the set, and append `--enable-issues=false` only when the project tracks issues elsewhere. Query the repository REST payload and add the two secret-scanning flags only for a public repository or when `security_and_analysis.secret_scanning` is present; otherwise report that the capability is unavailable and continue with the remaining settings:
```bash
repository="$(gh repo view --json nameWithOwner --jq .nameWithOwner)"
repository_json="$(gh api "repos/$repository")"
desired_topics=(tag1 tag2 tag3)
args=(
--description "<description>" --homepage "<homepage-url>"
--delete-branch-on-merge --enable-squash-merge
--squash-merge-commit-message pr-title-description
--enable-merge-commit=false --enable-rebase-merge=false --allow-update-branch
--enable-wiki=false --enable-projects=false --enable-discussions=false
)
for topic in "${desired_topics[@]}"; do args+=(--add-topic "$topic"); done
while IFS= read -r topic; do
[[ " ${desired_topics[*]} " == *" $topic "* ]] || args+=(--remove-topic "$topic")
done < <(jq -r '.topics[]' <<<"$repository_json")
if [[ "$(jq -r .visibility <<<"$repository_json")" == public ]] ||
[[ "$(jq -r '.security_and_analysis.secret_scanning.status? // empty' <<<"$repository_json")" ]]; then
args+=(--enable-secret-scanning --enable-secret-scanning-push-protection)
else
echo "Secret scanning is unavailable for $repository; leaving it unchanged." >&2
fi
gh repo edit "$repository" "${args[@]}"
```
1. **Protect a public repository** in the same settings pass: enable private vulnerability reporting and add a default-branch ruleset that blocks deletion and force pushes without requiring pull requests or signatures, so direct pushes keep working. Skip the ruleset when `gh api "repos/$repository/rules/branches/<default-branch>" --jq 'map(.type)'` already lists both rules:
```bash
gh api -X PUT "repos/$repository/private-vulnerability-reporting"
gh api -X POST "repos/$repository/rulesets" --input - <<'EOF'
{"name": "Protect default branch", "target": "branch", "enforcement": "active",
"conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
"rules": [{"type": "deletion"}, {"type": "non_fast_forward"}], "bypass_actors": []}
EOF
```
1. **Verify** with the same `gh repo view --json ...` call and report the fields that changed.
## Gotchas
- **Truncation**: keep the description single-line and under ~140 characters or the GitHub UI truncates it.
- **Secret scanning eligibility**: public repositories are covered; private and internal repositories require an eligible GitHub Secret Protection or Advanced Security entitlement. Capability-detect instead of inferring availability from personal versus organization ownership.
- **Visibility**: never pass `--visibility` or `--accept-visibility-change-consequences` unless the user explicitly asks.
- **Plan limits**: rulesets and branch protection on a private repository need GitHub Pro or Team; on Free the API answers 403 `Upgrade to GitHub Pro`. Report the gap instead of changing visibility. Private vulnerability reporting applies to public repositories only.
## Documentation
- [gh repo edit manual](https://cli.github.com/manual/gh_repo_edit)
- Releases: [GitHub CLI](https://github.com/cli/cli/releases)
- Companion skills: [github-pull-request](../github-pull-request/SKILL.md) (PR titles feed the squash message), [project-license](../project-scaffolding/references/project-license/GUIDE.md) (LICENSE), [project-scaffolding](../project-scaffolding/references/bootstrap.md) (bootstrap).