Skip to content

Latest commit

 

History

152 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Linear Command line interface (Elixir)

A command line interface to https://linear.app - list, take, create, develop, and update issues without leaving your terminal.

listings.cinema

This is an Elixir/OTP port of linear-cli-rb (the original Ruby CLI): same commands, same wrapper scripts (lcls, lcreate, …​), but shipped as a single standalone binary - no Ruby runtime or gem install - via Burrito, and real concurrency (Task.async_stream) for operations that touch several issues at once. Looking up 10 issues by id, for example, runs in ~1.5s here vs ~5s doing it one at a time.

Installation

I don’t want to install

You can run the CLI from the container image without installing anything.

$ podman run --rm -e LINEAR_CLI_DAEMON= -e LINEAR_API_KEY="$LINEAR_API_KEY" ghcr.io/rubyists/linear-cli:v2 lcls (1)
$ docker run --rm -e LINEAR_CLI_DAEMON= -e LINEAR_API_KEY="$LINEAR_API_KEY" ghcr.io/rubyists/linear-cli:v2 lcls (2)
  1. Podman usage

  2. Docker usage - :v1 tracks the latest 1.x release series; pin :v1.13.2 (or whichever version) for a fixed image

The image sets LINEAR_CLI_DAEMON=true by default so its own entrypoint can also run as the long-lived Oban scheduling daemon. Override it to an empty value (as above) for one-off interactive CLI usage - otherwise lc/the wrapper scripts never see your command at all.

Download a release binary (Most should use this)

Grab the tarball for your platform from the latest release - macOS (Apple Silicon), Linux (x86_64), and Windows (x86_64) are all built as standalone executables with no Erlang/Elixir install required. Each tarball bundles lc with the wrapper scripts (lcreate, lcls, lclose, lcomment, lproj).

