or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-utilities.mdclient-management.mddata-models-types.mdindex.mdissue-operations.mdproject-management.mdteam-administration.mduser-management.md

data-models-types.mddocs/

0

# Data Models and Types

1

2

Rich Pydantic models covering all Linear entities with complete field definitions, input/output types, enums, and connection types for GraphQL pagination.

3

4

## Core Data Models

5

6

### Issue Models

7

8

Comprehensive models for issue management with full field coverage and dynamic properties.

9

10

```python { .api }

11

class LinearIssue(LinearModel):

12

# Required fields

13

id: str

14

title: str

15

url: str

16

state: LinearState

17

priority: LinearPriority

18

team: LinearTeam

19

createdAt: datetime

20

updatedAt: datetime

21

number: int

22

customerTicketCount: int

23

24

# Optional fields (50+ additional fields)

25

description: Optional[str] = None

26

assignee: Optional[LinearUser] = None

27

project: Optional[LinearProject] = None

28

labels: Optional[List[LinearLabel]] = None

29

dueDate: Optional[datetime] = None

30

parentId: Optional[str] = None

31

estimate: Optional[int] = None

32

attachments: Optional[List[LinearAttachment]] = None

33

# ... many more optional fields

34

35

# Dynamic properties (accessed through client reference)

36

@property

37

def parent(self) -> Optional['LinearIssue']: ...

38

39

@property

40

def children(self) -> Dict[str, 'LinearIssue']: ...

41

42

@property

43

def comments(self) -> List['Comment']: ...

44

45

@property

46

def history(self) -> List[Dict[str, Any]]: ...

47

48

@property

49

def relations(self) -> List['IssueRelation']: ...

50

51

@property

52

def metadata(self) -> Dict[str, Any]: ...

53

```

54

55

```python { .api }

56

class LinearIssueInput(LinearModel):

57

"""Input model for creating issues with metadata auto-conversion."""

58

title: str # Required

59

teamName: str # Required

60

description: Optional[str] = None

61

priority: Optional[LinearPriority] = None

62

assigneeId: Optional[str] = None

63

projectId: Optional[str] = None

64

stateId: Optional[str] = None

65

parentId: Optional[str] = None

66

labelIds: Optional[List[str]] = None

67

estimate: Optional[int] = None

68

dueDate: Optional[datetime] = None

69

metadata: Optional[Dict[str, Any]] = None # Auto-converted to attachment

70

```

71

72

```python { .api }

73

class LinearIssueUpdateInput(LinearModel):

74

"""Input model for updating issues with partial field updates."""

75

title: Optional[str] = None

76

description: Optional[str] = None

77

priority: Optional[LinearPriority] = None

78

assigneeId: Optional[str] = None

79

projectId: Optional[str] = None

80

stateId: Optional[str] = None

81

teamId: Optional[str] = None

82

labelIds: Optional[List[str]] = None

83

estimate: Optional[int] = None

84

dueDate: Optional[datetime] = None

85

metadata: Optional[Dict[str, Any]] = None

86

```

87

88

Usage examples:

89

90

```python

91

from linear_api import LinearIssue, LinearIssueInput, LinearPriority

92

93

# Create issue input

94

issue_input = LinearIssueInput(

95

title="New feature request",

96

teamName="Engineering",

97

description="Detailed feature description",

98

priority=LinearPriority.HIGH,

99

metadata={"category": "feature", "source": "customer-feedback"}

100

)

101

102

# Access issue properties

103

issue = client.issues.get("issue-id")

104

print(f"Issue: {issue.title}")

105

print(f"State: {issue.state.name}")

106

print(f"Priority: {issue.priority}")

107

print(f"Assignee: {issue.assignee.name if issue.assignee else 'Unassigned'}")

108

109

# Access dynamic properties

110

children = issue.children # Automatically fetched from API

111

comments = issue.comments # Automatically fetched with pagination

112

```

113

114

### Label and Attachment Models

115

116

Models for issue categorization and file attachments.

117

118

```python { .api }

119

class LinearLabel(LinearModel):

120

id: str

121

name: str

122

color: str

123

archivedAt: Optional[datetime] = None

124

createdAt: Optional[datetime] = None

125

updatedAt: Optional[datetime] = None

126

description: Optional[str] = None

127

isGroup: Optional[bool] = None

128

inheritedFrom: Optional[Dict[str, Any]] = None

129

parent: Optional[Dict[str, Any]] = None

130

creator: Optional[LinearUser] = None

131

issue_ids: Optional[List[str]] = None # When include_issue_ids=True

132

```

