{"id":50731346,"url":"https://github.com/nsexceptional/gh-projects","last_synced_at":"2026-06-10T09:01:14.348Z","repository":{"id":363184939,"uuid":"1262236863","full_name":"NSExceptional/gh-projects","owner":"NSExceptional","description":"A gh CLI extension for GitHub Projects (v2): concise, agent-friendly commands for boards, items, fields, and repo links.","archived":false,"fork":false,"pushed_at":"2026-06-07T19:27:09.000Z","size":33,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T21:08:21.562Z","etag":null,"topics":["cli","gh-extension","github-projects","projects-v2"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NSExceptional.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T18:39:16.000Z","updated_at":"2026-06-07T19:27:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/NSExceptional/gh-projects","commit_stats":null,"previous_names":["nsexceptional/gh-projects"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/NSExceptional/gh-projects","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NSExceptional%2Fgh-projects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NSExceptional%2Fgh-projects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NSExceptional%2Fgh-projects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NSExceptional%2Fgh-projects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NSExceptional","download_url":"https://codeload.github.com/NSExceptional/gh-projects/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NSExceptional%2Fgh-projects/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34144680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","gh-extension","github-projects","projects-v2"],"created_at":"2026-06-10T09:01:12.415Z","updated_at":"2026-06-10T09:01:14.270Z","avatar_url":"https://github.com/NSExceptional.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gh-projects\n\nA [`gh`](https://cli.github.com) extension for working with **GitHub Projects (v2)** from the\ncommand line — built to be concise enough for both humans and agents.\n\nThe built-in `gh project` commands can read and write Projects, but every\nmutation makes you resolve a chain of opaque node IDs first (the project's\n`PVT_…` id, the item's `PVTI_…` id, the field's id, and an option hash like\n`df73e18b`), there's no convenience for \"what's ready to work on,\" and you\ncan't toggle a task-list checkbox at all. `gh-projects` resolves those IDs for\nyou and adds the project-management verbs you actually use:\n\n```sh\ngh projects ready 4                         # items in the \"Todo\" column\ngh projects move 4 12 \"Needs review\"        # by issue number + column name\ngh projects check 4 12 \"write tests\"        # tick a checkbox in the issue body\ngh projects create 4 --title \"Add caching\" --label enhancement\n```\n\nYou address **projects by number**, **items by issue number**, and\n**columns/fields by name**. It reuses `gh`'s authentication, so there are no\ntokens to manage.\n\n## Install\n\n```sh\ngh extension install NSExceptional/gh-projects\n```\n\nUpgrade with `gh extension upgrade gh-projects`.\n\n### Authentication scopes\n\nReading needs `read:project`; writing needs `project`:\n\n```sh\ngh auth refresh -s project     # read + write\n```\n\n## Usage\n\n`gh projects \u003ccommand\u003e [\u003cproject-number\u003e] [flags]`\n\nThe project owner defaults to the authenticated user; pass `--owner \u003clogin\u003e`\nfor organizations or other users. Most read commands accept `--json` for\nmachine-readable output.\n\n### Reading\n\n| Command | Description |\n| --- | --- |\n| `list` | List projects (number, title, item count, linked repos) |\n| `view \u003cproject\u003e` | Project details, columns, field list, counts |\n| `board \u003cproject\u003e` | Items grouped by their `Status` column |\n| `items \u003cproject\u003e [--status NAME]` | List items, optionally filtered by column |\n| `ready \u003cproject\u003e` | Shortcut for `items --status Todo` |\n| `fields \u003cproject\u003e` | Field definitions and single-select options |\n| `links \u003cproject\u003e` | Repositories the project is linked to |\n\n### Items\n\n| Command | Description |\n| --- | --- |\n| `create \u003cproject\u003e --title T [--repo O/R] [--body B] [--label L]… [--status S]` | Create a **real issue** and add it to the board (default way to make a task). `--repo` defaults to the project's sole linked repo. |\n| `draft \u003cproject\u003e --title T [--body B] [--status S]` | Add a draft issue (project-only) |\n| `add \u003cproject\u003e \u003cissue-url-or-#\u003e [--repo O/R]` | Add an existing issue/PR |\n| `rm \u003cproject\u003e \u003citem\u003e` | Remove an item from the project (does not delete the issue) |\n| `convert \u003cproject\u003e \u003cdraft\u003e --repo O/R` | Convert a draft into a real issue |\n\n### Field values \u0026 movement\n\n| Command | Description |\n| --- | --- |\n| `move \u003cproject\u003e \u003citem\u003e \u003ccolumn\u003e` | Set the `Status` field (move between columns) |\n| `set \u003cproject\u003e \u003citem\u003e \u003cfield\u003e \u003cvalue\u003e` | Set any field value (single-select by option name, plus text/number/date/iteration) |\n| `check \u003cproject\u003e \u003citem\u003e \u003ctask-text\u003e` | Tick the task-list box whose text uniquely matches |\n| `uncheck \u003cproject\u003e \u003citem\u003e \u003ctask-text\u003e` | Untick it |\n\n\u003e **Addressing items:** anywhere an `\u003citem\u003e` is expected, you can pass an issue/PR\n\u003e **number** (`12`), a **`PVTI_…` item id**, or a **unique substring of the item's\n\u003e title**. The title form is how you target **draft issues**, which have no number.\n\n### Field definitions \u0026 repo links\n\n| Command | Description |\n| --- | --- |\n| `field-create \u003cproject\u003e --name N --type TYPE [--option O]…` | Create a field (`text`, `number`, `date`, `single_select`) |\n| `field-delete \u003cproject\u003e \u003cfield-name\u003e` | Delete a field |\n| `link \u003cproject\u003e \u003cowner/repo\u003e` | Link the project to a repo (so it appears on that repo's Projects tab) |\n| `unlink \u003cproject\u003e \u003cowner/repo\u003e` | Remove that link |\n\n## Notes\n\n- A project is linked to **zero or more** repositories (it's many-to-many);\n  that link is what makes a project appear on a repo's Projects tab. Manage it\n  with `link` / `unlink` / `links`. (The web UI's \"default repository\" setting,\n  which only pre-selects a repo in dropdowns, is not exposed by GitHub's public\n  API, so it can't be read or changed here.)\n- `check`/`uncheck` require the matched task text to be **unique** within the\n  body; they error rather than risk toggling the wrong box.\n- **Read-after-write lag:** GitHub's project *items* connection is eventually\n  consistent, so an item you just created may take a few seconds to show up in\n  `items`/`board`. The write commands themselves use the returned IDs directly\n  and are unaffected.\n\n## Development\n\n```sh\ngo build -o gh-projects .     # build the binary\ngo test ./...                 # fast unit tests (no network)\n```\n\nLive integration tests exercise the real API and are gated behind a build tag.\nThey need gh authenticated with the `project` scope and operate on a disposable\nproject, cleaning up everything they create:\n\n```sh\n# link/unlink, set all field types, add existing item, draft body toggle\nGHP_TEST_PROJECT=5 go test -tags integration -run Integration ./internal/projects -v\n\n# also the issue-creating paths (create/convert); point at a throwaway repo\nGHP_TEST_PROJECT=5 GHP_TEST_ISSUE_REPO=you/throwaway \\\n  go test -tags integration -run Integration ./internal/projects -v\n```\n\nConfiguration env vars: `GHP_TEST_OWNER` (default: authed user), `GHP_TEST_PROJECT`\n(default: 5), `GHP_TEST_REPO` (default: `NSExceptional/home`, only referenced not\nmodified), `GHP_TEST_ISSUE_REPO` (required to run create/convert tests).\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsexceptional%2Fgh-projects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnsexceptional%2Fgh-projects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsexceptional%2Fgh-projects/lists"}