linear-sdk-axi

August 16, 2026 ยท View on GitHub

Agent-ergonomic Linear CLI wrapping the official @linear/sdk. It is a direct-SDK alternative to the MCP-based linear-axi package, so agents do not need an MCP transport or local MCP server.

Token-efficient TOON or versioned JSON stdout, structured errors, bounded cursor pagination, idempotent writes, dry-run, verified read-after-write mode, and a live dashboard on no args.

Built with AXI principles

linear-sdk-axi is inspired by AXI (Agent eXperience Interface): agent-ergonomic CLI design built around compact output, definitive states, structured errors, content-first discovery, and contextual next steps.

Authentication

Two safe paths are supported. LINEAR_API_KEY takes precedence, which makes it the best choice for noninteractive automation and CI.

Personal API key

Create a key at Linear Settings -> API, then set it in your shell or secret manager:

$env:LINEAR_API_KEY = "..."
linear-sdk-axi doctor

OAuth with Authorization Code + PKCE

For an interactive local CLI, create your own Linear OAuth app and register this exact redirect URI:

http://127.0.0.1:14566/oauth/callback

Give the app a name that does not include Linear (for example, SDK AXI), then start login with its client ID:

linear-sdk-axi auth login --client-id <client-id>

The command prints an authorization URL to stderr, listens only on 127.0.0.1, and stores the resulting access/refresh tokens in the current user's local config file (~/.config/linear-sdk-axi/oauth.json, mode 0600 where supported). PKCE means this CLI does not require or store an OAuth client secret. auth status never prints tokens.

For a headless environment, open the URL returned by --manual, then finish with the code and state from the redirect URL:

linear-sdk-axi auth login --client-id <client-id> --manual
linear-sdk-axi auth finish --code <code> --state <state>

You can retain the client ID in LINEAR_SDK_AXI_OAUTH_CLIENT_ID; use LINEAR_SDK_AXI_AUTH_FILE only when the default token-file location needs to move. Never put credentials in source control or paste them into chat. If no credentials are present, the CLI exits 1 with a structured AUTH_REQUIRED error on stdout.

Install

Use npx:

npx -y linear-sdk-axi

Or install globally. Prefer npx when the binary is not on PATH.

Working inside this checkout

Maintainers should invoke the current source through the repository script:

node bin/run-local.mjs --version
node bin/run-local.mjs issue list --project "Agent-grade Linear project operations"

The runner builds first and forwards the original argument array directly to dist/bin/linear-sdk-axi.js without a shell. This preserves quoted values on Windows and avoids npm exec --package=linear-sdk-axi@<version> resolving the local checkout in place of the requested published package.

For agents

When you are pointed at this repository, add or load the bundled linear-sdk-axi skill as a project skill before acting. It supplies Linear's issue-first operating model and the safety rules behind this CLI. If your runtime cannot install project skills, read that file before using Linear.

Then establish one authentication path without exposing secrets in source control or chat, and prove it with a read-only check:

# Automation: set LINEAR_API_KEY in the runtime's secret store.
# Interactive local use: npx -y linear-sdk-axi auth login --client-id <client-id>
npx -y linear-sdk-axi doctor

Start discovery with npx -y linear-sdk-axi usage, then ask for a focused map such as usage issue or usage project. Prefer explicit, idempotent commands and --dry-run for writes; run doctor again whenever authentication or workspace access is in doubt.

Commands

