{"id":"effda8d6-28f4-4481-a3e4-039ca1b7f1ce","shortId":"cR6X4X","kind":"skill","title":"lovstudio:gh-access","tagline":"Open a private GitHub repo to external clients or contractors without making it public. Accepts a mixed list of GitHub usernames and/or email addresses, resolves each to a GitHub account (falling back to an email invitation when the user has no discoverable account yet), and invi","description":"# lovstudio:gh-access\n\nGrant, revoke, and audit collaborator access on private GitHub repos — by\nusername **or** email, with read-only as the safe default.\n\n## Prerequisites\n\n- `gh` CLI authenticated (`gh auth status`) with a token that has:\n  - `repo` scope (always)\n  - `admin:org` scope (if the target repo is org-owned; caller must be org owner or repo admin)\n- The target repo exists and is accessible to the caller.\n\n## Subcommands\n\nThis skill has three modes. Pick based on the user's intent:\n\n| User intent | Subcommand |\n|---|---|\n| \"开权限 / share / invite / grant\" | **grant** |\n| \"撤销 / remove / revoke / 踢出\" | **revoke** |\n| \"谁有权限 / who has access / list\" | **list** |\n\nIf intent is unclear, use `AskUserQuestion` to disambiguate.\n\n## Workflow\n\n### Step 0: Collect inputs via AskUserQuestion\n\n**ALWAYS** collect the following BEFORE touching the API:\n\n1. **Target repo** — `<owner>/<repo>` (e.g. `lovstudio/private-demo`). If the\n   user is inside a git repo, pre-fill from `gh repo view --json nameWithOwner -q .nameWithOwner`.\n2. **Subcommand** — grant / revoke / list.\n3. **(grant/revoke only) Identifiers** — a whitespace- or comma-separated list\n   of GitHub usernames and/or email addresses. Mixed is fine.\n4. **(grant only) Permission level** — default `pull` (read-only). Offer:\n   - `pull` — read + issues + PRs (recommended default)\n   - `triage` — read + can label/close issues & PRs, no code write\n   - `push` — write access (⚠ confirm explicitly)\n   - `maintain` / `admin` — block unless user explicitly insists\n\nNever silently escalate. If the user just says \"给他权限\" without specifying\nlevel, default to `pull` and state that clearly.\n\n### Step 1: Resolve identifiers → GitHub usernames\n\nFor each identifier in the list, follow this resolution chain and record the\noutcome per identifier (for the final summary report):\n\n```\nidentifier → classify → resolve\n```\n\n**Classification rule:** an identifier containing `@` is treated as an email,\notherwise as a GitHub username.\n\n#### Case A — looks like a username\n\n1. Verify the account exists:\n   ```bash\n   gh api \"users/<login>\" --jq '.login' 2>/dev/null\n   ```\n2. If it returns the login → resolved as `login`, status `user_ok`.\n3. If the call 404s → status `user_not_found`. Do NOT fall back to email invite\n   (we don't have an email). Report and skip.\n\n#### Case B — looks like an email\n\n1. Search by email:\n   ```bash\n   gh api \"search/users?q=<email>+in:email\" --jq '.total_count, .items[0].login'\n   ```\n2. If `total_count >= 1` and a login is returned → resolved as `login`,\n   status `email_to_user`.\n3. If `total_count == 0` → fall back to **email invite** path:\n   - For org repos: `gh api -X POST \"orgs/<org>/invitations\" -f email=<email> -f role=direct_member` then add the pending member as an outside collaborator on the repo once they accept. **Note**: inviting directly-to-repo by email is not supported by the REST API for non-org personal repos — if the target is a personal repo, report `email_no_account` and ask the user to obtain the recipient's GitHub username.\n   - Status: `email_invited` (org) or `email_no_account` (personal repo).\n\nShow the resolution table to the user **before** performing writes:\n\n| Input | Type | Resolved | Status |\n|---|---|---|---|\n| `alice` | username | `alice` | user_ok |\n| `bob@example.com` | email | `bobhub` | email_to_user |\n| `carol@startup.io` | email | — | email_invited (or email_no_account) |\n| `typo-user` | username | — | user_not_found |\n\nAsk the user to confirm before proceeding with writes. Skip `user_not_found`\nand `email_no_account` entries by default.\n\n### Step 2: Execute\n\n#### grant\n\nFor each resolved username, issue a repo invitation:\n\n```bash\ngh api -X PUT \"repos/<owner>/<repo>/collaborators/<login>\" \\\n       -f permission=<pull|triage|push|maintain|admin>\n```\n\n- Response `201` = invitation sent (pending until recipient accepts).\n- Response `204` = already a collaborator; permission was updated.\n- Response `422` = user not found or already pending; inspect and report.\n\nFor org-repo email invites that resolved to `email_invited` above, no\nadditional call is needed — the org invitation covers repo access once the\nuser accepts. Tell the user to remind the recipient to check their email.\n\n#### revoke\n\n```bash\ngh api -X DELETE \"repos/<owner>/<repo>/collaborators/<login>\"\n```\n\n- Response `204` = removed (or was never a collaborator — idempotent).\n- For email-only identifiers with no resolved login: use\n  `gh api -X DELETE \"orgs/<org>/memberships/<login>\"` only if the user\n  explicitly wants to remove from the whole org; otherwise skip and report.\n\nBefore executing revokes, **show the list of logins that will be removed and\nask for a final confirmation** (revokes are visible to the recipient and can\nbe socially awkward to reverse).\n\n#### list\n\n```bash\ngh api \"repos/<owner>/<repo>/collaborators?affiliation=all\" \\\n       --jq '.[] | {login, permissions}' \\\n       --paginate\n```\n\nAlso list pending invitations:\n\n```bash\ngh api \"repos/<owner>/<repo>/invitations\" --paginate \\\n       --jq '.[] | {invitee: .invitee.login, email, permissions, created_at}'\n```\n\nPresent as two tables: **Active collaborators** and **Pending invitations**.\n\n### Step 3: Report\n\nShow a final summary table for grant/revoke operations:\n\n```\ngh-access report — <owner>/<repo>\n=================================\nGranted (pull): alice, bobhub\nInvited via email: carol@startup.io (pending org invite)\nSkipped: typo-user (user_not_found)\n```\n\nInclude the invitation URL the user can share manually if helpful:\n`https://github.com/<owner>/<repo>/invitations`\n\n## Rules\n\n- **Default to `pull` (read-only)** unless the user explicitly names a higher\n  permission. State the chosen level clearly before executing.\n- **Never escalate to `admin`/`maintain`** without an explicit, unambiguous\n  request — ask a confirming `AskUserQuestion` even if the user seemed to ask.\n- **Show the resolution table before writes.** Clients mistyping a username is\n  common; showing the resolved login prevents inviting the wrong person.\n- **Idempotent revokes.** A `204` on a non-collaborator is fine — don't panic.\n- **Batch-friendly.** A single invocation can process a long mixed list;\n  execute resolution in parallel where possible, but keep writes sequential so\n  partial failures are easy to report.\n- **Email invites only work cleanly for org repos.** For personal repos\n  without a resolved username, stop and ask the user to obtain a GitHub\n  username from the recipient.\n- **Private repos only are the typical case**, but this skill works on public\n  repos too — no need to refuse.\n\n## Common gh CLI quick reference\n\n```bash\n# Who am I? What scopes do I have?\ngh auth status\n\n# Is this a repo I can admin?\ngh api \"repos/<owner>/<repo>\" --jq '.permissions'\n\n# Cancel a pending invitation\ngh api -X DELETE \"repos/<owner>/<repo>/invitations/<invitation_id>\"\n\n# Show org membership of a user\ngh api \"orgs/<org>/memberships/<login>\" --jq '.role, .state'\n```","tags":["access","skills","lovstudio","agent-skills","ai-coding-assistant","cjk","claude-code","cursor","gemini-cli","markdown-to-docx","markdown-to-pdf"],"capabilities":["skill","source-lovstudio","skill-gh-access","topic-agent-skills","topic-ai-coding-assistant","topic-cjk","topic-claude-code","topic-cursor","topic-gemini-cli","topic-markdown-to-docx","topic-markdown-to-pdf"],"categories":["skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/lovstudio/skills/gh-access","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add lovstudio/skills","source_repo":"https://github.com/lovstudio/skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (6,978 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-21T01:36:44.558Z","embedding":null,"createdAt":"2026-04-18T22:18:59.578Z","updatedAt":"2026-04-21T01:36:44.558Z","lastSeenAt":"2026-04-21T01:36:44.558Z","tsv":"'/collaborators':595,675,753 '/dev/null':345 '/invitations':442,768,831,1024 '/memberships':700,1034 '0':163,404,427 '1':176,283,333,389,410 '2':200,344,346,406,578 '201':604 '204':612,677,899 '3':205,358,423,787 '4':225 '404s':362 '422':620 'accept':19,463,610,656 'access':4,54,60,117,150,253,652,799 'account':34,47,336,495,514,549,573 'activ':781 'add':450 'addit':643 'address':28,221 'admin':92,110,257,602,857,1009 'affili':754 'alic':531,533,803 'alreadi':613,625 'also':760 'alway':91,168 'and/or':26,219 'api':175,340,395,438,478,591,671,696,751,766,1011,1020,1032 'ask':497,557,730,864,874,956 'askuserquest':158,167,867 'audit':58 'auth':82,1001 'authent':80 'awkward':745 'b':384 'back':36,370,429 'base':128 'bash':338,393,589,669,749,764,991 'batch':911 'batch-friend':910 'block':258 'bob@example.com':536 'bobhub':538,804 'call':361,644 'caller':103,120 'cancel':1015 'carol@startup.io':542,808 'case':327,383,973 'chain':297 'check':665 'chosen':849 'classif':312 'classifi':310 'clean':943 'clear':281,851 'cli':79,988 'client':12,881 'code':249 'collabor':59,457,615,683,782,904 'collect':164,169 'comma':213 'comma-separ':212 'common':886,986 'confirm':254,561,734,866 'contain':316 'contractor':14 'count':402,409,426 'cover':650 'creat':775 'default':76,230,241,275,576,833 'delet':673,698,1022 'direct':447,467 'directly-to-repo':466 'disambigu':160 'discover':46 'e.g':179 'easi':936 'email':27,39,68,220,321,372,379,388,392,399,420,431,444,471,493,508,512,537,539,543,544,547,571,634,639,667,687,773,807,939 'email-on':686 'entri':574 'escal':265,855 'even':868 'execut':579,718,853,922 'exist':114,337 'explicit':255,261,705,842,861 'extern':11 'f':443,445,596 'failur':934 'fall':35,369,428 'fill':191 'final':306,733,791 'fine':224,906 'follow':171,294 'found':366,556,569,623,818 'friend':912 'gh':3,53,78,81,193,339,394,437,590,670,695,750,765,798,987,1000,1010,1019,1031 'gh-access':2,52,797 'git':187 'github':8,24,33,63,217,286,325,505,962 'github.com':830 'grant':55,140,141,202,226,580,801 'grant/revoke':206,795 'help':829 'higher':845 'idempot':684,896 'identifi':208,285,290,303,309,315,689 'includ':819 'input':165,527 'insid':185 'insist':262 'inspect':627 'intent':133,135,154 'invi':50 'invit':40,139,373,432,465,509,545,588,605,635,640,649,763,785,805,811,821,892,940,1018 'invite':771 'invitee.login':772 'invoc':915 'issu':238,246,585 'item':403 'jq':342,400,756,770,1013,1035 'json':196 'keep':929 'label/close':245 'level':229,274,850 'like':330,386 'list':22,151,152,204,215,293,722,748,761,921 'login':343,351,354,405,413,418,693,724,757,890 'long':919 'look':329,385 'lovstudio':1,51 'lovstudio/private-demo':180 'maintain':256,601,858 'make':16 'manual':827 'member':448,453 'membership':1027 'mistyp':882 'mix':21,222,920 'mode':126 'must':104 'name':843 'namewithown':197,199 'need':646,983 'never':263,681,854 'non':481,903 'non-collabor':902 'non-org':480 'note':464 'obtain':501,960 'offer':235 'ok':357,535 'open':5 'oper':796 'org':93,101,106,435,441,482,510,632,648,699,712,810,945,1026,1033 'org-own':100 'org-repo':631 'otherwis':322,713 'outcom':301 'outsid':456 'own':102 'owner':107 'pagin':759,769 'panic':909 'parallel':925 'partial':933 'path':433 'pend':452,607,626,762,784,809,1017 'per':302 'perform':525 'permiss':228,597,616,758,774,846,1014 'person':483,490,515,895,948 'pick':127 'possibl':927 'post':440 'pre':190 'pre-fil':189 'prerequisit':77 'present':777 'prevent':891 'privat':7,62,967 'proceed':563 'process':917 'prs':239,247 'public':18,979 'pull':231,236,277,598,802,835 'push':251,600 'put':593 'q':198,397 'quick':989 'read':71,233,237,243,837 'read-on':70,232,836 'recipi':503,609,663,740,966 'recommend':240 'record':299 'refer':990 'refus':985 'remind':661 'remov':143,678,708,728 'repo':9,64,89,98,109,113,178,188,194,436,460,469,484,491,516,587,594,633,651,674,752,767,946,949,968,980,1006,1012,1023 'report':308,380,492,629,716,788,800,938 'request':863 'resolut':296,519,877,923 'resolv':29,284,311,352,416,529,583,637,692,889,952 'respons':603,611,619,676 'rest':477 'return':349,415 'revers':747 'revok':56,144,146,203,668,719,735,897 'role':446,1036 'rule':313,832 'safe':75 'say':270 'scope':90,94,996 'search':390 'search/users':396 'seem':872 'sent':606 'separ':214 'sequenti':931 'share':138,826 'show':517,720,789,875,887,1025 'silent':264 'singl':914 'skill':123,976 'skill-gh-access' 'skip':382,566,714,812 'social':744 'source-lovstudio' 'specifi':273 'state':279,847,1037 'status':83,355,363,419,507,530,1002 'step':162,282,577,786 'stop':954 'subcommand':121,136,201 'summari':307,792 'support':474 'tabl':520,780,793,878 'target':97,112,177,487 'tell':657 'three':125 'token':86 'topic-agent-skills' 'topic-ai-coding-assistant' 'topic-cjk' 'topic-claude-code' 'topic-cursor' 'topic-gemini-cli' 'topic-markdown-to-docx' 'topic-markdown-to-pdf' 'total':401,408,425 'touch':173 'treat':318 'triag':242,599 'two':779 'type':528 'typic':972 'typo':551,814 'typo-us':550,813 'unambigu':862 'unclear':156 'unless':259,839 'updat':618 'url':822 'use':157,694 'user':43,131,134,183,260,268,341,356,364,422,499,523,534,541,552,554,559,567,621,655,659,704,815,816,824,841,871,958,1030 'usernam':25,66,218,287,326,332,506,532,553,584,884,953,963 'verifi':334 'via':166,806 'view':195 'visibl':737 'want':706 'whitespac':210 'whole':711 'without':15,272,859,950 'work':942,977 'workflow':161 'write':250,252,526,565,880,930 'wrong':894 'x':439,592,672,697,1021 'yet':48 '开权限':137 '撤销':142 '给他权限':271 '谁有权限':147 '踢出':145","prices":[{"id":"7b6febf3-035e-44c0-b136-dd0bc3b1c05c","listingId":"effda8d6-28f4-4481-a3e4-039ca1b7f1ce","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"lovstudio","category":"skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:18:59.578Z"}],"sources":[{"listingId":"effda8d6-28f4-4481-a3e4-039ca1b7f1ce","source":"github","sourceId":"lovstudio/skills/gh-access","sourceUrl":"https://github.com/lovstudio/skills/tree/main/skills/gh-access","isPrimary":false,"firstSeenAt":"2026-04-18T22:18:59.578Z","lastSeenAt":"2026-04-21T01:36:44.558Z"}],"details":{"listingId":"effda8d6-28f4-4481-a3e4-039ca1b7f1ce","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"lovstudio","slug":"gh-access","github":{"repo":"lovstudio/skills","stars":39,"topics":["agent-skills","ai-coding-assistant","cjk","claude-code","cursor","gemini-cli","markdown-to-docx","markdown-to-pdf"],"license":"mit","html_url":"https://github.com/lovstudio/skills","pushed_at":"2026-04-20T21:40:57Z","description":"Agent skills for AI coding assistants — Markdown to PDF/DOCX with 14 themes, CJK support","skill_md_sha":"c888bf88cd81d7265648d76cd5848e37fc63ca22","skill_md_path":"skills/gh-access/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/lovstudio/skills/tree/main/skills/gh-access"},"layout":"multi","source":"github","category":"skills","frontmatter":{"name":"lovstudio:gh-access","license":"MIT","description":"Open a private GitHub repo to external clients or contractors without making it public. Accepts a mixed list of GitHub usernames and/or email addresses, resolves each to a GitHub account (falling back to an email invitation when the user has no discoverable account yet), and invites them as collaborators with a chosen permission level (default: read-only, sufficient for pulling code and filing issues / PRs). Also supports revoking access and listing current collaborators. Use when the user says \"给客户开权限\", \"share private repo\", \"invite collaborator\", \"邀请外部协作者\", \"grant repo access\", \"客户要看代码\", \"revoke access\", \"撤销访问\", \"list collaborators\", or similar.","compatibility":"Requires gh CLI authenticated with a token that has `repo` + `admin:org` scope (for org-owned repos, the caller must be a repo admin or org owner)."},"skills_sh_url":"https://skills.sh/lovstudio/skills/gh-access"},"updatedAt":"2026-04-21T01:36:44.558Z"}}