skills/update-issues/SKILL.md
Find and update Linear issues that need labels, blocking relationships, or metadata. Use when user says '/update-issues' with criteria like 'no labels', 'missing agent-ready', 'needs size', etc.
npx skillsauth add jamesc/skills update-issuesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill searches for issues matching criteria and applies updates automatically.
When the user says /update-issues for ones with no labels or similar:
| User Says | What to Search For | |-----------|-------------------| | "no labels" | Issues with empty or missing labels | | "missing agent-ready" | Issues without agent-state labels | | "missing area" | Issues without item-area labels | | "missing type" | Issues without issue-type labels | | "missing size" | Issues without size estimate labels | | "not assigned" | Issues without assignee | | "in backlog" | Issues in Backlog state needing triage | | "all open" | All open issues (for bulk updates) | | "BT-X through BT-Y" | Specific range of issue numbers |
Extract what the user wants to update:
Examples:
/update-issues for ones with no labels → Find issues with no labels/update-issues for missing agent-ready → Find issues without agent-state labels/update-issues for issues in backlog → Find issues in Backlog state/update-issues for BT-21 through BT-30 → Specific rangeUse streamlinear-cli to find matching issues:
All open issues (or issues in a specific state):
streamlinear-cli search --state "Backlog" --team BT
streamlinear-cli search --team BT # all open
Get a specific issue:
streamlinear-cli get BT-21
Issues in a number range or with complex filters (use GraphQL):
streamlinear-cli graphql "query { issues(filter: { number: { gte: 21, lte: 40 }, team: { key: { eq: \"BT\" } } }) { nodes { id identifier title description labels { nodes { name id } } state { name } assignee { email } } } }"
Batch fetch by specific numbers:
streamlinear-cli graphql "query { issues(filter: { number: { in: [308, 309, 310] }, team: { key: { eq: \"BT\" } } }) { nodes { id identifier labels { nodes { name id } } } } }"
For each issue found, determine what's missing:
[email protected]Agent State: Must have one of agent-ready, needs-spec, blocked, human-review, done
Item Area: Must have one of class-system, stdlib, repl, cli, codegen, runtime, parser
Issue Type: Must have one of Epic, Feature, Bug, Improvement, Documentation, Infra, Language Feature, Refactor, Research, Samples
Note: Epic label is for large initiatives grouping 5+ related issues. Most issues should use other types.
Size: Must have one of S, M, L, XL
When labels are missing, infer from context:
Agent State:
agent-readyneeds-specblockedItem Area:
parsercodegenstdlibreplcliruntimeclass-systemIssue Type:
FeatureBugRefactorDocumentationResearchLanguage FeatureSize:
SMLXLUse the CLI for these fields:
streamlinear-cli update BT-123 --assignee me
streamlinear-cli update BT-123 --priority 3
streamlinear-cli update BT-123 --state "In Progress"
IMPORTANT: The CLI update command does NOT support labels. You MUST use GraphQL.
Query all available labels and store the ID mapping:
streamlinear-cli graphql "query { issueLabels(first: 50) { nodes { id name } } }"
Store the results in a SQL table for reuse:
CREATE TABLE label_map (name TEXT PRIMARY KEY, id TEXT);
INSERT INTO label_map VALUES ('agent-ready', '<uuid>'), ('Bug', '<uuid>'), ...;
Query multiple issues at once to get their UUIDs and existing labels:
streamlinear-cli graphql "query { issues(filter: { number: { in: [308, 309, 310] }, team: { key: { eq: \"BT\" } } }) { nodes { id identifier labels { nodes { name id } } } } }"
Preserve existing labels! Merge inferred label IDs with existing ones.
Batch up to 6 updates per mutation using aliases:
streamlinear-cli graphql "mutation { bt308: issueUpdate(id: \"<issue-uuid>\", input: { labelIds: [\"<label-uuid-1>\", \"<label-uuid-2>\", \"<label-uuid-3>\", \"<label-uuid-4>\"] }) { success issue { identifier } } bt309: issueUpdate(id: \"<issue-uuid>\", input: { labelIds: [\"<label-uuid-1>\", \"<label-uuid-2>\"] }) { success issue { identifier } } }"
Key rules:
labelIds REPLACES all labels (not additive) — always include existing label IDsbt308:, bt309:, etc.)| Field | Via CLI update | Via GraphQL | Example |
|-------|-----------------|-------------|---------|
| state | ✅ | ✅ | --state "Backlog" |
| priority | ✅ | ✅ | --priority 3 |
| assignee | ✅ | ✅ | --assignee me |
| labels | ❌ | ✅ labelIds | Array of label UUIDs |
| title | ❌ | ✅ | String |
| body | ❌ | ✅ description | Markdown |
After updating, report what was changed:
Updated 5 issues:
✓ BT-21: Added labels [agent-ready, Feature, stdlib, M]
✓ BT-32: Added labels [agent-ready, Feature, stdlib, M], set assignee
✓ BT-33: Added labels [needs-spec, Feature, stdlib, M]
✓ BT-34: Added labels [agent-ready, Feature, stdlib, S]
✓ BT-35: Added labels [agent-ready, Feature, stdlib, M]
/update-issues for ones with no labelsstreamlinear-cli graphql "query { issueLabels(first: 50) { nodes { id name } } }"
Store in SQL: CREATE TABLE label_map (name TEXT PRIMARY KEY, id TEXT);
streamlinear-cli graphql "query { issues(filter: { number: { in: [308, 309, 310, 311, 312] }, team: { key: { eq: \"BT\" } } }) { nodes { id identifier title labels { nodes { name id } } state { name } } } }"
Filter to issues with empty labels — check labels.nodes is empty
For each unlabeled issue:
label_map tableExample: BT-21 "Implement String class core API"
agent-readystdlibFeatureMstreamlinear-cli graphql "mutation { bt21: issueUpdate(id: \"<bt21-uuid>\", input: { labelIds: [\"<agent-ready-uuid>\", \"<Feature-uuid>\", \"<stdlib-uuid>\", \"<M-uuid>\"] }) { success issue { identifier } } }"
/update-issues for missing agent-readystreamlinear-cli graphql "query { issues(filter: { team: { key: { eq: \"BT\" } }, state: { name: { nin: [\"Done\", \"Canceled\"] } } }, first: 50) { nodes { id identifier title description labels { nodes { name id } } } } }"
Filter to issues where labels.nodes has NO entry with name in [agent-ready, needs-spec, blocked, human-review, done]
For each, analyze and infer agent-state label
Apply via batched GraphQL mutation — include ALL existing label IDs plus the new one
/update-issues for BT-21 through BT-40streamlinear-cli graphql "query { issues(filter: { number: { gte: 21, lte: 40 }, team: { key: { eq: \"BT\" } } }) { nodes { id identifier title description labels { nodes { name id } } state { name } } } }"
Analyze and update each one
Skip issues in Done or Canceled states
Batch updates in groups of 6 per mutation
agent-readyneeds-specblockedparsercodegenstdlibreplcliruntimeclass-systemFeatureBugRefactorDocumentationResearchLanguage FeatureSMLXLIf the user also mentions dependencies (e.g., "and set up blocking relationships"):
streamlinear-cli get BT-21 # note the `id` field (UUID)
streamlinear-cli get BT-32 # note the `id` field (UUID)
streamlinear-cli graphql "mutation { issueRelationCreate(input: { issueId: \"<blocker-uuid>\", relatedIssueId: \"<blocked-uuid>\", type: blocks }) { success } }"
BT-21 (API definitions) blocks:
- BT-32 (block evaluation)
- BT-33 (collections)
- BT-34 (strings)
For each blocked issue, get both UUIDs then create the relation.
Linear supports these relationship types:
| Type | Description |
|------|-------------|
| blocks | This issue blocks another (dependency) |
| blocked_by | This issue is blocked by another (inverse) |
| related | Generic relationship |
| duplicate | Mark as duplicate |
Note: Use blocks type. Linear automatically creates the inverse blocked_by relationship.
update command does NOT support labelslabel_map tableissues(filter: { number: { in: [...] } }) not individual getslabelIds REPLACES all labels — always merge existing IDs with new onesbt308: issueUpdate(...) bt309: issueUpdate(...) in one callTeam BT uses these workflow states:
| State | Description |
|-------|-------------|
| Backlog | Idea captured, not yet specified |
| Todo | Ready to start, fully specified |
| In Progress | Actively being worked on |
| In Review | Code complete, needs verification |
| Done | Merged and verified |
| Canceled | Won't do |
| Duplicate | Duplicate of another issue |
tools
Find the next logical piece of work. Use when user types /whats-next or asks what they should work on next, or wants recommendations for the next task.
development
Use when navigating code, finding references, looking up definitions, understanding types, or tracing call hierarchies in TypeScript, Rust, or Beamtalk (.bt) files. Prefer LSP over Grep/Glob for any navigation task where symbol semantics matter.
data-ai
Sync modified skills and agents back to the repo and create a PR. Use when user types /sync-skills or wants to save in-session skill improvements.
development
Review current branch changes vs main. Use when user types /review-code or asks for a code review of their changes.