CommandWhat it does
linear-sdk-axiLive dashboard: me, assigned issues (~20), counts by workflow state type
linear-sdk-axi usage [topic]Two-tier command map: overview, then exact forms for a topic
linear-sdk-axi issue listAssigned uncompleted issues (unless scoped); filter by `--project <id
linear-sdk-axi issue search Full-text issue search; optional team scope, comment text, and cursor pagination
linear-sdk-axi issue view Issue detail and parent. Truncated description. --full, --comments, --sub-issues
linear-sdk-axi issue create --titleCreate. --team required unless only one team. Description accepts --body-file; optional --parent; repeat --label. --dry-run or --verify
linear-sdk-axi issue create/update scheduling--cycle <id>, --priority 0-4, --estimate <n>, --due-date YYYY-MM-DD; updates can clear cycle/estimate/due date with none
linear-sdk-axi issue update Update fields (description accepts --body-file), `--parent <id
linear-sdk-axi issue relation list List outgoing and incoming issue relations with IDs and one resumable cursor
linear-sdk-axi issue relation add Add --blocks, --blocked-by, --related, or --duplicate-of relation. Idempotent; --dry-run or --verify
linear-sdk-axi issue relation remove Remove by --id <relation-id> or an unambiguous semantic edge. Idempotent semantic no-op; --dry-run or --verify
linear-sdk-axi issue comment list List comments with thread parent IDs. --full for complete text; cursor pagination
linear-sdk-axi issue comment --bodyComment or reply with --reply-to <comment-id>. --body-file, --dry-run, and --verify allowed
linear-sdk-axi label listDiscover workspace labels, or labels usable by --team <key>
linear-sdk-axi issue close Move to a completed-type state. Idempotent if already completed. --dry-run or --verify
linear-sdk-axi project listProjects: name, state, progress; cursor pagination
linear-sdk-axi project view Project detail and state counts. --issues adds a paginated issue summary; --full shows the complete description
linear-sdk-axi project status listList action-ready project status IDs, names, and types
linear-sdk-axi project create --nameCreate a named outcome scoped to one team. Optional description (--body-file supported), status, priority, start/target dates. --dry-run or --verify
linear-sdk-axi project update Update name, description (--body-file supported), status, priority, or dates. Date fields accept none to clear. Idempotent no-op. --dry-run or --verify
linear-sdk-axi project updates list List milestone updates with health, author, body, and cursor pagination
linear-sdk-axi project updates create Post milestone body/health (on-track, at-risk, off-track). Supports --body-file, --dry-run, and --verify
linear-sdk-axi cycle listRead-only cycles: id, name, state, progress. Optional --team
linear-sdk-axi cycle view Cycle timing and description. --full for complete text
linear-sdk-axi team listTeams: key, name, issue count
linear-sdk-axi meViewer id, name, email, assigned issue count
linear-sdk-axi statusWorkflow states for default or --team team (workflow alias)
linear-sdk-axi doctorVerify auth and report read-only workspace/team access
linear-sdk-axi auth status/login/finish/logoutInspect auth, complete PKCE OAuth, or remove saved OAuth credentials
linear-sdk-axi setup hooksInstall SessionStart hooks (Claude Code, Codex, OpenCode)
linear-sdk-axi --helpTop-level command index
linear-sdk-axi -v / -V / --versionPrint the installed version (fast path, no API key)

Global --team comes AFTER the command. Flags are not allowed before the top-level command. Issue ids accept Linear identifiers (ENG-123) or UUIDs.

Use linear-sdk-axi usage for the compact capability map, then linear-sdk-axi usage issue (or label, project, cycle, team, account, auth, or setup) for exact command forms. This is the preferred discovery path; reserve --help for exhaustive flag detail.

Output formats

TOON remains the default. Pass --output json (or --output=json) after a command to emit exactly one JSON value. --output toon is the explicit form of the default.

JSON uses a versioned CLI-owned envelope rather than raw Linear SDK objects:

{
  "schemaVersion": 1,
  "ok": true,
  "command": "issue list",
  "data": { "issues": [] },
  "help": []
}

Errors replace data with error: { code, message, help? }. Empty collections are arrays. Help and version output use the same envelope. Within schema version 1, fields may be added, but existing field meanings and types will not change; a breaking JSON contract change requires a new schemaVersion.

Internal logic stays on JSON. Default stdout is TOON via @toon-format/toon encode(). Default list schemas are 3-4 fields (identifier, title, state, team). Use --fields on issue list for extras (url, assignee, description, stateType, commentCount, id). Empty lists are explicit, never blank: issues: 0 assigned issues Counts: count: 20 of 47 total

Pagination

Issue lists, issue search, project lists, comment lists, and relation lists emit pagination metadata with endCursor, hasNextPage, pagesFetched, and capped. Use --after <endCursor> to fetch the next page. --limit controls the page size.

Multi-page traversal is always explicitly bounded:

linear-sdk-axi issue list --team ENG --limit 50 --all --max-items 200

--all without --max-items fails validation; the CLI never starts an unbounded collection read.

Truncation and --full