$ curl --retry 5 --retry-all-errors -sLO https://github.com/rubyists/linear-cli/releases/latest/download/lc_macos_aarch64.tar.gz
$ curl --retry 5 --retry-all-errors -sLo SHA256SUMS https://github.com/rubyists/linear-cli/releases/latest/download/SHA256SUMS
$ grep -q lc_macos_aarch64.tar.gz SHA256SUMS && grep lc_macos_aarch64.tar.gz SHA256SUMS | shasum -a 256 -c - (1)
$ mkdir lc && tar -xzf lc_macos_aarch64.tar.gz -C lc
$ sudo mv lc/* /usr/local/bin/
  1. Linux: sha256sum -c - instead of shasum -a 256 -c -.

Every release also publishes sbom.cdx.json - a CycloneDX SBOM covering the app, its Hex dependencies, and the Erlang/OTP and Elixir versions it was built with. The container image has its own separate SBOM (its OS packages - irrelevant if you’re not using the container), published as a workflow artifact on the release’s build rather than a release asset.

On macOS, Gatekeeper blocks lc itself (the wrapper scripts are plain shell, so they’re unaffected) since it isn’t signed/notarized yet:

$ xattr -d com.apple.quarantine /usr/local/bin/lc

Homebrew (macOS Apple Silicon, Linux x86_64, Linux ARM64)

$ brew tap rubyists/tap
$ brew install lc

See https://github.com/rubyists/homebrew-tap for the formula itself.

install.sh (fetches a release binary, for machines without Homebrew)

$ curl --retry 5 --retry-all-errors -fsSL https://raw.githubusercontent.com/rubyists/linear-cli/main/install.sh | bash

Detects your platform, downloads and checksum-verifies the matching release tarball (the same one the "Download a release binary" section above uses), and installs lc plus the bin/ wrapper scripts onto a directory already on your $PATH - no Erlang/Elixir/Zig toolchain required. LC_VERSION pins a specific release tag instead of the latest one; LC_INSTALL_DIR pins a specific install directory.

$ curl --retry 5 --retry-all-errors -fsSL https://raw.githubusercontent.com/rubyists/linear-cli/main/uninstall.sh | bash

Removes exactly what install.sh installed, by replaying the manifest it wrote - not a guess at where things ended up.

From Source (You are obviously a developer)

$ git clone https://github.com/rubyists/linear-cli.git
$ cd linear-cli/app
$ mise install
$ mise exec -- mix deps.get
$ mise exec -- env MIX_ENV=prod mix release lc
$ ./burrito_out/lc_<target> --version

Usage

Configuration

You must set the LINEAR_API_KEY environment variable to your Linear API key. You can find your API key in your Linear Settings.

Commands

Command Aliases

Short aliases are available for the top-level commands and some subcommands, so you don’t have to type the full name every time:

Command Aliases

whoami

me, w, who, whodat

version

v

issue

i, issues

team

t, teams

project

p, projects

issue create

c, new, add

issue develop

d, dev

issue list

l, ls

issue status

s, st, stat

issue assign

a

issue move

m, mv

issue update

u

issue pr

pull-request

team list

l, ls

project list

l, ls

$ lc w --teams
$ lc i ls
$ lc i dev CRY-1234

issue take has no alias.

Help

You can get help/usage for any command or subcommand by using the --help flag.

$ lc --help
$ lc [COMMAND] --help
$ lc [COMMAND] [SUBCOMMAND] --help

Who Am I?

$ lc whoami
$ lc whoami --teams (1)
  1. Include the teams you are a member of

List Issues

lcls is a wrapper script provided to list issues. It’s an alias for lc issue list.

$ lcls
$ lcls --full
$ lcls -f CRY-1
$ lcls -N (1)
$ lcls --state started (2)
$ lcls --status "Human Review" (3)
$ lcls --state started --status "Human Review,Gate Approved" (4)
  1. Include issues not assigned to you (short for --no-mine)

  2. Filter by Linear’s internal workflow state type

  3. Filter by a friendly workflow status name (case-insensitive)

  4. Combine state and status filters; both must match

Assign one or more issues to yourself (take em!)

$ lc issue take CRY-1234
$ lc issue take CRY-456 CRY-789
$ lc issue take CRY-1234 --status "In Progress" (1)
$ lc issue take CRY-1234 -s Todo (2)
  1. Self-assign and move to the named workflow state in one update

  2. Short form of --status

Assign an issue to a team member

$ lc issue assign CRY-1234 --assignee alice (1)
$ lc issue assign CRY-1234 -a alice --status "In Progress" (2)
$ lc issue assign CRY-1234 -a alice -s Todo (3)
$ lc issue assign CRY-1234 (4)
  1. Assign to a team member by name (case-insensitive, prefix match)

  2. Assign and move to the named workflow state in one update

  3. Short form of --status

  4. Prompts for the assignee interactively

Create an issue

$ lc issue create --title "My new issue" --description "This is a new issue" --labels Bug,Feature --team CRY
$ lc issue create -t "My new issue" -T CRY -l Improvement,Feature
ℹ️
If you don’t provide a title, team, labels, or description, you will be prompted to enter them.
💡
When creating an issue, you can use the --dev (or --develop) option to immediately start development on the issue.

Develop an issue

Switches to the branch for the issue, creating the branch if it doesn’t exist.

$ lc issue develop CRY-1234
Create a Pull Request (using the semantic PR title)

Requires the gh CLI to be installed and configured.

$ lc issue pr CRY-1234

Update an issue

All of the update options can work on multiple issues at a time.

Add a comment to one or more issues
$ lc issue update --comment "Here is a comment" CRY-1234 (1)
$ lc issue update --close --status Done --reason "I do not like you" CRY-14 CRY-15 (2)
$ lc issue update --cancel --status Cancelled --trash --reason "I have no idea why you are here" CRY-16 CRY-17 (3)
$ lc issue update --comment - CRY-14 CRY-15 (4)
$ lcomment CRY-1234 CRY-3 (5)
  1. Comments on the issue with the provided text

  2. Closes multiple issues without prompting (reason is added as a comment)

  3. Cancels multiple issues without prompting and moves them to the trash (reason is added as a comment)

  4. Opens your editor for the comment (use - to prompt)

  5. Always prompts for a comment (lcomment is a wrapper for lc issue update --comment -)

Close one or many issues

Use --status/-s to choose the completed or cancelled workflow state by case-insensitive name or unique prefix. Omit it to select interactively when the team has more than one matching state.

$ lc issue update --close --status Done --reason "These were closable" CRY-1234 CRY-2

Move an issue to a different workflow state

Changes the workflow state of one or more issues. Prompts interactively when --status/-s is omitted.

$ lc issue status CRY-1234 (1)
$ lc issue status CRY-1234 -s "In Progress" (2)
$ lc issue status CRY-1 CRY-2 CRY-3 -s Done (3)
$ lc issue status CRY-1234 -s Done -m "Wrapped up" (4)
  1. Prompts interactively to pick a state

  2. Move to a named workflow state (case-insensitive, unique-prefix match)

  3. Move multiple issues at once — updates run concurrently

  4. Add a comment alongside the state change

Move issues to a project

Two modes: move specific issues by ID, or bulk-move an entire project’s backlog.

By ID — moves the listed issues to a target project:

$ lc issue move --project Manhattan CRY-1 (1)
$ lc issue move -p Manhattan CRY-1 CRY-2 CRY-3 (2)
$ lc issue move --project Manhattan --dry-run CRY-1 (3)
$ lc issue move --project Manhattan --yes CRY-1 (4)
$ lc issue move --project Manhattan --team ENG CRY-1 (5)
  1. Move a single issue; prompts for confirmation before executing

  2. Move multiple issues at once — updates run concurrently

  3. Preview the planned moves without executing any mutations

  4. Skip the confirmation prompt

  5. Scope project search to the ENG team

Bulk project-to-project (--from/--to) — moves all open issues from one project to another. Useful for retiring a project or consolidating backlogs. Issues keep their original team.

$ lc issue move --from Retired --to Active (1)
$ lc issue move --from Retired --to Active --all (2)
$ lc issue move --from p-uuid-1 --to p-uuid-2 (3)
$ lc issue move --from Retired --to Active --dry-run (4)
  1. Moves all open issues from "Retired" to "Active", prompts for confirmation

  2. Includes completed and cancelled issues too

  3. Move by project UUID — the way to target a project in another team

  4. Preview without mutating

Default team/project (profiles)

Not in Ruby’s linear-cli - save a named team/project bundle once, then switch to it instead of passing --team/--project on every issue create/issue list.

$ lc profile create manhattan --team CRY --project Manhattan
$ lc profile use manhattan
$ lc profile list
$ lc profile show
$ lc profile delete manhattan

An explicit --team/--project on the command line always overrides the active profile.

Issue commands also accept a bare number (lc issue develop 1234) in place of a full team-prefixed identifier - it’s resolved via the active profile’s team, then favorited teams, then a prompt across every team you belong to.

Favorite teams/projects

Not in Ruby’s linear-cli - favorite the teams/projects you actually care about, and once any exist, team list/project list default to showing just favorites of that kind. --all bypasses the favorites filter only - it doesn’t change team list’s `--no-mine or project list’s `--mine/--team scope, it just shows everything within whatever scope you already asked for.

$ lc team favorite CRY
$ lc team list
$ lc team list --all
$ lc team unfavorite CRY
$ lc project favorite Manhattan
$ lc project list

Post a project status update

Not in Ruby’s linear-cli - a status post on a project (Linear’s own "Project Update" feature), not an edit to the project itself.

$ lc project update Manhattan --body "Shipping ahead of schedule" --health onTrack

Wrapper scripts

The bin/ wrapper scripts (ported verbatim from linear-cli’s own `exe/scripts/) make the common commands shorter to type. They just exec lc …​, so they work anywhere lc is on your $PATH.

$ lcls
$ lcreate --description "This is a new issue" --labels Bug,Feature --team CRY
$ lclose --reason "This issue sucks" CRY-1234 CRY-456
$ lcomment CRY-1234
$ lproj list --mine

Development

First, activate the repo’s git hooks (enforces conventional-commit subjects on every commit, and again on every commit about to be pushed):

$ mix setup

Run the development checkout directly from the repository root with mix lc. It compiles and starts the application as needed, then forwards arguments, interactive input, output, and exit status to the same CLI entry point used by the release binary:

$ mix lc whoami
$ mix lc issue list --output json

The project uses ExUnit and mix format. Run tests with:

$ cd app
$ mise exec -- mix test
$ mise exec -- mix format --check-formatted

Build a release binary

$ cd app
$ mise exec -- env MIX_ENV=prod BURRITO_TARGET=<target> mix release lc

<target> is one of macos_aarch64, linux_x86_64, linux_aarch64, or windows_x86_64.

Build the container

$ ./ci/build_image.sh <tag_name>

Conventional Commits (semantic commit messages)

This project follows the Conventional Commits specification.

To contribute, please follow that commit message format, or your pull request may be rejected.

License

WTFPL

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages