A comprehensive Python wrapper for the Linear API with rich Pydantic models, simplified workflows, and an object-oriented design.
npx @tessl/cli install tessl/pypi-linear-api@0.2.00
# Linear API
1
2
A comprehensive Python wrapper for the Linear API with rich Pydantic models, simplified workflows, and an object-oriented design. This package provides programmatic access to Linear's project management platform, enabling developers to integrate Linear functionality into their applications and workflows with type safety, automatic pagination handling, intelligent caching, and comprehensive error management.
3
4
## Package Information
5
6
- **Package Name**: linear-api
7
- **Language**: Python
8
- **Installation**: `pip install linear-api`
9
- **Minimum Python Version**: 3.9+
10
- **Dependencies**: `pydantic>=2.0.0`, `requests>=2.25.0`
11
- **License**: MIT
12
13
## Core Imports
14
15
```python
16
from linear_api import LinearClient
17
```
18
19
Import domain models and types:
20
21
```python
22
from linear_api import (
23
LinearIssue,
24
LinearProject,
25
LinearUser,
26
LinearTeam,
27
LinearState,
28
LinearLabel,
29
LinearAttachment,
30
LinearIssueInput,
31
LinearIssueUpdateInput,
32
LinearAttachmentInput,
33
LinearPriority,
34
IntegrationService,
35
SLADayCountType,
36
ProjectStatusType,
37
)
38
```
39
40
Import utility functions for low-level access:
41
42
```python
43
from linear_api.utils import call_linear_api
44
```
45
46
## Basic Usage
47
48
```python
49
from linear_api import LinearClient
50
51
# Create client with API key
52
client = LinearClient(api_key="your_api_key_here")
53
54
# Or use environment variable LINEAR_API_KEY
55
client = LinearClient()
56
57
# Get an issue by ID
58
issue = client.issues.get("issue-id")
59
print(f"Issue: {issue.title} ({issue.state.name})")
60
61
# Create a new issue
62
from linear_api import LinearIssueInput
63
64
new_issue = client.issues.create(LinearIssueInput(
65
title="New task from API",
66
teamName="Engineering",
67
description="Task created via Python API"
68
))
69
70
# Get all projects for a team
71
projects = client.projects.get_all()
72
print(f"Found {len(projects)} projects")
73
74
# Get current user info
75
me = client.users.get_me()
76
print(f"Current user: {me.name} ({me.email})")
77
```
78
79
## Architecture
80
81
The Linear API package follows a manager-based architecture that provides a clean separation of concerns:
82
83
### Core Components
84
85
- **LinearClient**: Central client managing authentication, configuration, and resource access
86
- **Resource Managers**: Specialized managers for different Linear entities (issues, projects, teams, users)
87
- **Domain Models**: Rich Pydantic models with complete field coverage and dynamic properties
88
- **Caching System**: Intelligent caching with TTL support to optimize API calls
89
- **Utility Layer**: Low-level GraphQL access and data transformation utilities
90
91
### Design Patterns
92
93
- **Manager Pattern**: Each resource type has a dedicated manager with consistent CRUD operations
94
- **Active Record**: Domain models include dynamic properties for accessing related data through client references
95
- **Connection Unwrapping**: Automatic handling of GraphQL pagination for improved usability
96
- **Decorator-based Enhancement**: Client references are automatically injected into returned models for method chaining
97
98
This architecture enables both high-level abstractions for common workflows and low-level GraphQL access for advanced use cases, with comprehensive type safety throughout.
99
100
## Capabilities
101
102
### Client Management
103
104
Central client configuration and authentication for accessing Linear's API with caching, connection management, and schema validation capabilities.
105
106
```python { .api }
107
class LinearClient:
108
def __init__(
109
self,
110
api_key: Optional[str] = None,
111
enable_cache: bool = True,
112
cache_ttl: int = 3600,
113
auto_unwrap_connections: bool = True,
114
): ...
115
116
def call_api(self, query: Dict[str, Any] | str) -> Dict[str, Any]: ...
117
def execute_graphql(self, query: str, variables: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: ...
118
def clear_cache(self, cache_name: Optional[str] = None) -> None: ...
119
def enable_connection_unwrapping(self) -> None: ...
120
def disable_connection_unwrapping(self) -> None: ...
121
```
122
123
[Client Management](./client-management.md)
124
125
### Issue Operations
126
127
Comprehensive issue management including creation, updates, querying, and relationship management with support for attachments, comments, and metadata.
128
129
```python { .api }
130
class IssueManager:
131
def get(self, issue_id: str) -> LinearIssue: ...
132
def create(self, issue: LinearIssueInput) -> LinearIssue: ...
133
def update(self, issue_id: str, update_data: LinearIssueUpdateInput) -> LinearIssue: ...
134
def delete(self, issue_id: str) -> bool: ...
135
def get_by_team(self, team_name: str) -> Dict[str, LinearIssue]: ...
136
def get_by_project(self, project_id: str) -> Dict[str, LinearIssue]: ...
137
def get_all() -> Dict[str, LinearIssue]: ...
138
```
139
140
[Issue Operations](./issue-operations.md)
141
142
### Project Management
143
144
Full project lifecycle management including creation, updates, member management, and relationship tracking with milestones, updates, and documentation.
145
146
```python { .api }
147
class ProjectManager:
148
def get(self, project_id: str) -> LinearProject: ...
149
def create(self, name: str, team_name: str, description: Optional[str] = None) -> LinearProject: ...
150
def update(self, project_id: str, **kwargs) -> LinearProject: ...
151
def delete(self, project_id: str) -> bool: ...
152
def get_all(self, team_id: Optional[str] = None) -> Dict[str, LinearProject]: ...
153
def get_id_by_name(self, project_name: str, team_id: Optional[str] = None) -> str: ...
154
```
155
156
[Project Management](./project-management.md)
157
158
### Team Administration
159
160
Team configuration and member management including workflow states, labels, cycles, templates, and organizational hierarchy.
161
162
```python { .api }
163
class TeamManager:
164
def get(self, team_id: str) -> LinearTeam: ...
165
def get_all() -> Dict[str, LinearTeam]: ...
166
def get_id_by_name(self, team_name: str) -> str: ...
167
def get_states(self, team_id: str, include_issue_ids: bool = False) -> List[LinearState]: ...
168
def get_members(self, team_id: str) -> List[LinearUser]: ...
169
def get_labels(self, team_id: str, include_issue_ids: bool = False) -> List[LinearLabel]: ...
170
```
171
172
[Team Administration](./team-administration.md)
173
174
### User Management
175
176
User operations including profile access, team memberships, issue assignments, and organizational data management.
177
178
```python { .api }
179
class UserManager:
180
def get(self, user_id: str) -> LinearUser: ...
181
def get_all() -> Dict[str, LinearUser]: ...
182
def get_me() -> LinearUser: ...
183
def get_id_by_email(self, email: str) -> str: ...
184
def get_id_by_name(self, name: str) -> str: ...
185
def get_assigned_issues(self, user_id: str) -> Dict[str, LinearIssue]: ...
186
```
187
188
[User Management](./user-management.md)
189
190
### Data Models and Types
191
192
Rich Pydantic models covering all Linear entities with complete field definitions, input/output types, enums, and connection types for GraphQL pagination.
193
194
```python { .api }
195
class LinearIssue(LinearModel):
196
id: str
197
title: str
198
url: str
199
state: LinearState
200
priority: LinearPriority
201
team: LinearTeam
202
# 50+ additional fields...
203
204
class LinearIssueInput(LinearModel):
205
title: str
206
teamName: str
207
# Optional fields for creation...
208
209
class LinearPriority(Enum):
210
URGENT = 0
211
HIGH = 1
212
MEDIUM = 2
213
LOW = 3
214
NONE = 4
215
```
216
217
[Data Models and Types](./data-models-types.md)
218
219
### Cache and Utilities
220
221
Low-level utilities including direct GraphQL access, caching management, data processing functions, and schema validation tools for advanced use cases.
222
223
```python { .api }
224
def call_linear_api(query: str | Dict[str, Any], api_key: Optional[str] = None) -> Dict[str, Any]: ...
225
226
class CacheManager:
227
def get(self, cache_name: str, key: Any) -> Optional[Any]: ...
228
def set(self, cache_name: str, key: Any, value: Any, ttl: Optional[int] = None) -> None: ...
229
def clear(self, cache_name: Optional[str] = None) -> None: ...
230
```
231
232
[Cache and Utilities](./cache-utilities.md)
233
234
## Environment Configuration
235
236
### Authentication
237
238
Set your Linear API key as an environment variable:
239
240
```bash
241
export LINEAR_API_KEY="your_api_key_here"
242
```
243
244
Or pass it directly to the client:
245
246
```python
247
client = LinearClient(api_key="your_api_key_here")
248
```
249
250
### Caching Configuration
251
252
Control caching behavior:
253
254
```python
255
# Disable caching entirely
256
client = LinearClient(enable_cache=False)
257
258
# Custom cache TTL (in seconds)
259
client = LinearClient(cache_ttl=7200) # 2 hours
260
261
# Runtime cache control
262
client.cache.disable()
263
client.cache.clear()
264
client.cache.enable()
265
```
266
267
### Connection Unwrapping
268
269
Control automatic GraphQL pagination handling:
270
271
```python
272
# Disable automatic connection unwrapping for performance
273
client = LinearClient(auto_unwrap_connections=False)
274
275
# Runtime control
276
client.disable_connection_unwrapping()
277
client.enable_connection_unwrapping()
278
```
279
280
## Error Handling
281
282
The package provides comprehensive error handling with descriptive messages:
283
284
```python
285
from linear_api import LinearClient
286
287
try:
288
client = LinearClient() # Will raise if no API key
289
issue = client.issues.get("invalid-id")
290
except ValueError as e:
291
print(f"API Error: {e}")
292
```
293
294
Common error scenarios:
295
- Missing or invalid API key authentication
296
- Invalid GraphQL queries or mutations
297
- Network connectivity issues
298
- Rate limiting from Linear API
299
- Invalid entity IDs or references