Claude-skill-registry extended
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/extended" ~/.claude/skills/majiayu000-claude-skill-registry-extended && rm -rf "$T"
skills/data/extended/SKILL.mdOverview
This skill extends Linear MCP capabilities by adding write operations for Documents and ProjectMilestones. While Linear MCP provides read-only access to documents and no milestone support, this skill enables full CRUD operations via direct GraphQL API calls.
What this skill adds:
- Document creation, updates, and deletion
- Project milestone management (create, update, delete, list, get)
- Direct GraphQL access for advanced operations
Prerequisites:
- Linear API Key from https://linear.app/settings/api
- Set environment variable:
export LINEAR_API_KEY="lin_api_xxxxx" - Optional:
for JSON formattingjq
Document Operations
Creating a Document
Basic example:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentCreate($input: DocumentCreateInput!) { documentCreate(input: $input) { success document { id title url slugId createdAt creator { name } } } }", "variables": { "input": { "title": "API Design Document" } } }'
With content and project:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentCreate($input: DocumentCreateInput!) { documentCreate(input: $input) { success document { id title url slugId } } }", "variables": { "input": { "title": "Q4 Roadmap", "content": "# Q4 Goals\n\n- Launch feature X\n- Improve performance by 30%", "projectId": "PROJECT_ID_HERE", "color": "#FF6B6B" } } }'
Available parameters:
(required): Document titletitle
: Markdown contentcontent
: Attach to projectprojectId
: Attach to initiativeinitiativeId
: Attach to issueissueId
: Icon color (hex format)color
: Icon emoji or name (optional, some emojis may not be valid - omit if validation fails)icon
: Display order (float)sortOrder
Updating a Document
Update title and content:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentUpdate($id: String!, $input: DocumentUpdateInput!) { documentUpdate(id: $id, input: $input) { success document { id title updatedAt updatedBy { name } } } }", "variables": { "id": "DOCUMENT_ID_OR_SLUG", "input": { "title": "Updated Title", "content": "# Updated Content\n\nNew information here." } } }'
Move to trash:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentUpdate($id: String!, $input: DocumentUpdateInput!) { documentUpdate(id: $id, input: $input) { success } }", "variables": { "id": "DOCUMENT_ID", "input": { "trashed": true } } }'
Available update parameters:
: New titletitle
: New markdown contentcontent
: New icon colorcolor
: New iconicon
: Move to trash (true) or restore (false)trashed
: Move to different projectprojectId
: Update display ordersortOrder
Deleting a Document
Permanently delete (archive):
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentDelete($id: String!) { documentDelete(id: $id) { success } }", "variables": { "id": "DOCUMENT_ID" } }'
Restore archived document:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation DocumentUnarchive($id: String!) { documentUnarchive(id: $id) { success entity { id title } } }", "variables": { "id": "DOCUMENT_ID" } }'
Project Milestone Operations
Creating a Milestone
Basic milestone:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation ProjectMilestoneCreate($input: ProjectMilestoneCreateInput!) { projectMilestoneCreate(input: $input) { success projectMilestone { id name status progress targetDate project { id name } } } }", "variables": { "input": { "projectId": "PROJECT_ID_HERE", "name": "Beta Release" } } }'
With description and target date:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation ProjectMilestoneCreate($input: ProjectMilestoneCreateInput!) { projectMilestoneCreate(input: $input) { success projectMilestone { id name status progress targetDate } } }", "variables": { "input": { "projectId": "PROJECT_ID_HERE", "name": "MVP Launch", "description": "# MVP Goals\n\n- Core features complete\n- 10 beta users onboarded", "targetDate": "2025-06-30" } } }'
Interactive approach (using AskUserQuestion):
When user doesn't specify a target date, use AskUserQuestion to ask:
// Step 1: Ask user for target date AskUserQuestion({ questions: [{ question: "What is the target date for this milestone?", header: "Target Date", multiSelect: false, options: [ { label: "End of this month", description: "Set target date to the last day of current month" }, { label: "End of next month", description: "Set target date to the last day of next month" }, { label: "Custom date", description: "I'll specify a custom date in YYYY-MM-DD format" }, { label: "No target date", description: "Create milestone without a specific target date" } ] }] }) // Step 2: Based on user's answer, construct the mutation // If custom date selected, prompt for YYYY-MM-DD format // If no target date, omit targetDate from input
Available parameters:
(required): Parent project IDprojectId
(required): Milestone namename
: Markdown descriptiondescription
: Target date (YYYY-MM-DD format)targetDate
: Display order (float)sortOrder
Status values (auto-calculated):
: No progress yetunstarted
: Next milestone to work onnext
: Past target dateoverdue
: All issues completeddone
Updating a Milestone
Update name and target date:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation ProjectMilestoneUpdate($id: String!, $input: ProjectMilestoneUpdateInput!) { projectMilestoneUpdate(id: $id, input: $input) { success projectMilestone { id name status targetDate } } }", "variables": { "id": "MILESTONE_ID", "input": { "name": "MVP Launch - Extended", "targetDate": "2025-07-15" } } }'
Available update parameters:
: New namename
: New markdown descriptiondescription
: New target date (YYYY-MM-DD)targetDate
: New display ordersortOrder
Listing Milestones
List all milestones:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "query ProjectMilestones($first: Int) { projectMilestones(first: $first) { nodes { id name status progress targetDate project { id name } issues { nodes { id title } } } } }", "variables": { "first": 50 } }'
List milestones for specific project:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "query Project($id: String!) { project(id: $id) { id name projectMilestones { nodes { id name status progress targetDate } } } }", "variables": { "id": "PROJECT_ID" } }'
Getting a Single Milestone
Detailed milestone info:
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "query ProjectMilestone($id: String!) { projectMilestone(id: $id) { id name description status progress progressHistory currentProgress targetDate createdAt updatedAt project { id name state } issues { nodes { id title state { name type } assignee { name } } } } }", "variables": { "id": "MILESTONE_ID" } }'
Deleting a Milestone
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation ProjectMilestoneDelete($id: String!) { projectMilestoneDelete(id: $id) { success } }", "variables": { "id": "MILESTONE_ID" } }'
Moving a Milestone to Another Project
curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation ProjectMilestoneMove($id: String!, $input: ProjectMilestoneMoveInput!) { projectMilestoneMove(id: $id, input: $input) { success projectMilestone { id name project { id name } } } }", "variables": { "id": "MILESTONE_ID", "input": { "projectId": "NEW_PROJECT_ID" } } }'
Usage Guidelines
When to use this skill
Document operations:
- User asks to "create a document" or "write a doc"
- User wants to "update document content"
- User needs to "delete" or "archive" a document
- User wants to "move document to trash" or "restore document"
Milestone operations:
- User asks to "create a milestone" or "add milestone"
- User wants to "set target date for milestone"
- User needs to "update milestone status" or "rename milestone"
- User asks to "list project milestones" or "show milestone progress"
- User wants to "delete milestone" or "move milestone to another project"
IMPORTANT for Milestones:
- Always use AskUserQuestion to ask for targetDate when creating or updating milestones
- Ask the user to provide a target date in YYYY-MM-DD format
- Validate the date format before making the API call
- If user doesn't provide a date, milestone can be created without targetDate (optional)
How to use
-
Always check for LINEAR_API_KEY:
if [ -z "$LINEAR_API_KEY" ]; then echo "Error: LINEAR_API_KEY not set. Get key from https://linear.app/settings/api" exit 1 fi -
Get IDs first:
- Use Linear MCP's
to get project IDslist_projects - Use Linear MCP's
to get issue IDslist_issues - Use
to get document IDs/slugslist_documents
- Use Linear MCP's
-
For milestone operations, use AskUserQuestion:
- When creating a milestone, ask for targetDate using AskUserQuestion tool
- Example question: "What is the target date for this milestone? (YYYY-MM-DD format, or leave empty for no date)"
- Parse the user's response and include in the mutation
- If user provides empty/no date, omit targetDate from the input
-
Handle JSON carefully:
- Escape newlines in markdown: use
\n - Escape quotes: use
\" - For complex content, consider using heredoc or jq
- Escape newlines in markdown: use
-
Check responses:
- Always verify
in mutation responsessuccess: true - If
, check thesuccess: false
arrayerrors - Show the document/milestone URL when available
- Always verify
-
Handle icon field carefully:
- The
field is optional for documentsicon - Some emojis may fail validation with "icon is not a valid icon" error
- If icon validation fails, omit the field and retry
- Linear API only accepts certain emojis - no definitive list available
- The
-
Format output for user:
- Use
to pretty-print JSONjq - Extract key fields like
,id
,urlstatus - Provide actionable next steps
- Use
Error Handling
Authentication errors:
{ "errors": [ { "message": "Authentication required", "extensions": { "code": "UNAUTHENTICATED" } } ] }
→ Check if LINEAR_API_KEY is set and valid
Not found errors:
{ "errors": [ { "message": "Resource not found", "extensions": { "code": "NOT_FOUND" } } ] }
→ Verify the ID exists using list operations first
Validation errors:
{ "data": { "documentCreate": { "success": false } }, "errors": [ { "message": "Title is required", "path": ["documentCreate", "input", "title"] } ] }
→ Check required fields are provided
Rate limiting:
{ "errors": [ { "message": "Rate limit exceeded", "extensions": { "code": "RATE_LIMITED" } } ] }
→ Wait and retry after a few seconds
Icon validation errors:
{ "errors": [ { "message": "Argument Validation Error", "extensions": { "code": "INVALID_INPUT", "validationErrors": [ { "property": "icon", "constraints": { "customValidation": "icon is not a valid icon" } } ] } } ] }
→ Omit the
icon field or try a different emoji/icon name. Linear API only accepts certain emojis.
Combining with Linear MCP
This skill works best alongside the official Linear MCP server:
Linear MCP provides (read operations):
- Get existing documentslist_documents
- Read document contentget_document
- Get project IDslist_projects
- Get issue IDslist_issues
- Get team infolist_teams
This skill adds (write operations):
- Create new documentsdocumentCreate
- Update documentsdocumentUpdate
- Delete documentsdocumentDelete
- Create milestonesprojectMilestoneCreate
- Update milestonesprojectMilestoneUpdate
- Delete milestonesprojectMilestoneDelete
query - List milestones (not in MCP)projectMilestones
Typical workflow:
- Use Linear MCP to list projects → Get project ID
- Use this skill to create a document for that project
- Use Linear MCP to verify the document appears in listings
- Use this skill to create milestones for the project
- Use this skill to query milestone progress
Advanced Usage
Using jq for complex operations
Extract just the document URL:
curl -X POST ... | jq -r '.data.documentCreate.document.url'
Format milestone list as table:
curl -X POST ... | jq -r '.data.projectMilestones.nodes[] | [.name, .status, (.progress * 100 | tostring + "%")] | @tsv'
Using heredoc for large content
CONTENT=$(cat <<'EOF' # Architecture Design ## Overview System architecture overview here. ## Components - API Gateway - Service Mesh - Data Layer EOF ) # Create temp file with Python for proper JSON encoding TEMP_FILE=$(mktemp) python3 << PEOF > "$TEMP_FILE" import json data = { "query": """mutation DocumentCreate(\$input: DocumentCreateInput!) { documentCreate(input: \$input) { success document { id url } } }""", "variables": { "input": { "title": "Architecture Design", "content": """$CONTENT""" } } } print(json.dumps(data, ensure_ascii=False)) PEOF curl -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d @"$TEMP_FILE" | jq '.' rm "$TEMP_FILE"
References
For detailed schema information:
- @references/document-schema.md - Complete Document type definitions
- Search patterns:
grep "DocumentCreateInput\|DocumentUpdateInput\|icon\|color" references/document-schema.md
- Search patterns:
- @references/milestone-schema.md - Complete ProjectMilestone type definitions
- Search patterns:
grep "ProjectMilestoneCreateInput\|ProjectMilestoneUpdateInput\|targetDate" references/milestone-schema.md
- Search patterns:
- @references/examples.md - Additional usage examples
- Search patterns:
grep "Example\|mutation\|query" references/examples.md
- Search patterns:
For the original GraphQL schema: