Add Issues 2.0 support: issue types, sub-issues, and relationships - #13057
Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for GitHub Issues 2.0 capabilities (issue types, sub-issues, and blocked-by/blocking relationships) across gh issue create/edit/view/list, including GHES feature detection for relationships.
Changes:
- Adds new GraphQL fields/types and mutations for issue types, sub-issues, and relationships; exports these via
--json. - Extends issue create/edit/list/view commands with new flags, interactive prompts, and TTY rendering for Issues 2.0 metadata.
- Introduces GHES relationship feature detection via schema introspection and adds/updates tests for flags and behaviors.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cmd/pr/shared/survey_test.go | Regression test ensuring issue-only editable fields don’t appear unless explicitly allowed. |
| pkg/cmd/pr/shared/params.go | Adds IssueType filtering into search query building. |
| pkg/cmd/pr/shared/editable.go | Adds IssueType/Parent editable fields, survey prompts, and option fetching. |
| pkg/cmd/issue/view/view_test.go | Adds TTY and JSON tests for Issues 2.0 fields in gh issue view. |
| pkg/cmd/issue/view/view.go | Adds default fields and TTY rendering for issue type/parent/sub-issues/relationships; GHES-gates relationship query fields. |
| pkg/cmd/issue/shared/resolve.go | Adds shared helpers to resolve issue refs and type names. |
| pkg/cmd/issue/list/list_test.go | Adds tests for --type flag parsing and query behavior. |
| pkg/cmd/issue/list/list.go | Adds --type filter support to issue list search path. |
| pkg/cmd/issue/edit/edit_test.go | Adds flag parsing and behavior tests for type/parent/sub-issues/relationships including GHES unsupported path. |
| pkg/cmd/issue/edit/edit.go | Implements new edit flags and mutations for type/parent/sub-issues/relationships, plus interactive picker integration. |
| pkg/cmd/issue/create/create_test.go | Adds flag parsing and behavior tests for type/parent/relationships including GHES unsupported path. |
| pkg/cmd/issue/create/create.go | Implements create flags, interactive type selection, and post-create mutations for Issues 2.0 fields. |
| internal/featuredetection/feature_detection_test.go | Adds tests for relationship support detection via schema introspection. |
| internal/featuredetection/feature_detection.go | Adds IssueRelationshipsSupported detection and plumbing. |
| api/query_builder.go | Adds GraphQL fragment cases and issue-only fields for Issues 2.0 fields. |
| api/queries_issue.go | Adds Issue struct fields/types plus mutations and helper queries for issue types/refs/relationships. |
| api/export_pr.go | Extends JSON export mapping for new issue fields (type, parent, sub-issues, relationships). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err == nil { | ||
| typeNames := make([]string, len(issueTypes)) | ||
| for i, t := range issueTypes { | ||
| typeNames[i] = t.Name | ||
| } | ||
| editable.IssueType.Options = typeNames | ||
| } |
There was a problem hiding this comment.
FetchOptions silently ignores errors from api.RepoIssueTypes when editable.IssueType.Edited is true. In interactive edit flows this can result in the user selecting “Type” but never being prompted (and no update happening) with no indication why. Recommend returning the error (or at least surfacing it) when the user has opted into editing Type, so failures don’t degrade silently.
| if err == nil { | |
| typeNames := make([]string, len(issueTypes)) | |
| for i, t := range issueTypes { | |
| typeNames[i] = t.Name | |
| } | |
| editable.IssueType.Options = typeNames | |
| } | |
| if err != nil { | |
| return fmt.Errorf("fetching issue types: %w", err) | |
| } | |
| typeNames := make([]string, len(issueTypes)) | |
| for i, t := range issueTypes { | |
| typeNames[i] = t.Name | |
| } | |
| editable.IssueType.Options = typeNames |
There was a problem hiding this comment.
I mean I think this could happen if it's a personal repo, so maybe this is actually a deeper thing in that we should be detecting if it's a repo that even supports issue types.
| if err != nil { | ||
| return err | ||
| } | ||
| editable.IssueType.Value = editable.IssueType.Options[selected] |
There was a problem hiding this comment.
If editable.IssueType.Edited is true but IssueType.Options is empty, the survey currently skips prompting and leaves IssueType.Value unchanged, even though the user explicitly chose to edit the field. This can lead to a “successful” submission that does nothing. Consider returning an error in this case (e.g., “no issue types available”) or falling back to a free-text input prompt.
| editable.IssueType.Value = editable.IssueType.Options[selected] | |
| editable.IssueType.Value = editable.IssueType.Options[selected] | |
| } else { | |
| editable.IssueType.Value, err = p.Input("Type", editable.IssueType.Default) | |
| if err != nil { | |
| return err | |
| } |
There was a problem hiding this comment.
Same as above comment - this is a deeper problem. We gotta check if there issue types are even possible.
Though I suppose this could still happen if there are no issue types available.
Add API infrastructure for issue types, sub-issues, and issue relationships (blocked-by/blocking): - New types: IssueType, LinkedIssue, SubIssues, SubIssuesSummary, LinkedIssueConnection - New Issue struct fields for all Issues 2.0 data - GraphQL query builder cases for new fields - ExportData cases for JSON output - Mutation functions: UpdateIssueIssueType, AddSubIssue, RemoveSubIssue, AddBlockedBy, RemoveBlockedBy - Helper functions: RepoIssueTypes, IssueNodeID - Feature detection: IssueRelationshipsSupported for GHES 3.19+ (issue types and sub-issues are GA on GHES 3.17+, no detection needed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Display new issue metadata in TTY view: - Issue type on state line (gray, before Open/Closed) - Type, Parent, Blocked by, Blocking metadata rows - Sub-issues section with completion progress (X/Y, Z%) - Cross-repo references show full owner/repo#N format All new fields included in defaultFields and JSON export. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Post-creation mutations for Issues 2.0 fields: - --type: resolve type name to ID via RepoIssueTypes, then updateIssueIssueType mutation - --parent: resolve issue ref (number or URL), then addSubIssue mutation (supports cross-repo URLs) - --blocked-by: resolve refs, then addBlockedBy mutations - --blocking: resolve refs, then addBlockedBy with swapped args Interactive mode: type picker when repo has issue types configured. GHES: relationships gated behind IssueRelationshipsSupported feature detection (3.19+). Types and sub-issues need no detection (GA 3.17+). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New flags for issue edit: - --type: set issue type by name - --set-parent / --remove-parent: set or remove parent issue (mutually exclusive via cmdutil.MutuallyExclusive) - --add-sub-issue / --remove-sub-issue: manage sub-issues - --add-blocked-by / --remove-blocked-by: manage blocked-by relationships - --add-blocking: add blocking relationships (swaps API args) Interactive mode: Type and Parent added to the field picker survey. FetchOptions loads issue types when Type is selected. Editable struct: added IssueType and Parent fields with Dirty(), Clone(), FieldsToEditSurvey, and EditFieldsSurvey support. GHES: relationships gated behind IssueRelationshipsSupported. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Filter issues by type using the search API path. The --type flag appends a type: qualifier to the search query, forcing the search path (same as --label and --milestone). Updated FilterOptions with IssueType field, IsDefault(), and SearchQueryBuild() to include the type qualifier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create tests (11 new): - Flag parsing: --type, --parent (number/URL), --blocked-by, --blocking - Behavior: type resolution + mutation, type not found error, parent resolution + addSubIssue, blocked-by/blocking with swapped args verification, GHES unsupported error Edit tests (18 new): - Flag parsing: --type, --set-parent, --remove-parent, mutual exclusivity, --add-sub-issue, --remove-sub-issue, --add-blocked-by, --remove-blocked-by, --add-blocking - Behavior: type edit, set/remove parent, add/remove sub-issues, add/remove blocked-by, add-blocking with swapped args, batch edit type across multiple issues - Bug fix: copy SetParent value into Editable.Parent.Value View tests (5 new): - TTY: full view with all Issues 2.0 fields, regression test with no new fields - JSON: issueType export, parent/subIssues/subIssuesSummary export, blockedBy/blocking export Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…okup Address code review findings: - Extract resolveIssueRef into shared.ResolveIssueRef (was duplicated between create.go and edit.go) - Extract issue type name→ID resolution into shared.ResolveIssueTypeName (was duplicated between create applyIssueTypes and edit applyEditIssueType) - Fix double import of issue/shared in view.go Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Critical fixes: - GHES data-flow regression: blockedBy/blocking fields now conditionally added to view lookupFields only when IssueRelationshipsSupported is true (GHES 3.19+). Previously would break gh issue view on GHES 3.17-3.18. - State line separator: restore original bullet (•) to avoid breaking downstream parsers. Issue type prefix uses middle dot (·). Optimizations: - Batch edit --type: resolve issueTypeID once before the loop instead of per-goroutine (eliminates N-1 redundant API calls) - Parent removal: include id in parent GraphQL fragment, use issue.Parent.ID directly instead of extra IssueNodeID lookup Nit fixes: - Fix formatLinkedIssueRef godoc to match actual behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add flag parsing and behavior tests for gh issue list --type: - TestNewCmdList/type_flag: verifies opts.IssueType is set - Test_issueList/with_issue_type: verifies search path is forced and query includes type:Bug qualifier Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Completes the symmetry of relationship flags: - --add-blocked-by / --remove-blocked-by - --add-blocking / --remove-blocking The --remove-blocking flag swaps API args (same as --add-blocking): calls RemoveBlockedBy(issueId=OTHER, blockingIssueId=THIS). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix PR edit regression: gate Type and Parent behind Allowed bool in FieldsToEditSurvey, matching the Reviewers.Allowed pattern. Only issue edit sets Allowed=true; PR edit won't show these fields. - Add missing RemoveBlocking assertion in flag parsing tests - Quote issue type names containing spaces in search queries (type:"Bug Report" instead of type:Bug Report) - Remove duplicate TODO comment in view.go - Avoid double RepoIssueTypes API call in interactive create: cache the resolved ID from the picker, skip re-resolution - Rename applyIssueTypes → applyIssueType (singular) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verifies Type and Parent only appear in the interactive picker when Allowed is explicitly set. Prevents regression where issue-only fields leak into gh pr edit's interactive mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Restore // TODO projectsV1Deprecation comment above TestProjectsV1Deprecation (was displaced when new tests were inserted at that location) - Add 'relationships unsupported on GHES' test case to edit command using DisabledDetectorMock (parity with create's GHES tests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ions The AddBlockedByPayload and RemoveBlockedByPayload types expose the result as 'issue', not 'blockedIssue'. Found during live spec testing against github.com — the mutations returned empty responses. Updated mutation queries and corresponding test fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| cmd.Flags().StringVar(&opts.SetParent, "set-parent", "", "Set the parent issue by `number` or URL") | ||
| cmd.Flags().BoolVar(&opts.RemoveParent, "remove-parent", false, "Remove the parent issue") |
There was a problem hiding this comment.
For consistency with the other --add-* and --remove-* options, it might be good to have a --add-parent <number/URL> option as well, so we'd have:
--remove-parent- only removes parent--add-parent <number/URL>- only adds parent, will not overwrite existing parent--set-parent <number/URL>- will overwrite parent: either add a parent if there is not one, or remove the existing parent and set a new one
I'd imagine these should be mutually exclusive: only pass one of --remove-parent, --add-parent, or --set-parent.
This could be a follow-up though, I think the two existing options are good.
There was a problem hiding this comment.
--add-parent <number/URL>- only adds parent, will not overwrite existing parent
Is it possible to have more than one parent? I think that was my motivation for setting it up this way - my understanding is you can only have one parent per issue. I think that's the line between --add-* and --set-*.
There was a problem hiding this comment.
--add-parent <number/URL>- only adds parent, will not overwrite existing parentIs it possible to have more than one parent? I think that was my motivation for setting it up this way - my understanding is you can only have one parent per issue. I think that's the line between
--add-*and--set-*.
No, that's correct: it is one parent per issue. I was thinking about it from the perspective of matching what the REST API supports (which has the replace_parent flag to disable destructive actions), and what agents might guess is the right flag. This does seem to be consistent though with the existing flags, so sorry for the noise! We can keep the two existing flags and add this later if necessary.
There was a problem hiding this comment.
No worries, this is good perspective! I was thinking as part of this release we'd off a skill file in this repo for issue management that instructs agents how to use these new flags, so maybe that'll also address some of the agentic uses. It would be installable with gh skill install cli/cli
There was a problem hiding this comment.
As we talked about this in sync, we decided that it's best to do it like --parent [ISSUE] and --remove-parent. This is more intuitive and also consistent with other flags like milestones in issue edit.
| stdout: "https://github.com/OWNER/REPO/issue/123\n", | ||
| }, | ||
| { | ||
| name: "edit type", |
There was a problem hiding this comment.
We also need TTY test cases for type and parent prompts.
There was a problem hiding this comment.
Added new tests covering the interactive type and parent prompts, but while writing the type prompt test I found a bug.
In interactive mode, editRun was resolving the issue type ID before EditFieldsSurvey ran, so when a user picked a type from the prompt, the mutation went out with an empty issueTypeId.
prShared.FetchOptions already calls RepoIssueTypes to populate the survey options for both interactive and non-interactive gh issue edit, but it was throwing away the IDs. So editRun was making a second RepoIssueTypes request via ResolveIssueTypeName just to map a name to an ID.
The fix teaches FetchOptions to store a name to ID map on Editable. Both ResolveIssueTypeName calls in editRun are replaced with a map lookup, and that lookup now lives inside the per-issue loop, which fixes the interactive prompt bug as a side effect.
Let me know what you think (leaving thread unresolved for feedback)
There was a problem hiding this comment.
Good call. I think we can actually pull the map lookup out of the loop since it doesn't need the issue under iteration. This bit:
// Look up the issue type ID using the map populated by FetchOptions
var issueTypeID string
if editable.IssueType.Edited && editable.IssueType.Value != "" {
id, ok := editable.IssueTypeNameToID[editable.IssueType.Value]
if !ok {
return fmt.Errorf("type %q not found; available types: %s",
editable.IssueType.Value,
strings.Join(editable.IssueType.Options, ", "))
}
issueTypeID = id
}
babakks
left a comment
There was a problem hiding this comment.
Here are my comments re list and view.
Addresses review feedback on PR #13057. Quick fixes: - Replace em-dashes with regular dashes in code comments per AGENTS.md. - Add JSON tags to SubIssues and LinkedIssueConnection (and TotalCount on the latter) for consistent struct serialization. - Add comment to defensive ID-empty check in IssueNodeID explaining why the guard is kept after a GraphQL call. - Reject --add-sub-issue and --remove-sub-issue when multiple issues are passed to issue edit (one parent per issue makes batching ambiguous). - Add godoc to Editable.{X}.Allowed. Substantive fixes: - Add canonical `id` field to relationship exports (parent, sub-issues nodes, blockedBy nodes, blocking nodes), and update the GraphQL fragments in query_builder.go to fetch them. - Wrap subIssues, blockedBy, and blocking JSON output in {nodes: [...], totalCount: N} so consumers can see the true total when more than 50 items exist. The query_builder fragments now request totalCount for blockedBy/blocking. - In issue edit and issue create, validate IssueRelationshipsSupported up-front when relationship flags are used, before any mutation, so GHES users get a clear error instead of partial state. - Refactor IssueType handling out of ImmutableKeywords and into the Qualifiers struct in pkg/search/query.go. The new IssueType field renders as type:X (with proper quoting via quote()), eliminating the ad-hoc escaping in pr/shared/params.go. - In prShared.FetchOptions, surface errors from api.RepoIssueTypes when the user has explicitly opted into editing the issue type instead of silently ignoring them. - In EditFieldsSurvey, return a clear error when the user opts to edit Type but no issue types are available, instead of silently skipping the prompt. Tests: - New tests for IssueType qualifier in standard and advanced search query strings (including quoting behavior). - Updated TestIssueView_json_ParentSubIssues and TestIssueView_json_BlockedByBlocking to verify the new {nodes, totalCount} shape and `id` fields. - New TestEditFieldsSurvey_IssueTypeNoOptions covering the new error case in the survey. - New cases in TestNewCmdEdit covering the multi-arg sub-issue guard. Pushback / deferred (intentionally not in this round): - T6 (mutex on add/remove relationship flags): rejected. Add and remove collection deltas are not conflicting, matching --add-label/--remove-label. - T19/T24 (large architectural reordering of validate-then-mutate and capture-errors-then-continue): deferred to a follow-up. - T23 (--remove-type/--set-type for unsetting issue type): follow-up. - T3 (cross-host validation in ResolveIssueRef): follow-up. - T5 (non-TTY field selection): follow-up. - TTY+IssueType prompt test for issue create: follow-up (large mock setup). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ADR's heaviest deferral reason — `gh issue` has no relationship flags, so any push needs raw `gh api` — was invalidated by gh 2.94.0 (cli/cli#13057, Issues 2.0), which makes dependencies, sub-issues, and issue types native to `gh issue`. The decision (v1 defers relationship sync) still holds, but the recorded rationale was false. Rewrite rather than append an amendment: the false reason sat at the top of the body, so a reader met retracted reasoning before the correction. The deferral now rests on slice size and the gh-independent pre-Promote Epic gate. Issue-type → TicketKind moves into tk-34's Pull (now cheap and first-class); tk-107 is re-scoped to the native flags. A one-line History note preserves why tk-107 was originally framed around raw `gh api`.
* Add issue dependency read/write MCP tools Add two feature-flagged tools for issue blocked-by / blocking relationships, gated behind the issue_dependencies flag so they stay off the default tool surface (auto-enabled for insiders only): - issue_dependency_read: get_blocked_by / get_blocking via the Issue.blockedBy / Issue.blocking GraphQL connections, cursor-paginated. - issue_dependency_write: add / remove x blocked_by / blocking via the addBlockedBy / removeBlockedBy mutations. Accepts issue numbers and resolves them to node IDs in a single aliased query; "blocking" is the inverse of "blocked_by" with the subject/related roles swapped. Closes the MCP gap behind the gh CLI dependency verbs (cli/cli#13057). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fail fast on self-dependency in issue_dependency_write Reject a write where the subject and related issue are identical before resolving node IDs or issuing a mutation, avoiding two API round-trips. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert addition of `any of` for required ui_get scopes --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add issue dependency read/write MCP tools Add two feature-flagged tools for issue blocked-by / blocking relationships, gated behind the issue_dependencies flag so they stay off the default tool surface (auto-enabled for insiders only): - issue_dependency_read: get_blocked_by / get_blocking via the Issue.blockedBy / Issue.blocking GraphQL connections, cursor-paginated. - issue_dependency_write: add / remove x blocked_by / blocking via the addBlockedBy / removeBlockedBy mutations. Accepts issue numbers and resolves them to node IDs in a single aliased query; "blocking" is the inverse of "blocked_by" with the subject/related roles swapped. Closes the MCP gap behind the gh CLI dependency verbs (cli/cli#13057). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fail fast on self-dependency in issue_dependency_write Reject a write where the subject and related issue are identical before resolving node IDs or issuing a mutation, avoiding two API round-trips. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert addition of `any of` for required ui_get scopes --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Issues 2.0 support: issue types, sub-issues, and relationships
Closes #10298
Closes #9696
Closes #11757
Closes #12477
Closes #12152
Adds support for GitHub's Issues 2.0 features across
gh issue create,edit,view, andlist.New flags
gh issue create--type Bug--parent 100--blocked-by 200,201--blocking 300Interactive mode prompts for issue type when the repo has types configured.
gh issue edit--type Bug--set-parent 100--remove-parent--add-sub-issue 123,124--remove-sub-issue 123--add-blocked-by 200--remove-blocked-by 201--add-blocking 300,301--remove-blocking 300Interactive mode adds Type and Parent to the field picker. Batch editing
supported for
--typeacross multiple issues.gh issue viewTTY output now displays:
Bug · Open)Sub-issues · 3/5 (60%))JSON output supports new fields:
issueType,parent,subIssues,subIssuesSummary,blockedBy,blocking. ThesubIssues,blockedBy,and
blockingfields are objects of the shape{ "nodes": [...], "totalCount": N }(rather than flat arrays) so consumers can detect when the truncation
limit is reached. Each node and the
parentobject include the canonicalid.gh issue list--type BugGHES compatibility
__typeschema introspection for theblockedByfield on the Issue type. Unsupported GHES versions receive a clear error message. Gated with// TODO IssueRelationshipsCleanupfor cleanup when GHES 3.18 support ends.Implementation details
--blockingand--add-blockingswap API arguments: callsaddBlockedBy(issueId=OTHER, blockingIssueId=THIS)--parent,--blocked-by,--blocking, and sub-issue flagspkg/cmd/issue/shared/resolve.go(ResolveIssueRef,ResolveIssueTypeName)Allowedin the Editable pattern to prevent leaking intogh pr edittype:"Bug Report")Testing
Changes
17 files changed, 2105 insertions(+), 18 deletions(-)
api/queries_issue.goapi/query_builder.goissueOnlyFieldsapi/export_pr.gointernal/featuredetection/IssueRelationshipsSupporteddetectionpkg/cmd/issue/create/create.gopkg/cmd/issue/edit/edit.gopkg/cmd/issue/view/view.gopkg/cmd/issue/list/list.go--typefilter via search pathpkg/cmd/issue/shared/resolve.goResolveIssueRef,ResolveIssueTypeNamepkg/cmd/pr/shared/editable.goIssueType/Parentfields,Allowedgatingpkg/cmd/pr/shared/params.goIssueTypeinFilterOptionsand search queryKey notes for reviewers
--blockingarg swap: The GitHub API only hasaddBlockedBy(issueId, blockingIssueId). To support--blocking, we swap the arguments — the OTHER issue becomesissueIdand THIS issue becomesblockingIssueId. Same for--remove-blocking.Allowedgating:IssueTypeandParentare added to the sharedEditablestruct but gated behindAllowed = true, which only the issue edit command sets. This prevents these issue-only fields from leaking intogh pr edit's interactive picker. Regression test insurvey_test.go.blockedByandblockingare only added to the GraphQL query whenIssueRelationshipsSupportedis true. Without this,gh issue viewwould break on GHES 3.17–3.18 where these fields don't exist.--type, the type name is resolved to an ID once before the loop rather than per-issue, avoiding N-1 redundantRepoIssueTypesAPI calls.Manual test results
All scenarios tested against on github.com.
24/24 scenarios passing (click to expand)
Issue types
create-with-typegh issue create --title "..." --type Bugcreate-error-invalid-typegh issue create --title "Oops" --type Bugztype "Bugz" not found; available types: Task, Bug, Featureedit-change-typegh issue edit 1 --type Featurecreate-interactive-typegh issue create(interactive)Sub-issues
create-with-parentgh issue create --title "..." --parent 3edit-set-parentgh issue edit 5 --set-parent 3--json parentedit-remove-parentgh issue edit 5 --remove-parentedit-add-sub-issuesgh issue edit 3 --add-sub-issue 6,7--json subIssuesedit-remove-sub-issuegh issue edit 3 --remove-sub-issue 6edit-error-mutual-parentgh issue edit 5 --set-parent 1 --remove-parentspecify only one of --set-parent or --remove-parentRelationships
create-with-relationshipsgh issue create --blocked-by 8 --blocking 9edit-add-remove-blocked-bygh issue edit 14 --add-blocked-by 12 --remove-blocked-by 13edit-add-blockinggh issue edit 14 --add-blocking 15,16View
view-with-typeBug · Openon state line,Type: Bugrowview-parent-sub-issuesview-child-parentview-relationshipsview-json-issueType--json issueTypereturns id, name, description, colorview-json-parent-subIssues--json parent,subIssues,subIssuesSummaryreturns structured dataview-json-relationships--json blockedBy,blockingreturns{ nodes: [...], totalCount: N }with id, number, title, url, stateList
list-filter-by-typegh issue list --type BugCombined
create-all-flagsgh issue create --type Task --parent 3 --blocked-by 8 --blocking 9edit-batch-typegh issue edit 18 19 20 --type Bugedit-interactivegh issue edit 21(interactive)TODO: GHES-specific scenarios (
create-error-ghes-relationships), but GHES feature detection does have unit test coverage with mock introspection responses.