---
name: pp-linear
description: "Offline-capable, agent-native Linear CLI with SQLite-backed sync, FTS5 search, cross-cycle comparison, project... Trigger phrases: `what's on my Linear plate today`, `Linear sprint plan for the team`, `Linear cycle comparison`, `Linear burndown for the project`, `which Linear milestone is at risk`, `stale Linear issues`, `clean up the Linear test tickets I created`, `use linear-pp-cli`, `run linear-pp-cli`."
author: "Matt Van Horn"
license: "Apache-2.0"
argument-hint: "<command> [args] | install cli|mcp"
allowed-tools: "Read Bash"
metadata:
  openclaw:
    requires:
      bins:
        - linear-pp-cli
---
<!-- GENERATED FILE — DO NOT EDIT.
     This file is a verbatim mirror of library/project-management/linear/SKILL.md,
     regenerated post-merge by tools/generate-skills/. Hand-edits here are
     silently overwritten on the next regen. Edit the library/ source instead.
     See the repository agent guide, section "Generated artifacts: registry.json, cli-skills/". -->

# Linear — Printing Press CLI

## Prerequisites: Install the CLI

This skill drives the `linear-pp-cli` binary. **Do not invoke a command named `linear` when this skill is active.** If `linear-pp-cli` is missing, install it first:

