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
| Command | What it does |
|---|---|
| linear-sdk-axi | Live 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 list | Assigned 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 --title | Create. --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 | Comment or reply with --reply-to <comment-id>. --body-file, --dry-run, and --verify allowed |
| linear-sdk-axi label list | Discover 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 list | Projects: 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 list | List action-ready project status IDs, names, and types |
| linear-sdk-axi project create --name | Create 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 list | Read-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 list | Teams: key, name, issue count |
| linear-sdk-axi me | Viewer id, name, email, assigned issue count |
| linear-sdk-axi status | Workflow states for default or --team team (workflow alias) |
| linear-sdk-axi doctor | Verify auth and report read-only workspace/team access |
| linear-sdk-axi auth status/login/finish/logout | Inspect auth, complete PKCE OAuth, or remove saved OAuth credentials |
| linear-sdk-axi setup hooks | Install SessionStart hooks (Claude Code, Codex, OpenCode) |
| linear-sdk-axi --help | Top-level command index |
| linear-sdk-axi -v / -V / --version | Print the installed version (fast path, no API key) |
Global --team
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
intendedversusobservedstate. A read failure or mismatch exits nonzero.--verifyand--dry-runare 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-labelwithout 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-dateor--target-datewithnone. - 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:
- Hooks (live dashboard every session): linear-sdk-axi setup hooks
- 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.