tree: 8788381624ab9a062a1d169e44d50abf840efcb1
  1. api/
  2. e2e/
  3. impl/
  4. models/
  5. tasks/
  6. linear.go
  7. README.md
backend/plugins/linear/README.md

Linear

Summary

This plugin collects data from Linear through its GraphQL API and maps it into DevLake's standardized ticket domain, so Linear issues appear in DevLake dashboards (throughput, lead/cycle time, sprint burndown, etc.).

The selectable scope is a Linear Team, which maps to a domain Board.

Supported data

Linear entityTool-layer tableDomain-layer table
Team_tool_linear_teams (scope)boards
User_tool_linear_accountsaccounts
Workflow state_tool_linear_workflow_states(drives issue status mapping)
Issue_tool_linear_issuesissues, board_issues
Label_tool_linear_issue_labelsissue_labels
Comment_tool_linear_commentsissue_comments
Cycle_tool_linear_cyclessprints, board_sprints, sprint_issues
Issue history_tool_linear_issue_historyissue_changelogs

Field mapping highlights

  • Status — derived deterministically from Linear's WorkflowState.type (no manual mapping needed, unlike Jira):
    • backlog, unstartedTODO
    • startedIN_PROGRESS
    • completed, canceledDONE
  • Priority — Linear's integer priority maps to a label: 0 No priority, 1 Urgent, 2 High, 3 Medium, 4 Low.
  • Type — Linear has no native issue type, so issues default to REQUIREMENT.
  • Lead timecompletedAt − createdAt (Linear provides startedAt/completedAt natively; the history changelog captures every status transition).
  • Story points — Linear's estimate.

Authentication

The plugin uses a Linear personal API key, passed verbatim in the Authorization header (no Bearer prefix). Create one under Settings → Security & access → Personal API keys in Linear.

Configuration

Create a connection:

curl 'http://localhost:8080/api/plugins/linear/connections' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "linear",
    "endpoint": "https://api.linear.app/graphql",
    "token": "<YOUR_LINEAR_API_KEY>",
    "rateLimitPerHour": 1500
}'

Add a team scope (the team id is the Linear team UUID):

curl 'http://localhost:8080/api/plugins/linear/connections/<CONNECTION_ID>/scopes' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": [{ "connectionId": <CONNECTION_ID>, "teamId": "<TEAM_ID>", "name": "Engineering" }]
}'

Collecting data

curl 'http://localhost:8080/api/pipelines' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "linear pipeline",
    "plan": [[{
        "plugin": "linear",
        "options": { "connectionId": <CONNECTION_ID>, "teamId": "<TEAM_ID>" }
    }]]
}'

Rate limiting

Linear enforces a per-API-key request budget (1,500 requests/hour) plus a complexity budget. The collector paces requests against the configured rateLimitPerHour (default 1500). Issues are collected incrementally using updatedAt ordering so re-runs only fetch changes.

Limitations / roadmap

  • Authentication is personal API key only; OAuth2 is a planned follow-up.
  • Issue type defaults to REQUIREMENT; label-based type mapping via the scope config is a planned follow-up.
  • config-ui integration (connection form + team picker) and the website documentation page are planned follow-ups; for now connections and scopes are managed via the API calls shown above.