Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linear

A command-line tool for the Linear GraphQL API.

Patterned after an internal request-cli tool: a thin, low-level passthrough as the core primitive (linear graphql ...), with a handful of convenience subcommands layered on top (issue, team, project, viewer).

Building

cargo build --release

The compiled binary will be at target/release/linear.

Installation

# Copies the binary to ~/.local/bin (no sudo required)
target/release/linear configure install

# Or install to a directory of your choice
target/release/linear configure install --path /usr/local/bin

The installed path is recorded in ~/.config/linear-cli/installation so it can be cleanly reversed:

linear configure uninstall

Shell completions

# Bash
linear configure completions bash > ~/.local/share/bash-completion/completions/linear

# Zsh (make sure ~/.zfunc is in your $fpath)
linear configure completions zsh > ~/.zfunc/_linear

# Fish
linear configure completions fish > ~/.config/fish/completions/linear.fish

# PowerShell
linear configure completions powershell | Out-File -Encoding UTF8 linear.ps1

# Elvish
linear configure completions elvish > ~/.elvish/lib/linear.elv

Authentication

Linear personal API keys are used (no OAuth app registration required). Generate one at https://linear.app/settings/account/security, then:

linear auth set --api-key lin_api_xxxxxxxx
# or, to be prompted (input hidden) and verified against the API:
linear auth set

This stores the key in $XDG_CONFIG_HOME/linear-cli/config (typically ~/.config/linear-cli/config):

endpoint=https://api.linear.app/graphql
api_key=lin_api_xxxxxxxx

Personal API keys are sent as-is in the Authorization header (Linear does not use a Bearer prefix for these, unlike OAuth tokens).

Check who you're authenticated as:

linear auth status

Config profiles

Multiple profiles are supported by suffixing the filename with -config:

~/.config/linear-cli/work-config
~/.config/linear-cli/personal-config
linear -c work issue list
linear -c personal issue list

Overrides

  • LINEAR_CLI_CONFIG — profile name or path, same precedence as -c
  • LINEAR_API_KEY / LINEAR_ENDPOINT — override the config file

Usage

Raw GraphQL passthrough

The core primitive. Takes a literal query/mutation string, @path/to/file, or - (stdin):

linear graphql 'query { viewer { id name } }'

linear graphql @query.graphql --variable id=abc123

echo 'query { viewer { id } }' | linear graphql -

linear graphql 'mutation IssueCreate($input: IssueCreateInput!) {
  issueCreate(input: $input) { success issue { identifier url } }
}' --variables-json '{"input":{"teamId":"...","title":"Fix the thing"}}'

Convenience commands

linear viewer

linear team list

linear issue list --team ENG --mine
linear issue view ENG-123
linear issue create --team ENG --title "Fix the thing" --priority 2
linear issue update ENG-123 --state <workflow-state-id>
linear issue comment ENG-123 "Looking into this now."

linear project list
linear project view <project-id>
linear project create --name "Q1 Roadmap" --team-id <team-id>

Global flags

  • -c, --config <PROFILE> — alternate config profile
  • -H, --header <"Key: Value"> — extra request header (repeatable)
  • --dry-run — print the equivalent curl command instead of sending it
  • -v, --verbose — log request/response and rate-limit headers
  • --read-only — refuse to run anything that looks like a mutation
  • --json — compact JSON output instead of pretty-printed/tabular

Schema cache

# Default: pulls the published SDL from github.com/linear/linear (no auth,
# ~1MB, fast).
linear configure fetch-schema

# Live introspection instead. Cheap in rate-limit/complexity terms (it only
# reads the static schema, no business-data resolvers) but the response is
# several MB, so don't run this often.
linear configure fetch-schema --introspect

Cached at $XDG_DATA_HOME/linear-cli/schema.graphql (or schema.json for --introspect).

Agent skill

linear ships with a bundled Agent Skills Markdown file describing how an LLM/agent should use this CLI:

linear configure print-skill > linear-cli/SKILL.md

Drop the output into a skills directory your agent harness reads (e.g. for pi, .pi/skills/linear-cli/SKILL.md or ~/.pi/agent/skills/linear-cli/SKILL.md).

Using it as a library (SDK)

The CLI is a thin wrapper around a reusable library crate (same package, target name linear). Add it as a path/git dependency and use it directly:

[dependencies]
linear = { path = "../linear-cli" }
use linear::client::GraphQLClient;
use linear::config::Config;
use linear::ops;

fn main() -> anyhow::Result<()> {
    let config = Config { api_key: "lin_api_...".into(), ..Config::default() };
    let client = GraphQLClient::new(&config, Vec::new(), false);

    let me = ops::viewer(&client)?;
    println!("Hello, {}", me.name);

    let issues = ops::list_issues(&client, 50, ops::IssueListFilter {
        team_key: Some("ENG".into()),
        mine: true,
    })?;
    for issue in issues {
        println!("{}: {}", issue.identifier, issue.title);
    }

    // Escape hatch: raw GraphQL for anything `ops` doesn't cover, returning
    // serde_json::Value.
    let raw = client.execute("query { viewer { id } }", None)?.into_data()?;
    println!("{raw}");

    Ok(())
}

See examples/sdk_usage.rs for a runnable version (LINEAR_API_KEY=... cargo run --example sdk_usage).

Modules:

  • linear::clientGraphQLClient (raw execute, dry-run curl rendering)
  • linear::configConfig, XDG config/data dir + profile resolution
  • linear::model — typed request/response structs (Issue, Team, Project, Viewer, IssueCreate, IssueUpdate, ProjectCreate, ...)
  • linear::ops — typed operations (viewer, list_issues, get_issue, create_issue, update_issue, comment_issue, list_teams, list_projects, get_project, create_project)
  • linear::schema — fetch/cache the GraphQL SDL or run introspection
  • linear::util — variable parsing, mutation detection, query loading helpers used by the CLI's raw passthrough

Note: the CLI's --dry-run/--read-only guards live in the binary (AppContext), not the library — ops::* functions always execute. If you want similar guards in your own program, check linear::util::is_mutation before calling client.execute, or gate calls to ops::* yourself.

Rate limiting

Linear's API is rate-limited (complexity-based for most queries). -v shows x-ratelimit-* response headers so you can see how much headroom you have.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages