Cycle progress
Scope and completion per cycle: the numbers behind Linear's cycle graph.
- Grain
- team x cycle
- Built from
- 1Raw tables
- 1Staging
- 1Core
- 1Analytics
- Reads from Linear
- issues
- Ships as
- Weld and dbt SQL, open source on GitHub
1-- core.linear.cycle_progress
2-- Scope and completion per cycle: the numbers behind Linear's cycle graph.
3-- Grain: team x cycle.
4--
5-- Built from each issue's CURRENT cycle. Issues that were in a cycle and rolled
6-- over to the next one count in the cycle they are in now, so a finished cycle's
7-- scope here is what remained in it, not what was planned at the start. Linear's
8-- own cycle graph uses its history and will show a larger starting scope.
9-- Cycle start and end dates are not synced; the first and last activity dates
10-- below are a stand-in.
11
12SELECT
13 i.team_id,
14 ANY_VALUE(i.team_name) AS team_name,
15 i.cycle_id,
16 ANY_VALUE(i.cycle_number) AS cycle_number,
17 ANY_VALUE(i.cycle_name) AS cycle_name,
18 COUNT(*) AS scope_issues,
19 COUNTIF(i.state_type = 'completed') AS completed_issues,
20 COUNTIF(i.state_type = 'canceled') AS canceled_issues,
21 COUNTIF(i.state_type = 'started') AS in_progress_issues,
22 COUNTIF(i.state_type IN ('triage', 'backlog', 'unstarted')) AS not_started_issues,
23 SUM(COALESCE(i.estimate, 0)) AS scope_points,
24 SUM(IF(i.state_type = 'completed', COALESCE(i.estimate, 0), 0)) AS completed_points,
25 SAFE_DIVIDE(COUNTIF(i.state_type = 'completed'),
26 COUNTIF(i.state_type != 'canceled')) AS pct_issues_completed,
27 MIN(DATE(i.added_to_cycle_at)) AS first_added_date,
28 MAX(DATE(i.completed_at)) AS last_completed_date
29FROM {{staging.linear.issue}} i
30WHERE i.cycle_id IS NOT NULL
31GROUP BY i.team_id, i.cycle_idThis model and the 2 it depends on. Deploy them together; refs like {{staging.…}} resolve to the matching folders in Weld, and the dbt view uses source() and ref().
How it counts. And where it stops.
Built from each issue's CURRENT cycle. Issues that were in a cycle and rolled over to the next one count in the cycle they are in now, so a finished cycle's scope here is what remained in it, not what was planned at the start. Linear's own cycle graph uses its history and will show a larger starting scope. Cycle start and end dates are not synced; the first and last activity dates below are a stand-in.
Raw tables it reads
- raw.linear.issues
More Linear models
Put Linear in front
of your agents.
Connect Linear, deploy the models, and ask questions in Claude, Cursor or ChatGPT. Free for 14 days, no credit card.