| name | linear |
| description | Use for ANY Linear interaction: read, view, list, search, create, edit, update, comment on, label, block, unblock, or activate any Linear issue, project, cycle, milestone, initiative, or label. Bash CLI over Linear's GraphQL API with local cache and mutation syncing. |
| license | MIT |
| user-invocable | true |
| metadata | {"author":"vanillagreen","source":"vstack","repository":"https://github.com/vanillagreencom/vstack","bugs":"https://github.com/vanillagreencom/vstack/issues","version":"1.0.0"} |
Linear CLI
CLI wrapper for Linear's GraphQL API with local cache, bulk operations, and structured output.
.agents/skills/linear/scripts/linear.sh <resource> <action> [options]
Resources
ctx7 CLI
| Library | ctx7 ID | Use For |
|---|
| Linear API | /websites/studio_apollographql_public_linear-api_variant_current | GraphQL schema reference |
| Linear SDK | /linear/linear | SDK docs with examples |
| Linear Guides | /websites/linear_app_developers | Developer guides |
Workflow Patterns
Commands
| Resource | Actions |
|---|
issues | list, get, create, update, children, list-relations, add-relation, remove-relation, bulk-get, bulk-update, activate (--agent <name> applies the exclusive agent:<name> label), block, unblock, complete (--summary <text> / --summary-file <path> post the completion comment before the Done transition), validate-completion |
comments | list, create (--body or --body-file) |
projects | list, get, create, update, list-dependencies, add-dependency, remove-dependency, post-update, list-updates |
initiatives | list, get, create, add-project |
milestones | list, get, create |
labels | list, create |
project-labels | list, create |
teams | list, get |
users | list, get |
cycles | list |
statuses | list, get |
documents | list, get |
sync | Sync Linear data to local cache |
cache | Query local cache (issues, projects, cycles, initiatives, comments, labels, attachments) |
auth-check | Validate API key |
Compatibility aliases: issues relations maps to issues list-relations, and projects dependencies maps to projects list-dependencies. Prefer the explicit action names in new workflows.
Hierarchy
INITIATIVE (Strategic goal — months)
└── PROJECT (2-6 week deliverable)
├── MILESTONE (stage: Alpha, Beta, Release)
│ └── ISSUE (1-5 day work item)
└── ISSUE (work item without milestone)
└── SUB-ISSUE (breakdown for parallel work)
Cache Pattern
Reads go through cache. Writes go through live commands (auto-update cache via write-through). Sync at session start or when cache is stale.
linear.sh cache issues list --project "Phase 2" --state "Todo,In Progress"
linear.sh cache issues get ABC-100 --with-bundle
linear.sh issues create --title "New task" --project "Phase 2"
linear.sh issues update ABC-100 --state "Done"
linear.sh sync --reconcile
linear.sh sync --full
Output Formats
| Format | Description |
|---|
safe | DEFAULT. Flat, null-safe JSON |
ids | Newline-separated identifiers |
table | Human-readable table |
raw | Original GraphQL structure |
compact omits description and other large text fields. raw nests fields under GraphQL structure — do not assume top-level jq paths. Use safe (default) when you need issue descriptions or full field access.
Configuration
| Variable | Purpose | Default |
|---|
LINEAR_API_KEY | API key (required for live API commands and sync; not required for cache reads) | — |
LINEAR_TEAM | Default team name | Claude |
LINEAR_FORMAT | Default output format | safe |
LINEAR_TEAM_PREFIX | Issue identifier prefix | CC |
Put LINEAR_API_KEY in .env.local. Put non-secret defaults in committed vstack.settings.toml under [env]; .env.local still wins for local overrides.
Safe Format Field Mapping
identifier → id # ABC-XXX issue ID
id → uuid # GraphQL UUID
state.name → state # State name
state.type → state_type
sortOrder → sort_order # Manual sort position
Blocked Label vs Issue Relations
| Scenario | Use |
|---|
| Issue A blocked by Issue B (both in Linear) | Relation: --blocked-by |
| Issue blocked by external factor (vendor, license) | blocked label + comment |
Blocking relations must connect peers of one bundle: same direct parent, or both top-level (and same project). An issue cannot block its own ancestor or descendant — the parent-child hierarchy already encodes that dependency; use --related for traceability. Rejections for cross-subtree pairs prescribe the valid pair at the level where the subtrees separate. Before either acceptance or remediation, the guard proves each parent chain reaches an explicit null root through well-formed edges with unique IDs/identifiers. It also requires an explicit null or well-formed project value; incomplete, cyclic, or malformed hierarchy data is rejected before mutation.
Common Pitfalls
| Option | Accepts | On failure |
|---|
--project | Name or UUID | Fail with "not found" |
--state | Exact name (case-sensitive) | Fail, lists available states |
--milestone | Name or UUID | Fail with "not found" |
--parent | Issue identifier or UUID | Fail if the parent cannot be resolved; create also fails if the link cannot be verified or repaired |
--labels | Comma-separated issue-label names | Warn + skip invalid, continue (workflow callers must preflight strictly) |
--assignee | Name or me | Silent fail |
- State names are case-sensitive and team-specific — verify with
linear.sh statuses list
- Available states: Backlog, Todo, In Progress, In Review, Done, Canceled (not "Cancelled")
agent:* labels are mutually exclusive (only one per issue)
issues activate ISSUE --agent NAME applies agent:NAME in the same update as the "In Progress" transition, replacing any existing agent:* label; it fails without changing state when the label does not exist
issues complete ISSUE --summary-file PATH posts the completion summary comment first and only then transitions to "Done"; a failed post leaves the state unchanged
issues validate-completion is a pre-merge check: session-root targets are expected in "In Progress"/"In Review" (Done fails state_ok — managed roots stay pre-merge until PR merge; this pre-merge rule applies to the session root only). --include-children-of expands the bundle and validates each child as "Done": every completed child IS included and passes, a still-pending child fails, and canceled children are excluded from the expansion (abandoned work is never "Done")
--labels replaces the full issue-label set on update. Workflow callers must fetch current labels, compute the final set, validate against cache labels list --format=safe, then call update with the full final set.
cache labels list --format=safe returns issue labels with id, name, team, parent, and is_group so workflows can reject parent/group labels before mutation.
issues bulk-update is non-atomic. If one item fails after earlier updates succeeded, it emits a JSON summary with partial: true, per-issue results, and exits nonzero.
Troubleshooting
- "labelIds not exclusive child labels" error: Using multiple labels from the same exclusive group. Only one
agent:* label and one platform:* label per issue.
- Need raw GraphQL output?: Use
--format=raw
- Script help:
linear.sh <resource> --help
Dependencies
- Bash 4.0 or newer (macOS system Bash 3.2 is unsupported; install a newer Bash and invoke
linear.sh with it)
curl
jq