linear
The linear skill enables creation, retrieval, and modification of Linear workspace items including issues, comments, projects, cycles, users, and milestones through the Linear MCP server. Use this when you need to read or update Linear issues and related objects, attach screenshots to issues, or query Linear documentation to understand available operations.
git clone --depth 1 https://github.com/Lilac-Labs/gini-agent /tmp/linear && cp -r /tmp/linear/skills/integrations/linear ~/.claude/skills/linearSKILL.md
# Linear
Linear is reachable through the `mcp_call` tool. Each call hits the hosted Linear MCP server; the runtime resolves the Authorization header from the connected Linear token. You never see the token or the endpoint — you pass `server: "linear"` and a tool name.
Every Linear call has the same shape:
```
mcp_call({
server: "linear",
tool: "<tool name>",
arguments: { ... }
})
```
The response is a JSON string. Parse it before reporting back to the user — Linear sometimes returns nested `pageInfo` or arrays you should summarize, not dump.
## Discovering what's available
**The full inventory of Linear MCP tools is in your system prompt** under "Configured MCP servers — linear — tools: ...". That list is authoritative; do not assume a tool doesn't exist just because it isn't called out below. The categories below give you defaults and taste; reach for tools from the inventory list whenever the user asks for something outside them.
When you're unsure of a tool's argument shape, either:
- Call `mcp_call({ server: "linear", tool: "search_documentation", arguments: { query: "..." } })` to query Linear's own docs, or
- Just try the call — the server returns a clear validation error on bad args, which is recoverable.
**Do not refuse a Linear-related ask** unless you've actually checked. "Linear doesn't support that" is a claim that requires evidence.
## Defaults and common shapes
### Issues — list / read / save
`save_issue` handles both create and update — with an `id` it updates, without one it creates.
```
mcp_call({ server: "linear", tool: "list_issues",
arguments: { assignee: "me", state: "started" } })
mcp_call({ server: "linear", tool: "get_issue",
arguments: { id: "LIN-123" } })
mcp_call({ server: "linear", tool: "save_issue",
arguments: { team: "ENG", title: "Login fails on Safari 17",
description: "Steps to reproduce…" } })
```
Useful argument quirks Linear's tool descriptions sometimes leave terse:
- `assignee: "me"` resolves to the authenticated viewer — no user-id lookup needed.
- `team` accepts the team key (`ENG`) or UUID.
- `state` accepts either the workflow state id or its display name (`"In Progress"`, `"Done"`). Workflow state *groups* for filtering: `backlog`, `unstarted`, `started`, `completed`, `cancelled`.
- `priority` is `0|1|2|3|4` where `1` is urgent, `4` is low, `0` is no priority.
- `list_issues` truncates `description` for compactness. Follow up with `get_issue` when the user needs the full body.
- Paginate by passing the `cursor` from `pageInfo.endCursor` back into the same call.
### Attaching screenshots / images
When the user provides images in chat and asks you to file or update a Linear issue, attach them after you know the issue identifier. The flow is three steps; the middle step (PUT bytes to Linear's signed URL) lives in the **`attachments` skill** — `read_skill name='attachments'` for the full reference. Linear-specific args are documented here.
1. **Prepare (Linear-specific)** — `mcp_call({ server: "linear", tool: "prepare_attachment_upload", arguments: { issue, filename, contentType, size } })`. The response carries `uploadRequest.url`, `uploadRequest.headers`, and `assetUrl`. The signed URL expires in 60 seconds; move immediately.
2. **PUT the bytes (attachments skill)** — `skill_run({ skill: "attachments", script: "signed-upload", args: { uploadId, url: prep.uploadRequest.url, headers: prep.uploadRequest.headers } })`. The script reads the upload off disk and PUTs it; the model never has to touch raw bytes. Returns `{ ok, status, bytesSent }`.
3. **Finalize (Linear-specific)** — `mcp_call({ server: "linear", tool: "create_attachment_from_upload", arguments: { issue, assetUrl, title, subtitle } })` with the `assetUrl` from step 1 and an optional `title` / `subtitle`.
Each user message that carries attachments ends with a system note listing each upload's id, mime type, and size:
```
Attached image uploads (in order):
- abc-123-... (image/png, 36116 bytes)
- def-456-... (image/jpeg, 24512 bytes)
```
Read the size and mimeType from that marker — `prepare_attachment_upload` rejects requests where `size` doesn't match the actual bytes (GCS returns `EntityTooLarge` / `EntityTooSmall`). One 3-step sequence per image.
If the `skill_run` step returns `ok: false`, the bytes did not land. Don't run the finalize step; either re-prepare (the signed URL is dead after 60s) or tell the user the upload failed and offer to paste the `assetUrl` into the issue body manually.
### Reading attachments on existing issues
To inspect or describe an attachment that's already on a Linear issue: combine `mcp_call(get_attachment)` with the **attachments skill's `signed-download` script** to land the bytes as a Gini upload, then `vision_query` to ask the model about the image. The attachments skill documents the full pattern — `read_skill name='attachments'`.
### Everything else (projects, cycles, comments, documents, initiatives, milestones, status updates, labels, diffs, users, teams)
Use the matching tool from the inventory list in your system prompt. The shapes are predictable: `list_*` returns an array with `pageInfo`, `get_*` takes an `id`, `save_*` creates without `id` / updates with `id`, `delete_*` takes an `id`. Examples:
```
mcp_call({ server: "linear", tool: "list_teams", arguments: {} })
mcp_call({ server: "linear", tool: "list_projects", arguments: { team: "ENG" } })
mcp_call({ server: "linear", tool: "list_cycles",
arguments: { team: "ENG", type: "current" } }) // also "next", "previous"
mcp_call({ server: "linear", tool: "list_comments",
arguments: { issueId: "LIN-123" } })
mcp_call({ server: "linear", tool: "save_comment",
arguments: { issueId: "LIN-123", body: "Reproduced on macOS 14." } })
mcp_call({ server: "linear", tool: "list_issue_labels", arguments: { team: "ENG" } })
mcp_call({ server: "linear", tool: "list_issue_statuses", argumentDelegate coding work to Claude Code CLI for repository edits, reviews, and multi-turn implementation sessions.
Delegate coding work to the OpenAI Codex CLI for repository changes, reviews, and focused fixes.
Gini's self-knowledge: how Gini configures, extends, and operates on its own state via /api/* and registered tools. Load when the user asks Gini about its own capabilities or asks Gini to modify its own configuration.
Manage Apple Notes via memo CLI: create, search, edit.
Apple Reminders via remindctl: add, list, complete.
Move bytes between Gini upload space, external URLs, and workspace files. Used by every attachment / file-upload / file-download flow regardless of the target system (Linear, GitHub, S3, Notion, etc.).
File a locally-captured, already-redacted Gini crash report as a GitHub issue, with the user's consent. Reads the pending crash queue and delegates the actual filing to the github-issues skill.
Create, search, triage, label, assign, comment on, and close GitHub issues using the gh CLI, with a curl REST fallback.