Sarimarcus/claude-code-plugins/tree/main/plugins/linear-workflow
linear-workflow
为 Claude Code 提供 Linear 工作流:issue-next、issue-start、issue-review、issue-ship 和 issue-plan-cycle 技能由确定性 CLI、linear-manager agent 以及一个在提示列上方显示当前 issue、其他工作阶段和冲突警告的 mod 支持。
关于这个 mod
Linear 工作流
在 Claude Code 中处理 Linear issue,从挑选 cycle 中的下一个 issue,一直到 PR 合并。 处理过程中 Linear 会保持最新状态,当前 issue 始终显示在提示列上方。
概览
这个插件由四部分组成:
- **技能(斜杠命令)**把 issue 从 cycle 推进到已合并的 PR:
issue-next →issue-start → (work) →issue-review →issue-ship,另外还有用于填充 cycle 的 `issue-plan-cycle。 - CLI(`bin/linear-workflow.mjs)执行不需要判断的 Linear 和 GitHub 步骤:获取并排序 issue、变更状态、变更 cycle、检查 PR。它比 LLM 更快,而且每次给出相同结果。Claude 负责需要判断的部分:阅读 issue、编写代码、commit message、PR 摘要和评论。
- 一个 agent `linear-manager 创建和编辑 issue;当 CLI 无法连接 Linear 时,它会代替 CLI 工作。
- 一个 mod:在提示列上方实时显示当前 issue,列出你的其他 Claude Code 工作阶段,并在两个工作阶段发生冲突时发出警告。它与 CLI 共用代码(`lib/)。
Claude Code 会为插件技能和 agent 添加命名空间,因此完整名称是
/linear-workflow:issue-start 和 linear-workflow:linear-manager。输入 `/issue,然后从菜单中选择。
快速开始
/plugin marketplace add Sarimarcus/claude-code-plugins
/plugin install linear-workflow@sarimarcus
- 创建一个 Linear personal API key(Settings →
Security & access;参见 Linear's API docs)并设置它:在 shell 配置文件中加入
export LINEAR_API_KEY=lin_api_…, 或在仓库被 git 忽略的.env 中加入 `LINEAR_API_KEY=。CLI 和 mod 都会使用它。 - 可选:为
linear-manager agent 连接 [Linear's MCP server](https://linear.app/docs/mcp)(claude.ai 上的 Linear connector,或claude mcp add --transport http linear https://mcp.linear.app/mcp)。 - 运行 `/linear-workflow:issue-next。
技能
`/linear-workflow:issue-next
选择接下来要处理的内容。只读。在 Haiku 上运行,只显示 CLI 排序后的列表。
/linear-workflow:issue-next
Claude 会:
- 获取 active cycle 中分配给你、状态为 Todo 或 In Progress 且没有阻塞的 issue
- 用下一个没有阻塞的 sub-issue 替换正在进行的 epic
- 先按优先级,再按 milestone 日期,最后按创建时间排序,并显示前 5 个 issue 及各自的理由
- 提供启动第一项(
Y)、另一项(ABC-140)或不启动的选项
`/linear-workflow:issue-start <ABC-123>
开始处理一个 issue。
/linear-workflow:issue-start ENG-123
Claude 会:
- 将 issue 移到 In Progress
- 显示 Context、Implementation 和 Scope,但不显示 Acceptance Criteria,因为它们留给 reviewer
- 原样重现可执行的评论,并把它们视为 scope(较新的评论优先于描述)
- 如果 issue 存在未解决的阻塞,继续前先询问
- 创建 Linear 的 issue 分支,然后立即开始工作,不等待
`/linear-workflow:issue-review [ABC-123]
提交工作供 review。绝不会合并或部署。
/linear-workflow:issue-review
Claude 会:
- 如果你在 base 分支,或在名称指向其他 issue 的分支上,则拒绝执行
- 根据变更检查每条 acceptance criterion;如果有一条未满足,继续前先询问
- 运行检查(来自
.claude/linear.json,或明显需要的检查,例如npm test) - 只提交这个 issue 的文件(有无关文件时先询问),commit message 中包含 ` (ENG-123)
- 推送分支并创建 PR,正文写入 `Closes ENG-123
- 将 issue 移到 In Review,并发布完成评论
`/linear-workflow:issue-ship [ABC-123]
合并已 review 的 PR 并关闭 issue。
/linear-workflow:issue-ship
Claude 会:
- 没有 open PR、PR 是 draft、存在冲突、有人提出修改、检查失败,或分支上的工作尚未进入 PR 时拒绝执行
- 合并它(
gh pr merge,或者在本地执行git merge --no-ff,让 `pre-push hooks 运行) - 在触碰 Linear 前,先在 GitHub 上确认 PR 确实已合并
- 将 issue 移到 Done;所有 sub-issue 完成后,再汇总 parent issue
`/linear-workflow:issue-plan-cycle
从 backlog 填充 active cycle。运行在 Haiku 上,和 `issue-next 一样。其他技能使用当前工作阶段的模型,因为它们会编写代码、判断 acceptance criteria 或执行合并。
Claude 会:
- 按优先级列出 active cycle 尚未排期、没有阻塞的 Backlog 和 Todo issue;parent 已在 cycle 中的 sub-issue 会暂时保留
- 询问要添加哪些 issue(
all、none 或 id 列表),然后只为这些 issue 设置 cycle,不做其他修改
不带 id 时,issue-review 和 issue-ship 会依次使用当前工作阶段的 issue、分支名称,以及你在 Linear 中开始的 issue。如果 id 是推测出来的,它们会先显示 id;`issue-ship 在合并前会要求你确认。
`linear-manager agent
CLI 不负责的工作交给它:创建 issue、把计划拆成 sub-issue、设置 label、relation、milestone,以及搜索(「使用 linear-manager 创建一个关于……的 bug」)。当 CLI 无法连接 Linear 时,技能也会回退到它。它遵循与 CLI 相同的规则:
- 传递名称而不是 ID(
state: "In Review"、labels: ["Bug"]、`assignee: "me") - 让状态变更具备幂等性:issue 已经处于该状态时不执行任何操作
- 通过询问是否存在未完成的 sub-issue 来检查 parent,而不是列出全部 sub-issue
- 列表中绝不返回 issue 描述,避免很长的 backlog 淹没对话
- 绝不编辑文件或运行 git
CLI
技能通过 node "\${CLAUDE_PLUGIN_ROOT}/bin/linear-workflow.mjs" <command> 调用 CLI。你也可以在任何仓库中自行运行它。它在 stdout 输出紧凑 JSON,在 stderr 输出一行摘要,说明检查了什么。退出代码:0 表示成功,1 表示错误或输入无效,2 表示拒绝执行(需要人工处理)。
**为小上下文而构建。**每个技能步骤只进行一次调用,每次调用只返回该步骤读取的字段。每次工具调用都是一个会重新读取对话的模型回合,因此减少调用次数、缩小返回内容是主要节省来源。start 视图完全不包含 acceptance criteria,因此不需要依赖 Claude 遵守指令来避免实现者看到它们。
| 每个技能步骤一次调用 | 返回内容 |
| --- | --- |
| start <ABC-123> | 要处理的 issue(不含 acceptance criteria 的描述、阻塞、分支名称、每条原样评论)以及仓库状态(分支、base、分支设置、未提交文件) | | review [ABC-123] | 哪个 issue(参数、分支名称或唯一一个已开始的 issue),它的 acceptance criteria,以及仓库状态:base 分支、分支所指的 issue、该分支的 open PR、检查、未提交文件 |
| ship [ABC-123] [--pr N] | 哪个 issue、合并设置,以及 PR 判断结果(格式为 pr-check) |
| 单独步骤 | 作用 |
| --- | --- |
| config | 仓库根目录、当前分支及其指向的 issue(branchIssue)、解析出的 base 分支(否则使用 origin 的默认分支)、是否正位于该分支、此分支的 open PR、team key、是否找到 key、.claude/linear.json | | resolve [ABC-123|123] | 要操作的 issue:先看参数,再看分支名称,最后看你唯一一个已开始的 issue。无法判断时以带有 candidates 的退出代码 2 结束 |
| issue <ABC-123> [--view start\|review] | 完整 issue(描述、解析后的 acceptanceCriteria、阻塞、sub-issue、链接、分支名称、每条评论),或某个技能使用的视图 |
| queue [--limit N] | active cycle 中状态为 Todo 或 In Progress 的 issue(不含 In Review、没有阻塞),epic 会替换为下一个 sub-issue;每项都带有 rank 和可直接显示的 urgency(overdue 3d、ends in 5d……) | | plan-cycle [--limit N] | active cycle 尚未排期、没有阻塞的 backlog issue,按顺序排列 |
| transition <ABC-123> <state> [--comment TEXT \| --comment-file F] | 幂等的状态变更、评论、parent 汇总(使用 parent 自己的 team 状态) | | set-cycle <n> <ABC-123>… | 将 issue 放入 cycle,不做其他修改 |
| pr-check <ABC-123> [--pr N] | PR 能否合并:ready、wait(检查正在运行)或 stop,并给出理由。只有分支或标题包含 issue,或正文关闭 issue 的 PR 才会被计入;--pr 可从多个 PR 中选择一个 | | pr-merged <ABC-123> --pr N | 该 PR 是否确实落地:只有当 GitHub 表示已合并给出 merge commit 时,退出代码才为 `0 |
全局标志:--team KEY 覆盖 team key;--pretty 缩进 JSON;`--out FILE 将完整 JSON 写入文件,只输出文件路径。未提交文件列表最多显示前 20 个,并附带总数。
排序规则是优先级(Urgent 在前,没有优先级的在最后),然后是 milestone 目标日期,最后是创建时间。只有在没有未完成 sibling 时,parent 才会汇总;任何不是 done 或 canceled 的内容都算未完成(目标是 Done 时,In Review 也算)。
mod
── Linear ─────────────────────────────────────────────────────────
◆ ENG-2919 In Progress · High
Core affiliate link builders
root branch · scope: web · parent ENG-2900 Details Hide
sessions ENG-2748 In Review (eng-2748) · ⚠ ENG-2912 In Progress (main)
- 提示列上方的状态带:当前 issue 的 id、state、priority、title、scope 和 parent。
- Details pane(`/linear):description、sub-issue、链接、最新评论,以及 Open in Linear。
- 仅显示你自己的 issue:工作阶段会显示它接手的 issue:你固定的 issue(
/linear ENG-123、输入/linear-workflow:issue-start ENG-123,或 Claude 根据你的话开始处理的 issue),或分支名称中的 issue (alex/eng-2919-link-builders →ENG-2919),前提是该工作阶段自己切换到了这个分支。如果同一个 checkout 中的另一个实时工作阶段已经认领了该分支 issue,就交给那个工作阶段处理;你的界面会显示No Linear issue found 和sessions 行。单独在 feature branch 上打开的工作阶段仍然会接手它的 issue。 - 其他工作阶段(
sessions 行):机器上每个运行该插件的 Claude Code 工作阶段,并显示其 issue 和 checkout(main 或 worktree 名称)。 - 冲突警告:当同一 checkout 中的另一个工作阶段处理不同 issue(你们共用一个分支和工作树),或两个工作阶段处理同一个 issue 时,会显示 toast 和红色 ⚠。
- 你的 issue 不会移动。 如果另一个工作阶段把共享 checkout 切换到其他分支,你的工作阶段会一直保留自己的 issue(`held),直到该 issue 变为 Done 或 Canceled,或你自己的工作阶段切换分支。
- Scope drift(可选):如果有 sub-project registry,在 issue 标记的 sub-project 之外进行编辑会弹出 toast。
- 保持最新:任何写入 Linear 的回合结束时(技能的 transition、
linear-manager agent、Linear MCP 写入),都会重新获取 issue;其他时候每个pollMinutes 也会重新获取。状态变化时会显示 toast。
| /linear | 作用 | | --- | --- | | /linear | 打开 Details pane |
| /linear ENG-123 | 将 issue 固定到当前工作阶段。固定会持续到当前工作阶段自己切换到其他 issue 的分支 | | /linear clear | 取消固定,重新跟随分支 |
| /linear refresh | 立即从 Linear 重新获取 | | /linear hide / `show | 隐藏或显示状态带 |
要求
- Claude Code 2.1.289 或更高版本。Mods 是较新的功能,而这是插件构建和测试所用的版本。
- CLI 需要 Node.js 22.18 或更高版本(它直接运行 TypeScript,不需要 build 步骤)。
- 用于 CLI 和 mod 的 Linear personal API key。
- 可选:Linear MCP 连接,用于 `linear-manager agent。
- 可选:Linear's GitHub integration,它会把 PR 链接到 issue,并在合并时推进状态。由于状态变更具有幂等性,这些技能无论有没有它都能运行。
- GitHub CLI `gh,lo
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add Sarimarcus/claude-code-plugins claude plugin install linear-workflow
原文 / README
Linear Workflow
Work Linear issues from Claude Code, from picking the next issue in the cycle to the merged PR. Linear stays up to date along the way, and the current issue is always shown above the prompt.
Overview
The plugin has four parts:
- Skills (slash commands) take an issue from the cycle to a merged PR:
issue-next→issue-start→ (work) →issue-review→issue-ship, plusissue-plan-cycleto fill the cycle. - A CLI (
bin/linear-workflow.mjs) runs the Linear and GitHub steps that need no judgment: fetching and ranking issues, status changes, cycle changes, PR checks. It's faster than an LLM and gives the same answer every time. Claude keeps the parts that need judgment: reading the issue, writing the code, the commit message, PR summary and comments. - An agent,
linear-manager, creates and edits issues, and stands in for the CLI when it can't reach Linear. - A mod: live code that shows the current issue above the prompt, lists your other Claude Code
sessions, and warns when two of them collide. It shares its code with the CLI (
lib/).
Claude Code namespaces plugin skills and agents, so the full names are
/linear-workflow:issue-start and linear-workflow:linear-manager. Type /issue and pick from
the menu.
Quick start
/plugin marketplace add Sarimarcus/claude-code-plugins
/plugin install linear-workflow@sarimarcus
- Create a Linear personal API key (Settings →
Security & access; see Linear's API docs) and set it:
export LINEAR_API_KEY=lin_api_…in your shell profile, or aLINEAR_API_KEY=line in your repo's git-ignored.env. The CLI and the mod both use it. - Optional: connect Linear's MCP server for the
linear-manageragent (the Linear connector on claude.ai, orclaude mcp add --transport http linear https://mcp.linear.app/mcp). - Run
/linear-workflow:issue-next.
Skills
/linear-workflow:issue-next
Picks what to work on next. Read-only. Runs on Haiku: it only presents the CLI's ranked list.
/linear-workflow:issue-next
Claude will:
- Fetch the active cycle's Todo and In Progress issues that are assigned to you and unblocked
- Replace an in-progress epic with its next unblocked sub-issue
- Rank them by priority, then milestone date, then age, and show the top 5 with a reason for each
- Offer to start the top one (
Y), another (ABC-140), or none
/linear-workflow:issue-start <ABC-123>
Starts work on an issue.
/linear-workflow:issue-start ENG-123
Claude will:
- Move the issue to In Progress
- Show its Context, Implementation and Scope, but not the Acceptance Criteria, which are for the reviewer
- Reproduce actionable comments verbatim and treat them as scope (a newer comment beats the description)
- Ask before continuing if the issue has open blockers
- Create Linear's branch for the issue, then start working without waiting
/linear-workflow:issue-review [ABC-123]
Puts the work up for review. Never merges or deploys.
/linear-workflow:issue-review
Claude will:
- Refuse if you're on the base branch, or on a branch that names another issue
- Check each acceptance criterion against the change, and ask before going on if one isn't met
- Run your checks (from
.claude/linear.json, or the obvious ones such asnpm test) - Commit only the files for this issue (asking about unrelated ones) with
(ENG-123)in the message - Push the branch and open a PR whose body says
Closes ENG-123 - Move the issue to In Review and post a completion comment
/linear-workflow:issue-ship [ABC-123]
Merges the reviewed PR and closes the issue.
/linear-workflow:issue-ship
Claude will:
- Refuse when there's no open PR, it's a draft, it has conflicts, changes were requested, checks failed, or work on the branch isn't in the PR yet
- Merge it (
gh pr merge, orgit merge --no-fflocally so yourpre-pushhooks run) - Check on GitHub that the PR really merged before touching Linear
- Move the issue to Done, and roll up the parent issue once all its sub-issues are finished
/linear-workflow:issue-plan-cycle
Fills the active cycle from the backlog. Runs on Haiku, like issue-next. The other skills use your
session's model, because they write code, judge acceptance criteria or merge.
Claude will:
- List unscheduled, unblocked Backlog and Todo issues by priority, holding back sub-issues whose parent is already in the cycle
- Ask which to add (
all,none, or a list of ids), then set the cycle on those issues and change nothing else
Without an id, issue-review and issue-ship use the session's issue, then the branch name, then
your issues in Linear. If the id was guessed, they show it first, and issue-ship asks you to
confirm it before merging.
The linear-manager agent
Use it for what the CLI doesn't do: filing issues, splitting a plan into sub-issues, labels, relations, milestones, searches ("use linear-manager to file a bug for…"). The skills also fall back to it when the CLI can't reach Linear. It follows the same rules as the CLI:
- passes names, not IDs (
state: "In Review",labels: ["Bug"],assignee: "me") - makes status changes idempotent: a no-op when the issue is already in that state
- checks a parent's sub-issues by asking whether an unfinished one exists, instead of listing them all
- never returns issue descriptions in lists, so long backlogs don't flood your conversation
- never edits files or runs git
The CLI
The skills call it as node "${CLAUDE_PLUGIN_ROOT}/bin/linear-workflow.mjs" <command>. You can run it
yourself from any repo. It prints compact JSON on stdout and one summary line on stderr, stating what
it examined. Exit codes: 0 ok, 1 error or bad input, 2 refused (needs a human).
Built for a small context. Each skill step makes one call, and each call returns only the fields that step reads. Every tool call is a model turn that re-reads the conversation, so fewer, smaller calls are the main saving. The start view doesn't contain the acceptance criteria at all, so keeping them out of the implementer's view doesn't depend on Claude following an instruction.
| One call per skill step | Returns |
| --- | --- |
| start <ABC-123> | The issue to work from (description without acceptance criteria, blockers, branch name, every comment verbatim) and the repo state (branch, base, branching setting, uncommitted files) |
| review [ABC-123] | Which issue (argument, branch name, or your only started issue), its acceptance criteria, and the repo state: base branch, the issue the branch names, this branch's open PR, checks, uncommitted files |
| ship [ABC-123] [--pr N] | Which issue, merge settings, and the PR verdict (as pr-check) |
| Single steps | What it does |
| --- | --- |
| config | Repo root, current branch and the issue its name points to (branchIssue), resolved base branch (baseBranch, else origin's default) and whether you're on it, this branch's open PR, team keys, whether a key was found, .claude/linear.json |
| resolve [ABC-123\|123] | Which issue to act on: the argument, then the branch name, then your only started issue. Exit 2 with candidates when it can't tell |
| issue <ABC-123> [--view start\|review] | The full issue (description, parsed acceptanceCriteria, blockers, sub-issues, links, branch name, every comment), or just one skill's view of it |
| queue [--limit N] | The active cycle's Todo and In Progress issues (not In Review, not blocked), epics replaced by their next sub-issue, ranked, each with its rank and display-ready urgency (overdue 3d, ends in 5d…) |
| plan-cycle [--limit N] | Unscheduled, unblocked backlog issues for the active cycle, ranked |
| transition <ABC-123> <state> [--comment TEXT \| --comment-file F] | Idempotent status change, comment, parent roll-up (into the parent's own team states) |
| set-cycle <n> <ABC-123>… | Put issues in a cycle and change nothing else |
| pr-check <ABC-123> [--pr N] | Whether the issue's PR can merge: ready, wait (checks running) or stop, with reasons. Only PRs whose branch or title names the issue, or whose body closes it, count; --pr picks one of several |
| pr-merged <ABC-123> --pr N | Whether that PR really landed: exit 0 only when GitHub says merged and names the merge commit |
Global flags: --team KEY overrides the team key; --pretty indents the JSON; --out FILE writes
the full JSON to a file and prints only its path. Uncommitted-file lists are capped at the first 20,
with the total count.
Ranking is priority (Urgent first, no priority last), then milestone target date, then age. A parent rolls up only when no sibling is unfinished, and anything not done or canceled counts as unfinished (In Review included when the target is Done).
The mod
── Linear ─────────────────────────────────────────────────────────
◆ ENG-2919 In Progress · High
Core affiliate link builders
root branch · scope: web · parent ENG-2900 Details Hide
sessions ENG-2748 In Review (eng-2748) · ⚠ ENG-2912 In Progress (main)
- Band above the prompt: the current issue's id, state, priority, title, scope and parent.
- Details pane (
/linear): description, sub-issues, links, latest comments, and Open in Linear. - Only your own issue: a session shows an issue it took on: one you pinned (
/linear ENG-123, typing/linear-workflow:issue-start ENG-123, or Claude starting it from your words), or the issue in a branch name (alex/eng-2919-link-builders→ENG-2919) that this session switched to itself. A branch issue that another live session in the same checkout has claimed is left to that session, and yours showsNo Linear issue foundand thesessionsrow. A lone session opened on a feature branch still picks its issue up. - Other sessions (
sessionsrow): every Claude Code session on your machine that runs the plugin, with its issue and checkout (mainor the worktree name). - Conflict warnings: a toast and a red ⚠ when another session in the same checkout is on a different issue (you share one branch and one working tree), or two sessions are on the same issue.
- Your issue stays put. If another session switches the shared checkout to another branch, your
session keeps its issue (
held) until that issue is Done or Canceled, or your own session switches branches. - Scope drift (optional): with a sub-project registry, an edit outside the issue's labelled sub-projects raises a toast.
- Stays current: the issue is fetched again at the end of any turn that wrote to Linear (a
skill's transition, the
linear-manageragent, a Linear MCP write), and everypollMinutesotherwise. A toast says when its state changed.
| /linear | What it does |
| --- | --- |
| /linear | Open the details pane |
| /linear ENG-123 | Pin an issue to this session. The pin lasts until this session itself switches to another issue's branch |
| /linear clear | Drop the pin and follow the branch again |
| /linear refresh | Re-fetch from Linear now |
| /linear hide / show | Hide or show the band |
Requirements
- Claude Code 2.1.289 or later. Mods are a recent feature, and this is the version the plugin was built and tested on.
- Node.js 22.18 or later for the CLI (it runs TypeScript directly, no build step).
- A Linear personal API key, for the CLI and the mod.
- Optional: a Linear MCP connection, for the
linear-manageragent. - Optional: Linear's GitHub integration, which links PRs to issues and moves them on merge. The skills work with or without it, because their transitions are idempotent.
- GitHub CLI
gh, logged in, forissue-reviewandissue-ship. - git 2.23 or later (
git switch).
Configuration
Nothing is required beyond the API key. Everything else is inferred, and each layer below overrides the one before it:
- Built-in defaults: GitHub flow, a branch per issue, standard Linear state names.
- Plugin settings (per user): the API key, team keys, polling, the session list.
- Project settings (
.claude/linear.json, per repo, committed): states, branching, checks, merge method, issue template. - Project conventions (
CLAUDE.md,CONTRIBUTING.md, the PR template): the skills follow them for commit messages, PR bodies and anything else they describe. - Your own skills: see Customizing.
Plugin settings
| Option | Default | Meaning |
| --- | --- | --- |
| linearApiKey | — | Linear API key, stored as a secret (secret options are not shown in /config). If unset: LINEAR_API_KEY in the environment, then in <repo>/.env |
| teamKeys | (auto) | Team keys to find in branch names, for repos whose .claude/linear.json sets no teamKey. Else the keys of the teams you belong to. The mod passes this to the CLI too |
| pinCommand | issue-start | Skill whose first argument pins an issue to the session. Empty disables it |
| pollMinutes | 5 | How often the mod refreshes the issue |
| showOtherSessions | true | Share this session's issue with your other sessions and list theirs |
| registryFile | — | Sub-project registry for scope and drift (monorepos). Empty: off |
Project settings (.claude/linear.json)
Optional, all fields optional. A missing value is inferred, or the skill asks once. See
linear.example.json.
{
"team": "Engineering",
"teamKey": "ENG",
"project": "Website",
"assignee": "me",
"baseBranch": "main",
"checks": ["npm run build", "npm test"],
"mergeMethod": "squash",
"deleteBranch": true,
"branching": "create",
"states": { "inProgress": "Doing", "inReview": "Ready for QA", "done": "Shipped" },
"issueTemplate": ".github/linear-issue.md"
}
| Field | Default | Meaning |
| --- | --- | --- |
| team, teamKey, project, assignee | inferred | Where the skills look and file issues. teamKey also lets you type bare numbers (123) |
| baseBranch | origin's default branch | Base for new branches and PRs |
| checks | inferred (npm test, make test…) | Commands issue-review runs before committing |
| mergeMethod | merge | merge, squash, rebase, or local (git merge --no-ff + push, so your own pre-push hooks run) |
| deleteBranch | false | Delete the branch after merging |
| branching | create | issue-start creates the issue's branch (create), asks (ask), or stays on the current one (none) |
| states | Linear's usual names | Your team's names for In Progress, In Review and Done, used by every transition and by the queue's review filter |
| issueTemplate | 4-section template | A markdown file the agent uses for new issue descriptions |
Sub-project registry (monorepos)
Set the registryFile plugin setting to a JSON file at the repo root:
{ "projects": [ { "key": "web", "path": "apps/web" }, { "key": "api", "path": "services/api" } ] }
An issue labelled web (or whose parent is) is scoped to apps/web, so editing
services/api/... raises a drift toast once per issue and sub-project. An issue with no matching
label is scoped to everything.
Customizing
- Settings first. Most differences between teams (state names, branching, checks, merge method,
templates) are settings above, and project conventions in
CLAUDE.mdtake precedence over the skills' defaults. - Replace a skill. Copy
skills/<name>/SKILL.mdinto your project's.claude/skills/<name>/and edit it. Yours runs as/<name>, and the plugin's stays available as/linear-workflow:<name>. Keep calling the CLI for the deterministic steps so the checks stay the same. If you renameissue-start, set thepinCommandplugin setting to your skill's name so the band follows it. - Use the CLI directly. It works without the skills, in your own scripts or CI:
node <plugin>/bin/linear-workflow.mjs queue. - Turn parts off.
/linear hidehides the band;showOtherSessions: falsestops the session list; leavingregistryFileempty keeps scope and drift checks off.
Safety
issue-plan-cyclecan't be started by Claude on its own. You have to type it.issue-reviewandissue-shipcan also be invoked by Claude. When Claude does that without you asking to ship,issue-shipconfirms the issue and PR with you before merging.- Typing
issue-revieworissue-shipyourself authorizes the push or merge for that issue only. - The skills never run
git push --force,git reset --hard,git clean,git checkout -- .,git restore ., a baregit stashorgit commit --amend: each can destroy work that isn't yours. Every eval checks this. The only push to the base branch is the merge itself, whenissue-shipusesmergeMethod: local. issue-reviewrefuses on a branch that names another issue, so work never lands under the wrong issue.issue-shipchecks GitHub before writing to Linear, so a merge that failed is never reported as done.
Best practices
- One issue per session. Several sessions work best in separate
git worktrees. In a shared checkout the band warns you, but the shared tree is still shared. - Put the steps of the work in the issue (Context, Implementation, Scope).
issue-startgives Claude those sections and leaves out the acceptance criteria. - Put decisions made after filing in comments, because
issue-starttreats them as scope. - Set
checksin.claude/linear.jsonsoissue-reviewruns exactly what your CI runs.
Privacy and data handling
- The CLI and the mod send GraphQL queries and updates to
api.linear.appwith your key. They never write it to disk. When you set the key as the secret plugin option, the mod exports it asLINEAR_API_KEYto the session's shell so the CLI can use it. - The CLI's
pr-checkand the review and ship skills use theghCLI. The agent uses your Linear MCP connection. What any of them return goes into the conversation like any tool output. - Session list: each session writes
~/.claude/linear-workflow/sessions/<session-id>.json(checkout path, issue id, title, state) every minute. These files stay on your machine and are deleted when the session ends, or after a day if it crashed. To turn this off, setshowOtherSessions: false.
Troubleshooting
No band. It only shows when the branch names an issue or one is pinned. Check teamKeys, or
pin one with /linear ENG-123. If the band says Linear API key not found, set the key (see
Configuration).
The details pane doesn't open by itself. A pane the session opens on its own needs a wide
terminal (about 144 columns). /linear opens it at any width.
A skill says LINEAR_API_KEY not set. Set the key (Quick start, step 1). Run
node "<plugin>/bin/linear-workflow.mjs" config to see what the CLI finds.
The agent says Linear tools are missing. Connect the Linear MCP server (Quick start, step 2), then restart the session.
gh errors in issue-review or issue-ship. Run gh auth status. If the repository doesn't
allow your mergeMethod, issue-ship asks which one to use.
The band shows held. Another session moved the shared branch, and yours kept its issue (until it is Done or Canceled).
/linear clear follows the branch again.
Limitations
- Single-repository workflow (one PR per issue). Multi-repo or submodule shipping isn't supported.
- The skills follow GitHub's PR model through
gh. GitLab and Bitbucket aren't supported. - The mod sees branch switches made through Claude Code, but not ones made in your own terminal.
Use
/linear clearafter those. - The shared logic (ranking, roll-up, state matching, PR verdicts, mod helpers) has unit tests, including transitions against a fake Linear API. The skills have evals that check they follow the CLI's verdicts, run against canned CLI answers. Nothing runs end to end against a real Linear workspace or GitHub repo.
Development
claude --plugin-dir . # from this folder: load from source, hot-reloads on save
claude plugin validate .
claude plugin test . # unit tests (lib/ and the mod)
Dev tooling lives at the repo root, outside the plugin, so installing the plugin pulls in none of it:
npm install # at the repo root: TypeScript and Node types
npm run typecheck # mod + lib, then CLI + lib
npm test # same as claude plugin test
npm run eval # skill evals, then writes evals/RESULTS.md
Evals (evals/) check the skills' guardrails: issue-ship stops on a missing, draft or failing PR
asks when several PRs or running checks are involved, and doesn't merge on its own when Claude reaches it
without being asked to ship; issue-review refuses on the base branch
or another issue's branch, flags unmet acceptance criteria and never stages unrelated files;
no skill ever runs a destructive git command; issue-start never stashes or discards a dirty tree, quotes
actionable comments verbatim and hides acceptance criteria; issue-next keeps the CLI's order and
urgency. Each case's scaffold.sh builds a git repo and canned CLI answers in .lw/; with
EVAL_LINEAR_WORKFLOW_FIXTURES set, the CLI answers from there (and logs each call to calls.log)
instead of calling Linear or GitHub. Granting Bash needs Claude Code's sandbox: on Linux,
apt install bubblewrap socat. Each case runs 3 times, so a full run costs real tokens (about $3). The latest results are in
evals/RESULTS.md: commit it with each release.
The engine generates .claude-plugin/types/ when the mod loads, and the type-check needs it.
Layout: lib/ is shared code with no Node or browser APIs; hooks/ is the mod; bin/ is the CLI.
Author
Olivier Depiesse (@Sarimarcus)
Version
See CHANGELOG.md for the current version and its history. The version lives only in
plugin.json (and the marketplace entry): don't write it here.
License
MIT

