linear-sdk-cli 0.4.0 → 0.5.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,15 @@ 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.5.0](https://github.com/zhendalf/linear-sdk-cli/compare/v0.4.0...v0.5.0) (2026-09-03)
8
+
9
+ ### Features
10
+
11
+ - **config:** support per-workspace default teams ([#50](https://github.com/zhendalf/linear-sdk-cli/issues/50)) ([06be757](https://github.com/zhendalf/linear-sdk-cli/commit/06be757ddb81652dea4da32434e63de773cb6760)), closes [#44](https://github.com/zhendalf/linear-sdk-cli/issues/44)
12
+ - **issue:** add native agent delegation ([#52](https://github.com/zhendalf/linear-sdk-cli/issues/52)) ([15055ff](https://github.com/zhendalf/linear-sdk-cli/commit/15055ff73d46f6ddf31679b7bb5f37fc6e3fddda)), closes [#45](https://github.com/zhendalf/linear-sdk-cli/issues/45)
13
+ - **issue:** set labels by group ([#54](https://github.com/zhendalf/linear-sdk-cli/issues/54)) ([4c471cd](https://github.com/zhendalf/linear-sdk-cli/commit/4c471cd23c9409ba395cf43514f9e251a42ef4d6)), closes [#46](https://github.com/zhendalf/linear-sdk-cli/issues/46)
14
+ - standardize archived-resource listing ([#53](https://github.com/zhendalf/linear-sdk-cli/issues/53)) ([735d1c8](https://github.com/zhendalf/linear-sdk-cli/commit/735d1c87894736de257b8888edb8500934e502f3)), closes [#49](https://github.com/zhendalf/linear-sdk-cli/issues/49)
15
+
7
16
  ## [0.4.0](https://github.com/zhendalf/linear-sdk-cli/compare/v0.3.3...v0.4.0) (2026-08-28)
8
17
 
9
18
  ### Features
package/COVERAGE.md CHANGED
@@ -11,6 +11,10 @@ Generated by `bun run audit:coverage`. Total LinearClient members: **472**.
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
+ ## Curated field capabilities
15
+
16
+ - 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
+
14
18
  ## Curated (107)
15
19
 
16
20
  - `agentSession` — issue
package/MIGRATING.md CHANGED
@@ -124,6 +124,10 @@ Everything with no row is spelled identically.
124
124
 
125
125
  Passing both spellings at once (`--due` _and_ `--due-date`) is a usage error, not a coin flip.
126
126
 
127
+ This CLI previously taught `initiative list --archived`. Its canonical spelling is now
128
+ `--include-archived`, matching issue, project, and notification lists. The old spelling remains a
129
+ compatibility alias throughout `0.x`; passing both spellings together is a usage error.
130
+
127
131
  **Short flags are the one place we did not follow.** schpet 2.5's own tree assigns `-a` four
128
132
  meanings (`--app`, `--all`, `--assignee`, `--attach`), `-f` four, `-y` three, `-t` two (`--title`
129
133
  and `--team`). There is no consistent target to copy. Ours holds **one meaning per letter across
@@ -154,6 +158,8 @@ Every one is now either identical, or says so on stderr, or is a usage error. Kn
154
158
  under `--quiet`) that deactivated users are still excluded and names `--include-disabled`, and
155
159
  `--help` says so up front. Not adopted: making `--all` mean "and deactivated" on two commands
156
160
  would give one global two meanings.
161
+ The same rule applies to lifecycle history: `--all` never includes archived records. Use
162
+ `--include-archived --all` to widen lifecycle visibility and exhaust pagination independently.
157
163
  5. **`-f <file>` on `project create/update`, `document create/update`** — theirs: `--description-file` /
158
164
  `--content-file`. Ours: `-f` is `--fields`, and it used to be _dropped_ on those commands, so
159
165
  `project create --name X -f desc.md` created the project with no description and exited 0.
package/README.md CHANGED
@@ -64,7 +64,8 @@ retains their best ideas and provides a careful compatibility and migration path
64
64
  - **Git-aware** — the current issue is inferred from your branch (`tes-123-fix` → `TES-123`), so most issue commands let you drop the id.
65
65
  - **Git + GitHub workflow** — `issue start` checks out the branch and marks the issue started, `issue describe` prints a commit message with Linear-issue trailers, `issue pr` opens a GitHub PR — all linked back to the issue.
66
66
  - **Forgiving inputs** — refer to things the way you think of them: `TES-123`, team `TES`, `--assignee me`, `--cycle current`, state and label by name.
67
- - **Multi-workspace** — store credentials for several workspaces and switch with a global `--workspace`.
67
+ - **Multi-workspace** — store credentials and a non-secret default team per workspace, then switch
68
+ both contexts with a global `--workspace`.
68
69
  - **Complete & honest** — first-class commands for the core resource graph, a raw `linear api` for everything else, and a [measured coverage audit](#coverage) that CI keeps honest.
69
70
 
70
71
  ## Install
@@ -230,6 +231,7 @@ linear auth login --workspace other-org # …and another workspace
230
231
  linear auth login --workspace acme --key - # personal API-key fallback via stdin
231
232
  linear auth list # show configured workspaces + which is default
232
233
  linear auth default acme # choose the default workspace
234
+ linear config set team ENG --user --workspace acme # set its validated default team
233
235
  linear --workspace other-org issue list # use a specific workspace for one command
234
236
  linear auth logout --workspace acme # revoke OAuth, then remove one credential
235
237
  ```
@@ -239,11 +241,13 @@ If browser login temporarily superseded an existing personal API-key profile for
239
241
  OAuth logout preserves and reactivates the API key instead of deleting it.
240
242
 
241
243
  **Selection precedence** (strict): an explicit `--api-key` or `--access-token` flag bypasses the
242
- environment and workspace selection entirely. Otherwise `LINEAR_API_KEY` or
243
- `LINEAR_ACCESS_TOKEN` is absolute. With no invocation-scoped credential, the workspace is chosen
244
- by `--workspace` → `LINEAR_WORKSPACE` env → project config `workspace` → `default_workspace` in the
245
- user config. With one configured workspace it's used automatically; with several and no selection,
246
- the CLI asks you to pick (via `--workspace`, project config, or `auth default`).
244
+ environment and stored-credential lookup. Otherwise `LINEAR_API_KEY` or `LINEAR_ACCESS_TOKEN` is
245
+ absolute. With no invocation-scoped credential, the workspace is chosen by `--workspace` →
246
+ `LINEAR_WORKSPACE` env → project config `workspace` → `default_workspace` in the user config. With
247
+ one configured workspace it's used automatically; with several and no selection, the CLI asks you
248
+ to pick (via `--workspace`, project config, or `auth default`). An invocation credential does not
249
+ silently inherit the default or project profile's team; pair it with `--workspace` (or
250
+ `LINEAR_WORKSPACE`) naming a configured profile when that profile metadata should apply.
247
251
 
248
252
  ## Core concepts
249
253
 
@@ -267,10 +271,76 @@ A few ideas run through every command:
267
271
  linear issue create --title "Fix login redirect" --team TES -P 2 --assignee me
268
272
  linear issue list --assignee me --state started
269
273
  linear issue update TES-42 --state "In Review" --add-label backend
274
+ linear issue label TES-42 --set-group 'Team=QA'
275
+ linear issue delegate TES-42 Codex
270
276
  linear issue comment TES-42 "ready for another look"
271
277
  linear issue archive TES-42 --yes
272
278
  ```
273
279
 
280
+ **Agent delegation (Developer Preview)** — the assignee remains the human owner; the delegate is
281
+ the agent working on their behalf. Create/update accept `--delegate <name|id>` and
282
+ `--clear-delegate`; the focused command is convenient on a matching branch:
283
+
284
+ ```sh
285
+ linear issue create --title "Investigate flaky CI" --assignee me --delegate Codex
286
+ linear issue update TES-42 --delegate Codex
287
+ linear issue update TES-42 --clear-delegate
288
+ linear issue delegate TES-42 Codex
289
+ linear issue delegate --clear # issue inferred from the branch
290
+ linear issue delegate TES-42 Codex --dry-run --json
291
+ linear issue delegate TES-42 Codex --full-result --json
292
+ ```
293
+
294
+ Delegate resolution accepts an agent-user UUID, exact display name, or exact full name, preferring
295
+ case-sensitive matches. It rejects human, inactive, non-assignable, ambiguous, and team-ineligible
296
+ users before writing. `--dry-run` resolves every field and prints the exact nullable `delegateId`
297
+ input without a mutation; `--full-result` (hidden alias `--read-back`) returns the relationship
298
+ receipt plus the canonical issue read-back and verifies the resulting delegate. These modes are
299
+ currently the delegation slice only: on `issue create`/`update`, pair them with `--delegate` or
300
+ `--clear-delegate`.
301
+
302
+ Delegating can trigger an externally observable Agent Session/webhook. Clearing a delegate does
303
+ not claim to cancel a session that is already running. Linear for Agents is in Developer Preview;
304
+ an unsupported workspace/schema returns `feature_not_accessible`, while ordinary `issue view`
305
+ falls back safely and reports `delegate: null` if the preview field itself is unavailable.
306
+ See Linear's current [agent integration guide](https://linear.app/developers/agents) and
307
+ [issue-assignment guide](https://linear.app/docs/assigning-issues) for the platform semantics.
308
+
309
+ **Label-group replacement** — replace only the selected group's direct member while preserving
310
+ every unrelated issue label. Repeat `--set-group` to plan several groups into one relative-label
311
+ mutation:
312
+
313
+ ```sh
314
+ linear issue label TES-42 --set-group 'Team=QA'
315
+ linear issue label TES-42 \
316
+ --set-group 'Team=QA' \
317
+ --set-group 'Issue Type=Bug' \
318
+ --json
319
+ linear issue label TES-42 --set-group 'Team=QA' --dry-run --json
320
+ linear issue label TES-42 --set-group 'Team=QA' --full-result --json
321
+ ```
322
+
323
+ Both sides accept a UUID or an exact, case-sensitive name. The value is split on the first `=`:
324
+ shell-quote the whole assignment when either name contains spaces or shell metacharacters; a label
325
+ name may contain additional `=` characters without escaping. If the group name itself contains
326
+ `=`, use its UUID on the left. Group containers, archived labels, labels outside the issue team's
327
+ workspace/team/inherited scope, and labels that are not direct members of the named group are
328
+ rejected before writing. Repeating an identical assignment normalizes to one operation; conflicting
329
+ targets for the same resolved group are a usage error. `--set-group` cannot be mixed with the
330
+ existing `--add`/`--remove` mode.
331
+
332
+ The JSON receipt includes the resolved group/member IDs plus `changed` and `mutationSent`. An
333
+ already-satisfied request succeeds with both fields `false` and sends no mutation. `--dry-run`
334
+ returns the shared mutation-plan envelope and the exact `addedLabelIds`/`removedLabelIds` input;
335
+ `--full-result` adds the canonical issue read-back, verification, and each requested group's prior
336
+ members (including all members repaired from an inconsistent pre-existing state).
337
+
338
+ This is a read/modify/write operation: the CLI reads the current labels, then sends one update with
339
+ relative added/removed IDs, so unrelated concurrent label changes are not overwritten. Linear does
340
+ not expose a compare-and-swap precondition here, so another writer changing the same group between
341
+ the read and update can race; use `--full-result` when post-write verification matters. See Linear's
342
+ current [label documentation](https://linear.app/docs/labels) for group and inheritance semantics.
343
+
274
344
  **Git + GitHub PR** — turn an issue into commits and a pull request. The id is inferred from the
275
345
  branch everywhere below.
276
346
 
@@ -311,7 +381,9 @@ EOF
311
381
 
312
382
  ```sh
313
383
  linear project list --team TES
384
+ linear project list --include-archived --all --json
314
385
  linear project view "Q3 Launch"
386
+ linear initiative list --include-archived --json
315
387
  linear project-update create "Q3 Launch" --health onTrack --body "Beta is out to 10% of users."
316
388
  linear initiative-update create "Platform" --health atRisk --body-file update.md
317
389
  ```
@@ -355,33 +427,89 @@ Every group has `--help` with full options and (for the busy ones) an Examples s
355
427
  are shown in parentheses. For a machine-readable tree of _every_ command, run
356
428
  `linear commands --json`.
357
429
 
358
- | Group | What you can do |
359
- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
360
- | **`issue`** (`i`) | `view` · `list` · `mine` · `search` · `create` · `update` · `delete` · `archive`/`unarchive` · `start` (git branch) · `describe` · `pull-request`/`pr` · `assign` · `state` · `label` · `comment`/`comments` · `relation` · `subscribe`/`unsubscribe` · `id`/`title`/`url`/`branch` |
361
- | **`team`** (`t`) | `list` · `view` · `members` · `states` · `labels` · `cycles` · `create` · `update` |
362
- | **`project`** (`p`) | `list` · `view` · `create` · `update` · `archive` · `milestones` |
363
- | **`project-update`** (`pu`) | `create` · `list` (project status updates, with `--health`) |
364
- | **`milestone`** (`m`) | `list` · `view` · `create` · `update` · `delete` |
365
- | **`cycle`** (`c`) | `list` · `view` · `current` · `create` · `update` |
366
- | **`user`** (`u`) | `list` · `view` · `me` |
367
- | **`label`** (`lb`) | `list` · `create` · `update` · `delete` |
368
- | **`state`** (`st`) | `list` · `view` (workflow states) |
369
- | **`comment`** (`cm`) | `list` · `add` · `reply` · `update` · `delete` · `resolve`/`unresolve` |
370
- | **`document`** (`doc`) | `list` · `view` · `create` · `update` · `delete` |
371
- | **`attachment`** (`at`) | `list` · `create` · `delete` |
372
- | **`favorite`** (`fav`) | `list` · `add` · `remove` |
373
- | **`custom-view`** (`cv`) | `list` · `view` · `results` · `create` · `update` · `delete` |
374
- | **`initiative`** (`init`) | `list` · `view` · `create` · `update` · `archive` · `delete` |
375
- | **`initiative-update`** (`iu`) | `create` · `list` (initiative status updates, with `--health`) |
376
- | **`roadmap`** (`rm`) | `list` · `view` · `create` · `update` · `delete` &nbsp;<sup>†</sup> |
377
- | **`notification`** (`notif`) | `list` · `read`/`unread` · `read-all` · `archive` · `snooze` |
378
- | **`organization`** (`org`) | `view` · `members` · `invites` |
379
- | **`webhook`** (`wh`) | `list` · `view` · `create` · `update` · `delete` |
380
- | **top-level** | `whoami` · `auth` (`login` · `list` · `default` · `token` · `status` · `logout`) · `config` · `api` · `commands` · `schema` · `completion` |
430
+ | Group | What you can do |
431
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
432
+ | **`issue`** (`i`) | `view` · `list` · `mine` · `search` · `create` · `update` · `delete` · `archive`/`unarchive` · `start` (git branch) · `describe` · `pull-request`/`pr` · `assign` · `delegate` · `state` · `label` · `comment`/`comments` · `relation` · `subscribe`/`unsubscribe` · `id`/`title`/`url`/`branch` |
433
+ | **`team`** (`t`) | `list` · `view` · `members` · `states` · `labels` · `cycles` · `create` · `update` |
434
+ | **`project`** (`p`) | `list` · `view` · `create` · `update` · `archive` · `milestones` |
435
+ | **`project-update`** (`pu`) | `create` · `list` (project status updates, with `--health`) |
436
+ | **`milestone`** (`m`) | `list` · `view` · `create` · `update` · `delete` |
437
+ | **`cycle`** (`c`) | `list` · `view` · `current` · `create` · `update` |
438
+ | **`user`** (`u`) | `list` · `view` · `me` |
439
+ | **`label`** (`lb`) | `list` · `create` · `update` · `delete` |
440
+ | **`state`** (`st`) | `list` · `view` (workflow states) |
441
+ | **`comment`** (`cm`) | `list` · `add` · `reply` · `update` · `delete` · `resolve`/`unresolve` |
442
+ | **`document`** (`doc`) | `list` · `view` · `create` · `update` · `delete` |
443
+ | **`attachment`** (`at`) | `list` · `create` · `delete` |
444
+ | **`favorite`** (`fav`) | `list` · `add` · `remove` |
445
+ | **`custom-view`** (`cv`) | `list` · `view` · `results` · `create` · `update` · `delete` |
446
+ | **`initiative`** (`init`) | `list` · `view` · `create` · `update` · `archive` · `delete` |
447
+ | **`initiative-update`** (`iu`) | `create` · `list` (initiative status updates, with `--health`) |
448
+ | **`roadmap`** (`rm`) | `list` · `view` · `create` · `update` · `delete` &nbsp;<sup>†</sup> |
449
+ | **`notification`** (`notif`) | `list` · `read`/`unread` · `read-all` · `archive` · `snooze` |
450
+ | **`organization`** (`org`) | `view` · `members` · `invites` |
451
+ | **`webhook`** (`wh`) | `list` · `view` · `create` · `update` · `delete` |
452
+ | **top-level** | `whoami` · `auth` (`login` · `list` · `default` · `token` · `status` · `logout`) · `config` · `api` · `commands` · `schema` · `completion` |
381
453
 
382
454
  <sup>†</sup> Linear has **deprecated roadmaps** in favor of initiatives — reads still work, but the
383
455
  API rejects roadmap mutations with a deprecation notice. Use `initiative` for new work.
384
456
 
457
+ ### Archived resources
458
+
459
+ Linear hides archived resources from paginated connections by default. On curated listings that
460
+ expose lifecycle history, `--include-archived` widens the result to live plus historical records;
461
+ it is not an archived-only filter. Linear can return trashed resources in that widened set, so
462
+ project, initiative, and issue JSON rows expose both `archivedAt: string|null` and
463
+ `trashed: boolean`, and human tables label `(archived)` and `(trashed)` separately. Notification
464
+ rows expose `archivedAt` (the public schema has no `trashed` field for notifications).
465
+
466
+ `--all` remains pagination-only. The two flags are independent and composable:
467
+
468
+ ```sh
469
+ linear project list --include-archived --all --json
470
+ linear initiative list --include-archived --status Completed --json
471
+ linear issue search "migration" --include-archived --all --json
472
+ ```
473
+
474
+ `initiative list --archived` remains a compatibility alias for `--include-archived`; passing both
475
+ spellings is an explicit usage error. The alias is retained for the current compatibility window
476
+ (all `0.x` releases; removal no earlier than `1.0`) and is listed by help and
477
+ `linear commands --json`.
478
+
479
+ The following matrix audits every curated list/search surface against the installed
480
+ `@linear/sdk@92.0.0` types and the live public schema exposed by `linear schema`. “Schema support”
481
+ means that the exact connection used by the command accepts `includeArchived`; it does not by
482
+ itself add a CLI contract. This change standardizes the four resource families named by
483
+ the issue. The remaining schema-capable collections stay unchanged until their own output and
484
+ resolver semantics are designed, rather than acquiring a silent partial implementation.
485
+
486
+ | Curated command(s) | Connection audited | Schema support | CLI lifecycle option | Lifecycle fields in list JSON |
487
+ | ------------------------------------------------------ | --------------------------------------------- | -------------- | ---------------------------------------------- | ----------------------------- |
488
+ | `issue list`, `issue mine` | `Query.issues` | yes | `--include-archived` | `archivedAt`, `trashed` |
489
+ | `issue search` | `Query.searchIssues` | yes | `--include-archived` | `archivedAt`, `trashed` |
490
+ | `project list` | `Query.projects` | yes | `--include-archived` | `archivedAt`, `trashed` |
491
+ | `initiative list` | `Query.initiatives` | yes | `--include-archived` (`--archived` alias) | `archivedAt`, `trashed` |
492
+ | `notification list` | `Query.notifications` | yes | `--include-archived` | `archivedAt` |
493
+ | `attachment list` | `Issue.attachments` | yes | not exposed | not exposed |
494
+ | `comment list`, `issue comment list`, `issue comments` | `Issue.comments` | yes | not exposed | not exposed |
495
+ | `cycle list`, `team cycles` | `Team.cycles` | yes | not exposed | not exposed |
496
+ | `custom-view list` | `Query.customViews` | yes | not exposed | `archivedAt` |
497
+ | `custom-view results` | `CustomView.issues/projects/initiatives` | yes | not exposed | not exposed |
498
+ | `document list` | `Query.documents` | yes | not exposed | not exposed |
499
+ | `favorite list` | `Query.favorites` | yes | not exposed | not exposed |
500
+ | `initiative-update list` | `Initiative.initiativeUpdates` | yes | not exposed | not exposed |
501
+ | `issue agent-session list` | `Query.agentSessions` / `Issue.agentSessions` | yes | not exposed | not exposed |
502
+ | `label list`, `team labels` | `Query.issueLabels` / `Team.labels` | yes | not exposed | not exposed |
503
+ | `milestone list`, `project milestones` | `Project.projectMilestones` | yes | not exposed | not exposed |
504
+ | `project-update list` | `Project.projectUpdates` | yes | not exposed | not exposed |
505
+ | `roadmap list` | `Query.roadmaps` | yes | not exposed | not exposed |
506
+ | `state list`, `team states` | `Team.states` | yes | not exposed | not exposed |
507
+ | `team list` | `Query.teams` | yes | not exposed | not exposed |
508
+ | `team members`, `user list`, `organization members` | user connections | yes | not exposed (`--include-disabled` is separate) | not exposed |
509
+ | `organization invites` | `Query.organizationInvites` | yes | not exposed | not exposed |
510
+ | `webhook list` | `Query.webhooks` | yes | not exposed | not exposed |
511
+ | `auth list` | local credential registry (no API connection) | no | not applicable | not applicable |
512
+
385
513
  ### Global flags
386
514
 
387
515
  | Flag | Effect |
@@ -452,7 +580,8 @@ so prefer the `code` field for fine-grained handling and the exit code for coars
452
580
  - **`-q, --quiet`** — suppress success/status lines on stderr (errors still print).
453
581
  - **`-n, --limit <n>` / `--all`** — `--limit` caps results; `--all` exhausts pagination. With
454
582
  neither, the default cap is **50**. `--all` (and very large `--limit`) can be slow and
455
- rate-limit-prone on big workspaces.
583
+ rate-limit-prone on big workspaces. It never includes archived resources; combine it with
584
+ `--include-archived` where that option is available.
456
585
 
457
586
  ```sh
458
587
  # agent-safe: no prompts, no chatter, fail fast with a parseable error
@@ -563,41 +692,54 @@ Non-secret defaults live in `~/.config/linear/config.toml` (user-wide) or a proj
563
692
  file. **Secrets never go in a project file** — the API key is only ever read from the flag, the
564
693
  env, the user config, or the OS keyring.
565
694
 
566
- Precedence, highest first — `linear config` prints each value with the tier and file it came from:
695
+ Effective team precedence, highest first — `linear config` prints the tier, file, and selected
696
+ profile slug where applicable:
567
697
 
568
698
  1. the flag (`--team`, `--workspace`, `--sort`)
569
699
  2. the environment (`LINEAR_TEAM`/`LINEAR_TEAM_ID`, `LINEAR_WORKSPACE`, `LINEAR_ISSUE_SORT`)
570
700
  3. the **project config**: the first file found walking up from the working directory, checking in
571
701
  each directory `linear.toml`, then `.linear.toml`, then `.config/linear.toml`; compatible
572
702
  existing project configuration is picked up as-is
573
- 4. the **user config**, `~/.config/linear/config.toml` (`$XDG_CONFIG_HOME` honored)
574
- 5. the legacy **global config**, `~/.config/linear/linear.toml` — read for non-secret settings
703
+ 4. `team` on the selected `[workspaces."<slug>"]` profile
704
+ 5. the legacy top-level `team` in the **user config**, `~/.config/linear/config.toml`
705
+ (`$XDG_CONFIG_HOME` honored)
706
+ 6. the legacy **global config**, `~/.config/linear/linear.toml` — read for non-secret settings
575
707
  only, so a migrating user's defaults carry over
708
+ 7. no default team
709
+
710
+ `workspace` and `sort` keep their existing flag → environment → project → user → legacy-global
711
+ order. Workspace credential selection is independent and follows the order described above.
576
712
 
577
713
  Keys: `team` (or `team_id`), `workspace`, and `sort` (or `issue_sort`). You can write these from
578
- the CLI — comments and layout in an existing file are preserved, and the write is atomic:
714
+ the CLI. Project and top-level setting edits preserve comments and layout. Profile updates preserve
715
+ all TOML data and use the same locked, atomic rewrite as credential updates:
579
716
 
580
717
  ```sh
581
718
  linear config init # pick a team from a list → <git root>/.linear.toml
582
719
  linear config init --team TES # …or say which (scripts); --sort, --path, --force
583
720
  linear config set sort updated # edit one key in the project config in effect
584
- linear config set team ENG --user # …or in ~/.config/linear/config.toml
721
+ linear config set team ENG --user # legacy top-level user fallback (backward compatible)
722
+ linear config set team ENG --user --workspace acme # validated default for the acme profile
585
723
  linear config # show the result, with each value's source
586
724
  ```
587
725
 
588
726
  `config set` will not write `api_key` or anything else that belongs to the credential store — that
589
- is what `auth login` is for.
727
+ is what `auth login` is for. A profile team is validated against the selected workspace whenever a
728
+ credential is available. Login, adopt, OAuth refresh/fallback, and credential migration preserve
729
+ profile metadata. Logout reports whether removing a whole profile also removed its team metadata.
590
730
 
591
731
  ```toml
592
732
  # ~/.config/linear/config.toml
593
733
  default_workspace = "acme" # which stored credential is active
594
- team = "TES" # default team key
734
+ team = "TES" # optional legacy/global fallback team
595
735
  sort = "priority" # default issue-list sort: priority | updated | created
596
736
 
597
737
  [workspaces."acme"] # per-workspace credentials (hyphenated slugs are quoted)
598
738
  keyring = true # secret lives in the OS keyring (service linear-cli, account acme)
739
+ team = "ENG" # non-secret default team for this workspace
599
740
  [workspaces."other-org"]
600
741
  api_key = "lin_api_yyyyyyyy" # …or, with `auth login --plaintext`, in this 0600 file
742
+ team = "OPS"
601
743
  ```
602
744
 
603
745
  Relevant environment variables: **`LINEAR_API_KEY`** or **`LINEAR_ACCESS_TOKEN`** (absolute —
@@ -655,6 +797,15 @@ bun run audit:coverage # regenerate COVERAGE.md (add --update to re-baseline t
655
797
  bun run janitor # sweep leaked `clitest-` fixtures from the test workspace
656
798
  ```
657
799
 
800
+ The live delegation suite is additionally gated by `LINEAR_CLI_LIVE_AGENT_ID`, the UUID of an
801
+ explicit disposable-test agent. It can trigger that integration's Agent Session/webhook and is
802
+ never enabled by the general live-test flag alone.
803
+
804
+ The live label-group suite is additionally gated by `LINEAR_CLI_TEST_LABEL_GROUP` and
805
+ `LINEAR_CLI_TEST_LABEL_GROUP_MEMBER`, naming (or identifying by UUID) a pre-existing group and one
806
+ direct member usable by `LINEAR_CLI_TEST_TEAM`. It creates only a disposable issue; it does not
807
+ create, rename, move, or delete the shared label-group fixture.
808
+
658
809
  Architecture is three layers — **commands** (commander wiring) → **services** (one module per
659
810
  resource, the only place that touches the SDK) → **`@linear/sdk`**. The machine JSON envelope is
660
811
  locked and contract-tested so output never silently drifts.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linear-sdk-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Ergonomic command-line interface for Linear, built on @linear/sdk",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -69,7 +69,7 @@
69
69
  "janitor": "bun run test/janitor.ts"
70
70
  },
71
71
  "dependencies": {
72
- "@inquirer/prompts": "^8.7.0",
72
+ "@inquirer/prompts": "^8.7.1",
73
73
  "@linear/sdk": "^92.0.0",
74
74
  "commander": "^15.0.0",
75
75
  "graphql": "^17.0.2",
@@ -79,9 +79,9 @@
79
79
  "packageManager": "bun@1.4.0",
80
80
  "devDependencies": {
81
81
  "@types/bun": "^1.4.0",
82
- "@types/node": "^26.4.0",
83
- "oxfmt": "^0.65.0",
84
- "oxlint": "^1.80.0",
82
+ "@types/node": "^26.4.1",
83
+ "oxfmt": "^0.66.0",
84
+ "oxlint": "^1.81.0",
85
85
  "typescript": "^7.0.2"
86
86
  }
87
87
  }
@@ -374,6 +374,7 @@ linear issue comment list
374
374
  linear issue comment update
375
375
  linear issue comments
376
376
  linear issue create
377
+ linear issue delegate
377
378
  linear issue delete
378
379
  linear issue describe
379
380
  linear issue id
@@ -119,6 +119,7 @@ workspace: string
119
119
  removed: boolean
120
120
  revocation: string
121
121
  fallbackCredentialType: string | null
122
+ teamMetadataRemoved: boolean
122
123
  ```
123
124
 
124
125
  ### `linear auth migrate`
@@ -22,10 +22,11 @@ apiKeySource: string
22
22
  accessToken: string
23
23
  accessTokenSource: string
24
24
  credentialWorkspace: string | null
25
+ workspaceProfile: string | null
25
26
  team: string | null
26
27
  workspace: string | null
27
28
  sort: string
28
- origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: 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}}
29
30
  userConfigPath: string
30
31
  projectConfigPath: string | null
31
32
  globalConfigPath: string | null
@@ -57,16 +58,16 @@ sort?: string
57
58
 
58
59
  ### `linear config set`
59
60
 
60
- Set one project setting (team, workspace, sort) in the project config
61
+ Set one project or user setting (team, workspace, sort)
61
62
 
62
63
  ```
63
64
  linear config set [options] <key> <value>
64
65
  ```
65
66
 
66
- | Option | Description |
67
- | --------------- | ------------------------------------------------------------ |
68
- | `--user` | write the user config (~/.config/linear/config.toml) instead |
69
- | `--path <file>` | write this file instead of the project config in effect |
67
+ | Option | Description |
68
+ | --------------- | ------------------------------------------------------------------------- |
69
+ | `--user` | write the user config (team + --workspace targets that workspace profile) |
70
+ | `--path <file>` | write this file instead of the project config in effect |
70
71
 
71
72
  **Output (`--json`)**: a receipt object
72
73
 
@@ -75,6 +76,7 @@ success: boolean
75
76
  path: string
76
77
  key: string
77
78
  value: string
79
+ workspace?: string
78
80
  ```
79
81
 
80
82
  ### `linear config show`
@@ -93,10 +95,11 @@ apiKeySource: string
93
95
  accessToken: string
94
96
  accessTokenSource: string
95
97
  credentialWorkspace: string | null
98
+ workspaceProfile: string | null
96
99
  team: string | null
97
100
  workspace: string | null
98
101
  sort: string
99
- origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: 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}}
100
103
  userConfigPath: string
101
104
  projectConfigPath: string | null
102
105
  globalConfigPath: string | null
@@ -38,6 +38,7 @@ updatedAt: string
38
38
  startedAt: string | null
39
39
  completedAt: string | null
40
40
  archivedAt: string | null
41
+ trashed: boolean
41
42
  owner: string | null
42
43
  creator: string | null
43
44
  projects: Array<{id: string, name: string, status: {name: string, type: string} | null}>
@@ -138,11 +139,12 @@ Aliases: `ls`
138
139
  linear initiative list [options]
139
140
  ```
140
141
 
141
- | Option | Description |
142
- | ----------------- | ----------------------------------------------------------------- |
143
- | `--status <name>` | filter by status (Planned, Active, Completed, Canceled, Proposed) |
144
- | `--owner <who>` | filter by owner (me\|email\|name\|id) |
145
- | `--archived` | include archived initiatives |
142
+ | Option | Description |
143
+ | -------------------- | -------------------------------------------------------------------- |
144
+ | `--status <name>` | filter by status (Planned, Active, Completed, Canceled, Proposed) |
145
+ | `--owner <who>` | filter by owner (me\|email\|name\|id) |
146
+ | `--include-archived` | include archived resources (the API may also return trashed records) |
147
+ | `--archived` | compatibility alias of --include-archived |
146
148
 
147
149
  **Output (`--json`)**: a bare array of objects
148
150
 
@@ -154,6 +156,8 @@ priority: number
154
156
  targetDate: string | null
155
157
  health: string | null
156
158
  url: string
159
+ archivedAt: string | null
160
+ trashed: boolean
157
161
  ```
158
162
 
159
163
  ### `linear initiative remove-project`
@@ -250,6 +254,7 @@ updatedAt: string
250
254
  startedAt: string | null
251
255
  completedAt: string | null
252
256
  archivedAt: string | null
257
+ trashed: boolean
253
258
  owner: string | null
254
259
  creator: string | null
255
260
  projects: Array<{id: string, name: string, status: {name: string, type: string} | null}>