### Summary
- Add `linear cycle list` and `linear cycle view` commands for browsing
team cycles
- Add `--cycle` filter to `linear issue list` for filtering issues by
cycle
- Regenerate skill docs to include new commands
### Problem
PR #150 added cycle support to issue create/update/view, but there was
no way to browse cycles themselves or filter issue lists by cycle. Users
had to know cycle names/numbers without being able to look them up from
the CLI. See #64.
### Fix
Adds a `cycle` command group (aliased `cy`) with two subcommands,
following the same patterns as the existing `milestone` commands:
**`cycle list`** shows all cycles for a team with number, name, dates,
and status. Active cycle is highlighted in green, upcoming cycles use
default color, and completed/past cycles are muted.
```
$ linear cycle list --team XXX
# NAME START END STATUS
3 Sprint 3 2026-03-10 2026-03-24 Upcoming
2 Sprint 2 2026-02-24 2026-03-10 Active
1 Sprint 1 2026-02-10 2026-02-24 Completed
```
**`cycle view`** shows full cycle details including a progress
indicator, description, issue breakdown by state, and first 10 issues.
Accepts cycle name, number, or "active".
```
$ linear cycle view active --team XXX
# Sprint 2
**Number:** 2
**Start:** 2026-02-24
**End:** 2026-03-10
**Status:** Active
**Team:** MyTeam (XXX)
## Issues
**Progress:** 17/50 (34%)
**Total Issues:** 50
**Completed:** 17
**In Progress:** 12
**To Do:** 21
**Issues:**
- XXX-412: Fix auth token refresh (In Progress)
- XXX-398: Add dark mode toggle (Todo)
...
```
**`issue list --cycle`** filters the issue list to a specific cycle,
reusing the existing `getCycleIdByNameOrNumber()` utility and the
GraphQL `IssueFilter.cycle` field.
```
$ linear issue list --cycle active --team XXX --sort priority
◌ ID TITLE LABELS E STATE UPDATED
--- XXX-101 Some task Backend, Feature - Todo 1 day ago
--- XXX-102 Another task Feature - Todo 1 day ago
```
### Why
Cycles are a core part of the Linear workflow and the CLI should support
browsing them. `cycle list` lets you see what's available, `cycle view`
gives you sprint progress at a glance, and `--cycle` on issue list lets
you scope your view to a specific sprint.
### Test Plan
- Tested all three commands against a real Linear workspace with 11
cycles and 50+ issues
- `cycle view` tested with active, by number, and by exact name lookup
- All 220 unit/snapshot tests pass
Adds `linear issue comment delete <commentId>` to delete comments via
the commentDelete GraphQL mutation. Includes snapshot test and updated
skill documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add snapshot test for 'issue update -p <priority>' to verify -p maps
to --priority (not --parent), mirroring the fix tested in issue create
- Regenerate skill docs to reflect corrected flag assignments:
--parent (no short flag) and -p, --priority
When the --project flag value doesn't match any project by exact name
(e.g. because the name contains special characters like quotes or
parentheses), try matching by slugId before returning undefined.
This lets users pass either the full project name or the 12-char hex
slug ID (visible in `project list` output and Linear URLs) as the
--project value.
Fixes#157
Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019ca8f4-4000-732f-91e2-5ad51d27008c
When using 'relation add X blocked-by Y', the API is called with swapped
IDs (Y blocks X), but the success message was showing the API's returned
identifiers (in the swapped order) instead of the user-specified order.
Fixes: the message now uses the original issueIdentifier and
relatedIssueIdentifier variables, so 'relation add ENG-123 blocked-by ENG-456'
correctly shows '✓ Created relation: ENG-123 blocked-by ENG-456'.
Closes#152
Add --cycle flag to issue create and update commands, accepting cycle
name, number, or 'active' keyword. Display cycle in issue view output
alongside project and milestone metadata.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
- Adds `--milestone` flag to `issue create` and `issue update` commands
- Resolves milestones by name (case-insensitive) within the specified
project
- For `issue update`, automatically falls back to the issue's existing
project if `--project` is not explicitly provided
- Validates that a project context exists before attempting milestone
lookup, with helpful error messages
- Shows **project** and **milestone** in `issue view` output (displayed
below the title when present)
## Example usage
```sh
# Create an issue with a milestone
linear issue create --title "Implement feature" --team ENG --project "My Project" --milestone "Phase 1"
# Update an issue's milestone (project inferred from issue)
linear issue update ENG-123 --milestone "Phase 2"
# View an issue — now shows project and milestone
linear issue view ENG-123
# => Project: My Project | Milestone: Phase 1
```
## Test plan
- [x] Happy path tests for create and update with milestone
- [x] Snapshot test for `issue view` with project and milestone
displayed
- [x] All 205 tests pass
- [x] `deno check` and `deno lint` pass
- [x] GraphQL codegen regenerated
- [x] Verified end-to-end against Linear API
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- Replace incorrect URL `https://linear.app/settings/api` with
`https://linear.app/settings/account/security` in the `auth login`
command prompt and error message
- The old URL isn't the correct one where you can create those API keys.
The new one correctly redirects to the API key management page.
## Test plan
- `deno task check` isn't passing due to pre-existing failures on `main`
- [x] `deno lint` passes
- [x] `deno task dev auth login` shows the corrected URL in the prompt
hint
## Test evidence:
<img width="759" height="134" alt="CleanShot 2026-02-16 at 17 05 16"
src="https://github.com/user-attachments/assets/a8d7813b-f609-4599-93f5-cc9a20e71bad"
/>
- Add CI workflow step to verify generated skill docs are up-to-date
- Add development section to README with instructions for:
- Updating skill documentation with deno task generate-skill-docs
- Running code formatting with deno fmt
- Update generate-docs.ts to automatically format generated files
- Regenerate skill docs to ensure they match current CLI version
Fixes#135
Previously, with jj would:
1. Prepare working state (create empty commit if needed)
2. Describe the commit with issue details
3. Create a new empty commit to work on
This left the user on an empty commit with the described commit as parent.
Now it stops after step 2, leaving the user on the described commit itself.
This matches the expected behavior where you work directly on the commit
associated with the issue.
Adds a `linear api` subcommand for making raw GraphQL requests,
mirroring [`gh api`](https://cli.github.com/manual/gh_api) conventions.
## Changes
- Accepts a GraphQL query as a positional arg, from stdin with `-`, or
via auto-detected piped input
- `--variable key=value` for typed variable coercion (booleans, numbers,
null, `@file` for file reads, `@-` for stdin)
- `--variables-json '{"key": "value"}'` for passing all variables as a
JSON object (merged with `--variable`, which takes precedence)
- `--paginate` walks `pageInfo.endCursor` automatically and outputs
concatenated `nodes` array
- `--silent` suppresses response output while exit code still reflects
errors
- Pretty-prints JSON when stdout is a TTY, raw JSON otherwise for piping
to `jq`
- Exits with code 1 on HTTP errors (status >= 400) and GraphQL-level
errors
- Uses raw `fetch` so users see the exact server response including both
`data` and `errors` fields
## Testing
- Snapshot tests using `MockLinearServer` cover query resolution,
variable handling (type coercion, `@file`, `--variables-json`,
precedence), output modes, pagination (multi-page, single-page,
non-connection), auth errors, and `--silent` behavior for both
successful and HTTP error responses
- Manual testing against live Linear API: cycles, workflow states,
notifications (with `--paginate`), non-existent issue lookup, variable
type mismatch errors, stdin piping
## Related
- Closes#123
The children query defaulted to 50 items, which truncated issues with
many sub-issues (e.g., INFRA-823 has 179 sub-issues but only showed ~50).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes#116
Error messages are now clean and user-friendly by default. Stack traces
are only shown when LINEAR_DEBUG=1 is set, similar to RUST_BACKTRACE.
Changes:
- Add src/utils/errors.ts with error handling infrastructure:
- CliError base class with user-facing messages and suggestions
- NotFoundError for entity lookups
- ValidationError for invalid input
- AuthError for authentication issues
- handleError() for consistent error display
- extractGraphQLMessage() to parse Linear API errors
- Update all commands to use handleError() for consistent error display
- Error output goes to stderr with ✗ prefix
- GraphQL errors show userPresentableMessage when available
Example before:
Error: Entity not found: Issue: {"response":{"data":null...
Example after:
✗ Issue not found: FAKE-9999
Updated bulk.ts to use the centralized shouldShowSpinner() function instead
of directly checking Deno.stdout.isTerminal(). This ensures progress display
during bulk operations also respects the NO_COLOR environment variable.
Fixes#113
Add shouldShowSpinner() utility that checks both Deno.stdout.isTerminal()
and the NO_COLOR environment variable before showing spinners. This
prevents garbled spinner output when the CLI is used with tools that
capture output (e.g., AI assistants, scripts).
Removes --no-color flags from commands where they only controlled spinner
visibility, since spinners now automatically disable in non-TTY
environments.
Fixes#113
Adds sourceType field (e.g., github, githubCommit, zendesk) to attachment
display so users can identify what kind of link they're looking at.
Closes#21
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Adds `linear issue relation` command with subcommands for managing issue
relations/dependencies:
- **`add`** - Create relations between issues
- **`remove`** - Remove existing relations
- **`list`** - List all relations for an issue
## Supported Relation Types
| Type | Description | Example |
|------|-------------|---------|
| `blocks` | Issue blocks another | `linear issue relation add ENG-123
blocks ENG-456` |
| `blocked-by` | Issue is blocked by another | `linear issue relation
add ENG-123 blocked-by ENG-100` |
| `related` | Issues are related | `linear issue relation add ENG-123
related ENG-456` |
| `duplicate` | Issue is duplicate of another | `linear issue relation
add ENG-123 duplicate ENG-100` |
## Examples
```bash
# Mark ENG-123 as blocked by ENG-100
linear issue relation add ENG-123 blocked-by ENG-100
# Mark ENG-123 as blocking ENG-456
linear issue relation add ENG-123 blocks ENG-456
# List all relations for an issue
linear issue relation list ENG-123
# Remove a relation
linear issue relation remove ENG-123 blocked-by ENG-100
```
## Implementation Notes
- The `blocked-by` relation type is implemented by reversing the issue
order with the `blocks` API type, providing a more intuitive CLI
experience
- Uses existing utilities (`getIssueIdentifier`, `getIssueId`) for
consistent issue resolution
- Follows the existing command structure and patterns in the codebase
## Motivation
This enables CLI users to manage issue dependencies, which is useful
for:
- Automating issue management in scripts
- AI agents that need to set up dependency relationships
- Quick dependency management without leaving the terminal
The auth login command is now stable, so remove the warning from README.
Regenerated skill docs and updated marketplace.json and plugin.json
versions to match deno.json.
- Add explicit type annotations to team-list.ts and project-list.ts to fix implicit any errors
- Add CI workflow (.github/workflows/ci.yml) that runs type check, format, lint, and tests on PRs
- Update justfile to use 'deno check src/main.ts' instead of '--all' to avoid npm dependency type errors
Previously, --workspace would silently fall back to other credential
sources when the specified workspace wasn't found. Now it errors with
a helpful message suggesting `linear auth login` or `linear auth list`.
Also errors when both LINEAR_API_KEY env var and --workspace are set,
since these are conflicting ways to specify credentials.
Added error handling guidelines to CLAUDE.md to prevent silent failures.
- Add `issue attach` command to attach files to issues
- Add `--attach` flag on `issue comment add`
- Show attachments section in `issue view` with auto-download
- Add `attachment_dir` and `auto_download_attachments` config options
- Add network permission for storage.googleapis.com (upload destination)
## Problem
`--assignee self` fails with:
```
Could not determine user ID for assignee self
```
## Root Cause
The code in `issue-create.ts` uses `"self"` as the keyword for
auto-assigning to the current user (lines 184, 389, 648), but
`lookupUserId()` only checks for `"@me"`.
When `"self"` is passed, it falls through to the user search query which
looks for a user literally named "self" - which doesn't exist.
## Fix
Add `"self"` as an alias alongside `"@me"` in `lookupUserId()`:
```typescript
if (input === "@me" || input === "self") {
```
Now both `--assignee self` and `--assignee @me` work correctly.
When no LINEAR_API_KEY is set, the config command now uses stored
credentials. Single workspace is auto-selected; multiple workspaces
prompt the user to choose.
Add a warning callout in the setup section noting that `linear auth login` is new and may have issues, with a link to the v1.8.1 README for stable setup instructions.
Add built-in credential storage for managing multiple Linear workspaces:
- ~/.config/linear/credentials.toml stores API keys by workspace slug
- auth login: add credentials (auto-detects workspace from API)
- auth logout: remove credentials
- auth list: show configured workspaces with org/user info
- auth default: set the default workspace
- global -w/--workspace flag to target specific workspace
API key precedence: CLI flag > env var > config > workspace flag > project workspace > default
- Fixes a bug where `--sort` flag was ignored after interactive prompts
(like project selection)
- The sort option was validated in `issue-list.ts` but
`fetchIssuesForState` independently read sort from config only, causing
the CLI flag to be lost