1. Install via the Printing Press installer. It defaults binaries to `$HOME/.local/bin` on macOS/Linux and `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows:
   ```bash
   npx -y @mvanhorn/printing-press-library install linear --cli-only
   ```
2. Verify: `linear-pp-cli --version`
3. Ensure the reported install directory is on `$PATH` for the agent/runtime that will invoke this skill.

If the `npx` install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.6 or newer):

```bash
go install github.com/mvanhorn/printing-press-library/library/project-management/linear/cmd/linear-pp-cli@latest
```

If `--version` reports "command not found" after install, the runtime cannot see the binary directory on `$PATH`. Do not proceed with skill commands until verification succeeds.

## Agent Contract

- Add `--agent` to commands unless a human-readable table is explicitly needed. It implies JSON, compact output, non-interactive mode, no color, and confirmation-safe scripting.
- Use `--data-source live` for closeout/state/description checks where current truth matters. Use `issues search` for duplicate checks; it refreshes stale issue search data or fails visibly. Use `--data-source local` or `similar` only when stale/offline local duplicate search is intentional.
- Fields omitted from compact output are not absent from the issue. Request them explicitly, including nested labels: `linear-pp-cli issues ENG-123 --agent --data-source live --select identifier,title,description,state.name,labels.nodes.id,labels.nodes.name,url`.
- Fetch several known issues in one call with comma-separated identifiers: `linear-pp-cli issues ENG-123,ENG-124 --agent`. The result array preserves caller order and removes duplicate identifiers; a missing member fails the whole read instead of returning a partial set.
- Prefer the canonical read and comment forms shown here. Common agent phrasing is accepted without changing behavior: `issues get|view|show ENG-123`, `documents get|view <ref>`, and `comments create` are compatibility aliases for `issues ENG-123`, `documents <ref>`, and `comments add`. The aliases accept the same global flags, comma reads, body files, targets, and media flags as their canonical commands; there is deliberately no `documents show` alias.
- `--label` is UUID-only; `--label-name` resolves an exact label name at write time (team-owned or workspace-global). Before passing UUIDs to `issues create` or `issues edit`, run `linear-pp-cli labels list --team ENG --agent --select id,name,global,team.key`. The CLI preflights ownership and refuses cross-team labels before mutating.
- Never pass multiline Markdown, shell snippets, GraphQL, logs, backticks, `$()` expansions, or media-rich content as inline shell arguments. Write the body to a file or stdin and use the `*-file` / `*-stdin` flags below.

## When to Use This CLI

Reach for this CLI when you need joined queries that span issues, cycles, projects, and milestones — questions Linear's UI answers across multiple tabs and the API answers across multiple round-trips. It's the right pick for agents driving Linear over MCP (the orchestration pair plus named intents covers the full surface in ~1K tokens), for engineering managers preparing Friday updates (cycle comparison, slipped, burndown, blocking queue), and for any agent that must mutate a real workspace under the pp_created fixture-lifecycle contract.

## Unique Capabilities

These capabilities aren't available in any other tool for this API.

### Local state that compounds
- **`today`** — See all of your assigned issues across every team for today, ranked by priority and cycle deadline.

  _Reach for this when an agent or human needs a single ranked work queue across every team, without naming the underlying joins._

  ```bash
  linear-pp-cli today --json --agent
  ```
- **`bottleneck`** — See which team members are overloaded and which issues are blocked before sprint planning.

  _Reach for this in sprint planning when you need to see who is overloaded and where work is stuck in one view._

  ```bash
  linear-pp-cli bottleneck --team ENG --json
  ```
- **`stale`** — Find issues that haven't been touched in N days, grouped by team and project.

  _Reach for this during backlog grooming when you need to surface forgotten issues without exhausting the API rate limit._

  ```bash
  linear-pp-cli stale --days 30 --team ENG --json
  ```
- **`issues search` / `similar`** — Find issues that look like duplicates of a query string using local FTS5 search.

  _Reach for this during triage when you suspect an incoming bug duplicates an existing issue._

  ```bash
  linear-pp-cli issues search "login redirect bug" --limit 5 --agent
  linear-pp-cli issues search "pipeline follow-up" --team SYMPH --limit 10 --agent
  linear-pp-cli similar "login redirect bug" --limit 5 --json
  linear-pp-cli similar "pipeline follow-up" --team SYMPH --limit 10 --agent
  ```

  Prefer `issues search` when checking for existing tickets before creating or updating follow-up work; it is the supported issue-search spelling agents tend to reach for. It coordinates freshness for duplicate checks: fresh local data is searched immediately, stale or empty issue data refreshes behind a cross-process lock before search, and refresh failures return a typed error instead of silently serving stale results. Add `--team <key-name-or-uuid>` when a common project name or label appears across teams and the duplicate check must stay inside the target team's queue. Multi-word `issues search` queries may be quoted or passed as separate words; both forms are joined into one FTS query. Under `--agent` / `--json`, `issues search` returns a provenance envelope with freshness metadata; `similar` keeps the legacy raw result array. Use `--data-source local` only when stale/offline local results are intentional.

### Cross-entity rollups
- **`projects burndown`** — Project a project's landing date by linear-regressing remaining estimate against the team's measured velocity.

  _Reach for this when stakeholders ask when a project will land and the project page only shows a static target date someone typed in months ago._

  ```bash
  linear-pp-cli projects burndown PROJ_ID --weeks 8 --json
  ```
- **`cycles compare`** — Side-by-side metrics between any two cycles: completion %, scope added, scope cut, carryover, average cycle time.

  _Reach for this for cycle retros and Friday updates when you need a numeric diff rather than two browser tabs._

  ```bash
  linear-pp-cli cycles compare 42 43 --json
  ```
- **`slipped`** — Show what carried over from last cycle into this cycle, grouped by team and reason heuristic.

  _Reach for this in Friday stakeholder updates when you need a structured slipped-from-last-cycle list, not just a saved view._

  ```bash
  linear-pp-cli slipped --team ENG --json
  ```
- **`velocity`** — Track sprint completion rates over the last N cycles to spot productivity trends.

  _Reach for this in Monday sprint planning to ground rebalance decisions in actual completion data, not the team's last cycle alone._

  ```bash
  linear-pp-cli velocity --weeks 8 --json
  ```
- **`initiatives health`** — Rolled-up portfolio view per initiative: child project progress, milestone target-vs-projected dates, slippage flags.

  _Reach for this in portfolio reviews when stakeholders want the initiative-level rollup, not seven open project tabs._

  ```bash
  linear-pp-cli initiatives health --json
  ```
- **`milestones at-risk`** — List portfolio milestones whose projected landing date has slipped past their target, ranked by slip magnitude.

  _Reach for this in weekly portfolio review when the question is which milestone is most at risk, not which initiative is healthy._

  ```bash
  linear-pp-cli milestones at-risk --json
  ```

### Personal queues
- **`blocking`** — Show issues you are blocking — sorted by downstream impact (downstream count × downstream priority).

  _Reach for this every morning when you need to know which of your in-flight issues are stalling teammates downstream._

  ```bash
  linear-pp-cli blocking --json
  ```

### Agent-native plumbing
- **`pp-test list`** — List Linear issues this CLI created in the current or named session, then archive them with pp-cleanup.

  _Reach for this when an agent needs to clean up only the tickets it created in a session — the workspace's existing data must not be touched._

  ```bash
  linear-pp-cli pp-test list --json
  ```
- **`issues create --trust-mode strict`** — Refuse mutations on Linear issues not in the local pp_created ledger when --trust-mode strict is set; works on create and any future mutation surface.

  _Reach for this when running an agent against a real workspace with real data — strict mode makes accidental mutation impossible._

  ```bash
  linear-pp-cli issues create --title "Test ticket" --team ENG --trust-mode strict
  ```
- **Parent and sub-issue linking** — Create child issues and set, change, or clear parent links without leaving the CLI for raw GraphQL.

  _Reach for this when an agent is creating issue trees, epics, or follow-up hierarchies and needs parentage wired safely._

  ```bash
  linear-pp-cli issues create --title "Child task" --team ENG --parent ENG-123 --description-file /tmp/body.md --agent
  linear-pp-cli issues edit ENG-124 --parent ENG-123 --agent
  linear-pp-cli issues edit ENG-124 --no-parent --agent
  ```
- **Issue relations** — Read, add, and remove blocks, blocked-by, and related links between issues, each reported from the named issue's side.

  _Reach for this when an agent must record that one issue waits on another, or check what blocks an issue before scheduling it. `add` and `remove` take exactly one of `--blocked-by`, `--blocks`, or `--related`; under `--trust-mode strict` offline `--dry-run` checks both issue references against the `pp_created` ledger; live writes also check both resolved UUIDs._

  ```bash
  linear-pp-cli issues relations add ENG-124 --blocked-by ENG-123 --agent
  linear-pp-cli issues relations list ENG-124 --agent
  linear-pp-cli issues relations remove ENG-124 --blocked-by ENG-123 --agent
  ```
- **Team-safe issue labels** — Discover labels that are valid for the target Linear team, including global labels, then attach them by UUID or exact name.

  _Reach for this before attaching labels. `--label` is UUID-only; use `--label-name` when the input is a human label name. Linear rejects labels owned by another team, and the CLI preflights ownership before mutating._

  ```bash
  linear-pp-cli labels list --team ENG --agent --select id,name,global,team.key
  linear-pp-cli issues create --title "Title" --team ENG --label <global-or-eng-label-id> --agent
  linear-pp-cli issues create --title "Title" --team ENG --label-name "kind:bug" --label-name "source:user-report" --agent
  linear-pp-cli issues edit ENG-123 --label-name "area:review-tooling" --dry-run --agent
  linear-pp-cli issues edit ENG-123 --label-name "area:review-tooling" --agent
  ```

  `--label-name` always performs a live Linear read to resolve the UUID, even when the surrounding issue write is a dry-run. Writes require a normalized exact label-name match. Team-owned labels and workspace-global labels (no team) both resolve; labels owned by another team do not. `--label` and `--label-name` can be combined; resolved IDs are de-duplicated before the mutation. On create, the CLI verifies the mutation's returned label IDs and fails visibly if Linear did not attach the requested set; the exit-5 agent envelope includes `created_issue.id`, `created_issue.identifier`, and `created_issue.url` so the remote issue remains recoverable if local persistence is unavailable.
- **Project and initiative name resolution** — Resolve portfolio objects by human name before writing issue relationships.

  _Reach for this when a user gives an issue identifier plus a project or initiative name. `--project` is UUID-only; use `--project-name` when the input is a human project name._

  ```bash
  linear-pp-cli projects list --agent --select id,name,team.key,state,url
  linear-pp-cli projects search "Autonomous Backlog Manager & Dispatch Governance" --team SYMPH --agent --select id,name,team.key,initiative.name,url
  linear-pp-cli initiatives list --agent --select id,name,status,url
  linear-pp-cli initiatives search "Dispatch Governance" --agent --select id,name,status,url
  linear-pp-cli issues edit SYMPH-795 --project-name "Autonomous Backlog Manager & Dispatch Governance" --dry-run --agent
  linear-pp-cli issues edit SYMPH-795 --project-name "Autonomous Backlog Manager & Dispatch Governance" --agent
  ```

  `--project-name` always performs a live Linear read to resolve the UUID, even when the surrounding issue write is a dry-run. Use `projects search` first when the name is partial; writes require a normalized exact project-name match.
- **Shell-safe Linear writes with media** — Create and update issue descriptions, comments, and Linear docs without putting Markdown bodies on the shell command line.

  _Reach for this whenever a body contains newlines, quotes, backticks, `$()` expansions, shell commands, images, logs, or agent-generated Markdown._

  ```bash
  linear-pp-cli issues create --title "Title" --team ENG --description-file /tmp/body.md --media /tmp/screenshot.png --agent
  linear-pp-cli issues edit ENG-123 --description-file /tmp/body.md --agent
  linear-pp-cli issues edit ENG-123 --media /tmp/screenshot.png --agent
  linear-pp-cli comments add --issue ENG-123 --body-file /tmp/comment.md --media /tmp/screenshot.png --agent
  linear-pp-cli comments edit <comment-id> --body-file /tmp/comment.md --agent
  linear-pp-cli documents create --title "Runbook" --issue ENG-123 --content-file /tmp/runbook.md --agent
  linear-pp-cli documents create --title "Team runbook" --team ENG --content-file /tmp/runbook.md --agent
  linear-pp-cli documents edit <document-id-or-slug> --content-file /tmp/updated.md --agent
  ```

  `documents create` requires exactly one parent (`--issue`, `--project`, `--team`, `--initiative`, `--cycle`, `--release`, or `--folder`); `--team` accepts a key such as `ENG` or a UUID. `issues edit --media`, `comments edit --media`, and `documents edit --media` with no body/content flag fetch the existing Markdown live and append uploaded media links. Images become Markdown image embeds; non-images become Markdown links. Add `--media-public` only when the uploaded asset must be reachable outside the Linear workspace.
- **Current issue reads and comments** — Read full issue bodies and discussion without falling back to stale local state. `comments list` takes the issue positionally (preferred) or via `--issue`.

  ```bash
  linear-pp-cli issues ENG-123 --agent --data-source live --select identifier,title,description,state.id,state.name,labels.nodes.id,labels.nodes.name,url
  linear-pp-cli issues ENG-123,ENG-124 --agent --data-source live --select identifier,title,description,state.name,url
  linear-pp-cli comments list ENG-123 --agent
  linear-pp-cli comments list --issue ENG-123 --agent --limit 100
  ```
- **State transitions** — Move an issue between workflow states without raw SQL, GraphQL, or `api` spelunking. The exact recipe:

  1. List the states for the issue's team: `workflow-states list --team <key>` (alias: `states list`).
  2. Pick the target by `name` or `type` and copy its `id` UUID.
  3. Pass that UUID to `issues edit --state`.

  ```bash
  linear-pp-cli workflow-states list --team ENG --agent --select id,name,type
  linear-pp-cli issues edit ENG-123 --state <state-uuid> --agent
  ```

  Or skip the lookup entirely with one-command transitions resolved against the issue's own team:

  ```bash
  linear-pp-cli issues edit ENG-123 --state-name "In Progress" --agent
  linear-pp-cli issues edit ENG-123 --state-type started --agent   # usage error if the team has several 'started' states
  ```

  `issues create` takes the same trio, resolved against `--team`, so an issue can open directly in the right state. `--state` requires a UUID (a non-UUID value is a usage error pointing at `--state-name`):

  ```bash
  linear-pp-cli issues create --title "..." --team ENG --state-name "In Progress" --agent
  ```

  Do not use `linear-pp-cli api` or `linear-pp-cli sql` for workflow states — `api` only exposes generated REST-shaped interfaces (currently `integrations`), not Linear GraphQL objects.
- **Linear document reads** — `documents <ref>` accepts every identifier form Linear surfaces: the document UUID, the bare `slugId` (`f7f48ab36080`), the full URL slug (`my-runbook-f7f48ab36080`), or the entire document URL. Copy whichever you have; no slug trimming or parsing shims needed.

  ```bash
  linear-pp-cli documents my-runbook-f7f48ab36080 --agent --select title,updatedAt,content
  linear-pp-cli documents "https://linear.app/<org>/document/my-runbook-f7f48ab36080" --agent
  ```

## Command Reference

**attachments** — Manage attachments

- `linear-pp-cli attachments <id>` — Get a single attachment

**audit-entry-types** — Manage audit-entry-types

- `linear-pp-cli audit-entry-types` — Get a single auditentrytype

**auth-resolver-responses** — Manage auth-resolver-responses

- `linear-pp-cli auth-resolver-responses` — Get a single authresolverresponse

**authentication-session-responses** — Manage authentication-session-responses

- `linear-pp-cli authentication-session-responses` — Get a single authenticationsessionresponse

**email-intake-addresses** — Manage email-intake-addresses

- `linear-pp-cli email-intake-addresses <id>` — Get a single emailintakeaddress

**favorites** — Manage favorites

- `linear-pp-cli favorites <id>` — Get a single favorite

**initiative-relations** — Manage initiative-relations

- `linear-pp-cli initiative-relations <id>` — Get a single initiativerelation

**initiative-to-projects** — Manage initiative-to-projects

- `linear-pp-cli initiative-to-projects <id>` — Get a single initiativetoproject

**initiatives** — Manage initiatives

- `linear-pp-cli initiatives <id>` — Get a single initiative
- `linear-pp-cli initiatives list` — List Linear initiatives
- `linear-pp-cli initiatives search <query>` — Search Linear initiatives by name
- `linear-pp-cli initiatives resolve <name>` — Resolve one Linear initiative name to its UUID

**integrations** — Manage integrations

- `linear-pp-cli integrations create` — Create a integration
- `linear-pp-cli integrations delete` — Delete a integration

**issue-priority-values** — Manage issue-priority-values

- `linear-pp-cli issue-priority-values` — Get a single issuepriorityvalue

**labels** — List Linear issue labels with team ownership

- `linear-pp-cli labels list --team ENG