133

134

```python { .api }

135

class LinearAttachment(LinearModel):

136

id: str

137

url: str

138

title: Optional[str] = None

139

subtitle: Optional[str] = None

140

metadata: Optional[Dict[str, Any]] = None

141

issueId: str

142

createdAt: datetime

143

updatedAt: datetime

144

creator: Optional[LinearUser] = None

145

```

146

147

```python { .api }

148

class LinearAttachmentInput(LinearModel):

149

"""Input for creating attachments with metadata support."""

150

url: str # Required

151

issueId: str # Required

152

title: Optional[str] = None

153

subtitle: Optional[str] = None

154

metadata: Optional[Dict[str, Any]] = None

155

```

156

157

Usage examples:

158

159

```python

160

# Create attachment

161

attachment_input = LinearAttachmentInput(

162

url="https://docs.company.com/spec.pdf",

163

issueId="issue-id",

164

title="Technical Specification",

165

subtitle="Version 2.0",

166

metadata={"version": "2.0", "type": "specification"}

167

)

168

169

# Access label information

170

for label in issue.labels or []:

171

print(f"Label: {label.name} ({label.color})")

172

```

173

174

### Project Models

175

176

Comprehensive project management models with lifecycle tracking.

177

178

```python { .api }

179

class LinearProject(LinearModel):

180

# Required fields

181

id: str

182

name: str

183

createdAt: datetime

184

updatedAt: datetime

185

slugId: str

186

url: str

187

color: str

188

priority: int

189

status: ProjectStatus

190

progress: float

191

scope: int

192

193

# Optional fields (20+ additional fields)

194

description: Optional[str] = None

195

startDate: Optional[TimelessDate] = None

196

targetDate: Optional[TimelessDate] = None

197

completedAt: Optional[datetime] = None

198

canceledAt: Optional[datetime] = None

199

health: Optional[str] = None

200

# ... many more optional fields

201

202

# Dynamic properties

203

@property

204

def members(self) -> List['LinearUser']: ...

205

206

@property

207

def issues(self) -> List['LinearIssue']: ...

208

209

@property

210

def projectUpdates(self) -> List['ProjectUpdate']: ...

211

212

@property

213

def relations(self) -> List['ProjectRelation']: ...

214

```

215

216

```python { .api }

217

class ProjectStatus(LinearModel):

218

type: ProjectStatusType # Enum: PLANNED, BACKLOG, STARTED, etc.

219

```

220

221

```python { .api }

222

class ProjectMilestone(LinearModel):

223

id: str

224

name: str

225

# Additional milestone fields...

226

```

227

228

Usage examples:

229

230

```python

231

from linear_api import ProjectStatusType

232

233

# Access project information

234

project = client.projects.get("project-id")

235

print(f"Project: {project.name}")

236

print(f"Status: {project.status.type}")

237

print(f"Progress: {project.progress}%")

238

print(f"Priority: {project.priority}")

239

240

# Check project dates

241

if project.startDate:

242

print(f"Start: {project.startDate.year}-{project.startDate.month}-{project.startDate.day}")

243

if project.targetDate:

244

print(f"Target: {project.targetDate.year}-{project.targetDate.month}-{project.targetDate.day}")

245

```

246

247

### Team Models

248

249

Team configuration and workflow models with extensive settings.

250

251

