A fast, no-nonsense CLI for Linear. Manage issues, cycles, and teams without leaving your terminal.
Built in Go. Works with personal API keys. Plays nice with scripts.
brew install duailibe/tap/linear-cliOr with Go:
go install github.com/duailibe/linear-cli/cmd/linear@latestOr clone and build:
git clone https://github.com/duailibe/linear-cli
cd linear-cli
make buildThe binary is written to bin/linear by default.
The CLI looks for credentials in this order:
--api-keyLINEAR_API_KEY- Stored credentials from
linear auth login
Recommended: export an environment variable in your shell profile:
export LINEAR_API_KEY=lin_api_...Or store it locally:
linear auth loginCheck which API key source is configured (use whoami to verify):
linear auth status
linear whoamiCredentials are stored at ~/.local/share/linear/auth.json (respects $XDG_DATA_HOME).
linear issue list List and filter issues
linear issue view View issue details, comments, and uploads
linear issue create Create new issues
linear issue update Update existing issues
linear issue close Close an issue
linear issue reopen Reopen a closed issue
linear issue comment Add comments
linear issue uploads Download uploads
linear cycle list List team cycles
linear cycle view View cycle details
linear team list List teams
linear auth login Store API key
linear auth status Show API key configuration
linear auth logout Remove stored credentials
linear whoami Show current user
List issues in the current cycle:
linear issue list --team ENG --cycle currentCreate an issue with dependencies:
linear issue create --team ENG --title "Ship new auth" \
--priority 2 --blocked-by ENG-101 --blocks ENG-220Pipe a description from a file:
cat spec.md | linear issue create --team ENG --title "New feature" --description -Add a quick comment:
linear issue comment ENG-123 --body "Fixed in latest deploy"Download uploads from an issue:
linear issue uploads ENG-456 --dir ./downloadsGet JSON output for scripting:
linear issue list --team ENG --json | jq '.nodes[].identifier'Issue references are passed to the issue(id: ...) GraphQL query. In most
workspaces this accepts either the issue ID or the issue identifier (for example
ENG-123). If you see "not found" errors, use the canonical ID from --json
output.
--json Output JSON instead of tables
--no-color Disable colored output
--quiet, -q Suppress non-essential output
--verbose, -v Enable verbose diagnostics
--no-input Disable interactive prompts
--yes, -y Auto-confirm prompts
--timeout API request timeout (default 10s)
--api-key API key (overrides env/stored auth)
--version Print version and exit
Notes:
--no-inputis enforced inlinear auth login; you must pass--api-keywhen it is set.--no-color,--quiet,--verbose, and--yesare currently accepted for forward compatibility, but not all commands change behavior yet.
Store a Linear API key in the local auth file.
- Reads the key from
--api-keyif provided. - Otherwise prompts on stdin (unless
--no-inputis set).
linear auth login
linear auth login --api-key "$LINEAR_API_KEY"Show whether an API key is configured and report its source.
This does not verify the key; use linear whoami to validate access.
linear auth statusRemove the stored API key.
linear auth logoutPrint the authenticated Linear user (verifies API key access).
linear whoamiList teams you have access to.
linear team listList cycles for a team.
--team Team key or ID (required)
--current Only show current/active cycles
--limit Maximum number of cycles to fetch (default 20)
--after Pagination cursor
linear cycle list --team ENG --currentView a cycle by ID.
linear cycle view <cycle-id>List issues with filters.
--team Team key or ID
--assignee Assignee (me, id, or email)
--state Workflow state name or ID
--label Comma-separated label names or IDs
--project Project name or ID
--cycle Cycle ID or 'current'
--search Search issue titles
--priority Priority (0-4)
--limit Maximum number of issues (default 50)
--after Pagination cursor
Notes:
--staterequires--teamwhen using state names. If you pass a state ID,--teamcan be omitted.--cycle currentrequires--team.
linear issue list --team ENG --cycle current --assignee meView issue details.
Argument:
<issue-id> Issue ID or identifier
Flags:
--comments Include comments
--comments-limit Maximum number of comments (default 20)
--uploads Include uploads
--uploads-limit Maximum number of uploads/comments to scan (default 50)
linear issue view ENG-123 --commentsCreate a new issue.
--team Team key or ID (required)
--title Issue title (required)
--description Issue description or '-' for stdin
--assignee Assignee (me, id, or email)
--state Workflow state name or ID
--priority Priority (0-4)
--project Project name or ID
--cycle Cycle ID or 'current'
--labels Comma-separated label names or IDs
--blocks Comma-separated issue IDs or keys this issue blocks
--blocked-by Comma-separated issue IDs or keys blocking this issue
linear issue create --team ENG --title "Bug in auth" --priority 1Update an existing issue.
<issue-id> Issue ID or identifier
--team Team key or ID
--title Issue title
--description Issue description or '-' for stdin
--assignee Assignee (me, id, or email)
--state Workflow state name or ID
--priority Priority (0-4)
--project Project name or ID
--cycle Cycle ID or 'current'
--labels Comma-separated label names or IDs
--blocks Comma-separated issue IDs or keys this issue blocks
--blocked-by Comma-separated issue IDs or keys blocking this issue
--remove-blocks Comma-separated issue IDs or keys to remove from blocks
--remove-blocked-by Comma-separated issue IDs or keys to remove from blocked-by
Notes:
- If you set
--stateor--cyclewithout--team, the CLI fetches the issue to determine the team before resolving names.
linear issue update ENG-123 --state "In Progress"Set the issue to the workflow state of type completed.
linear issue close ENG-123Set the issue to the workflow state of type unstarted.
linear issue reopen ENG-123Add a comment to an issue.
<issue-id> Issue ID or identifier
--body Comment body or '-' for stdin
linear issue comment ENG-123 --body "Working on this"Download uploads from the issue description and comments (uploads.linear.app only).
<issue-id> Issue ID or identifier
--dir Directory to save uploads (default "uploads")
--limit Maximum number of comments to scan (default 50)
--overwrite Overwrite existing files
linear issue uploads ENG-123 --dir ./downloadsThe CLI looks for credentials in this order:
--api-keyLINEAR_API_KEY- Stored credentials from
linear auth login
Stored credentials live in:
$XDG_DATA_HOME/linear/auth.jsonwhen XDG_DATA_HOME is set~/.local/share/linear/auth.jsonotherwise
The file is created with restrictive permissions.
The --timeout flag accepts Go duration strings (for example 10s, 1m, 1m30s).
linear --timeout 30s issue list --team ENG--no-input disables prompts. For linear auth login, this means you must pass
--api-key explicitly or the command fails.
By default, commands render human-readable tables to stdout. Pass --json to
return JSON suitable for scripts.
linear issue list --team ENG --json | jq '.nodes[].identifier'
linear issue view ENG-123 --json | jq '{id, title, state}'The default table output includes these columns:
linear issue list: ID, Title, State, Assignee, Team, Cyclelinear issue view: ID, Title, State, Assignee, Team, Cycle, Project, Prioritylinear issue create/update/close/reopen: ID, Title, URLlinear issue comment: prints a confirmation line with the new comment IDlinear issue uploads: ID, Title, Pathlinear cycle list/view: ID, Name, Number, Starts, Ends, Activelinear team list: ID, Key, Namelinear whoami: ID, Name, Email
linear issue view prints additional lines for URL, labels, description, timestamps,
comments (when --comments is provided), and uploads (when --uploads is provided).
The JSON output mirrors the internal types in internal/linear/types.go. Common
shapes include:
IssuePage:{ nodes: [IssueSummary], page_info: { has_next_page, end_cursor } }CyclePage:{ nodes: [Cycle], page_info: { has_next_page, end_cursor } }IssueDetail: detailed issue fields plus optionalcommentsanduploadsUser,Team, andCycleobjects with straightforward scalar fieldsIssueCommentcreation returns{ id: "..." }
Errors are printed to stderr and return non-zero exit codes. The most common codes are:
0: success1: general error2: usage error (invalid flags, missing required inputs)3: authentication error (missing/invalid API key)4: not found5: rate limited or temporarily unavailable
Use these codes when scripting the CLI in CI or automation.
Code-focused documentation lives in docs/:
docs/README.mddocs/architecture.mddocs/development.md
This repo includes a SKILL file for AI coding agents. Install it with:
npx add-skill duailibe/linear-cligo test ./...Smoke tests run the CLI against a playground workspace. Each run creates a new issue and updates it to validate the update flow.
Required environment variables:
LINEAR_API_KEY(playground API key)LINEAR_SMOKE_TEAM(team key, for exampleDUA)
Optional environment variables:
Run:
scripts/smoke_test.shMIT