A comprehensive Python wrapper for the Linear API with rich Pydantic models, simplified workflows, and an object-oriented design.
Full project lifecycle management including creation, updates, member management, and relationship tracking with milestones, updates, and documentation.
Basic project management operations for creating, reading, updating, and deleting projects.
def get(self, project_id: str) -> LinearProject:
"""
Fetch a project by ID with comprehensive details including status, dates,
relationships, and document content.
Args:
project_id: The ID of the project to fetch
Returns:
LinearProject with complete details
Raises:
ValueError: If project not found
"""
def create(self, name: str, team_name: str, description: Optional[str] = None) -> LinearProject:
"""
Create a new project in Linear for a specific team with optional description.
Args:
name: Project name
team_name: Name of the team that owns the project
description: Optional project description
Returns:
Created LinearProject object
Raises:
ValueError: If creation fails
"""
def update(self, project_id: str, **kwargs) -> LinearProject:
"""
Update an existing project with flexible field updates.
Args:
project_id: The ID of the project to update
**kwargs: Fields to update (name, description, status, etc.)
Returns:
Updated LinearProject object
Raises:
ValueError: If update fails
"""
def delete(self, project_id: str) -> bool:
"""
Delete a project by its ID.
Args:
project_id: The ID of the project to delete
Returns:
True if successful
Raises:
ValueError: If deletion fails
"""Usage examples:
from linear_api import LinearClient
client = LinearClient()
# Get a project
project = client.projects.get("project-id")
print(f"Project: {project.name} ({project.status.type})")
# Create a new project
new_project = client.projects.create(
name="Q4 Feature Development",
team_name="Engineering",
description="Major feature development for Q4 release"
)
# Update project status
updated = client.projects.update(
project.id,
description="Updated project description",
status="STARTED"
)
# Delete a project
success = client.projects.delete("project-id")Find and query projects by various criteria.
def get_all(self, team_id: Optional[str] = None) -> Dict[str, LinearProject]:
"""
Get all projects, optionally filtered by team.
Args:
team_id: Optional team ID to filter projects
Returns:
Dictionary mapping project IDs to LinearProject objects
"""
def get_id_by_name(self, project_name: str, team_id: Optional[str] = None) -> str:
"""
Get a project ID by its name, optionally within a specific team.
Args:
project_name: Name of the project to find
team_id: Optional team ID to narrow search
Returns:
Project ID string
Raises:
ValueError: If project not found
"""Usage examples:
# Get all projects
all_projects = client.projects.get_all()
print(f"Found {len(all_projects)} projects")
# Get projects for specific team
team_projects = client.projects.get_all(team_id="team-id")
# Find project by name
project_id = client.projects.get_id_by_name("Q4 Feature Development")
project = client.projects.get(project_id)Manage project team membership and access.
def get_members(self, project_id: str) -> List[LinearUser]:
"""
Get members of a project with automatic pagination and LinearUser model conversion.
Args:
project_id: The ID of the project
Returns:
List of LinearUser objects
"""Usage examples:
# Get project members
members = client.projects.get_members("project-id")
print(f"Project has {len(members)} members:")
for member in members:
print(f" - {member.name} ({member.email})")Manage project milestones and timeline tracking.
def get_milestones(self, project_id: str) -> List[ProjectMilestone]:
"""
Get milestones for a project with automatic model conversion.
Args:
project_id: The ID of the project
Returns:
List of ProjectMilestone objects
"""Usage examples:
# Get project milestones
milestones = client.projects.get_milestones("project-id")
for milestone in milestones:
print(f"Milestone: {milestone.name}")Access project comments and communication history.
def get_comments(self, project_id: str) -> List[Comment]:
"""
Get comments for a project with automatic pagination and Comment model conversion.
Args:
project_id: The ID of the project
Returns:
List of Comment objects
"""Usage examples:
# Get project comments
comments = client.projects.get_comments("project-id")
print(f"Project has {len(comments)} comments")
for comment in comments:
print(f"Comment by {comment.creator.name}: {comment.body[:50]}...")Access issues associated with projects.
def get_issues(self, project_id: str) -> List[LinearIssue]:
"""
Get issues for a project with basic issue information.
Args:
project_id: The ID of the project
Returns:
List of LinearIssue objects
"""Usage examples:
# Get project issues
issues = client.projects.get_issues("project-id")
print(f"Project has {len(issues)} issues")
# Group by status
from collections import defaultdict
by_status = defaultdict(list)
for issue in issues:
by_status[issue.state.name].append(issue)
for status, issue_list in by_status.items():
print(f"{status}: {len(issue_list)} issues")Track project progress updates and status changes.
def get_project_updates(self, project_id: str) -> List[ProjectUpdate]:
"""
Get updates for a project with automatic model conversion.
Args:
project_id: The ID of the project
Returns:
List of ProjectUpdate objects
"""Usage examples:
# Get project updates
updates = client.projects.get_project_updates("project-id")
for update in updates:
print(f"Update: {update.id}")Manage project relationships and dependencies.
def get_relations(self, project_id: str) -> List[ProjectRelation]:
"""
Get relations for a project including related projects and relationship types.
Args:
project_id: The ID of the project
Returns:
List of ProjectRelation objects
"""Usage examples:
# Get project relations
relations = client.projects.get_relations("project-id")
for relation in relations:
print(f"Relation: {relation.type}")Access teams associated with projects.
def get_teams(self, project_id: str) -> List[LinearTeam]:
"""
Get teams associated with a project.
Args:
project_id: The ID of the project
Returns:
List of LinearTeam objects
"""Usage examples:
# Get project teams
teams = client.projects.get_teams("project-id")
for team in teams:
print(f"Team: {team.name}")Access project documentation and external resources.
def get_documents(self, project_id: str) -> List[Document]:
"""
Get documents associated with a project.
Args:
project_id: The ID of the project
Returns:
List of Document objects
"""
def get_external_links(self, project_id: str) -> List[EntityExternalLink]:
"""
Get external links associated with a project.
Args:
project_id: The ID of the project
Returns:
List of EntityExternalLink objects
"""Usage examples:
# Get project documents
documents = client.projects.get_documents("project-id")
for doc in documents:
print(f"Document: {doc.title}")
# Get external links
links = client.projects.get_external_links("project-id")
for link in links:
print(f"Link: {link.label} - {link.url}")Track project change history and audit trail.
def get_history(self, project_id: str) -> List[ProjectHistory]:
"""
Get the history of a project with change entries.
Args:
project_id: The ID of the project
Returns:
List of ProjectHistory objects
"""Usage examples:
# Get project history
history = client.projects.get_history("project-id")
for entry in history:
print(f"History: {entry.id} at {entry.createdAt}")Access initiatives associated with projects for strategic planning.
def get_initiatives(self, project_id: str) -> List[Dict[str, Any]]:
"""
Get initiatives associated with a project.
Args:
project_id: The ID of the project
Returns:
List of initiative dictionaries
"""Usage examples:
# Get project initiatives
initiatives = client.projects.get_initiatives("project-id")
for initiative in initiatives:
print(f"Initiative: {initiative.get('name')}")Access project labels for categorization and organization.
def get_labels(self, project_id: str) -> List[LinearLabel]:
"""
Get labels associated with a project.
Args:
project_id: The ID of the project
Returns:
List of LinearLabel objects
"""Usage examples:
# Get project labels
labels = client.projects.get_labels("project-id")
for label in labels:
print(f"Label: {label.name} ({label.color})")Access customer needs associated with projects for product management.
def get_needs(self, project_id: str) -> List[CustomerNeed]:
"""
Get customer needs associated with a project.
Args:
project_id: The ID of the project
Returns:
List of CustomerNeed objects
"""Usage examples:
# Get customer needs
needs = client.projects.get_needs("project-id")
for need in needs:
print(f"Customer need: {need.id}")Control caching for project-related data.
def invalidate_cache(self) -> None:
"""
Invalidate all project-related caches.
"""Usage examples:
# Clear project caches
client.projects.invalidate_cache()Projects in Linear have specific status types that control their lifecycle:
from linear_api import ProjectStatusType
# Available status types
statuses = [
ProjectStatusType.PLANNED, # Planning phase
ProjectStatusType.BACKLOG, # In backlog
ProjectStatusType.STARTED, # Active development
ProjectStatusType.PAUSED, # Temporarily paused
ProjectStatusType.COMPLETED, # Successfully completed
ProjectStatusType.CANCELED # Cancelled
]
# Update project status
client.projects.update("project-id", status=ProjectStatusType.STARTED)# Create a comprehensive project
project = client.projects.create(
name="Mobile App Redesign",
team_name="Design",
description="Complete redesign of mobile application UI/UX"
)
# Add initial configuration
client.projects.update(project.id,
status=ProjectStatusType.STARTED,
priority=1, # High priority
targetDate="2024-12-31"
)def generate_project_report(project_id: str):
project = client.projects.get(project_id)
issues = client.projects.get_issues(project_id)
members = client.projects.get_members(project_id)
# Calculate completion metrics
completed_issues = [i for i in issues if i.state.type == "completed"]
completion_rate = len(completed_issues) / len(issues) if issues else 0
print(f"Project: {project.name}")
print(f"Status: {project.status.type}")
print(f"Progress: {project.progress}%")
print(f"Issues: {len(completed_issues)}/{len(issues)} completed ({completion_rate:.1%})")
print(f"Team: {len(members)} members")
return {
"project": project,
"completion_rate": completion_rate,
"total_issues": len(issues),
"completed_issues": len(completed_issues),
"team_size": len(members)
}
# Generate report
report = generate_project_report("project-id")def analyze_team_projects(team_name: str):
# Get team ID
team_id = client.teams.get_id_by_name(team_name)
# Get all projects for team
projects = client.projects.get_all(team_id=team_id)
# Analyze by status
status_counts = {}
for project in projects.values():
status = project.status.type
status_counts[status] = status_counts.get(status, 0) + 1
print(f"Team {team_name} project status distribution:")
for status, count in status_counts.items():
print(f" {status}: {count} projects")
return status_counts
# Analyze team projects
analysis = analyze_team_projects("Engineering")Install with Tessl CLI
npx tessl i tessl/pypi-linear-api