| name | create-linear-ticket |
| description | Use when the user wants to file, create, or open a Linear ticket / issue — "make a Linear ticket for this bug", "file an issue to track X", "open a ticket and ping a reviewer", or when turning a bug report, TODO, or Slack thread into a tracked ticket. Especially use it to avoid Linear API rejections from bad priority/status/team enum values or missing required fields, and to run the post-creation steps (ping reviewer, link in Slack) so the ticket doesn't get filed and forgotten. |
create-linear-ticket
Overview
Creating a Linear ticket has two ways to go wrong: the API rejects it (an invalid enum for priority/status/team, or a required field omitted), or it succeeds and then dies (filed with no reviewer pinged, no link dropped in Slack, so nobody sees it). This skill enforces a valid payload before the create call, then runs the post-creation workflow so the ticket actually enters someone's awareness.
It also guards against the quiet failure mode of agents and retries: double-creation. A network blip on the create call followed by a retry can file the same ticket twice. The skill makes creation idempotent on a stable key so a retry is a no-op, not a duplicate.
When to Use
Use this skill when the user is:
- Filing a new Linear ticket / issue from a bug, request, or thread.
- Asking to "open a ticket", "make an issue", "track this in Linear".
- Wanting a ticket created and the reviewer pinged / link posted.
Do NOT use this for: editing or transitioning an existing ticket's status, bulk triage of a backlog, or reading/searching tickets. This skill is for the create-plus-handoff path of a single new ticket.
Setup (config.json)
Read config.json in this skill directory first:
team_id — the Linear team the ticket is filed under.
project_id — default project for the ticket.
default_reviewer — who to ping after creation.
If any value is empty, call the AskUserQuestion tool to collect it before creating anything — present the real teams/projects/people as options where you can fetch them. After collecting, offer to persist back into config.json. Never guess a team_id; the API rejects an unknown team and a wrong-but-valid team files the ticket where nobody is looking.
Schema — validate BEFORE the create call
Linear enums are closed sets. Resolve every value to one the API actually accepts before calling create; do not send a free-text label and hope.
- Priority is an integer enum, not a word:
0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low. Map any natural-language priority ("high", "p1") to the integer. Sending the string "High" is rejected.
- Status / state must be a workflow state id that exists for this team — states are per-team. "Todo"/"In Progress"/"Done" are display names, not ids; resolve the name to the team's state id. A state id from another team is rejected.
- Team must be the configured
team_id (or one the user explicitly names and you resolved to an id).
- Required fields:
title and team_id at minimum. A ticket with no title is rejected. If the user gave only a vague description, write a crisp imperative title — don't submit an empty or "Untitled" one.
If you cannot resolve an enum to a valid value, ask via AskUserQuestion rather than sending a guess that the API will bounce.
Post-creation workflow
A created ticket is not a finished task. After a successful create:
- Ping the reviewer —
default_reviewer (or the one the user named): assign or mention them on the ticket.
- Link it in Slack — drop the ticket URL in the relevant channel/thread so it's discoverable, not buried in Linear.
- Report back the ticket id, URL, and who was pinged.
Skipping these is the most common real failure: the ticket exists but is invisible.
Gotchas
ALWAYS treat these as real, observed failure modes.
-
Invalid enum values are rejected, not coerced. Priority must be the integer (2), not "High". Status must be a per-team workflow-state id, not the display name "In Progress". Resolve names → ids/integers before the create call. A rejected create that you blindly retry with the same bad payload just fails again — fix the value, don't re-send.
-
Required-field omissions fail the whole create. Missing title or team_id rejects the request. Don't submit "Untitled"; synthesize a real imperative title from the user's description. Confirm team_id is set (from config or resolved) before calling.
-
Idempotency: do NOT double-create on retry. If the create call errors ambiguously (timeout, 5xx) it may have succeeded server-side. Before re-creating, search for a ticket with the same title in team_id created in the last few minutes; if found, treat the create as done and proceed to the post-creation steps. Derive any idempotency/dedup key from stable inputs (title + team + source thread), not a fresh random id each attempt — a new key per try defeats the check and files duplicates.
-
project_id and state ids are namespaced to the team. A project or workflow state valid for one team is rejected for another. Always pair project_id/state ids with the matching team_id; don't mix a state from team A into a ticket on team B.
-
Don't post the Slack link before the create confirms. Link only after you hold a real ticket id/URL. Announcing a ticket that failed to create points people at a 404.
Files
config.json — setup: team_id, project_id, default_reviewer (empty by default; collected via AskUserQuestion when unset, optionally persisted back).