Linear Roadmap Sync
Installation
$ npx skills add Mihirmodi27/product-management-skills --skill linear-roadmap-syncSummary
Sync a Project Roadmap & Timeline xlsx into Linear by creating project milestones for each major component/pipeline and issues for each deliverable underneath them.
Fires when
Use whenever the user wants to push a roadmap into Linear, populate Linear from a tracker, or set up a Linear project from a roadmap doc — phrased like ‘put this roadmap into Linear’, ‘create Linear issues from the tracker’, ‘sync this xlsx to Linear’. Trigger when the user provides or references a Project Roadmap xlsx and asks for it to be reflected in Linear. Maps roadmap statuses (Completed/In-Process/Testing/Cancelled) to Linear workflow states, skips milestones and issues whose names already exist in the project, and always shows a plan for the user to confirm before writing. Do NOT trigger when creating Linear issues from scratch without a roadmap xlsx, when the source is DOCX/PDF/Markdown only, or when the destination is non-Linear (Jira, Asana, Notion).
In the box
SKILL.md, 1 script, 3 test inputs
On this page
SKILL.md
This skill takes a Project Roadmap xlsx (the output of the roadmap-generator skill) and creates the corresponding project milestones and issues in Linear.
The xlsx parsing is deterministic (handled by parse_roadmap.py). The Linear interactions go through the Linear tools (Linear:list_projects, Linear:save_milestone, Linear:save_issue, etc.). See Environment below for how those are provided in each host.
The skill never writes to Linear without explicit user confirmation of the plan — even if the user has already given a general "go ahead" earlier in the conversation.
Workflow
Stage 1 — Confirm the source xlsx
a. If the user has uploaded or referenced a single Project Roadmap xlsx, state the filename and confirm it's the one to sync. If multiple xlsx files are present, ask which one.
b. Run the parser:
python <skill-dir>/scripts/parse_roadmap.py <path-to-roadmap>.xlsx <temp>/roadmap_spec.json
c. Show the user a one-paragraph summary derived from the parsed spec: project name, milestone count, deliverable count, status breakdown (e.g., "20 In-Process, 2 Completed, 2 Testing, 1 Cancelled"). Ask the user to confirm this is the document to sync before proceeding.
If the parser emits warnings (unrecognized status, deliverable before milestone, milestone with no deliverables), surface them to the user and resolve before continuing.
Stage 2 — Identify the Linear destination
a. Ask which Linear project to sync into. Don't guess from the xlsx project name — Linear projects often have different naming conventions, and this is the user's chance to point at the right destination.
b. If the user gives a project name, find it with Linear:list_projects. Show 1–3 best matches and confirm. If they give an exact ID or URL, use it directly.
c. Get the project details with Linear:get_project. Note the project's accessible teams.
d. Team selection:
- If the project is associated with exactly one team, use it.
- If multiple teams have access, ask the user which team to file the issues under.
- All issues in a single sync run go under one team.
Stage 3 — Resolve workflow states
a. List the team's workflow states with Linear:list_issue_statuses (passing the team ID).
b. Apply the fixed status mapping. For each roadmap status, find the team's workflow state by case-insensitive name match first; fall back to type match if the name isn't present:
| Roadmap status | Preferred Linear state name | Type fallback |
|---|---|---|
| Completed | "Done" | type=completed |
| In-Process | "In Progress" | type=started |
| Testing | "In Review" (or "Testing" if the team has it) | type=started (any state with "review" or "test" in the name) |
| Cancelled | "Cancelled" | type=canceled |
c. If any roadmap status can't be confidently mapped (e.g., the team has no completed-type state at all), stop and ask the user before proceeding. Do not invent a mapping.
Stage 4 — Detect existing entities (skip duplicates)
a. List existing project milestones with Linear:list_milestones for the project. Build a set of existing milestone names (case-insensitive, trimmed).
b. List existing issues with Linear:list_issues filtered to the project. Build a set of existing issue titles (case-insensitive, trimmed).
c. For each parsed milestone, mark it as create or skip (already exists). For each parsed deliverable, mark it the same way. Issues are deduplicated by title within the project, regardless of which milestone they're associated with.
Stage 5 — Show the plan and get confirmation
Display a clear plan with three sections:
Plan for syncing "<roadmap project name>" into Linear project "<linear project name>" (team: <team name>):
NEW MILESTONES (will be created):
- 1. Foundation & Infrastructure
- 2. Document Intake Pipeline
...
NEW ISSUES (will be created):
Under "1. Foundation & Infrastructure":
- Postgres + S3 backend [In Progress]
- Okta / Azure AD SSO integration [In Progress]
...
Under "2. Document Intake Pipeline":
- PDF upload flow [Done]
- Email-forwarding intake [Cancelled]
...
SKIPPED (already exist in Linear):
Milestones: <list, or "none">
Issues: <list, or "none">
Total: N milestones, M issues to create. K skipped.
Then ask explicitly: "Confirm to proceed with creating these in Linear, or let me know if you want to adjust the plan." Wait for an affirmative response.
This step is not optional. Even if the user said "go ahead and do it" earlier, always show the plan and wait for confirmation before any write call.
Stage 6 — Execute writes
a. Create milestones first with Linear:save_milestone, one per create milestone. Capture each new milestone's ID and remember which roadmap milestone it corresponds to.
b. Create issues with Linear:save_issue. For each issue:
title: the deliverable name from the xlsxteamId: the resolved teamprojectId: the Linear projectprojectMilestoneId: the new (or existing) milestone for that deliverable's parentstateId: the workflow state from the status mappingdueDate: only if the deliverable has a non-empty deadline in the xlsx (the roadmap-generator skill leaves these blank by default; partners may have filled some in)
c. Cancelled deliverables are still created as issues, with the Cancelled state. They're recorded as scoped-out work, not omitted.
d. If a write fails, log which entity failed and continue with the rest. At the end, report: number of milestones created, number of issues created, and a list of any failures with the error message.
Stage 7 — Summarize
Tell the user what was created (counts), what was skipped (counts), and any failures. If everything succeeded, link to the Linear project URL if available from the project details.
Environment
This skill runs in both Claude chat and Claude Code. A few things differ:
| Claude chat / Cowork | Claude Code | |
|---|---|---|
| Linear access | Linear connector | Linear MCP server |
| Where the xlsx is | /mnt/user-data/uploads/ |
wherever the user says |
| Scratch files | /tmp/ |
/tmp/ or the working directory |
The Linear tool names are identical either way, so the workflow above is unchanged. If the Linear tools aren't available at all, stop and tell the user to enable the connector or MCP server — never fabricate the sync.
Notes
- Re-run safety. The skip-by-name behavior makes this safe to re-run after editing the xlsx — only new milestones/issues will be added. It does NOT update existing issues whose status changed in the xlsx; the user can adjust those directly in Linear.
- Single-team scope. All issues in one sync go under one team. Cross-team projects with deliverables that should belong to different teams aren't supported in a single sync — the user can run the skill twice with different team selections.
- Don't fabricate milestone descriptions. The xlsx has no description column. Leave
descriptionempty when callingsave_milestoneunless the user provides one. - Order matters. Milestones must be created before their issues, since issues need a
projectMilestoneId. The execute stage handles this ordering.
Reference files
scripts/parse_roadmap.py— parses a roadmap xlsx into structured JSON. Inverts the schema produced by theroadmap-generatorskill'sbuild_roadmap.py.