```python { .api }

252

class LinearTeam(LinearModel):

253

# Required fields

254

id: str

255

name: str

256

key: str

257

258

# Optional configuration fields (50+ fields)

259

description: Optional[str] = None

260

color: Optional[str] = None

261

icon: Optional[str] = None

262

createdAt: Optional[datetime] = None

263

updatedAt: Optional[datetime] = None

264

parentId: Optional[str] = None

265

266

# Automation settings

267

autoArchivePeriod: Optional[int] = None

268

autoCloseChildIssues: Optional[bool] = None

269

autoCloseParentIssues: Optional[bool] = None

270

271

# Cycle configuration

272

cycleDuration: Optional[int] = None

273

cycleStartDay: Optional[int] = None

274

cyclesEnabled: Optional[bool] = None

275

276

# Estimation settings

277

defaultIssueEstimate: Optional[int] = None

278

issueEstimationType: Optional[str] = None

279

280

# Template settings

281

defaultIssueState: Optional[Dict[str, Any]] = None

282

defaultProjectTemplate: Optional[Dict[str, Any]] = None

283

284

# SCIM integration

285

scimGroupName: Optional[str] = None

286

scimManaged: Optional[bool] = None

287

288

# Dynamic properties

289

@property

290

def members(self) -> List['LinearUser']: ...

291

292

@property

293

def states(self) -> List['LinearState']: ...

294

295

@property

296

def labels(self) -> List['LinearLabel']: ...

297

298

@property

299

def activeCycle(self) -> Optional[Dict[str, Any]]: ...

300

301

@property

302

def projects(self) -> Dict[str, Any]: ...

303

```

304

305

```python { .api }

306

class LinearState(LinearModel):

307

id: str

308

name: str

309

type: str

310

color: str

311

archivedAt: Optional[datetime] = None

312

createdAt: Optional[datetime] = None

313

updatedAt: Optional[datetime] = None

314

description: Optional[str] = None

315

position: Optional[int] = None

316

inheritedFrom: Optional[Dict[str, Any]] = None

317

issue_ids: Optional[List[str]] = None # When include_issue_ids=True

318

```

319

320

Usage examples:

321

322

```python

323

# Access team configuration

324

team = client.teams.get("team-id")

325

print(f"Team: {team.name} ({team.key})")

326

print(f"Cycles enabled: {team.cyclesEnabled}")

327

print(f"Cycle duration: {team.cycleDuration}")

328

print(f"Auto-archive period: {team.autoArchivePeriod}")

329

330

# Access team states

331

states = team.states

332

for state in states:

333

print(f"State: {state.name} ({state.type}) - {state.color}")

334

```

335

336

### User Models

337

338

User profile and organizational relationship models.

339

340

```python { .api }

341

class LinearUser(LinearModel):

342

# Required fields

343

id: str

344

name: str

345

displayName: str

346

email: str

347

createdAt: datetime

348

updatedAt: datetime

349

350

# Boolean status fields

351

active: bool

352

admin: bool

353

app: bool

354

guest: bool

355

isMe: bool

356

357

# Optional profile fields

358

avatarUrl: Optional[str] = None

359

archivedAt: Optional[datetime] = None

360

avatarBackgroundColor: Optional[str] = None

361

calendarHash: Optional[str] = None

362

createdIssueCount: Optional[int] = None

363

description: Optional[str] = None

364

disableReason: Optional[str] = None

365

initials: Optional[str] = None

366

inviteHash: Optional[str] = None

367

lastSeen: Optional[datetime] = None

368

statusEmoji: Optional[str] = None

369

statusLabel: Optional[str] = None

370

statusUntilAt: Optional[datetime] = None

371

timezone: Optional[str] = None

372

url: Optional[str] = None

373

374

# Organizational context

375

organization: Optional[Organization] = None

376

377

# Dynamic properties

378

@property

379

def assignedIssues(self) -> Dict[str, 'LinearIssue']: ...

380

381

@property

382

def createdIssues(self) -> List[Dict[str, Any]]: ...

383

384

@property

385

def teams(self) -> List['LinearTeam']: ...

386

387

@property

388

def teamMemberships(self) -> List[Dict[str, Any]]: ...

389

```

390

391

```python { .api }

392

class LinearUserReference(LinearModel):

393

"""Simplified user reference for nested objects."""

394

id: str

395

name: str

396

displayName: str

397

email: Optional[str] = None

398

createdAt: Optional[datetime] = None

399

updatedAt: Optional[datetime] = None

400

avatarUrl: Optional[str] = None

401

```

402

403

Usage examples:

404

405

```python

406

# Access user information

407

user = client.users.get_me()

408

print(f"User: {user.displayName} ({user.email})")

409

print(f"Status: {'Active' if user.active else 'Inactive'}")

410

print(f"Admin: {'Yes' if user.admin else 'No'}")

411

412

# Access profile details

413

if user.statusEmoji:

414

print(f"Status: {user.statusEmoji} {user.statusLabel}")

415

if user.timezone:

416

print(f"Timezone: {user.timezone}")

417

```

418

419

