linear-sdk-cli 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ Release Please generates this file from Conventional Commits. Feature and fix pu
4
4
  not edit it directly; their squash-commit titles are the release-note source of truth. This project
5
5
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.9.0](https://github.com/zhendalf/linear-sdk-cli/compare/v0.8.3...v0.9.0) (2026-10-22)
8
+
9
+ ### Features
10
+
11
+ - add native release commands and folder project defaults ([#97](https://github.com/zhendalf/linear-sdk-cli/issues/97)) ([e382f52](https://github.com/zhendalf/linear-sdk-cli/commit/e382f52a8146ede0d9268d6c6aa557f9836e9274))
12
+ - **auth:** add resumable workspace API-key profile rename ([#95](https://github.com/zhendalf/linear-sdk-cli/issues/95)) ([9297b16](https://github.com/zhendalf/linear-sdk-cli/commit/9297b16e00928441124bffe291a0567e86c59f09))
13
+
7
14
  ## [0.8.3](https://github.com/zhendalf/linear-sdk-cli/compare/v0.8.2...v0.8.3) (2026-10-19)
8
15
 
9
16
  ### Bug Fixes
package/COVERAGE.md CHANGED
@@ -4,18 +4,19 @@ Generated by `bun run audit:coverage`. Total LinearClient members: **481**.
4
4
 
5
5
  | Status | Count | Meaning |
6
6
  | -------- | ----- | ----------------------------------------------- |
7
- | curated | 107 | Has a first-class CLI command |
7
+ | curated | 128 | Has a first-class CLI command |
8
8
  | raw-only | 146 | Reachable via `linear api` (no bespoke command) |
9
- | excluded | 228 | Out of scope (admin/integration/SDK plumbing) |
9
+ | excluded | 207 | Out of scope (admin/integration/SDK plumbing) |
10
10
 
11
11
  Every member is classified — CI fails otherwise. `raw-only` members are still
12
12
  100% reachable through the raw GraphQL escape hatch; they simply lack a tailored command.
13
13
 
14
14
  ## Curated field capabilities
15
15
 
16
+ - Release projections — `ReleasePipeline.stages`, `Release.issues/links`, and release-note document content are selected through the authenticated SDK GraphQL transport, with stable command JSON shapes and offline schema validation.
16
17
  - Issue delegation (Developer Preview) — `Issue.delegate`, `IssueCreateInput.delegateId`, `IssueUpdateInput.delegateId`, and eligible agent-user fields are covered by `issue delegate` and the delegation options on `issue create`/`issue update`.
17
18
 
18
- ## Curated (107)
19
+ ## Curated (128)
19
20
 
20
21
  - `agentSession` — issue
21
22
  - `agentSessions` — issue
@@ -41,9 +42,14 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
41
42
  - `createIssue` — issue
42
43
  - `createIssueLabel` — label
43
44
  - `createIssueRelation` — issue
45
+ - `createIssueToRelease` — release
44
46
  - `createProject` — project
45
47
  - `createProjectMilestone` — milestone
46
48
  - `createProjectUpdate` — project-update
49
+ - `createRelease` — release
50
+ - `createReleaseNote` — release-note
51
+ - `createReleasePipeline` — release-pipeline
52
+ - `createReleaseStage` — release-stage
47
53
  - `createRoadmap` — roadmap
48
54
  - `createTeam` — team
49
55
  - `createWebhook` — webhook
@@ -63,6 +69,7 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
63
69
  - `deleteIssueRelation` — issue
64
70
  - `deleteProject` — project
65
71
  - `deleteProjectMilestone` — milestone
72
+ - `deleteReleaseNote` — release-note
66
73
  - `deleteRoadmap` — roadmap
67
74
  - `deleteTeam` — team
68
75
  - `deleteWebhook` — webhook
@@ -82,6 +89,7 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
82
89
  - `issueRelations` — issue
83
90
  - `issueSearch` — issue
84
91
  - `issueSubscribe` — issue
92
+ - `issueToReleaseDeleteByIssueAndRelease` — release
85
93
  - `issueUnsubscribe` — issue
86
94
  - `issues` — issue
87
95
  - `notification` — notification
@@ -96,6 +104,16 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
96
104
  - `projectStatuses` — project
97
105
  - `projectUpdates` — project-update
98
106
  - `projects` — project
107
+ - `release` — release
108
+ - `releaseComplete` — release
109
+ - `releaseNote` — release-note
110
+ - `releaseNotes` — release-note
111
+ - `releasePipeline` — release-pipeline
112
+ - `releasePipelines` — release-pipeline
113
+ - `releaseStage` — release-stage
114
+ - `releaseSync` — release
115
+ - `releaseUpdateByPipeline` — release
116
+ - `releases` — release
99
117
  - `roadmap` — roadmap
100
118
  - `roadmaps` — roadmap
101
119
  - `searchIssues` — issue
@@ -114,6 +132,10 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
114
132
  - `updateNotification` — notification
115
133
  - `updateProject` — project
116
134
  - `updateProjectMilestone` — milestone
135
+ - `updateRelease` — release
136
+ - `updateReleaseNote` — release-note
137
+ - `updateReleasePipeline` — release-pipeline
138
+ - `updateReleaseStage` — release-stage
117
139
  - `updateRoadmap` — roadmap
118
140
  - `updateTeam` — team
119
141
  - `updateWebhook` — webhook
@@ -125,7 +147,7 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
125
147
  - `workflowState` — state
126
148
  - `workflowStates` — state
127
149
 
128
- ## Excluded (228)
150
+ ## Excluded (207)
129
151
 
130
152
  - `agentActivities` — specialized/raw api only
131
153
  - `agentActivity` — specialized/raw api only
@@ -161,14 +183,9 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
161
183
  - `createIntegrationGithubCommit` — integration/import (raw api only)
162
184
  - `createIntegrationTemplate` — integration/import (raw api only)
163
185
  - `createIntegrationsSettings` — integration/import (raw api only)
164
- - `createIssueToRelease` — specialized/raw api only
165
186
  - `createNotificationSubscription` — specialized/raw api only
166
187
  - `createOrganizationInvite` — admin/enterprise (raw api only)
167
188
  - `createPushSubscription` — specialized/raw api only
168
- - `createRelease` — specialized/raw api only
169
- - `createReleaseNote` — specialized/raw api only
170
- - `createReleasePipeline` — specialized/raw api only
171
- - `createReleaseStage` — specialized/raw api only
172
189
  - `createTemplate` — specialized/raw api only
173
190
  - `createTimeSchedule` — specialized/raw api only
174
191
  - `createTriageResponsibility` — specialized/raw api only
@@ -207,7 +224,6 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
207
224
  - `deleteOrganizationInvite` — admin/enterprise (raw api only)
208
225
  - `deletePushSubscription` — specialized/raw api only
209
226
  - `deleteRelease` — specialized/raw api only
210
- - `deleteReleaseNote` — specialized/raw api only
211
227
  - `deleteReleasePipeline` — specialized/raw api only
212
228
  - `deleteTemplate` — specialized/raw api only
213
229
  - `deleteTimeSchedule` — specialized/raw api only
@@ -276,7 +292,6 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
276
292
  - `issueImportProcess` — integration/import (raw api only)
277
293
  - `issueTitleSuggestionFromCustomerRequest` — specialized/raw api only
278
294
  - `issueToRelease` — specialized/raw api only
279
- - `issueToReleaseDeleteByIssueAndRelease` — specialized/raw api only
280
295
  - `issueToReleases` — specialized/raw api only
281
296
  - `latestReleaseByAccessKey` — specialized/raw api only
282
297
  - `logout` — auth/session flows (out of scope)
@@ -291,22 +306,12 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
291
306
  - `pushSubscriptionTest` — specialized/raw api only
292
307
  - `rateLimitStatus` — SDK plumbing
293
308
  - `recentReleasesByAccessKey` — specialized/raw api only
294
- - `release` — specialized/raw api only
295
- - `releaseComplete` — specialized/raw api only
296
309
  - `releaseCompleteByAccessKey` — specialized/raw api only
297
- - `releaseNote` — specialized/raw api only
298
- - `releaseNotes` — specialized/raw api only
299
- - `releasePipeline` — specialized/raw api only
300
310
  - `releasePipelineByAccessKey` — specialized/raw api only
301
- - `releasePipelines` — specialized/raw api only
302
311
  - `releaseSearch` — specialized/raw api only
303
- - `releaseStage` — specialized/raw api only
304
312
  - `releaseStages` — specialized/raw api only
305
- - `releaseSync` — specialized/raw api only
306
313
  - `releaseSyncByAccessKey` — specialized/raw api only
307
- - `releaseUpdateByPipeline` — specialized/raw api only
308
314
  - `releaseUpdateByPipelineByAccessKey` — specialized/raw api only
309
- - `releases` — specialized/raw api only
310
315
  - `samlTokenUserAccountAuth` — auth/session flows (out of scope)
311
316
  - `semanticSearch` — specialized/raw api only
312
317
  - `slaConfigurations` — specialized/raw api only
@@ -341,10 +346,6 @@ Every member is classified — CI fails otherwise. `raw-only` members are still
341
346
  - `updateIntegrationsSettings` — integration/import (raw api only)
342
347
  - `updateIssueImport` — integration/import (raw api only)
343
348
  - `updateNotificationSubscription` — specialized/raw api only
344
- - `updateRelease` — specialized/raw api only
345
- - `updateReleaseNote` — specialized/raw api only
346
- - `updateReleasePipeline` — specialized/raw api only
347
- - `updateReleaseStage` — specialized/raw api only
348
349
  - `updateTemplate` — specialized/raw api only
349
350
  - `updateTimeSchedule` — specialized/raw api only
350
351
  - `updateTriageResponsibility` — specialized/raw api only
package/README.md CHANGED
@@ -298,6 +298,45 @@ Successful browser, app, and API-key login also save `workspace = "<authenticate
298
298
 
299
299
  Global defaults are optional: login, credential adoption, and logout never choose a new one. Use `linear auth default <slug>` to explicitly select a global fallback. Removing that workspace clears its default without promoting another workspace. Existing defaults, including defaults imported from the reference CLI, are preserved on upgrade because older files cannot distinguish a user choice from an automatically assigned default. To opt out of a legacy default, remove the top-level `default_workspace` from the user config and, if present, `default` from the reference CLI's `credentials.toml`; retain the workspace entries.
300
300
 
301
+ After a workspace URL slug changes, migrate its stored **API-key profile** with:
302
+
303
+ ```sh
304
+ linear auth rename old-workspace new-workspace --json
305
+ # Or include additional known project configs without editing them:
306
+ linear auth rename old-workspace new-workspace --project-config /path/to/another/.linear.toml
307
+ ```
308
+
309
+ The command validates the exact stored key against Linear's current organization/slug, preserving
310
+ the credential, storage type, profile team, user workspace/default, and the reference CLI's shared
311
+ keyring list/default. It ignores environment credentials and refuses credential flags. API-key
312
+ profiles do not contain a historical organization ID; the unchanged key proves its own organization,
313
+ which is returned in the result. Configured destinations and unlisted keyring entries are collisions,
314
+ even if they contain the same key. Nothing is revoked, exported, or placed on argv.
315
+ Keyring moves use an atomic create-only operation on macOS Keychain, so another client's
316
+ destination created during the rename cannot be replaced. The Linux `secret-tool` backend lacks
317
+ this operation and keyring-backed renames are refused before changes; file-only profiles remain
318
+ supported when no source keyring entry needs moving.
319
+
320
+ Project files are never edited. JSON reports `checkedProjectConfigs` and `projectConfigUpdates`
321
+ with exact paths and old/new workspace values; human output lists the same required edits. Discovery
322
+ covers the active project config plus explicit `--project-config` paths. Check other repositories
323
+ separately, update their `workspace` selectors, and update `LINEAR_WORKSPACE` overrides. The reference
324
+ CLI's global `linear.toml` selector, if affected, is reported in `globalConfigUpdates` for manual editing.
325
+
326
+ If storage fails or the process stops partway through, repeat **the same rename command**. A
327
+ non-secret `api_key_profile_rename` marker in the private user config reserves the destination and
328
+ records recovery progress. The source is kept until a verified destination and committed metadata
329
+ exist. Recovery checks for conflicting changes and resumes the remaining steps. Do not log out,
330
+ replace, or migrate either profile while recovery is pending. Fix the reported store/permission
331
+ problem, then retry; do not delete the recovery marker or print credential-store contents.
332
+
333
+ OAuth user and app profiles (including dormant keyring records) are refused before validation or
334
+ mutation. User sessions have rotating refresh tokens and require coordination with in-flight
335
+ refreshes; app profiles contain organization-bound client credentials, and token exchanges with
336
+ different scopes can revoke existing app tokens. This command does not refresh, exchange, revoke,
337
+ or rename either OAuth lifecycle. It does not require browser authorization. See Linear's
338
+ [OAuth lifecycle documentation](https://linear.app/developers/oauth-2-0-authentication).
339
+
301
340
  If revocation is intentionally unavailable, `auth logout --local-only` removes only local state.
302
341
  If browser login temporarily superseded an existing personal API-key profile for that workspace,
303
342
  OAuth logout preserves and reactivates the API key instead of deleting it.
@@ -484,6 +523,104 @@ linear cv results 01234567-89ab-cdef-0123-456789abcdef --json
484
523
  # [{"type":"issue","id":"…","identifier":"ENG-42","name":"Fix login","url":"…"}]
485
524
  ```
486
525
 
526
+ ### Releases
527
+
528
+ `release`, `release-pipeline`, `release-stage`, and `release-note` provide native release tracking.
529
+ Linear currently requires a [Business or Enterprise workspace](https://linear.app/docs/releases.md);
530
+ Business supports up to 15 pipelines. Schema visibility or an empty list does not establish
531
+ entitlement to create pipelines, or permission to change them. Linear enforces plan, role, team,
532
+ and credential permissions; the CLI preserves `feature_not_accessible` and `forbidden` errors.
533
+
534
+ These commands use the CLI's usual OAuth or personal API credentials and `--workspace` selection.
535
+ Pipeline **access keys** are separate credentials for the official
536
+ [`linear-release`](https://github.com/linear/linear-release) CI tool. Do not put a pipeline key in
537
+ `LINEAR_API_KEY` or `LINEAR_ACCESS_TOKEN`. This CLI does not consume `LINEAR_ACCESS_KEY`, create
538
+ pipeline keys, or invoke/install the official tool automatically.
539
+
540
+ ```sh
541
+ linear release-pipeline list --json
542
+ linear release-pipeline view production --json # UUID or API slug; not display name
543
+ linear release-stage list production --all --json
544
+ linear release list --pipeline production --stage-type started --json
545
+ linear release view RELEASE_ID --json # release UUID or slug
546
+ linear release issues RELEASE_ID --all --json
547
+ linear release links RELEASE_ID --json
548
+ ```
549
+
550
+ Create a pipeline explicitly as `scheduled` or `continuous`. Creation includes Linear's default
551
+ stages. Add further `started` stages for verification/observation, or rename/reorder the defaults:
552
+
553
+ ```sh
554
+ linear release-pipeline create --name Production --type scheduled --json
555
+ linear release-pipeline update PIPELINE_ID --rollover-issues false --json
556
+ linear release-stage create --pipeline PIPELINE_ID --name Observe --type started \
557
+ --color '#5e6ad2' --position 3 --frozen true --json
558
+ linear release-stage update STAGE_ID --frozen false --json
559
+ ```
560
+
561
+ Stage types are immutable. Only `started` stages can be frozen, and Linear requires at least one
562
+ unfrozen started stage. Freezing excludes releases in that stage from automated sync; it is not a
563
+ deployment approval or a lock on manual membership edits. Pipeline updates support explicit
564
+ `true|false` for production, automatic notes, and issue rollover. Repeated `--include-path` and
565
+ `--team-id` replace the corresponding collections; `--clear-paths` and `--clear-teams` clear them.
566
+ Team associations use UUIDs, not the global default `--team`.
567
+
568
+ For a scheduled rollout, create the release with a full commit SHA, explicit version and stage,
569
+ then add the exact issue scope. `release create` otherwise defaults to a started stage on scheduled
570
+ pipelines and a completed stage on continuous pipelines:
571
+
572
+ ```sh
573
+ linear release create --pipeline PIPELINE_ID --name 'Release 1.2.3' \
574
+ --release-version 1.2.3 --commit-sha "$approved_sha" --stage PLANNED_STAGE_ID \
575
+ --target-date 2026-10-30 --description-file release-plan.md --json
576
+ linear release add-issue RELEASE_ID ENG-42 --json
577
+ linear release update RELEASE_ID --stage VERIFY_STAGE_ID --json
578
+ linear release-note create --pipeline PIPELINE_ID --release RELEASE_ID \
579
+ --title 'Verification' --body-file verification.md --json
580
+ ```
581
+
582
+ `release update <id>` edits that exact release, including SHA/version/dates or a stage UUID from
583
+ the same pipeline. `release update-version`, `sync`, and `complete` require **both** `--pipeline`
584
+ and `--release-version`; they never implicitly pick the latest release. `update-version` accepts a
585
+ stage **name**, matched by Linear, and attaches links without changing the version:
586
+
587
+ ```sh
588
+ linear release update-version --pipeline PIPELINE_ID --release-version 1.2.3 \
589
+ --stage Observe --link "CI=https://ci.example/run/123" --json
590
+ # Only after the external deployment, verification and observation gates pass:
591
+ linear release complete --pipeline PIPELINE_ID --release-version 1.2.3 \
592
+ --link "GitHub=https://github.com/acme/app/releases/tag/v1.2.3" --json
593
+ ```
594
+
595
+ Completion records Linear lifecycle state; it does not deploy, enforce service ordering, check
596
+ approvals, verify a running revision, or wait for observation. Completing a scheduled release may
597
+ move its open issues into the next release (creating one if needed), depending on pipeline settings.
598
+ When `complete --commit-sha` targets a version, Linear preserves an existing stored SHA. Set and
599
+ verify the intended SHA with `create`/`update` first. Stage transitions through `update` also trigger
600
+ Linear's lifecycle behavior, including rollover on completion.
601
+
602
+ For explicit, already-attributed data, `release sync --pipeline PIPELINE_ID --release-version 1.2.3
603
+ --commit-sha FULL_SHA --issue ENG-42 --issue ENG-43=OTHER_FULL_SHA` calls Linear's native sync API.
604
+ It does not scan Git. References accumulate; omitted issues are not removed. `--reverted-issue`
605
+ removes reverted attribution, and `release remove-issue RELEASE_ID ENG-42 --yes` removes exact
606
+ membership. Scheduled sync can assign the version to an unversioned started release or create a
607
+ release; continuous sync creates/completes a release immediately. Use sync at the appropriate point
608
+ in your deployment process, and read the returned release ID, version, SHA and stage.
609
+
610
+ Use the official `linear-release` when you need commit-range scanning, path/subject filters,
611
+ revert detection, branch/PR attribution, and pipeline-key CI authentication. It can work alongside
612
+ this CLI against the same pipeline; pass the same explicit release version. Native commands are
613
+ useful for preparation, exact membership, management, inspection, and subsequent lifecycle steps.
614
+ No Git attribution implementation or additional runtime dependency is duplicated here.
615
+
616
+ Release notes can cover repeated `--release <id>` values, or an inclusive **createdAt** range using
617
+ both `--from-release` and `--to-release`. These shapes are mutually exclusive and all releases must
618
+ belong to the note's pipeline. `release-note update` changes title, Markdown or scope; delete needs
619
+ confirmation (`--yes` noninteractively). Use `--body-file -` or `--description-file -` for stdin.
620
+ List commands emit bare arrays, views and mutations emit objects, and errors remain JSON on stderr.
621
+ `linear commands release sync --json` exposes options and output fields without credentials.
622
+ Archive/trash operations and other advanced fields remain available through `linear api`.
623
+
487
624
  ## Command overview
488
625
 
489
626
  Every group has `--help` with full options and (for the busy ones) an Examples section. Aliases
@@ -498,6 +635,10 @@ are shown in parentheses. For a machine-readable tree of _every_ command, run
498
635
  | **`project-update`** (`pu`) | `create` · `list` (project status updates, with `--health`) |
499
636
  | **`milestone`** (`m`) | `list` · `view` · `create` · `update` · `delete` |
500
637
  | **`cycle`** (`c`) | `list` · `view` · `current` · `create` · `update` |
638
+ | **`release`** | `list` · `view` · `create` · `update` · `sync` · `update-version` · `complete` · `issues` · `links` · `add-issue` · `remove-issue` |
639
+ | **`release-pipeline`** | `list` · `view` · `create` · `update` |
640
+ | **`release-stage`** | `list` · `view` · `create` · `update` |
641
+ | **`release-note`** | `list` · `view` · `create` · `update` · `delete` |
501
642
  | **`user`** (`u`) | `list` · `view` · `me` |
502
643
  | **`label`** (`lb`) | `list` · `create` · `update` · `delete` |
503
644
  | **`state`** (`st`) | `list` · `view` (workflow states) |
@@ -556,6 +697,11 @@ resolver semantics are designed, rather than acquiring a silent partial implemen
556
697
  | `attachment list` | `Issue.attachments` | yes | not exposed | not exposed |
557
698
  | `comment list`, `issue comment list`, `issue comments` | `Issue.comments` | yes | not exposed | not exposed |
558
699
  | `cycle list`, `team cycles` | `Team.cycles` | yes | not exposed | not exposed |
700
+ | `release list` | `Query.releases` | yes | `--include-archived` | `archivedAt` |
701
+ | `release-pipeline list` | `Query.releasePipelines` | yes | `--include-archived` | `archivedAt` |
702
+ | `release-stage list` | `ReleasePipeline.stages` | yes | `--include-archived` | `archivedAt` |
703
+ | `release-note list` | `Query.releaseNotes` | yes | `--include-archived` | `archivedAt` |
704
+ | `release issues`, `release links` | `Release.issues/links` | yes | not exposed | not exposed |
559
705
  | `custom-view list` | `Query.customViews` | yes | not exposed | `archivedAt` |
560
706
  | `custom-view results` | `CustomView.issues/projects/initiatives` | yes | not exposed | not exposed |
561
707
  | `document list` | `Query.documents` | yes | not exposed | not exposed |
@@ -772,10 +918,10 @@ profile slug where applicable:
772
918
  only, so a migrating user's defaults carry over
773
919
  7. no default team
774
920
 
775
- `workspace` and `sort` keep their existing flag → environment → project → user → legacy-global
921
+ `workspace`, `project`, and `sort` use flag → environment → project → user → legacy-global
776
922
  order. Workspace credential selection is independent and follows the order described above.
777
923
 
778
- Keys: `team` (or `team_id`), `workspace`, and `sort` (or `issue_sort`). You can write these from
924
+ Keys: `team` (or `team_id`), `workspace`, `project`, and `sort` (or `issue_sort`). You can write these from
779
925
  the CLI. Project and top-level setting edits preserve comments and layout. Profile updates preserve
780
926
  all TOML data and use the same locked, atomic rewrite as credential updates:
781
927
 
@@ -783,11 +929,26 @@ all TOML data and use the same locked, atomic rewrite as credential updates:
783
929
  linear config init # pick a team from a list → <git root>/.linear.toml
784
930
  linear config init --team TES # …or say which (scripts); --sort, --path, --force
785
931
  linear config set sort updated # edit one key in the project config in effect
932
+ linear config set project "My Project" # default Linear project for new issues (name or UUID)
786
933
  linear config set team ENG --user # legacy top-level user fallback (backward compatible)
787
934
  linear config set team ENG --user --workspace acme # validated default for the acme profile
788
935
  linear config # show the result, with each value's source
789
936
  ```
790
937
 
938
+ To associate a particular folder and its descendants with a Linear project, run
939
+ `linear config set project "My Project" --path .linear.toml` inside that folder. Without `--path`,
940
+ `config set` edits the discovered config, or creates one at the Git root (cwd outside Git).
941
+ Keep `team` and `workspace` in the same file when needed: discovery reads the nearest config
942
+ file, without merging ancestor files.
943
+
944
+ `issue create` (also `issue new`) uses this project automatically. `--project <name|id>` overrides
945
+ it; sub-issues inherit their parent's project ahead of the configured default. `--no-project`
946
+ creates outside any project, including parent and template defaults. `LINEAR_PROJECT` overrides
947
+ the configured value for an invocation. A configured project is resolved before creation, so
948
+ an unknown or ambiguous name fails without creating an issue; UUIDs avoid name ambiguity.
949
+ This default applies to issue creation; list, search, and update commands keep their explicit
950
+ project selection. Remove the `project` line from the config to clear the association.
951
+
791
952
  `config set` will not write `api_key` or anything else that belongs to the credential store — that
792
953
  is what `auth login` is for. A profile team is validated against the selected workspace whenever a
793
954
  credential is available. Login, adopt, OAuth refresh/fallback, and credential migration preserve
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linear-sdk-cli",
3
- "version": "0.8.3",
3
+ "version": "0.9.0",
4
4
  "description": "Ergonomic command-line interface for Linear, built on @linear/sdk",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -122,6 +122,23 @@ The CLI supports distinct human, hosted-app, and personal-key lifecycles:
122
122
 
123
123
  Login associates the authenticated workspace with the discovered project config, or creates `.linear.toml` at the Git root (cwd outside Git). Use `--no-project` for credential-only login; JSON reports `projectConfigPath` or null. Credentials stay global. Workspace selection is `--workspace` → `LINEAR_WORKSPACE` → project config → optional global default. A sole stored workspace is automatic; multiple unselected workspaces prompt only interactively and fail in JSON/noninteractive mode. Login/adoption/logout never assign a new default. Existing legacy defaults remain valid because their original intent is unknown; `auth default` is an explicit convenience.
124
124
 
125
+ When a workspace URL slug changes, use `linear auth rename <old-slug> <new-slug> --json`
126
+ for an existing API-key profile. It validates the exact stored key's current organization/slug,
127
+ ignores environment credentials, preserves storage/team/default metadata, and refuses destination
128
+ collisions (including unlisted keyring records). Keyring moves require atomic create-only support
129
+ (macOS Keychain). Linux Secret Service keyring entries are refused before changes; file-only profiles
130
+ remain supported. API-key profiles have no historical organization ID; the unchanged stored key proves
131
+ its organization, returned in `organization`. Never export the key or
132
+ combine login/logout to rename it. If interrupted, repeat the same command to resume its non-secret
133
+ recovery marker; do not log out, replace, or migrate either profile while recovery is pending.
134
+ Project files stay unchanged: inspect `checkedProjectConfigs`, `projectConfigUpdates`, and
135
+ `globalConfigUpdates`, then update the authorized selectors separately. Supply
136
+ `--project-config /absolute/path/.linear.toml` to inspect additional known configs. Other repositories
137
+ and `LINEAR_WORKSPACE` overrides require a separate check; discovery is not machine-wide.
138
+ OAuth user/app profiles and dormant OAuth records are explicitly unsupported and left untouched:
139
+ user refresh-token rotation needs coordination, and app token exchange has scope/revocation effects.
140
+ The command performs no OAuth refresh, exchange, browser authorization, or revocation.
141
+
125
142
  An explicit credential flag overrides environment credentials. If both credential kinds occur at
126
143
  the same precedence level, the CLI fails rather than silently choosing an actor. Inspect resolution
127
144
  with `linear auth status`. `linear auth token` exports stored API keys only and never OAuth tokens.
@@ -135,6 +152,16 @@ forbidden errors include stable `error.details` with the required scope and reme
135
152
 
136
153
  ## Agent best practices
137
154
 
155
+ Folder defaults: `linear config set project "My Project" --path .linear.toml` associates the
156
+ current folder and descendants with a Linear project (name or UUID). Include `team` and
157
+ `workspace` in that file when needed; discovery reads the nearest config without merging
158
+ ancestor files. Omit `--path` to edit the discovered config, or create one at the Git root
159
+ (cwd outside Git). `linear config show --json` reports `project` and `origins.project`.
160
+ `issue create` / `issue new` uses the default; `--project` overrides it, a parent's project
161
+ takes precedence over it, and `--no-project` suppresses config, parent, and template defaults.
162
+ `LINEAR_PROJECT` overrides file defaults. List/search/update commands do not inherit this
163
+ project selection. Remove the config's `project` line to clear the association.
164
+
138
165
  This CLI is built for non-interactive use. Follow these and it will never hang and
139
166
  always emit parseable output.
140
167
 
@@ -318,6 +345,40 @@ Lead with these two machine-readable commands:
318
345
  grep -n 'type Issue ' "${TMPDIR:-/tmp}/linear.graphql"
319
346
  ```
320
347
 
348
+ ### Releases and CI
349
+
350
+ Use `release-pipeline list`, `release-stage list <pipeline>`, and `release list --pipeline <id|slug>`
351
+ to inspect releases. Pipeline/release lookups accept UUIDs or API slugs, not display names.
352
+ Releases require Business/Enterprise; successful schema introspection or an empty list does not
353
+ prove mutation permission or plan eligibility. Preserve `feature_not_accessible`/`forbidden` errors.
354
+
355
+ Native commands use ordinary CLI OAuth/API credentials. Pipeline access keys and
356
+ `LINEAR_ACCESS_KEY` belong to the official [linear-release](https://github.com/linear/linear-release)
357
+ CI tool; this CLI does not consume them or install/invoke that tool. Use the official tool for Git
358
+ scanning, path filtering, revert handling and PR attribution. Native `release sync` takes explicit
359
+ `--issue KEY-123[=FULL_SHA]` references and never scans the checkout.
360
+
361
+ For scheduled releases, prepare with `release create --pipeline <id> --name <name>
362
+ --release-version <version> --commit-sha <full-sha> --stage <planned-stage-id>`. Set exact membership
363
+ with `release add-issue <release-id> <issue>`. `release update <id> --stage <stage-id>` edits an exact
364
+ release; `release update-version --pipeline <id> --release-version <version> --stage <name>` can
365
+ also attach repeated `--link Label=URL`. Freeze a started stage with `release-stage update <id>
366
+ --frozen true` to exclude its releases from automated sync, while keeping one started stage unfrozen.
367
+
368
+ `sync`, `update-version` and `complete` require a pipeline AND version; no latest fallback is used.
369
+ Scheduled sync can label an unversioned started release or create a release; continuous sync creates
370
+ a completed release immediately. Synced references accumulate; omission does not remove issues.
371
+ Use `--reverted-issue` or `release remove-issue <id> <issue> --yes` for explicit removal.
372
+ Complete only after separately authorized deployment/verification/observation gates pass. Completion
373
+ and transitions to a completed stage may move open issues into another release according to the
374
+ pipeline's rollover setting. `complete --commit-sha` preserves an existing SHA when targeting a
375
+ version: set/verify it using create/update first. No command deploys code or proves verification.
376
+
377
+ `release-note create --pipeline <id> --release <id> --body-file <path>` supports repeated release
378
+ IDs or a paired `--from-release`/`--to-release` inclusive createdAt range, all in the same pipeline.
379
+ Use file/stdin body input, inspect `release-note view`, and keep release-note deletion confirmation
380
+ and exact membership removal explicit. Archive/trash and advanced operations remain under `api`.
381
+
321
382
  ## Available commands
322
383
 
323
384
  Generated from `linear commands --json` (run `bun run skill:docs` to refresh):
@@ -339,6 +400,7 @@ linear auth list
339
400
  linear auth login
340
401
  linear auth logout
341
402
  linear auth migrate
403
+ linear auth rename
342
404
  linear auth status
343
405
  linear auth token
344
406
  linear auth whoami
@@ -498,6 +560,38 @@ linear project-update
498
560
  linear project-update create
499
561
  linear project-update list
500
562
 
563
+ linear release
564
+ linear release add-issue
565
+ linear release complete
566
+ linear release create
567
+ linear release issues
568
+ linear release links
569
+ linear release list
570
+ linear release remove-issue
571
+ linear release sync
572
+ linear release update
573
+ linear release update-version
574
+ linear release view
575
+
576
+ linear release-note
577
+ linear release-note create
578
+ linear release-note delete
579
+ linear release-note list
580
+ linear release-note update
581
+ linear release-note view
582
+
583
+ linear release-pipeline
584
+ linear release-pipeline create
585
+ linear release-pipeline list
586
+ linear release-pipeline update
587
+ linear release-pipeline view
588
+
589
+ linear release-stage
590
+ linear release-stage create
591
+ linear release-stage list
592
+ linear release-stage update
593
+ linear release-stage view
594
+
501
595
  linear roadmap
502
596
  linear roadmap create
503
597
  linear roadmap delete
@@ -570,6 +664,10 @@ prints the same). These are supplementary — `--help` on any command is authori
570
664
  - [project-label](references/project-label.md) — Manage project labels (distinct from issue labels)
571
665
  - [project-status](references/project-status.md) — Manage workspace project-status definitions
572
666
  - [project-update](references/project-update.md) — Post and list project status updates
667
+ - [release](references/release.md) — Track releases, lifecycle and issue membership
668
+ - [release-pipeline](references/release-pipeline.md) — Manage release pipelines
669
+ - [release-stage](references/release-stage.md) — Manage release stages and freezing
670
+ - [release-note](references/release-note.md) — Manage Markdown release notes
573
671
  - [roadmap](references/roadmap.md) — Work with roadmaps
574
672
  - [schema](references/schema.md) — Print the Linear GraphQL schema as SDL
575
673
  - [state](references/state.md) — Inspect workflow states
@@ -144,6 +144,37 @@ migrated: string[]
144
144
  path: string
145
145
  ```
146
146
 
147
+ ### `linear auth rename`
148
+
149
+ Rename a stored API-key profile after its Linear workspace URL slug changes
150
+
151
+ ```
152
+ linear auth rename [options] <old-slug> <new-slug>
153
+ ```
154
+
155
+ | Option | Description |
156
+ | ----------------------------- | -------------------------------------------------------------------------- |
157
+ | `--project-config <paths...>` | also inspect these project configs for old workspace selectors (read-only) |
158
+
159
+ **Output (`--json`)**: a receipt object
160
+
161
+ ```text
162
+ success: boolean
163
+ from: string
164
+ workspace: string
165
+ credentialType: string
166
+ organization: {id: string, name: string, urlKey: string}
167
+ path: string
168
+ storage: string
169
+ team: string | null
170
+ defaultWorkspace: string | null
171
+ referenceCredentialsPath: string | null
172
+ checkedProjectConfigs: string[]
173
+ projectConfigUpdates: Array<{path: string, key: string, from: string, to: string}>
174
+ globalConfigUpdates: Array<{path: string, key: string, from: string, to: string}>
175
+ otherProjects: string
176
+ ```
177
+
147
178
  ### `linear auth status`
148
179
 
149
180
  Show where the active credential is resolved from (value redacted)
@@ -25,8 +25,9 @@ credentialWorkspace: string | null
25
25
  workspaceProfile: string | null
26
26
  team: string | null
27
27
  workspace: string | null
28
+ project: string | null
28
29
  sort: string
29
- origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
30
+ origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, project: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
30
31
  userConfigPath: string
31
32
  projectConfigPath: string | null
32
33
  globalConfigPath: string | null
@@ -40,12 +41,13 @@ Write a project .linear.toml (at the git root, or here outside a repository)
40
41
  linear config init [options]
41
42
  ```
42
43
 
43
- | Option | Description |
44
- | ---------------- | ------------------------------------------------------------------ |
45
- | `--team <key>` | default team key (otherwise chosen from a list) |
46
- | `--sort <order>` | default issue-list sort (priority \| manual \| updated \| created) |
47
- | `--path <file>` | write this file instead of <git root>/.linear.toml |
48
- | `--force` | overwrite an existing file |
44
+ | Option | Description |
45
+ | ---------------------- | ------------------------------------------------------------------ |
46
+ | `--team <key>` | default team key (otherwise chosen from a list) |
47
+ | `--project <name\|id>` | default Linear project for new issues |
48
+ | `--sort <order>` | default issue-list sort (priority \| manual \| updated \| created) |
49
+ | `--path <file>` | write this file instead of <git root>/.linear.toml |
50
+ | `--force` | overwrite an existing file |
49
51
 
50
52
  **Output (`--json`)**: a receipt object
51
53
 
@@ -54,11 +56,12 @@ success: boolean
54
56
  path: string
55
57
  team: string
56
58
  sort?: string
59
+ project?: string
57
60
  ```
58
61
 
59
62
  ### `linear config set`
60
63
 
61
- Set one project or user setting (team, workspace, sort)
64
+ Set one project or user setting (team, workspace, sort, project)
62
65
 
63
66
  ```
64
67
  linear config set [options] <key> <value>
@@ -98,8 +101,9 @@ credentialWorkspace: string | null
98
101
  workspaceProfile: string | null
99
102
  team: string | null
100
103
  workspace: string | null
104
+ project: string | null
101
105
  sort: string
102
- origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
106
+ origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, project: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
103
107
  userConfigPath: string
104
108
  projectConfigPath: string | null
105
109
  globalConfigPath: string | null
@@ -378,8 +378,9 @@ linear issue create [options]
378
378
  | `-s, --state <name>` | workflow state name or type |
379
379
  | `-P, --priority <0-4>` | priority |
380
380
  | `-l, --label <name>` | label (repeatable / comma-separated) |
381
- | `-p, --project <name>` | project name or id |
382
- | `--milestone <name>` | project milestone (requires --project) |
381
+ | `-p, --project <name>` | project name or id (overrides the configured default) |
382
+ | `--no-project` | create outside any project, ignoring configured and parent defaults |
383
+ | `--milestone <name>` | project milestone (requires an explicit, configured, or parent project) |
383
384
  | `--cycle <n>` | cycle number, name, id, or 'current' |
384
385
  | `--estimate <n>` | estimate points |
385
386
  | `--parent <id>` | parent issue id (the sub-issue joins the parent's project unless --project says otherwise) |