Repository navigation
feat(linear): add --linear to start a worktree from a Linear issue - #111
Merged
Merged
Conversation
Phase 1 of #107. src/integrations/linear.ts fetches one issue by identifier with a single GraphQL query (identifier, title, url, labels), authenticates with the bare personal API key, bounds every request at 15 s, and derives the branch prefix from the issue's labels. `linear.apiKey` joins CONFIG_NAMES and `lin_api_` keys are redacted from every output route. Auth and rate-limit errors are read from errors[].extensions.code, which is where Linear puts them (a live 401 probe and the rate-limiting docs), not extensions.type as the plan first said. Gate 1: pnpm check, typecheck, build, test (1056), docs:test (69) and the test-marker grep exit 0. Gate 2: reviewer subagent, FAIL then PASS WITH NOTES after one loopback. Refs #107
Phase 2 of #107. `worktree config` gains a Linear group: one confirm, then the API key prompt with instructions for finding a personal key. The stored key is never offered as a default or prefill, and an empty answer leaves a stored key in place, as `github.token` does. `--names linear.apiKey` skips the confirm, `--missing` lists the key while it is unset, and a non-interactive run with no key names `worktree config linear.apiKey <key>`. Coder commit 5a82376 in the phase tree; the empty-answer rule replaced its validate in-host after Gate 2's first pass. Gate 1: pnpm check, typecheck, build, test (1066), docs:test (69) and the test-marker grep exit 0. Gate 2: reviewer subagent, PASS WITH NOTES, then PASS WITH NOTES on the note fix. Refs #107
Phase 3 of #107. `worktree branch --linear ENG-123` (`-l`) fetches the issue once and derives `<prefix>ENG-123-<slug>` from it, the prefix from the issue's labels. `--json` carries `issue: {provider:"linear", key, url}`, the url as Linear returns it. `--linear` is exclusive with `--github` and `--jira`. `--assign` with it warns that assignment is not supported yet and carries on, and a missing `linear.apiKey` exits 2 with `missing_value`. Coder commit 1efb8a6 in the phase tree. Three assertions were added in-host after Gate 2: one fetch only, `-l`, and the help's linear `issue` shape. Gate 1: pnpm check, typecheck, build, test (1077), docs:test (69) and the test-marker grep exit 0. Gate 2: reviewer subagent, PASS WITH NOTES. Refs #107
Phase 4 of #107. A new Linear Issue Integration guide covers usage, how branch names are built, the label -> prefix rule, getting a key and setup. The branch, config and configuration pages, the README, the shipped skill and the docs chat route map gain Linear beside Jira, and the route list is regenerated by `worker:build-context`. The guides index now lists the Jira guide too, which it never did. No changeset: context/release.md has the note written once per feature, by /feature-close. Gate 1: pnpm check, typecheck, build, test (1077), docs:test (69) and the test-marker grep exit 0. Gate 2: reviewer subagent, PASS WITH NOTES; four doc inaccuracies it found were fixed before this commit. Refs #107
Closed
craig-o-curtis
approved these changes
Oct 23, 2026
craig-o-curtis
left a comment
Contributor
There was a problem hiding this comment.
Looks good, thanks. Approving.
What I checked:
- Tests:
pnpm verifypasses locally (Biome, typecheck, 1077 tests). The "Unexpected subprocess calls" warnings also show up onmain, so they are not from this PR. - Linear API: checked against Linear's developer docs and the SDK's
schema.graphql.- The personal key goes in a bare
Authorizationheader, with noBearer. issue(id: String!)accepts a shorthand likeENG-123, so the$id: String!variable type is right.- A rate-limited GraphQL request gets HTTP 400 with
RATELIMITEDinerrors[].extensions.code. Keeping 429 as well does no harm.
- The personal key goes in a bare
- Flags:
-ldoesn't clash with any other flag. The three issue sources exclude each other, and--assignwith--linearwarns instead of failing. - Secrets:
lin_api_keys are redacted. A missing key stops the run before a worktree is created, and an empty answer inworktree configkeeps the stored key.
One small thing, not blocking: validateLinearCredentials is only used by its tests. That matches validateJiraCredentials, so it's fine to keep for consistency, or you can drop both in a later cleanup.
#109 (a run against a real workspace) and #110 (the label rules) are still open, as the description says.
Contributor
Author
|
Thanks for the review. On |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #107
worktree branch --linear <ID>(-l) starts a worktree from a Linear issue, the way--githuband--jiraalready do.src/integrations/linear.ts): one GraphQL query for identifier, title, url and label names; the personal API key goes in the bareAuthorizationheader; every call is bounded at 15 s. Auth and rate-limit errors are read fromerrors[].extensions.code, where Linear puts them.<prefix><IDENTIFIER>-<slug>. The prefix comes from labels, since Linear has no issue type:bug→ bugfix,chore/maintenance→ chore, otherwise feature.worktree configasks forlinear.apiKey; an empty answer keeps a stored key.lin_api_keys are redacted from all output.--json:issuegains{provider:"linear", key, url}.--linearis exclusive with--github/--jira;--assign --linearwarns that assignment is not supported yet.Plan and phase ledger: #107. Four phases, one commit each, plus the release note (
minor).Still needs a person: #109 (run it once against a real Linear workspace) and #110 (confirm the label rules). Related, not caused here: #108 (
worktree configprints stored tokens in clear).Merging does not release this: it waits for the release pull request.