agentleFS
JeanKadangJeanKadang/DOC-GitHub-Practice-Skills/skills/github-projects/SKILL.md

github-projects

Skill1 starsChanged 45 days agoMITView on GitHub

Use when a GitHub repo has (or is about to have) more than one maintainer and work needs a shared board — setting up a GitHub Projects v2 board, adding fields, adding issues or PRs to a board, updating Status/Priority/Effort on items, auditing a board that has drifted out of sync with the Issues tab, or deciding whether a board is warranted at all.

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. 0 are common, 2 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 2

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Never create a board silently as part of some other task.

    line 29
  2. Very specific:

    Every field created above (Priority, Effort, Confidence, Target date) is shared across every linked repo's items automatically — there's no …

    line 113
  3. Distinctive:

    Board fields mirror issue metadata: When you change an issue's priority label, change the board's Priority field in the same breath.

    line 176

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GitHub Projects v2 (multi-maintainer repos)

A Projects board is a view over issues, never a replacement for them. Labels, milestones, assignees, and issue bodies stay the source of truth; the board mirrors them so several maintainers can see who is doing what without reading every issue. If a fact lives only on the board, it is lost to anyone reading the repo through the API, the Issues tab, or gh.

Companion skills: github-issue-first (filing, labels, assignment, dependencies), github-hygiene (branch/PR conventions), and github-releases (milestones — this skill's iteration-field guidance is the Projects-board complement to github-releases's milestone conventions). Anything you create here still follows those.

Decide whether a board is warranted

SituationDo this
Solo maintainerNo board. Milestones + labels are the whole system; an unmaintained board is worse than none.
Second maintainer joining, or an outside contributor picking up issuesCreate the board before they arrive, so it is populated on day one.
Multiple maintainers, work already spans several reposOne org-level board linked to each repo, not one board per repo.
Maintainer explicitly asks for a boardCreate it, and say what the ongoing upkeep is.

Never create a board silently as part of some other task. Boards are visible, shared, and annoying to unwind — confirm with the maintainer first.

Prerequisite: token scope

gh project needs the project scope, which the default gh auth login token does not include. Check before you start; every project command fails with a scope error otherwise.

gh auth status                 # look for 'project' in Token scopes
gh auth refresh -s project     # add it (interactive — the user must run this)

For org-owned projects add read:org as well. If the scope is missing, stop and tell the user the exact command — do not work around it by editing issues instead.

Creating and wiring up a board

# 1. Create. --owner is a user login or an org login, not the repo.
gh project create --owner "@me" --title "Roadmap"          # personal
gh project create --owner <org> --title "Roadmap"          # org-owned (preferred for teams)

# 2. Link it to the repo(s) so it appears on the repo's Projects tab.
gh project link <number> --owner <org> --repo <repo>
gh project link <number> --owner <org> --team <team>       # org boards: give the team access

# 3. Confirm.
gh project list --owner <org>
gh project view <number> --owner <org>

New boards ship with a Status single-select field (Todo/In Progress/Done). Add the rest:

gh project field-create <number> --owner <org> --name "Priority" \
  --data-type SINGLE_SELECT --single-select-options "P0,P1,P2,P3"
gh project field-create <number> --owner <org> --name "Effort" \
  --data-type SINGLE_SELECT --single-select-options "Small,Medium,Large,Unknown"
gh project field-create <number> --owner <org> --name "Confidence" \
  --data-type SINGLE_SELECT --single-select-options "High,Medium,Low"
gh project field-create <number> --owner <org> --name "Target date" --data-type DATE

PowerShell:

gh project field-create <number> --owner <org> --name "Priority" `
  --data-type SINGLE_SELECT --single-select-options "P0,P1,P2,P3"
gh project field-create <number> --owner <org> --name "Effort" `
  --data-type SINGLE_SELECT --single-select-options "Small,Medium,Large,Unknown"
gh project field-create <number> --owner <org> --name "Confidence" `
  --data-type SINGLE_SELECT --single-select-options "High,Medium,Low"
gh project field-create <number> --owner <org> --name "Target date" --data-type DATE

Match the Priority options to the repo's existing priority labels — if the repo uses priority-high/medium/low, the field options are those, not P0–P3. Two schemes side by side is the failure mode.

Iteration fields cannot be created from the CLI. gh project field-create only accepts TEXT, SINGLE_SELECT, DATE, NUMBER. Iterations must be added in the web UI (or via a GraphQL createProjectV2Field mutation). Don't fake one with a text field, and don't repurpose milestones for it: milestones are delivery buckets, not cadence (see github-releases). Say it needs the UI or GraphQL, or agree with the maintainer to go without cadence tracking.

Multi-repo boards

The org-level pattern from the decision table above (one board linked to several repos, not one board per repo) is the same gh project create and gh project link primitives shown earlier — just called once per repo instead of once total (this is a how-to for an already-decided pattern, not a policy question):

gh project create --owner <org> --title "Team roadmap"
gh project link <number> --owner <org> --repo <org>/<repo-a>
gh project link <number> --owner <org> --repo <org>/<repo-b>
gh project link <number> --owner <org> --repo <org>/<repo-c>

Every field created above (Priority, Effort, Confidence, Target date) is shared across every linked repo's items automatically — there's no per-repo field configuration. The one thing a single-repo board doesn't need: keep the board's built-in Repository field visible in every view. Nothing else on a shared board tells you which repo an item belongs to, and a filtered/grouped view (group by Repository, or a saved view per repo) is what keeps a multi-repo board readable once it has more than a handful of items.

Adding and updating items

# Add an existing issue or PR
gh project item-add <number> --owner <org> --url https://github.com/<org>/<repo>/issues/<N>

Setting a field value needs IDs, not names, and one field per invocation. Resolve them first. Dump the raw JSON once (gh project field-list <number> --owner <org> --format json) and read the shape before relying on the jq paths below — if a key differs on your gh version, adjust the filter rather than assuming the command is broken:

project_id=$(gh project view <number> --owner <org> --format json --jq .id)
field_id=$(gh project field-list <number> --owner <org> --format json \
  --jq '.fields[] | select(.name=="Priority") | .id')
option_id=$(gh project field-list <number> --owner <org> --format json \
  --jq '.fields[] | select(.name=="Priority") | .options[] | select(.name=="P1") | .id')
item_id=$(gh project item-list <number> --owner <org> --format json -L 200 \
  --jq '.items[] | select(.content.number==<N>) | .id')

gh project item-edit --id "$item_id" --project-id "$project_id" \
  --field-id "$field_id" --single-select-option-id "$option_id"

PowerShell:

$projectId = gh project view <number> --owner <org> --format json --jq .id
$fieldId = gh project field-list <number> --owner <org> --format json `
  --jq '.fields[] | select(.name=="Priority") | .id'
$optionId = gh project field-list <number> --owner <org> --format json `
  --jq '.fields[] | select(.name=="Priority") | .options[] | select(.name=="P1") | .id'
$itemId = gh project item-list <number> --owner <org> --format json -L 200 `
  --jq '.items[] | select(.content.number==<N>) | .id'

gh project item-edit --id "$itemId" --project-id "$projectId" `
  --field-id "$fieldId" --single-select-option-id "$optionId"

--text / --number / --date set the other field types; --clear removes a value. There is no name-based shortcut — every one of these is an ID lookup.

Don't create draft items (gh project item-create) for real work. A draft lives only on the board: no labels, no assignee, no URL, invisible to gh issue list, and it silently violates issue-first. File a real issue and add it.

Board hygiene

  • Every item is a real issue or PR. Audit for drafts periodically and convert or delete them.
  • Every item has an assignee — on the issue, not just a board column. Unassigned means unowned, board or not.
  • Board fields mirror issue metadata. When you change an issue's priority label, change the board's Priority field in the same breath; when they disagree, the label wins.
  • Nothing on the board that isn't in the repo. Decisions, blockers, and sequencing go in issue comments (see github-issue-first) — a note typed into a board field is invisible to anyone reading the issue.
  • Archive, don't delete, finished items: gh project item-archive. Deleting loses the history; the Done column silently becomes the board's whole weight otherwise.
  • Close the board when the phase ends: gh project close <number> --owner <org>.

Automation (must be enabled in the web UI)

Built-in workflows — auto-add items matching a filter, item closed → Status: Done, PR merged → Status: Done, auto-archive Done after N days — are not exposed through gh project. Turn them on under Project → ⋯ → Workflows. Recommend them explicitly rather than hand-syncing the board:

WorkflowWhy
Auto-add: is:issue is:open for the repoNew issues land on the board without anyone remembering
Item closed → DoneBoard stops lying the moment an issue closes
PR merged → DoneKeeps PR items in step with merges
Auto-archive Done after 14 daysBoard stays readable

Anything more (cross-field rules, notifications) is a GitHub Actions job using the actions/add-to-project action, which needs a PAT with project scope stored as a repo secret — document the secret if you add it.

Multi-maintainer scaffolding that goes with the board

A board without these is just a nicer-looking backlog:

  • Branch protection on the default branch: required CI status checks + at least one review; nobody pushes to it directly.
  • CODEOWNERS so reviews route automatically.
  • CONTRIBUTING.md stating the branch/commit/PR conventions (see github-hygiene).
  • Native blocked-by/blocks relations plus Depends on: #N body lines, so pick-up order is visible from the board.
  • Assign at triage, always.

Common mistakes

MistakeFix
gh project ... fails with a scope errorgh auth refresh -s project (read:org too for org boards) — the user must run it
Creating a board for a solo repoDon't; milestones + labels are the system
item-edit --field-id PriorityField, option, item and project all need real IDs — resolve via field-list/item-list --format json
Trying to create an Iteration field from the CLINot supported; use the web UI or GraphQL, or go without cadence tracking. Don't repurpose milestones
Draft items standing in for issuesFile the issue, then item-add the URL
Board Priority drifting from the priority labelLabel is source of truth; fix the field
One board per repo for a team working across reposOne org board, linked to each repo
Setting priority only on the boardSet the label too — API/gh users never see the board

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.