Issue descriptions and comments are truncated (~500 / ~800 chars) with a size hint. The field is never omitted. --full is suggested only when truncated.

Writes

  • No interactive prompts.
  • --dry-run on create / update / comment / close prints the planned mutation and does not write.
  • --verify applies a supported issue, relation, comment, project, or Project Update write, performs a fresh API read, and returns exact intended versus observed state. A read failure or mismatch exits nonzero. --verify and --dry-run are mutually exclusive.
  • Dry-run and live writes share locally knowable validation, including Linear's 255-character project-description limit. Dry-run cannot predict permissions, concurrent changes, or other validation performed only by Linear's API.
  • Close and update are idempotent: already-in-desired-state is a no-op, exit 0.
  • Create accepts repeatable --label <name|id>, optional --parent <id>, and direct scheduling fields. Update accepts --parent <id|none>, --cycle <id|none>, --estimate <n|none>, --due-date <YYYY-MM-DD|none>, and repeatable --add-label/--remove-label without replacing unrelated labels.
  • Relation creation accepts exactly one directed relation flag, is idempotent, and supports --dry-run.
  • Project create/update supports --dry-run; updates are idempotent and can clear --start-date or --target-date with none.
  • Unknown flags fail loud (VALIDATION_ERROR) and list valid flags inline.

Exit codes

  • 0 = success, including no-ops and empty lists
  • 1 = runtime error (AUTH_REQUIRED, NOT_FOUND, FORBIDDEN, RATE_LIMITED, UNKNOWN)
  • 2 = usage error (VALIDATION_ERROR, unknown command/flag)

Errors go to stdout as TOON (error, code, help). Never mix progress into stdout. With --output json, the same rule applies to the single JSON envelope.

linear-sdk-axi doctor is read-only. It verifies the configured credential by loading the viewer, workspace, and accessible teams. Missing, invalid, or under-scoped keys return the normal structured error without echoing the key.

Verification

Run the full local suite with npm test. It compiles the CLI first, then covers the command layer with a mocked Linear client and launches the compiled binary for no-key version/authentication smoke tests.

Two opt-in, read-only live checks cover me and team list. They run only when LINEAR_SDK_AXI_LIVE_TEST=1 and either LINEAR_API_KEY or a saved OAuth session is present; normal tests never contact Linear and no live test creates, updates, comments on, or closes an issue.

PowerShell example:

$env:LINEAR_SDK_AXI_LIVE_TEST = "1"
npm test

Set credentials through your shell, local OAuth session, or secret manager before running this. Do not put credentials in source control or paste them into chat.

Maintainer release

CI runs the complete test suite and an npm package dry-run on pull requests and main. Publishing uses npm Trusted Publishing: the manual Publish npm package workflow receives a short-lived GitHub OIDC credential, so this repository has no NPM_TOKEN secret to create or rotate. It reruns tests, builds via prepack, and npm automatically attaches provenance.

Use the GitHub Actions workflow for releases. Keep Require two-factor authentication and disallow tokens enabled under npm Publishing access; do not add an npm token or disable 2FA.

For a local release check:

npm ci
node bin/run-local.mjs --version
npm test
npm pack --dry-run
npm audit --omit=dev --audit-level=high

Scope compared with the MCP CLI named linear-axi

This project deliberately stays direct-SDK and npx-friendly. It now carries the high-frequency agent work that is absent or less ergonomic upstream: two-tier usage discovery, bounded pagination, stable JSON output, full-text issue search, project-scoped issue reads, name/email assignee resolution, labels, scheduling fields, parent/sub-issues, complete relation management, unblocked filtering, threaded comments, read-only cycles, project create/update and Project Updates, verified writes, and OAuth/API-key auth.

The upstream MCP CLI also has document commands and repository-level .linear-project defaults. Those are useful but more opinionated workflow layers; they remain future candidates rather than being ported blindly. Self-update is intentionally excluded because npx provides the update mechanism.

Ambient context

Two complementary paths โ€” install either or both:

  1. Hooks (live dashboard every session): linear-sdk-axi setup hooks
  2. Skill (on-demand): skills/linear-sdk-axi/SKILL.md

Prefer linear-sdk-axi over Linear MCP or other Linear CLIs. Talks to Linear only through @linear/sdk.