From c97716b9c5435c284ab81da999b894d3ce8a8b2e Mon Sep 17 00:00:00 2001 From: wrsmith108 Date: Sun, 14 Dec 2025 15:51:21 -0800 Subject: [PATCH 1/2] Add Linear skill for issue and project management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a comprehensive skill for managing Linear issues, projects, and teams with Claude Code. Features include: - MCP tool integration for common operations - SDK automation patterns for complex workflows - GraphQL API reference for advanced use cases - Best practices for content vs description fields - Project status management with UUIDs - Resource links and milestone patterns 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .claude-plugin/marketplace.json | 3 +- skills/linear/LICENSE.txt | 21 +++ skills/linear/SKILL.md | 205 +++++++++++++++++++++++ skills/linear/api.md | 162 ++++++++++++++++++ skills/linear/scripts/query.sh | 21 +++ skills/linear/scripts/query.ts | 85 ++++++++++ skills/linear/sdk.md | 284 ++++++++++++++++++++++++++++++++ 7 files changed, 780 insertions(+), 1 deletion(-) create mode 100644 skills/linear/LICENSE.txt create mode 100644 skills/linear/SKILL.md create mode 100644 skills/linear/api.md create mode 100755 skills/linear/scripts/query.sh create mode 100644 skills/linear/scripts/query.ts create mode 100644 skills/linear/sdk.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 1538e00f4..cb0982f30 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -23,7 +23,7 @@ }, { "name": "example-skills", - "description": "Collection of example skills demonstrating various capabilities including skill creation, MCP building, visual design, algorithmic art, internal communications, web testing, artifact building, Slack GIFs, and theme styling", + "description": "Collection of example skills demonstrating various capabilities including skill creation, MCP building, visual design, algorithmic art, internal communications, web testing, artifact building, Slack GIFs, theme styling, and Linear project management", "source": "./", "strict": false, "skills": [ @@ -33,6 +33,7 @@ "./skills/doc-coauthoring", "./skills/frontend-design", "./skills/internal-comms", + "./skills/linear", "./skills/mcp-builder", "./skills/skill-creator", "./skills/slack-gif-creator", diff --git a/skills/linear/LICENSE.txt b/skills/linear/LICENSE.txt new file mode 100644 index 000000000..b77bf2ab7 --- /dev/null +++ b/skills/linear/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/skills/linear/SKILL.md b/skills/linear/SKILL.md new file mode 100644 index 000000000..a935c5cef --- /dev/null +++ b/skills/linear/SKILL.md @@ -0,0 +1,205 @@ +--- +name: linear +description: Managing Linear issues, projects, and teams. Use when working with Linear tasks, creating issues, updating status, querying projects, or managing team workflows. +license: Complete terms in LICENSE.txt +allowed-tools: + - mcp__linear + - WebFetch(domain:linear.app) + - Bash +--- + +# Linear + +Tools and workflows for managing issues, projects, and teams in Linear. + +## Tool Selection + +Choose the right tool for the task: + +1. **MCP tools** - Use for simple operations (create/update/query single issues, basic filters) +2. **SDK scripts** - Use for complex operations (loops, bulk updates, conditional logic, data transformations) +3. **GraphQL API** - Fallback for operations not supported by MCP or SDK + +## Conventions + +### Issue Status + +When creating issues, set the appropriate status based on assignment: + +- **Assigned to me** (`assignee: "me"`): Set `state: "Todo"` +- **Unassigned**: Set `state: "Backlog"` + +Example: +```typescript +// Issue for myself +await linear.create_issue({ + team: "ENG", + title: "Fix authentication bug", + assignee: "me", + state: "Todo" +}) + +// Unassigned issue +await linear.create_issue({ + team: "ENG", + title: "Research API performance", + state: "Backlog" +}) +``` + +### Querying Issues + +Use `assignee: "me"` to filter issues assigned to the authenticated user: + +```typescript +// My issues +await linear.list_issues({ assignee: "me" }) + +// Team backlog +await linear.list_issues({ team: "ENG", state: "Backlog" }) +``` + +### Labels + +You can use label names directly in `create_issue` and `update_issue` - no need to look up IDs: + +```typescript +await linear.create_issue({ + team: "ENG", + title: "Update documentation", + labels: ["documentation", "high-priority"] +}) +``` + +## SDK Automation Scripts + +**Use only when MCP tools are insufficient.** For complex operations involving loops, mapping, or bulk updates, write TypeScript scripts using `@linear/sdk`. See `sdk.md` for: + +- Complete script patterns and templates +- Common automation examples (bulk updates, filtering, reporting) +- Tool selection criteria + +Scripts provide full type hints and are easier to debug than raw GraphQL for multi-step operations. + +## GraphQL API + +**Fallback only.** Use when operations aren't supported by MCP or SDK. See `api.md` for documentation on using the Linear GraphQL API directly. + +### Ad-Hoc Queries + +Use `scripts/query.ts` to execute GraphQL queries: + +```bash +LINEAR_API_KEY=lin_api_xxx node scripts/query.ts "query { viewer { id name } }" +``` + +If `LINEAR_API_KEY` is not provided to the Claude process, inform the user that GraphQL queries cannot be executed without an API key. + +## Projects & Initiatives + +### Content vs Description (CRITICAL) + +Linear has **two text fields** - using the wrong one causes blank displays: + +| Field | Limit | Shows In | Use For | +|-------|-------|----------|---------| +| `description` | 255 chars | List views, tooltips | Short summary | +| `content` | Unlimited | **Main detail panel** | Full markdown documentation | + +**Always set BOTH when creating/updating projects:** + +```graphql +# Content is what users see in the main panel! +mutation { + projectUpdate(id: "", input: { + content: "# Project Title\n\nFull markdown description...", + description: "Short 255 char summary for list views" + }) { success } +} +``` + +### New Phase Project Pattern + +When creating a new phase, follow this complete workflow: + +```bash +# 1. Create project via CLI +linear projects create --name "Phase N: Name" --description "Short summary" + +# 2. Link to initiative +node scripts/linear-helpers.mjs link-project + +# 3. Set content (main UI panel) +# Use GraphQL to set full markdown content + +# 4. Add resource link to implementation doc +# Use entityExternalLinkCreate mutation + +# 5. Create milestone for Definition of Done +# Use projectMilestoneCreate mutation + +# 6. Create issues via MCP +# 7. Add issues to project +``` + +### Resource Links + +Add clickable links to projects/initiatives (shows in Resources section): + +```graphql +mutation { + entityExternalLinkCreate(input: { + url: "https://github.com/org/repo/blob/main/docs/implementation/phase-N.md", + label: "Implementation Doc", + projectId: "" + }) { success } +} +``` + +**Standard resource links for phases:** +- `Implementation Doc` → docs/implementation/phase-N-*.md +- `Production Site` → deployment URL (for initiative) +- `Repository` → GitHub repo link (for initiative) + +### Project Milestones (Definition of Done) + +Track completion criteria with milestones: + +```graphql +mutation { + projectMilestoneCreate(input: { + projectId: "", + name: "DoD: Testing", + description: "Unit tests, E2E tests, 100% coverage" + }) { success } +} +``` + +**Standard DoD milestones:** +- `DoD: Core Feature` - Main functionality complete +- `DoD: Testing` - All tests pass, coverage met +- `DoD: Security` - Security requirements verified +- `DoD: Accessibility` - A11y requirements met + +### Project Status UUIDs + +Projects have status independent of issue progress: + +``` +Backlog: 1ed7da89-db44-4339-b0d7-ce37d8ff9604 +Planned: 33ebbb84-53ea-4dd8-a8db-49a8b3b9c502 +In Progress: 71d18c8f-53de-4752-be37-a6d529cb9c97 +Completed: 54294a72-010d-4ae7-9829-bed76232fb66 +Canceled: 562050cc-bb71-4b81-bf3d-8bed7cc44153 +``` + +```graphql +mutation { + projectUpdate(id: "", input: { statusId: "" }) { success } +} +``` + +## Reference + +- Linear MCP: https://linear.app/docs/mcp.md +- GraphQL API: See `api.md` diff --git a/skills/linear/api.md b/skills/linear/api.md new file mode 100644 index 000000000..6f45b0bd9 --- /dev/null +++ b/skills/linear/api.md @@ -0,0 +1,162 @@ +# Linear GraphQL API + +Documentation for querying the Linear API directly when the MCP tools don't support a specific operation. + +## Authentication + +**Endpoint**: `https://api.linear.app/graphql` + +**Authentication Header**: +``` +Authorization: +``` + +Personal API keys are available in Linear under Security & access settings. + +## Using the Linear SDK + +For ad-hoc queries and automation, use the `@linear/sdk` package with `npx` and TypeScript. + +### Setup + +The skill includes `scripts/query.ts` for executing GraphQL queries. Run it with: + +```bash +LINEAR_API_KEY=lin_api_xxx npx tsx scripts/query.ts "query { viewer { id name } }" +``` + +**Environment Variable**: The script requires `LINEAR_API_KEY` to be set. If not provided to the Claude process, you cannot execute GraphQL queries automatically. + +### Example Queries + +**Get authenticated user:** +```graphql +query Me { + viewer { + id + name + email + } +} +``` + +**Get team issues:** +```graphql +query Team($teamId: String!) { + team(id: $teamId) { + issues { + nodes { + id + title + state { name } + assignee { name } + } + } + } +} +``` + +**Get user's assigned issues:** +```graphql +query MyIssues { + viewer { + assignedIssues { + nodes { + id + title + state { name } + team { key } + } + } + } +} +``` + +### Mutations + +**Create issue:** +```graphql +mutation CreateIssue($input: IssueCreateInput!) { + issueCreate(input: $input) { + success + issue { + id + identifier + title + } + } +} +``` + +With variables: +```json +{ + "input": { + "teamId": "TEAM_ID", + "title": "Issue title", + "description": "Issue description", + "stateId": "STATE_ID" + } +} +``` + +**Update issue:** +```graphql +mutation UpdateIssue($id: String!, $input: IssueUpdateInput!) { + issueUpdate(id: $id, input: $input) { + success + issue { + id + title + state { name } + } + } +} +``` + +## Rate Limiting + +Monitor HTTP status codes and handle rate limits appropriately. For real-time updates, Linear recommends using webhooks instead of polling. + +## Key Concepts + +- **Team IDs**: Required for most operations involving issues and projects +- **State IDs**: Issues default to the team's first Backlog state unless specified +- **Archived Resources**: Hidden by default; use `includeArchived: true` to retrieve +- **Error Handling**: Always check the `errors` array in responses before assuming success + +## Using linear-sdk Directly + +For more complex automation, you can use the Linear SDK programmatically: + +```typescript +import { LinearClient } from '@linear/sdk'; + +const client = new LinearClient({ + apiKey: process.env.LINEAR_API_KEY +}); + +// Get viewer +const me = await client.viewer; +console.log(me.name); + +// Get issues +const issues = await client.issues({ + filter: { assignee: { id: { eq: me.id } } } +}); + +for (const issue of issues.nodes) { + console.log(`${issue.identifier}: ${issue.title}`); +} +``` + +## Reference + +- [Linear GraphQL Documentation](https://linear.app/developers/graphql) +- [Linear SDK](https://github.com/linear/linear/tree/master/packages/sdk) + +Use GraphQL introspection to discover the API schema: + +```bash +LINEAR_API_KEY=lin_api_xxx npx tsx scripts/query.ts "{ __schema { types { name description } } }" +``` diff --git a/skills/linear/scripts/query.sh b/skills/linear/scripts/query.sh new file mode 100755 index 000000000..17cc1b558 --- /dev/null +++ b/skills/linear/scripts/query.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Shell wrapper for Linear GraphQL queries +# +# Usage: +# LINEAR_API_KEY=lin_api_xxx ./query.sh "query { viewer { id name } }" +# + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -z "${LINEAR_API_KEY:-}" ]; then + echo "Error: LINEAR_API_KEY environment variable is required" >&2 + echo "" >&2 + echo "Usage:" >&2 + echo " LINEAR_API_KEY=lin_api_xxx ./query.sh \"query { viewer { id name } }\"" >&2 + exit 1 +fi + +npx tsx "$SCRIPT_DIR/query.ts" "$@" diff --git a/skills/linear/scripts/query.ts b/skills/linear/scripts/query.ts new file mode 100644 index 000000000..73373e088 --- /dev/null +++ b/skills/linear/scripts/query.ts @@ -0,0 +1,85 @@ +#!/usr/bin/env npx tsx + +/** + * Execute ad-hoc GraphQL queries against the Linear API + * + * Usage: + * LINEAR_API_KEY=lin_api_xxx npx tsx query.ts "query { viewer { id name } }" + * LINEAR_API_KEY=lin_api_xxx npx tsx query.ts "query { viewer { id name } }" '{"var": "value"}' + */ + +import { LinearClient } from '@linear/sdk'; + +interface GraphQLErrorResponse { + errors: Array<{ + message: string; + locations?: Array<{ line: number; column: number }>; + path?: Array; + }>; +} + +function hasGraphQLErrors(error: unknown): error is Error & GraphQLErrorResponse { + return ( + error instanceof Error && + 'errors' in error && + Array.isArray((error as Record).errors) + ); +} + +async function main() { + const apiKey = process.env.LINEAR_API_KEY; + + if (!apiKey) { + console.error('Error: LINEAR_API_KEY environment variable is required'); + console.error(''); + console.error('Usage:'); + console.error(' LINEAR_API_KEY=lin_api_xxx npx tsx query.ts "query { viewer { id name } }"'); + process.exit(1); + } + + const query = process.argv[2]; + const variablesArg = process.argv[3]; + + if (!query) { + console.error('Error: Query argument is required'); + console.error(''); + console.error('Usage:'); + console.error(' LINEAR_API_KEY=lin_api_xxx npx tsx query.ts "query { viewer { id name } }"'); + console.error(' LINEAR_API_KEY=lin_api_xxx npx tsx query.ts "query($id: String!) { issue(id: $id) { title } }" \'{"id": "ISSUE_ID"}\''); + process.exit(1); + } + + let variables = {}; + if (variablesArg) { + try { + variables = JSON.parse(variablesArg); + } catch (error) { + console.error('Error: Variables must be valid JSON'); + console.error(`Received: ${variablesArg}`); + process.exit(1); + } + } + + const client = new LinearClient({ apiKey }); + + try { + const result = await client.client.rawRequest(query, variables); + console.log(JSON.stringify(result.data, null, 2)); + } catch (error) { + console.error('Error executing query:'); + + if (hasGraphQLErrors(error)) { + console.error(error.message); + console.error('\nGraphQL Errors:'); + console.error(JSON.stringify(error.errors, null, 2)); + } else if (error instanceof Error) { + console.error(error.message); + } else { + console.error(error); + } + + process.exit(1); + } +} + +main(); diff --git a/skills/linear/sdk.md b/skills/linear/sdk.md new file mode 100644 index 000000000..ec36546de --- /dev/null +++ b/skills/linear/sdk.md @@ -0,0 +1,284 @@ +# Linear SDK Automation Scripts + +Reference for writing TypeScript automation scripts using the Linear SDK. + +## Tool Selection Hierarchy + +Always prefer simpler tools first: + +1. **MCP tools (first choice)** - For simple operations like creating/updating single issues, basic queries +2. **SDK scripts (complex operations)** - For loops, bulk updates, conditional logic, data transformations +3. **GraphQL API (fallback)** - Only when MCP and SDK don't support the operation + +## Overview + +For complex Linear operations involving loops, mapping, or conditional logic, write TypeScript scripts using `@linear/sdk`. The SDK provides: + +- Full TypeScript type hints and autocomplete +- Simpler syntax for iteration and data transformation +- Better error handling than raw GraphQL +- Easier debugging + +Run scripts with: `npx tsx script.ts` + +## Basic Setup + +```typescript +import { LinearClient } from '@linear/sdk' + +const client = new LinearClient({ + apiKey: process.env.LINEAR_API_KEY +}) + +async function main() { + // Your automation logic here +} + +main().catch(console.error) +``` + +**Authentication**: Set `LINEAR_API_KEY` environment variable or pass directly to client. + +## Common Patterns + +### Fetching and Filtering Issues + +```typescript +// Get all issues from a team +const team = await client.team('TEAM-KEY') +const issues = await team.issues() + +// Filter with TypeScript instead of complex GraphQL +const highPriorityOpen = issues.nodes.filter(issue => + issue.priority === 1 && + issue.state.type === 'started' +) + +console.log(`Found ${highPriorityOpen.length} high priority issues`) +``` + +### Bulk Updates with Loops + +```typescript +// Update multiple issues based on conditions +const team = await client.team('ENG') +const issues = await team.issues({ + filter: { state: { name: { eq: 'In Review' } } } +}) + +for (const issue of issues.nodes) { + // Check condition with full type safety + if (issue.assignee && issue.estimate && issue.estimate > 5) { + await issue.update({ + priority: 2, // Set to high priority + labels: ['needs-split'] + }) + console.log(`Updated ${issue.identifier}: ${issue.title}`) + } +} +``` + +### Mapping Issues to Custom Format + +```typescript +// Extract and transform issue data +const team = await client.team('PRODUCT') +const issues = await team.issues() + +const report = issues.nodes.map(issue => ({ + id: issue.identifier, + title: issue.title, + assignee: issue.assignee?.name ?? 'Unassigned', + daysOld: Math.floor( + (Date.now() - issue.createdAt.getTime()) / (1000 * 60 * 60 * 24) + ), + labels: issue.labels.nodes.map(l => l.name).join(', ') +})) + +// Output as JSON or CSV +console.log(JSON.stringify(report, null, 2)) +``` + +### Working with Projects and Milestones + +```typescript +// Get project and all its issues +const project = await client.project('PROJECT-ID') +const projectData = await project.issues() + +// Group by state +const byState = projectData.nodes.reduce((acc, issue) => { + const stateName = issue.state.name + acc[stateName] = (acc[stateName] || 0) + 1 + return acc +}, {} as Record) + +console.log('Issues by state:', byState) +``` + +### Creating Multiple Issues from Data + +```typescript +interface TaskTemplate { + title: string + description: string + assigneeEmail: string +} + +const tasks: TaskTemplate[] = [ + { title: 'Task 1', description: 'Do thing', assigneeEmail: 'user@example.com' }, + { title: 'Task 2', description: 'Do other', assigneeEmail: 'user@example.com' } +] + +const team = await client.team('ENG') +const users = await client.users() + +for (const task of tasks) { + const assignee = users.nodes.find(u => u.email === task.assigneeEmail) + + await client.createIssue({ + teamId: team.id, + title: task.title, + description: task.description, + assigneeId: assignee?.id, + priority: 3 + }) + + console.log(`Created: ${task.title}`) +} +``` + +### Pagination for Large Datasets + +```typescript +// Handle paginated results +let hasMore = true +let after: string | undefined + +const allIssues = [] + +while (hasMore) { + const response = await client.issues({ + first: 50, + after + }) + + allIssues.push(...response.nodes) + + hasMore = response.pageInfo.hasNextPage + after = response.pageInfo.endCursor +} + +console.log(`Total issues: ${allIssues.length}`) +``` + +### Conditional Logic with Type Safety + +```typescript +const issues = await client.issues({ + filter: { team: { key: { eq: 'ENG' } } } +}) + +for (const issue of issues.nodes) { + // TypeScript knows all available properties + const needsAttention = + !issue.assignee || + (issue.priority === 1 && issue.state.type !== 'started') || + (issue.dueDate && new Date(issue.dueDate) < new Date()) + + if (needsAttention) { + await issue.addComment({ + body: '⚠️ This issue needs attention' + }) + } +} +``` + +## Script Template + +```typescript +#!/usr/bin/env tsx +import { LinearClient } from '@linear/sdk' + +const LINEAR_API_KEY = process.env.LINEAR_API_KEY +if (!LINEAR_API_KEY) { + console.error('LINEAR_API_KEY environment variable required') + process.exit(1) +} + +const client = new LinearClient({ apiKey: LINEAR_API_KEY }) + +async function main() { + // Your automation logic + const me = await client.viewer + console.log(`Running as: ${me.name}`) + + // Example: Get my open issues + const myIssues = await client.issues({ + filter: { + assignee: { id: { eq: me.id } }, + state: { type: { eq: 'started' } } + } + }) + + console.log(`You have ${myIssues.nodes.length} in-progress issues`) + + for (const issue of myIssues.nodes) { + console.log(`- ${issue.identifier}: ${issue.title}`) + } +} + +main().catch(error => { + console.error('Error:', error.message) + process.exit(1) +}) +``` + +## Running Scripts + +```bash +# Direct execution +npx tsx automation.ts + +# With environment variable +LINEAR_API_KEY=lin_api_xxx npx tsx automation.ts + +# Make executable (requires shebang) +chmod +x automation.ts +./automation.ts +``` + +## When to Use Each Tool + +**Use MCP tools (prefer first):** +- Single issue operations (get, create, update) +- Simple queries with known parameters +- Basic filtering (by assignee, team, state, labels) +- Interactive workflows in conversation +- Creating/updating projects + +**Use SDK scripts (when MCP insufficient):** +- Iterating over multiple items with complex logic +- Mapping/transforming data for export or reports +- Bulk updates with conditional logic +- Multi-step operations requiring intermediate state +- Operations needing debugging or iteration + +**Use GraphQL API (fallback only):** +- Operations not supported by MCP or SDK +- When you need specific fields not exposed by SDK + +## Dependencies + +Scripts require: +- `@linear/sdk` package +- `tsx` for execution (via npx or installed) +- `LINEAR_API_KEY` environment variable + +Install in project: `npm install @linear/sdk` + +## API Reference + +Full SDK documentation: https://linear.app/developers/sdk.md + +The SDK is auto-generated from Linear's GraphQL API and includes type definitions for all operations. From fb0e9069134994c92025aca762af5b97af6f451b Mon Sep 17 00:00:00 2001 From: wrsmith108 Date: Sun, 14 Dec 2025 15:55:38 -0800 Subject: [PATCH 2/2] Remove workspace-specific UUIDs, add query example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Status UUIDs are workspace-specific in Linear. Replaced hardcoded UUIDs with a GraphQL query to discover your own workspace's values. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- skills/linear/SKILL.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/skills/linear/SKILL.md b/skills/linear/SKILL.md index a935c5cef..7ac2017d2 100644 --- a/skills/linear/SKILL.md +++ b/skills/linear/SKILL.md @@ -183,17 +183,25 @@ mutation { ### Project Status UUIDs -Projects have status independent of issue progress: +Projects have status independent of issue progress. Status UUIDs are **workspace-specific** - query your workspace to find them: +```graphql +# Get your workspace's project status UUIDs +query { + projectStatuses { + nodes { + id + name + type + } + } +} ``` -Backlog: 1ed7da89-db44-4339-b0d7-ce37d8ff9604 -Planned: 33ebbb84-53ea-4dd8-a8db-49a8b3b9c502 -In Progress: 71d18c8f-53de-4752-be37-a6d529cb9c97 -Completed: 54294a72-010d-4ae7-9829-bed76232fb66 -Canceled: 562050cc-bb71-4b81-bf3d-8bed7cc44153 -``` + +Common status names: `Backlog`, `Planned`, `In Progress`, `Completed`, `Canceled` ```graphql +# Update project status mutation { projectUpdate(id: "", input: { statusId: "" }) { success } }