## Enums and Constants

420

421

### Priority and Status Enums

422

423

```python { .api }

424

class LinearPriority(Enum):

425

"""Issue priority levels."""

426

URGENT = 0

427

HIGH = 1

428

MEDIUM = 2

429

LOW = 3

430

NONE = 4

431

```

432

433

```python { .api }

434

class ProjectStatusType(StrEnum):

435

"""Project lifecycle status types."""

436

PLANNED = "planned"

437

BACKLOG = "backlog"

438

STARTED = "started"

439

PAUSED = "paused"

440

COMPLETED = "completed"

441

CANCELED = "canceled"

442

```

443

444

```python { .api }

445

class ProjectUpdateHealthType(StrEnum):

446

"""Project health indicators."""

447

ON_TRACK = "onTrack"

448

AT_RISK = "atRisk"

449

OFF_TRACK = "offTrack"

450

```

451

452

453

### Service Integration Enums

454

455

```python { .api }

456

class IntegrationService(StrEnum):

457

"""Supported integration services."""

458

ASANA = "asana"

459

FIGMA = "figma"

460

GITHUB = "github"

461

GITLAB = "gitlab"

462

INTERCOM = "intercom"

463

JIRA = "jira"

464

NOTION = "notion"

465

SLACK = "slack"

466

ZENDESK = "zendesk"

467

```

468

469

```python { .api }

470

class SLADayCountType(StrEnum):

471

"""SLA day counting methods."""

472

ALL = "all"

473

ONLY_BUSINESS_DAYS = "onlyBusinessDays"

474

```

475

476

Usage examples:

477

478

```python

479

from linear_api import LinearPriority, ProjectStatusType, IntegrationService, SLADayCountType

480

481

# Use priority enum

482

issue_input = LinearIssueInput(

483

title="High priority issue",

484

teamName="Engineering",

485

priority=LinearPriority.HIGH

486

)

487

488

# Use project status enum

489

client.projects.update("project-id", status=ProjectStatusType.STARTED)

490

491

# Use SLA day counting

492

print("SLA counting methods:")

493

for method in SLADayCountType:

494

print(f" - {method.value}")

495

496

# Check integration services

497

print("Supported integrations:")

498

for service in IntegrationService:

499

print(f" - {service.value}")

500

```

501

502

## Base Classes and Utilities

503

504

### Base Model Class

505

506

```python { .api }

507

class LinearModel(BaseModel):

508

"""Base class for all Linear domain models with Pydantic integration."""

509

linear_class_name: ClassVar[str] # Maps to GraphQL type names

510

known_missing_fields: ClassVar[List[str]] = [] # Tracks missing API fields

511

known_extra_fields: ClassVar[List[str]] = [] # Tracks additional fields

512

_client: Any = PrivateAttr() # Private client reference

513

514

def with_client(self, client) -> 'LinearModel':

515

"""Sets client reference for dynamic property access."""

516

517

def model_dump(self, **kwargs) -> Dict[str, Any]:

518

"""Enhanced serialization excluding class variables."""

519

520

@classmethod

521

def get_linear_class_name(cls) -> str:

522

"""Returns GraphQL type name for this model."""

523

```

524

525

### Connection Types

526

527

Generic connection models for GraphQL pagination.

528

529

```python { .api }

530

class Connection(LinearModel, Generic[T]):

531

"""Generic connection model for GraphQL pagination."""

532

nodes: List[T]

533

pageInfo: Optional[Dict[str, Any]] = None

534

```

535

536

Specific connection types for different entities:

537

538

```python { .api }

539

class CommentConnection(LinearModel):

540

nodes: List[Comment]

541

pageInfo: Optional[Dict[str, Any]] = None

542

543

class UserConnection(LinearModel):

544

nodes: List[LinearUserReference]

545

pageInfo: Optional[Dict[str, Any]] = None

546

547

class TeamConnection(LinearModel):

548

nodes: List[LinearTeam]

549

pageInfo: Optional[Dict[str, Any]] = None

550

551

# ... many more connection types for different entities

552

```

553

554

## Common Models

555

556

Shared models used across different domain areas.

557

558

