0
# Issue Operations
1
2
Comprehensive issue management including creation, updates, querying, and relationship management with support for attachments, comments, and metadata.
3
4
## Capabilities
5
6
### Core CRUD Operations
7
8
Basic issue management operations for creating, reading, updating, and deleting issues.
9
10
```python { .api }
11
def get(self, issue_id: str) -> LinearIssue:
12
"""
13
Fetch a Linear issue by ID with comprehensive details including attachments,
14
labels, team, project, etc.
15
16
Args:
17
issue_id: The ID of the issue to fetch
18
19
Returns:
20
LinearIssue with complete details
21
22
Raises:
23
ValueError: If issue not found
24
"""
25
26
def create(self, issue: LinearIssueInput) -> LinearIssue:
27
"""
28
Create a new issue in Linear with support for team assignment, parent relationships,
29
and metadata attachments.
30
31
Args:
32
issue: LinearIssueInput with issue details
33
34
Returns:
35
Created LinearIssue object
36
37
Raises:
38
ValueError: If creation fails
39
"""
40
41
def update(self, issue_id: str, update_data: LinearIssueUpdateInput) -> LinearIssue:
42
"""
43
Update an existing issue with support for state changes, team transfers,
44
and metadata updates.
45
46
Args:
47
issue_id: The ID of the issue to update
48
update_data: LinearIssueUpdateInput with fields to update
49
50
Returns:
51
Updated LinearIssue object
52
53
Raises:
54
ValueError: If update fails
55
"""
56
57
def delete(self, issue_id: str) -> bool:
58
"""
59
Delete an issue by its ID.
60
61
Args:
62
issue_id: The ID of the issue to delete
63
64
Returns:
65
True if successful
66
67
Raises:
68
ValueError: If deletion fails
69
"""
70
```
71
72
Usage examples:
73
74
```python
75
from linear_api import LinearClient, LinearIssueInput, LinearIssueUpdateInput
76
77
client = LinearClient()
78
79
# Get an issue
80
issue = client.issues.get("issue-id")
81
print(f"Issue: {issue.title} ({issue.state.name})")
82
83
# Create a new issue
84
new_issue = client.issues.create(LinearIssueInput(
85
title="New task from API",
86
teamName="Engineering",
87
description="Task created via Python API",
88
priority=LinearPriority.HIGH
89
))
90
91
# Update an issue
92
updated = client.issues.update("issue-id", LinearIssueUpdateInput(
93
title="Updated title",
94
description="Updated description"
95
))
96
97
# Delete an issue
98
success = client.issues.delete("issue-id")
99
```
100
101
### Query Operations
102
103
Advanced querying capabilities for finding issues by various criteria.
104
105
```python { .api }
106
def get_by_team(self, team_name: str) -> Dict[str, LinearIssue]:
107
"""
108
Get all issues for a specific team.
109
110
Args:
111
team_name: Name of the team
112
113
Returns:
114
Dictionary mapping issue IDs to LinearIssue objects
115
"""
116
117
def get_by_project(self, project_id: str) -> Dict[str, LinearIssue]:
118
"""
119
Get all issues for a specific project.
120
121
Args:
122
project_id: The ID of the project
123
124
Returns:
125
Dictionary mapping issue IDs to LinearIssue objects
126
"""
127
128
def get_all(self) -> Dict[str, LinearIssue]:
129
"""
130
Get all issues from all teams in the organization.
131
Processes in batches for performance.
132
133
Returns:
134
Dictionary mapping issue IDs to LinearIssue objects
135
"""
136
```
137
138
Usage examples:
139
140
```python
141
# Get issues by team
142
team_issues = client.issues.get_by_team("Engineering")
143
print(f"Found {len(team_issues)} issues in Engineering team")
144
145
# Get issues by project
146
project_issues = client.issues.get_by_project("project-id")
147
for issue_id, issue in project_issues.items():
148
print(f"{issue.title} - {issue.state.name}")
149
150
# Get all issues (use with caution for large organizations)
151
all_issues = client.issues.get_all()
152
```
153
154
### Attachment Management
155
156
Handle issue attachments with URL validation and metadata support.
157
158
```python { .api }
159
def create_attachment(self, attachment: LinearAttachmentInput) -> Dict[str, Any]:
160
"""
161
Create an attachment for an issue with URL validation and metadata support.
162
163
Args:
164
attachment: LinearAttachmentInput with attachment details
165
166
Returns:
167
Created attachment data
168
169
Raises:
170
ValueError: If attachment creation fails
171
"""
172
173
def get_attachments(self, issue_id: str) -> List[Dict[str, Any]]:
174
"""
175
Get all attachments for an issue with creator and metadata information.
176
177
Args:
178
issue_id: The ID of the issue
179
180
Returns:
181
List of attachment dictionaries
182
"""
183
```
184
185
Usage examples:
186
187
```python
188
from linear_api import LinearAttachmentInput
189
190
# Create an attachment
191
attachment = client.issues.create_attachment(LinearAttachmentInput(
192
url="https://example.com/document.pdf",
193
issueId="issue-id",
194
title="Requirements Document",
195
subtitle="Project requirements v1.0",
196
metadata={"category": "documentation", "version": "1.0"}
197
))
198
199
# Get issue attachments
200
attachments = client.issues.get_attachments("issue-id")
201
for attach in attachments:
202
print(f"Attachment: {attach['title']} - {attach['url']}")
203
```
204
205
### History and Comments
206
207
Access issue change history and comment management.
208
209
```python { .api }
210
def get_history(self, issue_id: str) -> List[Dict[str, Any]]:
211
"""
212
Get the change history for an issue including state transitions and actors.
213
214
Args:
215
issue_id: The ID of the issue
216
217
Returns:
218
List of history entries
219
"""
220
221
def get_comments(self, issue_id: str) -> List[Comment]:
222
"""
223
Get all comments for an issue with automatic pagination and Comment model conversion.
224
225
Args:
226
issue_id: The ID of the issue
227
228
Returns:
229
List of Comment objects
230
"""
231
```
232
233
Usage examples:
234
235
```python
236
# Get issue history
237
history = client.issues.get_history("issue-id")
238
for entry in history:
239
print(f"Change: {entry.get('action')} by {entry.get('actor', {}).get('name')}")
240
241
# Get issue comments
242
comments = client.issues.get_comments("issue-id")
243
for comment in comments:
244
print(f"Comment by {comment.creator.name}: {comment.body[:50]}...")
245
```
246
247
### Relationship Management
248
249
Manage issue relationships including parent-child hierarchies and inter-issue relations.
250
251
```python { .api }
252
def get_children(self, issue_id: str) -> Dict[str, LinearIssue]:
253
"""
254
Get child issues for a parent issue.
255
256
Args:
257
issue_id: The ID of the parent issue
258
259
Returns:
260
Dictionary mapping issue IDs to LinearIssue objects
261
"""
262
263
def get_relations(self, issue_id: str) -> List[IssueRelation]:
264
"""
265
Get relations for an issue (blocks, duplicates, etc.)
266
267
Args:
268
issue_id: The ID of the issue
269
270
Returns:
271
List of IssueRelation objects
272
"""
273
274
def get_inverse_relations(self, issue_id: str) -> List[IssueRelation]:
275
"""
276
Get inverse relations for an issue (blocked by, duplicate of, etc.)
277
278
Args:
279
issue_id: The ID of the issue
280
281
Returns:
282
List of IssueRelation objects
283
"""
284
```
285
286
Usage examples:
287
288
```python
289
# Get child issues
290
children = client.issues.get_children("parent-issue-id")
291
print(f"Parent has {len(children)} child issues")
292
293
# Get issue relations
294
relations = client.issues.get_relations("issue-id")
295
for relation in relations:
296
print(f"Relation: {relation.type} to issue {relation.relatedIssue['id']}")
297
298
# Get inverse relations
299
inverse_relations = client.issues.get_inverse_relations("issue-id")
300
```
301
302
### Social Features
303
304
Access reactions, subscribers, and social interactions on issues.
305
306
```python { .api }
307
def get_reactions(self, issue_id: str) -> List[Reaction]:
308
"""
309
Get reactions to an issue with user information and emoji data.
310
311
Args:
312
issue_id: The ID of the issue
313
314
Returns:
315
List of Reaction objects
316
"""
317
318
def get_subscribers(self, issue_id: str) -> List[LinearUser]:
319
"""
320
Get subscribers of an issue with automatic pagination and LinearUser model conversion.
321
322
Args:
323
issue_id: The ID of the issue
324
325
Returns:
326
List of LinearUser objects
327
"""
328
```
329
330
Usage examples:
331
332
```python
333
# Get issue reactions
334
reactions = client.issues.get_reactions("issue-id")
335
for reaction in reactions:
336
print(f"{reaction.user.name} reacted with {reaction.emoji}")
337
338
# Get issue subscribers
339
subscribers = client.issues.get_subscribers("issue-id")
340
print(f"Issue has {len(subscribers)} subscribers")
341
```
342
343
### Customer Needs Integration
344
345
Access customer needs associated with issues for product management workflows.
346
347
```python { .api }
348
def get_needs(self, issue_id: str) -> List[CustomerNeedResponse]:
349
"""
350
Get customer needs associated with an issue.
351
352
Args:
353
issue_id: The ID of the issue
354
355
Returns:
356
List of CustomerNeedResponse objects
357
"""
358
```
359
360
Usage examples:
361
362
```python
363
# Get customer needs for an issue
364
needs = client.issues.get_needs("issue-id")
365
for need in needs:
366
print(f"Customer need: {need.priority} priority")
367
```
368
369
### Cache Management
370
371
Control caching for issue-related data to optimize performance.
372
373
```python { .api }
374
def invalidate_cache(self) -> None:
375
"""
376
Invalidate all issue-related caches.
377
"""
378
```
379
380
Usage examples:
381
382
```python
383
# Clear issue caches after bulk operations
384
client.issues.invalidate_cache()
385
386
# Or clear all caches
387
client.clear_cache()
388
```
389
390
## Input Models
391
392
### LinearIssueInput
393
394
For creating new issues with comprehensive field support.
395
396
```python { .api }
397
class LinearIssueInput(LinearModel):
398
title: str # Required: Issue title
399
teamName: str # Required: Team name for issue
400
description: Optional[str] = None
401
priority: Optional[LinearPriority] = None
402
assigneeId: Optional[str] = None
403
projectId: Optional[str] = None
404
stateId: Optional[str] = None
405
parentId: Optional[str] = None
406
labelIds: Optional[List[str]] = None
407
estimate: Optional[int] = None
408
dueDate: Optional[datetime] = None
409
metadata: Optional[Dict[str, Any]] = None # Auto-converted to attachment
410
```
411
412
### LinearIssueUpdateInput
413
414
For updating existing issues with all optional fields.
415
416
```python { .api }
417
class LinearIssueUpdateInput(LinearModel):
418
title: Optional[str] = None
419
description: Optional[str] = None
420
priority: Optional[LinearPriority] = None
421
assigneeId: Optional[str] = None
422
projectId: Optional[str] = None
423
stateId: Optional[str] = None
424
teamId: Optional[str] = None
425
labelIds: Optional[List[str]] = None
426
estimate: Optional[int] = None
427
dueDate: Optional[datetime] = None
428
metadata: Optional[Dict[str, Any]] = None # Auto-converted to attachment
429
```
430
431
### LinearAttachmentInput
432
433
For creating issue attachments with metadata support.
434
435
```python { .api }
436
class LinearAttachmentInput(LinearModel):
437
url: str # Required: Attachment URL
438
issueId: str # Required: Issue ID
439
title: Optional[str] = None
440
subtitle: Optional[str] = None
441
metadata: Optional[Dict[str, Any]] = None
442
```
443
444
## Advanced Usage Patterns
445
446
### Bulk Operations
447
448
```python
449
# Create multiple issues efficiently
450
issues_to_create = [
451
LinearIssueInput(title=f"Task {i}", teamName="Engineering")
452
for i in range(1, 11)
453
]
454
455
created_issues = []
456
for issue_input in issues_to_create:
457
created = client.issues.create(issue_input)
458
created_issues.append(created)
459
```
460
461
### Metadata Workflow
462
463
```python
464
# Use metadata for custom fields
465
issue_with_metadata = client.issues.create(LinearIssueInput(
466
title="Feature Request",
467
teamName="Engineering",
468
description="New feature from customer feedback",
469
metadata={
470
"customer_id": "cust_123",
471
"feature_type": "enhancement",
472
"business_value": "high",
473
"complexity": "medium"
474
}
475
))
476
477
# Metadata is automatically converted to an attachment
478
attachments = client.issues.get_attachments(issue_with_metadata.id)
479
metadata_attachment = next((a for a in attachments if a.get('title') == 'Metadata'), None)
480
print(metadata_attachment['metadata'])
481
```
482
483
### Parent-Child Issue Hierarchies
484
485
```python
486
# Create parent issue
487
parent = client.issues.create(LinearIssueInput(
488
title="Epic: User Authentication System",
489
teamName="Engineering",
490
description="Complete user authentication overhaul"
491
))
492
493
# Create child issues
494
child1 = client.issues.create(LinearIssueInput(
495
title="Implement JWT tokens",
496
teamName="Engineering",
497
parentId=parent.id
498
))
499
500
child2 = client.issues.create(LinearIssueInput(
501
title="Add OAuth integration",
502
teamName="Engineering",
503
parentId=parent.id
504
))
505
506
# Get all children
507
children = client.issues.get_children(parent.id)
508
print(f"Epic has {len(children)} child issues")
509
```