github-interaction-limits-hardening
Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.
Best use case
github-interaction-limits-hardening is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.
Teams using github-interaction-limits-hardening should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/github-interaction-limits-hardening/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How github-interaction-limits-hardening Compares
| Feature / Agent | github-interaction-limits-hardening | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# GitHub Interaction Limits Hardening
## When to Use
Use this skill when a public GitHub repository or a set of repositories should remain readable but prevent outside/non-collaborator interactions, such as issue comments, PRs, discussions, or drive-by solicitation. Typical triggers include spam, paid-work solicitation, unwanted outside PRs, public repo hardening, or a request like "only collaborators can touch issues/code/PRs".
## Class of Task
Repo security hardening across one or more GitHub repositories by applying collaborator-only public interaction limits, verifying the live API state, and creating a renewal path because GitHub requires expiry.
## Key GitHub Constraints
- Repository interaction limits apply to **public repositories**.
- Private repositories return `405 Interaction limits cannot be set for private repositories`; private visibility already gates repo access to collaborators/members with access.
- Interaction limits are **temporary**; GitHub requires an `expiry`.
- Use the longest supported expiry, currently `six_months`, when the intent is durable lock-down.
- Add a renewal reminder or scheduled job before expiry if the setting should remain in force.
- This setting does **not** change repo visibility, collaborators, branch protection, or existing issue/comment history.
## Workflow
### 1. Authenticate and enumerate repos
```bash
gh auth status
gh api user --jq '.login'
OWNER=<owner-or-org>
mkdir -p /tmp/github-interaction-limits
gh repo list "$OWNER" --limit 1000 \
--json nameWithOwner,visibility,isArchived,defaultBranchRef,hasIssuesEnabled,pushedAt,url \
> /tmp/github-interaction-limits/repos.json
python3 - <<'PY'
import json
from collections import Counter
repos=json.load(open('/tmp/github-interaction-limits/repos.json'))
print('total', len(repos))
print(Counter((r['visibility'], r['isArchived']) for r in repos))
for r in repos:
print(f"{r['nameWithOwner']}\t{r['visibility']}\tarchived={r['isArchived']}\tissues={r['hasIssuesEnabled']}")
PY
```
### 2. Create or update a tracking issue
For multi-repo changes, create a tracking issue first. Include:
- trigger / why now
- scope and non-goals
- GitHub API limitation: `six_months` expiry
- acceptance criteria
- verification table requirement
Use a body file to avoid shell quoting problems:
```bash
cat > /tmp/github-interaction-limits/issue-body.md <<'EOF'
## Summary
Lock down public GitHub repository interactions so only collaborators can create/interact with issues, pull requests, comments, discussions, and related user-generated surfaces where GitHub supports that control.
## Scope
- Enumerate target repositories.
- Apply GitHub repository interaction limits with `limit=collaborators_only` to public repos.
- Verify final settings via GitHub API.
- Leave private repos unchanged unless GitHub supports an equivalent setting.
## Non-goals
- Do not delete existing issues/comments.
- Do not remove legitimate collaborators.
- Do not change repository visibility.
- Do not globally disable Issues unless explicitly approved.
## Acceptance criteria
- [ ] Public repos are verified as `collaborators_only`.
- [ ] Private repos are inventoried or explicitly skipped with rationale.
- [ ] Renewal path exists before expiry.
EOF
gh issue create --repo "$OWNER/<tracking-repo>" \
--title 'chore(security): restrict public repo interactions to collaborators only' \
--body-file /tmp/github-interaction-limits/issue-body.md
```
### 3. Apply collaborator-only interaction limits to public repos
```bash
python3 - <<'PY'
import json, subprocess, sys, time
from pathlib import Path
repos = json.load(open('/tmp/github-interaction-limits/repos.json'))
results=[]
for r in repos:
if r['visibility'] != 'PUBLIC':
continue
full = r['nameWithOwner']
row = {'repo': full, 'archived': r['isArchived'], 'url': r['url']}
before = subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True)
row['before'] = before.stdout.strip() or before.stderr.strip()
setp = subprocess.run([
'gh','api','-X','PUT',f'repos/{full}/interaction-limits',
'-f','limit=collaborators_only','-f','expiry=six_months'
], text=True, capture_output=True)
row['set_rc'] = setp.returncode
row['set_stderr'] = setp.stderr.strip()
after = subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True)
row['after_rc'] = after.returncode
row['after'] = after.stdout.strip() or after.stderr.strip()
results.append(row)
time.sleep(0.15)
Path('/tmp/github-interaction-limits/results.json').write_text(json.dumps(results, indent=2))
for row in results:
print(f"{row['repo']}\tset_rc={row['set_rc']}\tafter={row['after'][:200]}")
if any(r['set_rc'] != 0 or r['after_rc'] != 0 for r in results):
sys.exit(1)
PY
```
### 4. Verify final state
```bash
python3 - <<'PY'
import json, subprocess, sys
repos=json.load(open('/tmp/github-interaction-limits/repos.json'))
fail=[]
for r in repos:
if r['visibility'] != 'PUBLIC':
continue
full=r['nameWithOwner']
p=subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True, check=True)
data=json.loads(p.stdout or '{}')
print(f"{full}: {data.get('limit')} expires {data.get('expires_at')}")
if data.get('limit') != 'collaborators_only':
fail.append((full, data))
if fail:
print('FAIL', fail, file=sys.stderr)
sys.exit(1)
PY
```
### 5. Check private repos only if needed
If the user asked for "all repos," document that private repos are already visibility-gated. If you attempt the API for uniformity, expect:
```text
405 Interaction limits cannot be set for private repositories.
```
Treat that as confirmation of GitHub's public-only interaction-limit constraint, not as a failure requiring repo changes.
### 6. Post verification and close the tracking issue
```bash
cat > /tmp/github-interaction-limits/verification-comment.md <<'EOF'
## Verification update
Applied and verified GitHub repository interaction limits for all public repositories in scope.
Important GitHub limitation: repository interaction limits require an expiry; the longest supported expiry is `six_months`. A renewal path is required if this should remain durable.
| Repo | Visibility | Archived | Limit | Expires |
|---|---:|---:|---|---|
| ... | PUBLIC | false | `collaborators_only` | `...` |
Private repositories were inventoried but not modified because GitHub interaction limits cannot be set for private repositories; private visibility already restricts access to collaborators/members.
EOF
gh issue comment <issue-number> --repo "$OWNER/<tracking-repo>" --body-file /tmp/github-interaction-limits/verification-comment.md
gh issue close <issue-number> --repo "$OWNER/<tracking-repo>" --reason completed
```
## Renewal Pattern
Because `six_months` expires, create a renewal job/reminder before expiry. A safe cadence is every 150 days.
Renewal job prompt should:
1. verify `gh auth status`
2. list repos
3. re-apply `limit=collaborators_only` / `expiry=six_months` to public repos
4. verify every public repo
5. post a concise verification comment to the tracking issue
6. avoid changing visibility, collaborators, branch protection, repository contents, or issues beyond the verification comment
## Future Follow-Up Issues and Exit Handoff
For emergency/public-repo lockdown tasks, create future issues before exit so the temporary API setting turns into durable governance. Typical follow-ups:
1. **Scheduled renewal / control-plane codification**
- Move any local/Hermes renewal reminder into the repo's canonical scheduled-task system.
- Include deterministic script, dry-run mode, verification report, schedule metadata, and tests.
2. **Branch protection / ruleset audit**
- Audit branch protection, repository rulesets, PR settings, status checks, and enabled public surfaces (Issues, Discussions, Wiki, Projects, Actions).
- Keep this separate from interaction limits because code-path protection can block workflows and usually needs explicit approval.
3. **External contributor / solicitation response runbook**
- Document when to ignore, hide, report, or safely route non-collaborator comments, unsolicited paid-help offers, and legitimate contributor requests.
- Include templates and collaborator-onboarding guardrails.
Exit handoff pattern:
- Write a concise handoff under `docs/handoffs/` or the repo's canonical handoff location.
- Link the completed tracking issue, future issues, verified public repo table, private-repo limitation (`405`), renewal job/reminder, and next-session order.
- Commit the handoff as a narrow docs-only change, push, verify local `HEAD` equals remote, and check the CI run triggered by the handoff commit.
- Post the handoff commit and CI link back to the completed tracking issue.
- Keep unrelated pre-existing working-tree modifications out of the handoff commit.
## Pitfalls
- Do not promise permanent interaction limits; GitHub requires expiry.
- Do not treat private repo 405 responses as errors that need remediation.
- Do not disable Issues as a first response unless the user explicitly approves; interaction limits preserve existing issue workflows for collaborators.
- Use body files for issue bodies/comments to avoid shell quoting and command-substitution bugs.
- Archived public repos can still accept the interaction-limit API; include them in the public-repo pass unless intentionally skipped.
- Do not conflate interaction limits with branch protection/rulesets; create a separate audit/plan for code-path hardening.
## Verification Checklist
- [ ] `gh auth status` passes for the intended owner/admin account.
- [ ] Repo inventory includes visibility and archived state.
- [ ] Every public repo returns `{"limit":"collaborators_only", ...}` from `GET /repos/{owner}/{repo}/interaction-limits`.
- [ ] Private repo behavior is documented as visibility-gated / public-only API constraint.
- [ ] Tracking issue has a verification table.
- [ ] Renewal path exists before `expires_at`.Related Skills
blender-worktree-test-hardening
Recover and harden digitalmodel Blender automation work in isolated worktrees when uv/editable dependency paths break and local machines lack a Blender executable.
tax-filing-session-setup-with-github-tracking
Structured workflow for preparing and tracking a tax filing session using prepared documents, task checklist, and GitHub issue cross-referencing
tax-filing-session-setup-with-github-traceability
Structured workflow for setting up a multi-file tax filing session with GitHub issue tracking and prepared-file validation
github-issue-structure-for-personal-finance-tracking
Pattern for organizing financial analysis work across multiple repos (data/config vs. logic separation)
post-smoke-ci-plan-boundary-hardening
Harden a CI follow-up plan after an initial smoke/unblock issue lands. Use for post-smoke red workflows where later gates surface broad lint/type debt and the plan must stay bounded, evidence-backed, and review-honest.
iterative-plan-hardening-with-adversarial-waves
Tighten a draft plan through repeated Codex/Gemini adversarial review waves without prematurely advancing it to plan-review.
github-actions-trigger-and-shell-gotchas
Prevent false verification gaps in GitHub Actions by checking push path filters, shell compatibility, and shared CI environment failures before concluding a workflow fix worked or failed.
github-actions-cross-platform-validation-gotchas
Execution-time GitHub Actions pitfalls discovered while fixing cross-platform CI workflows — path-filter non-triggers, Windows shell parsing mismatches, and job-scoped validation.
documentation-contract-plan-hardening
Harden a documentation/contract plan before adversarial review by mapping every issue-scope requirement to independent acceptance criteria and tests, especially for routing/indexing contracts.
canonical-doc-contract-plan-hardening
Harden a documentation or mission-contract plan so adversarial reviewers cannot reject it for vague validator contracts, wrong artifact authority, or semantic drift gaps.
bounded-post-smoke-ci-hardening-plan
Plan post-smoke CI hardening as a bounded blocker-removal tranche instead of overpromising full green. Includes issue-body alignment, follow-up split rules, honest review bookkeeping, and reliable local validation commands.
plan-review-adversarial-hardening
Class-level workflow for plan-review hardening, adversarial review reruns, artifact grounding, approval hygiene, and prompt/path drift recovery.