| name | meaningful-linear-issues |
| description | Create complete, analytics-ready Linear issues in ONE pass — resolve the right project (never guess it), and proactively fill the metadata that's technically optional but matters for planning/analytics: priority, estimate, labels (a Type + an Area from the team's existing taxonomy), milestone, assignee, cycle, and relations. Use when asked to 'create/file/open a Linear issue', 'log a ticket', 'add this to Linear', 'make an issue for X', or before any Linear `save_issue` that **creates** an issue or **backfills** missing metadata on a bare one — so the user doesn't have to come back and ask for the labels/estimate/project a second time, and so an issue doesn't land in the wrong project. NOT for routine field edits (status changes, reassignments) — those are also `save_issue` but don't need this. |
| metadata | {"author":"stealth-engine","co-author":"wiiiimm","version":"1.1.0"} |
Meaningful Linear issues
A good issue is not just a good description — that's the easy half. The half
agents skip is the metadata that makes Linear actually work as a planning tool:
estimates feed cycle velocity, labels feed breakdowns, milestones feed roadmaps, the
project feeds everything. Those fields are optional in the API, so agents leave them
blank and the user has to come back and ask again.
Flip the default: metadata is opt-OUT, not opt-in. Resolve and fill it before
calling save_issue, in one pass — propose concrete values, don't omit.
Cardinal rule: never guess the project
The single worst failure is dropping an issue into the wrong/random project.
Resolve the project in this order — stop at the first that's certain:
- Context — the issue's repo/area maps to a known project; the user named it; a
sibling issue you're relating to has one.
- Confirm — call
list_projects and match by name; if
one clearly fits, state which and proceed.
- Ask — if it's still ambiguous, ask the user which project rather than
picking one. A missing project is recoverable; a wrong one quietly pollutes the
wrong roadmap.
Never pass a project you inferred from vibes. Team is required too — usually
unambiguous from the project, but resolve it the same way.
The one-pass workflow
- Discover what's available (only what you don't already know): projects, the
team's label taxonomy, milestones, the current cycle, assignable users.
- Draft the issue with every applicable field filled (checklist below).
- Create with one
save_issue call. If anything was genuinely a judgment call
(estimate, priority), state the values you chose so the user can correct one —
that's still one pass, not "I left them blank, ask me again."
Create vs. backfill — mind the id
Same checklist, two save_issue modes — don't conflate them:
- Create (new issue):
save_issue with no id. Fill everything below.
- Backfill (existing bare issue):
save_issue WITH its id — update, don't
create. Omitting the id here would make a duplicate. get_issue first if you
need to see what's already set, then pass only the fields you're adding. labels
replaces the whole set — include existing labels alongside the new ones. Relations
(blocks / blockedBy / relatedTo) are append-only — adding one won't drop
existing links (use removeBlocks / removeBlockedBy / removeRelatedTo to remove).
Other fields you don't pass are left untouched.
Metadata checklist — fill before save_issue
| Field | How to set it well |
|---|
| team (required) | From the project. list_teams / get_team if unknown. |
| project | Resolve, never guess (above). |
| title | Imperative, specific, scannable. Lead with the verb + the object. |
| description | The implementation detail (see template). |
| priority | 1 Urgent · 2 High · 3 Medium · 4 Low · 0 None. Infer from impact/urgency; default 3 for normal work, ask if it's clearly load-bearing. |
| estimate | Set a real value; Linear snaps it to the team's scale, so you don't need the scale up front — but read back and surface the stored value (it may change: 3 on an exponential team 0,1,2,4,8,16 returns 4; Fibonacci 0,1,2,3,5,8 keeps 3). get_team doesn't expose the scale (as of this MCP version) — infer it from existing issues' estimates (list_issues) only if you need exact pointing. Some teams disable estimates — if save_issue rejects it, drop the field. |
| labels | Pick from the existing taxonomy (list_issue_labels for the team) — don't invent labels. Typically one Type (Feature / Bug / Improvement / Chore / Docs / Refactor / Security / Performance / Test / …) and one Area (the relevant module/domain). Match the team's grouped labels rather than guessing names. |
| assignee | "me", the named owner, or the project/issue's usual owner (list_users to resolve a name/email). Don't leave unassigned if an owner is obvious. |
| milestone | list_milestones for the project; attach if one fits the work. (None exist? skip — don't fabricate.) |
| cycle | Set the current cycle (list_cycles → current) for active work unless the user opts out — don't rely on auto-add, which some teams disable, leaving the issue out of every cycle (and out of velocity). Skip only for backlog/future work that isn't for the current cycle. |
| relations | parentId for sub-work; blocks / blockedBy for ordering; relatedTo for siblings. Link issues you reference in the description — it's cheap and powers dependency views. |
| dueDate | ISO date (YYYY-MM-DD). Set only when there's a real deadline — a launch, a dependency, a commitment. Don't fabricate one; most issues have none. |
If a field genuinely doesn't apply (e.g. no milestones exist), skip it knowingly —
the goal is "nothing useful left blank," not "every field stuffed."
Discover valid values
Only the values you don't already have in context. These are the Linear MCP tools:
list_projects (filter by name/team) — resolve the project.
list_issue_labels (by team) — the label taxonomy; reuse, don't invent.
list_milestones (by project) — fitting milestone, if any.
list_cycles (by teamId, type: current) — to set the current cycle (don't rely on auto-add).
list_users (by name/email, or "me") — resolve an assignee.
list_teams / get_team — when the team isn't obvious from the project.
Then create with save_issue (omit id to create). labels and assignee accept
names or IDs; priority is the 0–4 int.
Description template
Keep what makes implementation unambiguous; drop ceremony:
<one-line summary of the outcome>
## Context / problem
<why this exists; the symptom or goal; link related issues/PRs>
## Scope
<what's in; explicitly what's out>
## Acceptance
<how we'll know it's done — checkable bullets>
Use real newlines and markdown, not escaped \n. Mention related issues by ID so
Linear links them (and add them to relatedTo).
Gotchas
- Don't guess the project — the one unrecoverable mistake. Ask if unsure.
- Estimate snaps to the team's scale (a passed
3 stores as 4 on an exponential
team) — read back and surface the stored value so the snap isn't silent; and some
teams disable estimates entirely — drop the field if it's rejected.
- Labels must already exist — pull them from
list_issue_labels and pass the
exact names; creating ad-hoc labels pollutes the taxonomy. Prefer one Type + one Area.
- Milestone belongs to a project, cycle belongs to a team — don't cross them; a
milestone from another project will be rejected.
- Don't rely on cycle auto-add — some teams disable it, leaving the issue out of
every cycle. Set the current cycle explicitly; skip only for backlog/future work.
- One pass, not two — if you're unsure of priority/estimate, pick a sensible value
and say so; don't ship a bare issue and wait to be asked for the rest.
Pre-flight checklist (before save_issue)
See also
conventional-commits — the matching discipline
for commit/PR titles, so the issue → branch → PR → release chain stays clean.
Sources
- Linear MCP tool surface (
save_issue, list_projects, list_issue_labels,
list_milestones, list_cycles, list_users, get_team) and observed behaviour:
estimates snap to the team's scale, new issues auto-join the active cycle when the
team enables auto-add (don't rely on it), labels are a grouped Type/Area taxonomy
that must pre-exist.