```python { .api }

559

class Organization(LinearModel):

560

id: str

561

name: str

562

563

class Comment(LinearModel):

564

id: str

565

body: str

566

createdAt: datetime

567

updatedAt: datetime

568

creator: Optional[LinearUserReference] = None

569

570

class Document(LinearModel):

571

id: str

572

title: Optional[str] = None

573

icon: Optional[str] = None

574

createdAt: datetime

575

updatedAt: datetime

576

577

class EntityExternalLink(LinearModel):

578

id: str

579

url: str

580

label: Optional[str] = None

581

createdAt: datetime

582

583

class Reaction(LinearModel):

584

id: str

585

emoji: str

586

createdAt: datetime

587

user: Optional[LinearUserReference] = None

588

589

class TimelessDate(LinearModel):

590

"""Date without time information."""

591

year: int

592

month: int

593

day: int

594

```

595

596

## Relationship Models

597

598

Models for managing relationships between entities.

599

600

```python { .api }

601

class IssueRelation(LinearModel):

602

id: str

603

type: str

604

relatedIssue: Optional[Dict[str, Any]] = None

605

createdAt: datetime

606

607

class ProjectRelation(LinearModel):

608

id: str

609

createdAt: datetime

610

type: str

611

project: Optional[Dict[str, Any]] = None

612

relatedProject: Optional[Dict[str, Any]] = None

613

614

class TeamMembership(LinearModel):

615

id: str

616

createdAt: Optional[datetime] = None

617

updatedAt: Optional[datetime] = None

618

archivedAt: Optional[datetime] = None

619

owner: Optional[bool] = None

620

sortOrder: Optional[int] = None

621

user: Optional[LinearUser] = None

622

team: Optional[LinearTeam] = None

623

```

624

625

## Advanced Model Usage

626

627

### Model Validation and Type Safety

628

629

```python

630

from pydantic import ValidationError

631

632

try:

633

# Pydantic validation ensures type safety

634

issue_input = LinearIssueInput(

635

title="Valid issue",

636

teamName="Engineering",

637

priority="INVALID_PRIORITY" # This will raise ValidationError

638

)

639

except ValidationError as e:

640

print(f"Validation error: {e}")

641

642

# Proper usage with enum

643

issue_input = LinearIssueInput(

644

title="Valid issue",

645

teamName="Engineering",

646

priority=LinearPriority.HIGH # Type-safe enum usage

647

)

648

```

649

650

### Dynamic Property Access

651

652

```python

653

# Models with client references can access related data dynamically

654

issue = client.issues.get("issue-id")

655

656

# These properties trigger API calls automatically

657

parent_issue = issue.parent # Fetches parent issue if exists

658

child_issues = issue.children # Fetches all child issues

659

comments = issue.comments # Fetches all comments with pagination

660

history = issue.history # Fetches change history

661

662

# Properties return appropriate model types

663

for comment in comments:

664

print(f"Comment by {comment.creator.name}: {comment.body}")

665

```

666

667

### Model Serialization

668

669

```python

670

# Models can be serialized to dictionaries

671

issue_dict = issue.model_dump()

672

print(f"Issue as dict: {issue_dict}")

673

674

# Or to JSON

675

issue_json = issue.model_dump_json()

676

print(f"Issue as JSON: {issue_json}")

677

678

# Exclude private fields

679

clean_dict = issue.model_dump(exclude={'_client'})

680

```

681

682

### Custom Model Extensions

683

684

```python

685

# Models can be extended with custom properties

686

class ExtendedLinearIssue(LinearIssue):

687

@property

688

def is_overdue(self) -> bool:

689

"""Check if issue is overdue."""

690

if not self.dueDate:

691

return False

692

return datetime.now() > self.dueDate

693

694

@property

695

def priority_name(self) -> str:

696

"""Get human-readable priority name."""

697

priority_names = {

698

LinearPriority.URGENT: "πŸ”΄ Urgent",

699

LinearPriority.HIGH: "🟠 High",

700

LinearPriority.MEDIUM: "🟑 Medium",

701

LinearPriority.LOW: "πŸ”΅ Low",

702

LinearPriority.NONE: "βšͺ None"

703

}

704

return priority_names.get(self.priority, "Unknown")

705

706

# Use extended model

707

issue = client.issues.get("issue-id")

708

extended_issue = ExtendedLinearIssue(**issue.model_dump())

709

print(f"Priority: {extended_issue.priority_name}")

710

print(f"Overdue: {extended_issue.is_overdue}")

711

```