KosmoKrator

productivity

Linear Lua API for KosmoKrator Agents

Agent-facing Lua documentation and function reference for the Linear KosmoKrator integration.

Lua Namespace

Agents call this integration through app.integrations.linear.*. Use lua_read_doc("integrations.linear") inside KosmoKrator to discover the same reference at runtime.

Call Lua from the Headless CLI

Use kosmo integrations:lua when a shell script, CI job, cron job, or another coding CLI should run a deterministic Linear workflow without starting an interactive agent session.

Inline Lua call
kosmo integrations:lua --eval 'dump(app.integrations.linear.create_issue({team_id = "example_team_id", title = "example_title", description = "example_description", priority = 1, assignee_id = "example_assignee_id", label_ids = "example_label_ids", state_id = "example_state_id"}))' --json
Read Lua docs headlessly
kosmo integrations:lua --eval 'print(docs.read("linear"))' --json
kosmo integrations:lua --eval 'print(docs.read("linear.create_issue"))' --json

Workflow file

Put repeatable logic in a Lua file, then execute it with JSON output for the calling process.

workflow.lua
local linear = app.integrations.linear
local result = linear.create_issue({team_id = "example_team_id", title = "example_title", description = "example_description", priority = 1, assignee_id = "example_assignee_id", label_ids = "example_label_ids", state_id = "example_state_id"})

dump(result)
Run the workflow
kosmo integrations:lua workflow.lua --json
kosmo integrations:lua workflow.lua --force --json
Namespace note. integrations:lua exposes app.integrations.linear, app.mcp.*, docs.*, json.*, and regex.*. Use app.integrations.linear.default.* or app.integrations.linear.work.* when you configured named credential accounts.

MCP-only Lua

If the script only needs configured MCP servers and does not need Linear, use the narrower mcp:lua command.

MCP Lua command
# Use mcp:lua for MCP-only scripts; use integrations:lua for this integration namespace.
kosmo mcp:lua --eval 'dump(mcp.servers())' --json

Agent-Facing Lua Docs

This is the rendered version of the full Lua documentation exposed to agents when they inspect the integration namespace.

Linear — Lua API Reference

Linear is a purpose-built project management tool for software teams. This integration lets you create, read, update, and delete issues; manage teams, projects, and initiatives; apply labels; add comments; and run arbitrary GraphQL queries — all from Lua scripts.

Authentication

Uses a Personal API Key (starts with lin_api_…). Configure it in your integration settings. The key authenticates via the Linear GraphQL API at https://api.linear.app/graphql. API keys are scoped to the user who created them — the integration can only access teams and resources that user has permission for.


Overview

All tools are called via app.integrations.linear.<tool_name>({ ... }). Every function takes a single Lua table of named parameters and returns a result table.

local result = app.integrations.linear.get_issue({ id = "ENG-42" })

Errors surface as result.error (string). Check for it before using the response.

if result.error then
  print("Error: " .. result.error)
  return
end

Issues

app.integrations.linear.create_issue(...)

Create a new issue in Linear. Requires a team ID and title. Optionally set description, priority, assignee, labels, and initial state.

NameTypeRequiredDescription
team_idstringyesTeam ID to create the issue in. Use get_teams to discover team IDs.
titlestringyesIssue title.
descriptionstringnoIssue description (markdown supported).
priorityintegernoPriority: 0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low.
assignee_idstringnoUser ID to assign the issue to.
label_idsstringnoComma-separated label IDs to apply.
state_idstringnoWorkflow state ID for the initial status.

Returns: id, identifier, title, url, state, assignee, priority.

-- Create a simple issue
local result = app.integrations.linear.create_issue({
  team_id = "team-abc-123",
  title = "Fix login page crash on mobile",
  description = "Users on iOS Safari are seeing a blank screen after submitting credentials.",
  priority = 2
})

if result.error then
  print("Error: " .. result.error)
else
  print("Created: " .. result.identifier .. " — " .. result.url)
end
-- Create a fully-specified issue with assignee, labels, and state
local result = app.integrations.linear.create_issue({
  team_id = "team-abc-123",
  title = "Implement SSO support",
  description = "Add SAML-based SSO for enterprise customers.",
  priority = 2,
  assignee_id = "user-def-456",
  label_ids = "label-111,label-222",
  state_id = "state-todo-789"
})

print(result.identifier, result.state, result.assignee)

app.integrations.linear.get_issue(...)

Get a single Linear issue by ID or identifier (e.g., "TEAM-123"). Returns full details including description, state, assignee, labels, team info, and comments.

NameTypeRequiredDescription
idstringyesIssue ID or human-readable identifier (e.g., "ENG-42").

Returns: id, identifier, title, description, url, state, state_type, assignee (table with id, name, email), priority, labels (array of tables with id, name, color), team (table with id, name, key), comments (array of tables with id, body, user, created_at), created_at, updated_at.

-- Fetch an issue by its identifier
local result = app.integrations.linear.get_issue({ id = "ENG-42" })

if result.error then
  print("Error: " .. result.error)
else
  print(result.title)
  print("State: " .. result.state .. " (" .. result.state_type .. ")")
  print("Assignee: " .. (result.assignee and result.assignee.name or "Unassigned"))
  print("Priority: " .. tostring(result.priority))

  for _, label in ipairs(result.labels) do
    print("Label: " .. label.name .. " (" .. label.color .. ")")
  end

  for _, comment in ipairs(result.comments) do
    print("Comment by " .. comment.user .. ": " .. comment.body)
  end
end

app.integrations.linear.update_issue(...)

Update an existing Linear issue. Provide the issue ID or identifier and any fields to change. Only specified fields will be updated.

NameTypeRequiredDescription
idstringyesIssue ID or identifier to update.
titlestringnoNew title.
descriptionstringnoNew description (markdown).
priorityintegernoPriority: 0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low.
assignee_idstringnoUser ID to assign. Set to empty string "" to unassign.
state_idstringnoWorkflow state ID to set.
label_idsstringnoComma-separated label IDs to set (replaces existing labels).

Returns: id, identifier, title, url, state, assignee, priority, labels.

-- Update an issue's title and priority
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  title = "Fix login page crash — updated with repro steps",
  priority = 1
})

print("Updated: " .. result.identifier .. " — priority " .. tostring(result.priority))
-- Move an issue to a new state and assign it
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  state_id = "state-in-progress-abc",
  assignee_id = "user-xyz-789"
})

print("State: " .. result.state .. ", Assignee: " .. tostring(result.assignee))
-- Replace all labels on an issue
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  label_ids = "label-bug,label-critical"
})

for _, label in ipairs(result.labels) do
  print("Label: " .. label)
end

app.integrations.linear.search_issues(...)

Search Linear issues using flexible filter criteria. Supports filtering by text query, team, state name, assignee, and priority. Returns matching issues with pagination info.

NameTypeRequiredDescription
querystringnoText to search in issue titles and descriptions.
team_idstringnoFilter by team ID.
statestringnoFilter by state name (e.g., "In Progress", "Done").
assignee_idstringnoFilter by assignee user ID.
priorityintegernoFilter by priority: 0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low.
limitintegernoMax results to return. Default: 20.

Returns: issues (array), total, has_next_page, end_cursor. Each issue contains: id, identifier, title, state, assignee, priority, team, labels (array of strings), created_at.

-- Search for issues containing "crash" across all teams
local result = app.integrations.linear.search_issues({
  query = "crash",
  limit = 10
})

for _, issue in ipairs(result.issues) do
  print(issue.identifier .. ": " .. issue.title .. " [" .. issue.state .. "]")
end
-- Search for high-priority issues assigned to a specific user
local result = app.integrations.linear.search_issues({
  assignee_id = "user-xyz-789",
  priority = 2,
  state = "In Progress"
})

print("Found " .. result.total .. " matching issues")

app.integrations.linear.list_issues(...)

List issues for a specific Linear team with optional filters and cursor-based pagination.

NameTypeRequiredDescription
team_idstringyesTeam ID to list issues for.
statusstringnoFilter by state name (e.g., "In Progress", "Backlog").
assignee_idstringnoFilter by assignee user ID.
limitintegernoResults per page. Default: 25.
afterstringnoCursor for next page (from a previous response’s end_cursor).

Returns: issues (array), total, has_next_page, end_cursor. Each issue contains: id, identifier, title, state, assignee, priority, labels (array of strings), created_at, updated_at.

-- List the first 10 issues in a team
local result = app.integrations.linear.list_issues({
  team_id = "team-abc-123",
  limit = 10
})

for _, issue in ipairs(result.issues) do
  print(issue.identifier .. ": " .. issue.title .. " [" .. issue.state .. "]")
end

if result.has_next_page then
  print("More results available. Cursor: " .. tostring(result.end_cursor))
end
-- List "In Progress" issues for a specific assignee (paginated)
local cursor = nil

repeat
  local result = app.integrations.linear.list_issues({
    team_id = "team-abc-123",
    status = "In Progress",
    assignee_id = "user-xyz-789",
    limit = 25,
    after = cursor
  })

  for _, issue in ipairs(result.issues) do
    print(issue.identifier .. ": " .. issue.title)
  end

  cursor = result.has_next_page and result.end_cursor or nil
until not cursor

app.integrations.linear.delete_issue(...)

Delete a Linear issue by ID or identifier. This action is irreversible.

NameTypeRequiredDescription
idstringyesIssue ID or identifier to delete (e.g., "ENG-42").

Returns: deleted (boolean), id.

-- Delete an issue
local result = app.integrations.linear.delete_issue({ id = "ENG-42" })

if result.error then
  print("Error: " .. result.error)
else
  print("Deleted issue: " .. result.id)
end

app.integrations.linear.create_comment(...)

Add a comment to a Linear issue. Supports markdown formatting.

NameTypeRequiredDescription
issue_idstringyesIssue ID or identifier to comment on.
bodystringyesComment body text (markdown supported).

Returns: id, body, user, created_at.

-- Add a comment to an issue
local result = app.integrations.linear.create_comment({
  issue_id = "ENG-42",
  body = "I've reproduced this on iOS 17.4. Attaching screenshot below."
})

if not result.error then
  print("Comment added by " .. result.user .. " at " .. result.created_at)
end
-- Add a rich markdown comment
local result = app.integrations.linear.create_comment({
  issue_id = "ENG-42",
  body = "## Root Cause\n\nThe issue was caused by a **race condition** in the auth module.\n\n### Fix\n- Added mutex lock around token refresh\n- Added regression test"
})

app.integrations.linear.list_comments(...)

List all comments on a Linear issue, ordered chronologically.

NameTypeRequiredDescription
issue_idstringyesIssue ID or identifier to list comments for.

Returns: comments (array), total. Each comment contains: id, body, user, created_at, updated_at.

-- List all comments on an issue
local result = app.integrations.linear.list_comments({ issue_id = "ENG-42" })

for _, comment in ipairs(result.comments) do
  print(comment.user .. " (" .. comment.created_at .. "):")
  print("  " .. comment.body)
end

print("Total comments: " .. result.total)

Teams & Projects

app.integrations.linear.get_teams(...)

Get all Linear teams the authenticated user has access to, including team name, key, description, and member list. Use this to discover team IDs needed for other tools.

NameTypeRequiredDescription
(none)This tool takes no parameters. Pass an empty table {}.

Returns: teams (array), total. Each team contains: id, name, key, description, icon, members (array of tables with id, name, email).

-- List all teams and their members
local result = app.integrations.linear.get_teams({})

for _, team in ipairs(result.teams) do
  print("Team: " .. team.name .. " (" .. team.key .. ")")
  print("  Description: " .. (team.description or "—"))

  for _, member in ipairs(team.members) do
    print("  Member: " .. member.name .. " <" .. member.email .. ">")
  end
end

app.integrations.linear.list_projects(...)

List Linear projects with optional cursor-based pagination. Returns project details including state, dates, lead, and associated teams.

NameTypeRequiredDescription
limitintegernoResults per page. Default: 25.
afterstringnoCursor for next page (from a previous response’s end_cursor).

Returns: projects (array), total, has_next_page, end_cursor. Each project contains: id, name, description, state, start_date, target_date, lead, teams (array of tables with id, name, key), created_at, updated_at.

-- List the first 10 projects
local result = app.integrations.linear.list_projects({ limit = 10 })

for _, project in ipairs(result.projects) do
  print(project.name .. " [" .. (project.state or "—") .. "]")
  print("  Lead: " .. (project.lead or "Unassigned"))
  print("  Target: " .. (project.target_date or "No date"))

  for _, team in ipairs(project.teams) do
    print("  Team: " .. team.name .. " (" .. team.key .. ")")
  end
end

app.integrations.linear.create_project(...)

Create a new Linear project. Requires a name and at least one team ID. Optionally set description and lead.

NameTypeRequiredDescription
namestringyesProject name.
team_idsstringyesComma-separated team IDs to associate with the project.
descriptionstringnoProject description.
lead_idstringnoUser ID of the project lead.

Returns: id, name, description, state, url, teams (array of team names).

-- Create a new project
local result = app.integrations.linear.create_project({
  name = "Q3 Platform Overhaul",
  team_ids = "team-abc-123,team-def-456",
  description = "Major refactoring of the platform architecture for improved performance.",
  lead_id = "user-xyz-789"
})

if not result.error then
  print("Project created: " .. result.name)
  print("URL: " .. result.url)
end

app.integrations.linear.update_project(...)

Update a Linear project. Provide the project ID and any fields to change. Only specified fields will be updated.

NameTypeRequiredDescription
idstringyesProject ID to update.
namestringnoNew project name.
descriptionstringnoNew description.
statestringnoNew project state: "planned", "active", "paused", "completed", or "canceled".

Returns: id, name, description, state, url.

-- Mark a project as active
local result = app.integrations.linear.update_project({
  id = "project-abc-123",
  state = "active"
})

print("Project state updated to: " .. result.state)
-- Update project name and description
local result = app.integrations.linear.update_project({
  id = "project-abc-123",
  name = "Q3 Platform Overhaul (Revised)",
  description = "Updated scope: focus on API layer and database optimization."
})

print(result.name .. " — " .. result.url)

app.integrations.linear.list_initiatives(...)

List Linear initiatives. Returns initiative details including state, dates, and associated projects.

NameTypeRequiredDescription
limitintegernoMax results to return. Default: 25.

Returns: initiatives (array), total, has_next_page, end_cursor. Each initiative contains: id, name, description, state, start_date, target_date, projects (array of tables with id, name), created_at, updated_at.

-- List all initiatives
local result = app.integrations.linear.list_initiatives({ limit = 50 })

for _, initiative in ipairs(result.initiatives) do
  print(initiative.name .. " [" .. (initiative.state or "—") .. "]")
  print("  " .. (initiative.description or "No description"))

  for _, project in ipairs(initiative.projects) do
    print("  Project: " .. project.name)
  end
end

app.integrations.linear.create_initiative(...)

Create a new Linear initiative. Initiatives group related projects together. Requires a name.

NameTypeRequiredDescription
namestringyesInitiative name.
descriptionstringnoInitiative description.

Returns: id, name, description, state.

-- Create a new initiative
local result = app.integrations.linear.create_initiative({
  name = "2026 Technical Excellence",
  description = "Umbrella initiative for all infrastructure and developer experience improvements in 2026."
})

if not result.error then
  print("Initiative created: " .. result.name .. " (state: " .. tostring(result.state) .. ")")
end

Labels & Metadata

app.integrations.linear.list_labels(...)

List issue labels in Linear. Optionally filter by team. Returns label ID, name, color, and description.

NameTypeRequiredDescription
team_idstringnoTeam ID to filter labels by.

Returns: labels (array), total. Each label contains: id, name, color, description, team.

-- List all labels
local result = app.integrations.linear.list_labels({})

for _, label in ipairs(result.labels) do
  print(label.name .. " (" .. label.color .. ") — " .. (label.description or ""))
  print("  ID: " .. label.id)
end
-- List labels for a specific team
local result = app.integrations.linear.list_labels({ team_id = "team-abc-123" })

for _, label in ipairs(result.labels) do
  print(label.name)
end

app.integrations.linear.add_label(...)

Add a label to a Linear issue. The label will be appended to existing labels without removing any.

NameTypeRequiredDescription
issue_idstringyesIssue ID or identifier.
label_idstringyesLabel ID to add. Use list_labels to find label IDs.

Returns: id, identifier, labels (array of label names).

-- Add the "bug" label to an issue
local result = app.integrations.linear.add_label({
  issue_id = "ENG-42",
  label_id = "label-bug-123"
})

if not result.error then
  print("Labels on " .. result.identifier .. ":")
  for _, name in ipairs(result.labels) do
    print("  - " .. name)
  end
end

app.integrations.linear.remove_label(...)

Remove a label from a Linear issue. Other labels on the issue are preserved.

NameTypeRequiredDescription
issue_idstringyesIssue ID or identifier.
label_idstringyesLabel ID to remove.

Returns: id, identifier, labels (array of label names).

-- Remove the "bug" label from an issue
local result = app.integrations.linear.remove_label({
  issue_id = "ENG-42",
  label_id = "label-bug-123"
})

if not result.error then
  print("Remaining labels:")
  for _, name in ipairs(result.labels) do
    print("  - " .. name)
  end
end

app.integrations.linear.get_current_user(...)

Get the currently authenticated Linear user’s profile, including ID, name, email, and avatar URL.

NameTypeRequiredDescription
(none)This tool takes no parameters. Pass an empty table {}.

Returns: id, name, email, avatar_url.

-- Get the authenticated user's profile
local result = app.integrations.linear.get_current_user({})

print("Logged in as: " .. result.name .. " <" .. result.email .. ">")
print("User ID: " .. result.id)

app.integrations.linear.list_workflows(...)

List workflow states for a Linear team, showing all available issue statuses with their IDs, types, and colors. Use this to discover state_id values for creating and updating issues.

NameTypeRequiredDescription
team_idstringnoTeam ID to filter workflow states by.

Returns: workflow_states (array), total. Each state contains: id, name, type, color, team.

-- List all workflow states for a team
local result = app.integrations.linear.list_workflows({ team_id = "team-abc-123" })

for _, state in ipairs(result.workflow_states) do
  print(state.name .. " (type: " .. state.type .. ", id: " .. state.id .. ")")
end
-- List all workflow states across all teams
local result = app.integrations.linear.list_workflows({})

for _, state in ipairs(result.workflow_states) do
  local team = state.team or "Global"
  print("[" .. team .. "] " .. state.name .. " — " .. state.type .. " — " .. state.id)
end

app.integrations.linear.raw_query(...)

Execute an arbitrary GraphQL query or mutation against the Linear API. Use this for advanced operations not covered by the other tools.

NameTypeRequiredDescription
querystringyesGraphQL query or mutation document.
variablesstringnoVariables as a JSON object string.

Returns: The raw API response as a table (structure depends on your query).

-- Fetch a specific issue's comment count using a custom query
local result = app.integrations.linear.raw_query({
  query = [[
    query($id: String!) {
      issue(id: $id) {
        id
        identifier
        title
        commentCount
      }
    }
  ]],
  variables = '{"id": "ENG-42"}'
})

if not result.error then
  local issue = result.data.issue
  print(issue.identifier .. ": " .. issue.title .. " (" .. issue.commentCount .. " comments)")
end
-- List all organization members
local result = app.integrations.linear.raw_query({
  query = [[
    query {
      organization {
        name
        users(first: 50) {
          nodes {
            id
            name
            email
          }
        }
      }
    }
  ]]
})

for _, user in ipairs(result.data.organization.users.nodes) do
  print(user.name .. " <" .. user.email .. ">")
end

Pagination

Several list endpoints (list_issues, search_issues, list_projects, list_initiatives) support cursor-based pagination. The response includes:

FieldTypeDescription
has_next_pagebooleanWhether more results exist.
end_cursorstring or nilCursor to pass as after for the next page.

Paginating through all results

local issues = {}
local cursor = nil

repeat
  local result = app.integrations.linear.list_issues({
    team_id = "team-abc-123",
    limit = 50,
    after = cursor
  })

  if result.error then
    print("Error: " .. result.error)
    break
  end

  for _, issue in ipairs(result.issues) do
    table.insert(issues, issue)
  end

  cursor = result.has_next_page and result.end_cursor or nil
until not cursor

print("Fetched " .. #issues .. " issues total")

Notes

  • Priority values: Linear uses numeric priorities — 0 (none), 1 (urgent), 2 (high), 3 (medium), 4 (low).
  • IDs vs identifiers: Most tools accept either a UUID-style ID or a human-readable identifier like "ENG-42". The get_issue, update_issue, delete_issue, create_comment, and list_comments tools support both forms.
  • label_ids format: When multiple label IDs are needed (e.g., create_issue, update_issue), pass them as a single comma-separated string: "label-111,label-222".
  • update_issue replaces labels: The label_ids parameter on update_issue replaces the entire label set. To add or remove individual labels without affecting others, use add_label or remove_label instead.
  • Markdown support: Issue descriptions and comment bodies support full markdown.
  • GraphQL backend: All operations use the Linear GraphQL API at https://api.linear.app/graphql. For operations not covered by the built-in tools, use raw_query to run custom GraphQL queries or mutations.
  • Rate limits: Linear enforces API rate limits. If you encounter errors during bulk operations, add delays between calls.
  • Team discovery: Call get_teams({}) first to discover team IDs, then list_workflows({ team_id = "..." }) for available states, and list_labels({ team_id = "..." }) for available labels.

Multi-Account Usage

If you have multiple linear accounts configured, use account-specific namespaces:

-- Default account (always works)
app.integrations.linear.function_name({...})

-- Explicit default (portable across setups)
app.integrations.linear.default.function_name({...})

-- Named accounts
app.integrations.linear.work.function_name({...})
app.integrations.linear.personal.function_name({...})

All functions are identical across accounts — only the credentials differ.

Raw agent markdown
# Linear — Lua API Reference

Linear is a purpose-built project management tool for software teams. This integration lets you create, read, update, and delete issues; manage teams, projects, and initiatives; apply labels; add comments; and run arbitrary GraphQL queries — all from Lua scripts.

## Authentication

Uses a **Personal API Key** (starts with `lin_api_…`). Configure it in your integration settings. The key authenticates via the Linear GraphQL API at `https://api.linear.app/graphql`. API keys are scoped to the user who created them — the integration can only access teams and resources that user has permission for.

---

## Overview

All tools are called via `app.integrations.linear.<tool_name>({ ... })`. Every function takes a single Lua table of named parameters and returns a result table.

```lua
local result = app.integrations.linear.get_issue({ id = "ENG-42" })
```

Errors surface as `result.error` (string). Check for it before using the response.

```lua
if result.error then
  print("Error: " .. result.error)
  return
end
```

---

## Issues

### `app.integrations.linear.create_issue(...)`

Create a new issue in Linear. Requires a team ID and title. Optionally set description, priority, assignee, labels, and initial state.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `team_id` | string | yes | Team ID to create the issue in. Use `get_teams` to discover team IDs. |
| `title` | string | yes | Issue title. |
| `description` | string | no | Issue description (markdown supported). |
| `priority` | integer | no | Priority: `0` = none, `1` = urgent, `2` = high, `3` = medium, `4` = low. |
| `assignee_id` | string | no | User ID to assign the issue to. |
| `label_ids` | string | no | Comma-separated label IDs to apply. |
| `state_id` | string | no | Workflow state ID for the initial status. |

Returns: `id`, `identifier`, `title`, `url`, `state`, `assignee`, `priority`.

```lua
-- Create a simple issue
local result = app.integrations.linear.create_issue({
  team_id = "team-abc-123",
  title = "Fix login page crash on mobile",
  description = "Users on iOS Safari are seeing a blank screen after submitting credentials.",
  priority = 2
})

if result.error then
  print("Error: " .. result.error)
else
  print("Created: " .. result.identifier .. " — " .. result.url)
end
```

```lua
-- Create a fully-specified issue with assignee, labels, and state
local result = app.integrations.linear.create_issue({
  team_id = "team-abc-123",
  title = "Implement SSO support",
  description = "Add SAML-based SSO for enterprise customers.",
  priority = 2,
  assignee_id = "user-def-456",
  label_ids = "label-111,label-222",
  state_id = "state-todo-789"
})

print(result.identifier, result.state, result.assignee)
```

---

### `app.integrations.linear.get_issue(...)`

Get a single Linear issue by ID or identifier (e.g., `"TEAM-123"`). Returns full details including description, state, assignee, labels, team info, and comments.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | yes | Issue ID or human-readable identifier (e.g., `"ENG-42"`). |

Returns: `id`, `identifier`, `title`, `description`, `url`, `state`, `state_type`, `assignee` (table with `id`, `name`, `email`), `priority`, `labels` (array of tables with `id`, `name`, `color`), `team` (table with `id`, `name`, `key`), `comments` (array of tables with `id`, `body`, `user`, `created_at`), `created_at`, `updated_at`.

```lua
-- Fetch an issue by its identifier
local result = app.integrations.linear.get_issue({ id = "ENG-42" })

if result.error then
  print("Error: " .. result.error)
else
  print(result.title)
  print("State: " .. result.state .. " (" .. result.state_type .. ")")
  print("Assignee: " .. (result.assignee and result.assignee.name or "Unassigned"))
  print("Priority: " .. tostring(result.priority))

  for _, label in ipairs(result.labels) do
    print("Label: " .. label.name .. " (" .. label.color .. ")")
  end

  for _, comment in ipairs(result.comments) do
    print("Comment by " .. comment.user .. ": " .. comment.body)
  end
end
```

---

### `app.integrations.linear.update_issue(...)`

Update an existing Linear issue. Provide the issue ID or identifier and any fields to change. Only specified fields will be updated.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | yes | Issue ID or identifier to update. |
| `title` | string | no | New title. |
| `description` | string | no | New description (markdown). |
| `priority` | integer | no | Priority: `0` = none, `1` = urgent, `2` = high, `3` = medium, `4` = low. |
| `assignee_id` | string | no | User ID to assign. Set to empty string `""` to unassign. |
| `state_id` | string | no | Workflow state ID to set. |
| `label_ids` | string | no | Comma-separated label IDs to set (**replaces** existing labels). |

Returns: `id`, `identifier`, `title`, `url`, `state`, `assignee`, `priority`, `labels`.

```lua
-- Update an issue's title and priority
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  title = "Fix login page crash — updated with repro steps",
  priority = 1
})

print("Updated: " .. result.identifier .. " — priority " .. tostring(result.priority))
```

```lua
-- Move an issue to a new state and assign it
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  state_id = "state-in-progress-abc",
  assignee_id = "user-xyz-789"
})

print("State: " .. result.state .. ", Assignee: " .. tostring(result.assignee))
```

```lua
-- Replace all labels on an issue
local result = app.integrations.linear.update_issue({
  id = "ENG-42",
  label_ids = "label-bug,label-critical"
})

for _, label in ipairs(result.labels) do
  print("Label: " .. label)
end
```

---

### `app.integrations.linear.search_issues(...)`

Search Linear issues using flexible filter criteria. Supports filtering by text query, team, state name, assignee, and priority. Returns matching issues with pagination info.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `query` | string | no | Text to search in issue titles and descriptions. |
| `team_id` | string | no | Filter by team ID. |
| `state` | string | no | Filter by state name (e.g., `"In Progress"`, `"Done"`). |
| `assignee_id` | string | no | Filter by assignee user ID. |
| `priority` | integer | no | Filter by priority: `0` = none, `1` = urgent, `2` = high, `3` = medium, `4` = low. |
| `limit` | integer | no | Max results to return. Default: 20. |

Returns: `issues` (array), `total`, `has_next_page`, `end_cursor`. Each issue contains: `id`, `identifier`, `title`, `state`, `assignee`, `priority`, `team`, `labels` (array of strings), `created_at`.

```lua
-- Search for issues containing "crash" across all teams
local result = app.integrations.linear.search_issues({
  query = "crash",
  limit = 10
})

for _, issue in ipairs(result.issues) do
  print(issue.identifier .. ": " .. issue.title .. " [" .. issue.state .. "]")
end
```

```lua
-- Search for high-priority issues assigned to a specific user
local result = app.integrations.linear.search_issues({
  assignee_id = "user-xyz-789",
  priority = 2,
  state = "In Progress"
})

print("Found " .. result.total .. " matching issues")
```

---

### `app.integrations.linear.list_issues(...)`

List issues for a specific Linear team with optional filters and cursor-based pagination.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `team_id` | string | yes | Team ID to list issues for. |
| `status` | string | no | Filter by state name (e.g., `"In Progress"`, `"Backlog"`). |
| `assignee_id` | string | no | Filter by assignee user ID. |
| `limit` | integer | no | Results per page. Default: 25. |
| `after` | string | no | Cursor for next page (from a previous response's `end_cursor`). |

Returns: `issues` (array), `total`, `has_next_page`, `end_cursor`. Each issue contains: `id`, `identifier`, `title`, `state`, `assignee`, `priority`, `labels` (array of strings), `created_at`, `updated_at`.

```lua
-- List the first 10 issues in a team
local result = app.integrations.linear.list_issues({
  team_id = "team-abc-123",
  limit = 10
})

for _, issue in ipairs(result.issues) do
  print(issue.identifier .. ": " .. issue.title .. " [" .. issue.state .. "]")
end

if result.has_next_page then
  print("More results available. Cursor: " .. tostring(result.end_cursor))
end
```

```lua
-- List "In Progress" issues for a specific assignee (paginated)
local cursor = nil

repeat
  local result = app.integrations.linear.list_issues({
    team_id = "team-abc-123",
    status = "In Progress",
    assignee_id = "user-xyz-789",
    limit = 25,
    after = cursor
  })

  for _, issue in ipairs(result.issues) do
    print(issue.identifier .. ": " .. issue.title)
  end

  cursor = result.has_next_page and result.end_cursor or nil
until not cursor
```

---

### `app.integrations.linear.delete_issue(...)`

Delete a Linear issue by ID or identifier. This action is irreversible.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | yes | Issue ID or identifier to delete (e.g., `"ENG-42"`). |

Returns: `deleted` (boolean), `id`.

```lua
-- Delete an issue
local result = app.integrations.linear.delete_issue({ id = "ENG-42" })

if result.error then
  print("Error: " .. result.error)
else
  print("Deleted issue: " .. result.id)
end
```

---

### `app.integrations.linear.create_comment(...)`

Add a comment to a Linear issue. Supports markdown formatting.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `issue_id` | string | yes | Issue ID or identifier to comment on. |
| `body` | string | yes | Comment body text (markdown supported). |

Returns: `id`, `body`, `user`, `created_at`.

```lua
-- Add a comment to an issue
local result = app.integrations.linear.create_comment({
  issue_id = "ENG-42",
  body = "I've reproduced this on iOS 17.4. Attaching screenshot below."
})

if not result.error then
  print("Comment added by " .. result.user .. " at " .. result.created_at)
end
```

```lua
-- Add a rich markdown comment
local result = app.integrations.linear.create_comment({
  issue_id = "ENG-42",
  body = "## Root Cause\n\nThe issue was caused by a **race condition** in the auth module.\n\n### Fix\n- Added mutex lock around token refresh\n- Added regression test"
})
```

---

### `app.integrations.linear.list_comments(...)`

List all comments on a Linear issue, ordered chronologically.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `issue_id` | string | yes | Issue ID or identifier to list comments for. |

Returns: `comments` (array), `total`. Each comment contains: `id`, `body`, `user`, `created_at`, `updated_at`.

```lua
-- List all comments on an issue
local result = app.integrations.linear.list_comments({ issue_id = "ENG-42" })

for _, comment in ipairs(result.comments) do
  print(comment.user .. " (" .. comment.created_at .. "):")
  print("  " .. comment.body)
end

print("Total comments: " .. result.total)
```

---

## Teams & Projects

### `app.integrations.linear.get_teams(...)`

Get all Linear teams the authenticated user has access to, including team name, key, description, and member list. Use this to discover team IDs needed for other tools.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| *(none)* | | | This tool takes no parameters. Pass an empty table `{}`. |

Returns: `teams` (array), `total`. Each team contains: `id`, `name`, `key`, `description`, `icon`, `members` (array of tables with `id`, `name`, `email`).

```lua
-- List all teams and their members
local result = app.integrations.linear.get_teams({})

for _, team in ipairs(result.teams) do
  print("Team: " .. team.name .. " (" .. team.key .. ")")
  print("  Description: " .. (team.description or "—"))

  for _, member in ipairs(team.members) do
    print("  Member: " .. member.name .. " <" .. member.email .. ">")
  end
end
```

---

### `app.integrations.linear.list_projects(...)`

List Linear projects with optional cursor-based pagination. Returns project details including state, dates, lead, and associated teams.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `limit` | integer | no | Results per page. Default: 25. |
| `after` | string | no | Cursor for next page (from a previous response's `end_cursor`). |

Returns: `projects` (array), `total`, `has_next_page`, `end_cursor`. Each project contains: `id`, `name`, `description`, `state`, `start_date`, `target_date`, `lead`, `teams` (array of tables with `id`, `name`, `key`), `created_at`, `updated_at`.

```lua
-- List the first 10 projects
local result = app.integrations.linear.list_projects({ limit = 10 })

for _, project in ipairs(result.projects) do
  print(project.name .. " [" .. (project.state or "—") .. "]")
  print("  Lead: " .. (project.lead or "Unassigned"))
  print("  Target: " .. (project.target_date or "No date"))

  for _, team in ipairs(project.teams) do
    print("  Team: " .. team.name .. " (" .. team.key .. ")")
  end
end
```

---

### `app.integrations.linear.create_project(...)`

Create a new Linear project. Requires a name and at least one team ID. Optionally set description and lead.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `name` | string | yes | Project name. |
| `team_ids` | string | yes | Comma-separated team IDs to associate with the project. |
| `description` | string | no | Project description. |
| `lead_id` | string | no | User ID of the project lead. |

Returns: `id`, `name`, `description`, `state`, `url`, `teams` (array of team names).

```lua
-- Create a new project
local result = app.integrations.linear.create_project({
  name = "Q3 Platform Overhaul",
  team_ids = "team-abc-123,team-def-456",
  description = "Major refactoring of the platform architecture for improved performance.",
  lead_id = "user-xyz-789"
})

if not result.error then
  print("Project created: " .. result.name)
  print("URL: " .. result.url)
end
```

---

### `app.integrations.linear.update_project(...)`

Update a Linear project. Provide the project ID and any fields to change. Only specified fields will be updated.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | yes | Project ID to update. |
| `name` | string | no | New project name. |
| `description` | string | no | New description. |
| `state` | string | no | New project state: `"planned"`, `"active"`, `"paused"`, `"completed"`, or `"canceled"`. |

Returns: `id`, `name`, `description`, `state`, `url`.

```lua
-- Mark a project as active
local result = app.integrations.linear.update_project({
  id = "project-abc-123",
  state = "active"
})

print("Project state updated to: " .. result.state)
```

```lua
-- Update project name and description
local result = app.integrations.linear.update_project({
  id = "project-abc-123",
  name = "Q3 Platform Overhaul (Revised)",
  description = "Updated scope: focus on API layer and database optimization."
})

print(result.name .. " — " .. result.url)
```

---

### `app.integrations.linear.list_initiatives(...)`

List Linear initiatives. Returns initiative details including state, dates, and associated projects.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `limit` | integer | no | Max results to return. Default: 25. |

Returns: `initiatives` (array), `total`, `has_next_page`, `end_cursor`. Each initiative contains: `id`, `name`, `description`, `state`, `start_date`, `target_date`, `projects` (array of tables with `id`, `name`), `created_at`, `updated_at`.

```lua
-- List all initiatives
local result = app.integrations.linear.list_initiatives({ limit = 50 })

for _, initiative in ipairs(result.initiatives) do
  print(initiative.name .. " [" .. (initiative.state or "—") .. "]")
  print("  " .. (initiative.description or "No description"))

  for _, project in ipairs(initiative.projects) do
    print("  Project: " .. project.name)
  end
end
```

---

### `app.integrations.linear.create_initiative(...)`

Create a new Linear initiative. Initiatives group related projects together. Requires a name.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `name` | string | yes | Initiative name. |
| `description` | string | no | Initiative description. |

Returns: `id`, `name`, `description`, `state`.

```lua
-- Create a new initiative
local result = app.integrations.linear.create_initiative({
  name = "2026 Technical Excellence",
  description = "Umbrella initiative for all infrastructure and developer experience improvements in 2026."
})

if not result.error then
  print("Initiative created: " .. result.name .. " (state: " .. tostring(result.state) .. ")")
end
```

---

## Labels & Metadata

### `app.integrations.linear.list_labels(...)`

List issue labels in Linear. Optionally filter by team. Returns label ID, name, color, and description.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `team_id` | string | no | Team ID to filter labels by. |

Returns: `labels` (array), `total`. Each label contains: `id`, `name`, `color`, `description`, `team`.

```lua
-- List all labels
local result = app.integrations.linear.list_labels({})

for _, label in ipairs(result.labels) do
  print(label.name .. " (" .. label.color .. ") — " .. (label.description or ""))
  print("  ID: " .. label.id)
end
```

```lua
-- List labels for a specific team
local result = app.integrations.linear.list_labels({ team_id = "team-abc-123" })

for _, label in ipairs(result.labels) do
  print(label.name)
end
```

---

### `app.integrations.linear.add_label(...)`

Add a label to a Linear issue. The label will be appended to existing labels without removing any.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `issue_id` | string | yes | Issue ID or identifier. |
| `label_id` | string | yes | Label ID to add. Use `list_labels` to find label IDs. |

Returns: `id`, `identifier`, `labels` (array of label names).

```lua
-- Add the "bug" label to an issue
local result = app.integrations.linear.add_label({
  issue_id = "ENG-42",
  label_id = "label-bug-123"
})

if not result.error then
  print("Labels on " .. result.identifier .. ":")
  for _, name in ipairs(result.labels) do
    print("  - " .. name)
  end
end
```

---

### `app.integrations.linear.remove_label(...)`

Remove a label from a Linear issue. Other labels on the issue are preserved.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `issue_id` | string | yes | Issue ID or identifier. |
| `label_id` | string | yes | Label ID to remove. |

Returns: `id`, `identifier`, `labels` (array of label names).

```lua
-- Remove the "bug" label from an issue
local result = app.integrations.linear.remove_label({
  issue_id = "ENG-42",
  label_id = "label-bug-123"
})

if not result.error then
  print("Remaining labels:")
  for _, name in ipairs(result.labels) do
    print("  - " .. name)
  end
end
```

---

### `app.integrations.linear.get_current_user(...)`

Get the currently authenticated Linear user's profile, including ID, name, email, and avatar URL.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| *(none)* | | | This tool takes no parameters. Pass an empty table `{}`. |

Returns: `id`, `name`, `email`, `avatar_url`.

```lua
-- Get the authenticated user's profile
local result = app.integrations.linear.get_current_user({})

print("Logged in as: " .. result.name .. " <" .. result.email .. ">")
print("User ID: " .. result.id)
```

---

### `app.integrations.linear.list_workflows(...)`

List workflow states for a Linear team, showing all available issue statuses with their IDs, types, and colors. Use this to discover `state_id` values for creating and updating issues.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `team_id` | string | no | Team ID to filter workflow states by. |

Returns: `workflow_states` (array), `total`. Each state contains: `id`, `name`, `type`, `color`, `team`.

```lua
-- List all workflow states for a team
local result = app.integrations.linear.list_workflows({ team_id = "team-abc-123" })

for _, state in ipairs(result.workflow_states) do
  print(state.name .. " (type: " .. state.type .. ", id: " .. state.id .. ")")
end
```

```lua
-- List all workflow states across all teams
local result = app.integrations.linear.list_workflows({})

for _, state in ipairs(result.workflow_states) do
  local team = state.team or "Global"
  print("[" .. team .. "] " .. state.name .. " — " .. state.type .. " — " .. state.id)
end
```

---

### `app.integrations.linear.raw_query(...)`

Execute an arbitrary GraphQL query or mutation against the Linear API. Use this for advanced operations not covered by the other tools.

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `query` | string | yes | GraphQL query or mutation document. |
| `variables` | string | no | Variables as a JSON object string. |

Returns: The raw API response as a table (structure depends on your query).

```lua
-- Fetch a specific issue's comment count using a custom query
local result = app.integrations.linear.raw_query({
  query = [[
    query($id: String!) {
      issue(id: $id) {
        id
        identifier
        title
        commentCount
      }
    }
  ]],
  variables = '{"id": "ENG-42"}'
})

if not result.error then
  local issue = result.data.issue
  print(issue.identifier .. ": " .. issue.title .. " (" .. issue.commentCount .. " comments)")
end
```

```lua
-- List all organization members
local result = app.integrations.linear.raw_query({
  query = [[
    query {
      organization {
        name
        users(first: 50) {
          nodes {
            id
            name
            email
          }
        }
      }
    }
  ]]
})

for _, user in ipairs(result.data.organization.users.nodes) do
  print(user.name .. " <" .. user.email .. ">")
end
```

---

## Pagination

Several list endpoints (`list_issues`, `search_issues`, `list_projects`, `list_initiatives`) support cursor-based pagination. The response includes:

| Field | Type | Description |
|-------|------|-------------|
| `has_next_page` | boolean | Whether more results exist. |
| `end_cursor` | string or nil | Cursor to pass as `after` for the next page. |

### Paginating through all results

```lua
local issues = {}
local cursor = nil

repeat
  local result = app.integrations.linear.list_issues({
    team_id = "team-abc-123",
    limit = 50,
    after = cursor
  })

  if result.error then
    print("Error: " .. result.error)
    break
  end

  for _, issue in ipairs(result.issues) do
    table.insert(issues, issue)
  end

  cursor = result.has_next_page and result.end_cursor or nil
until not cursor

print("Fetched " .. #issues .. " issues total")
```

---

## Notes

- **Priority values**: Linear uses numeric priorities — `0` (none), `1` (urgent), `2` (high), `3` (medium), `4` (low).
- **IDs vs identifiers**: Most tools accept either a UUID-style ID or a human-readable identifier like `"ENG-42"`. The `get_issue`, `update_issue`, `delete_issue`, `create_comment`, and `list_comments` tools support both forms.
- **label_ids format**: When multiple label IDs are needed (e.g., `create_issue`, `update_issue`), pass them as a single comma-separated string: `"label-111,label-222"`.
- **update_issue replaces labels**: The `label_ids` parameter on `update_issue` **replaces** the entire label set. To add or remove individual labels without affecting others, use `add_label` or `remove_label` instead.
- **Markdown support**: Issue descriptions and comment bodies support full markdown.
- **GraphQL backend**: All operations use the Linear GraphQL API at `https://api.linear.app/graphql`. For operations not covered by the built-in tools, use `raw_query` to run custom GraphQL queries or mutations.
- **Rate limits**: Linear enforces API rate limits. If you encounter errors during bulk operations, add delays between calls.
- **Team discovery**: Call `get_teams({})` first to discover team IDs, then `list_workflows({ team_id = "..." })` for available states, and `list_labels({ team_id = "..." })` for available labels.

---

## Multi-Account Usage

If you have multiple linear accounts configured, use account-specific namespaces:

```lua
-- Default account (always works)
app.integrations.linear.function_name({...})

-- Explicit default (portable across setups)
app.integrations.linear.default.function_name({...})

-- Named accounts
app.integrations.linear.work.function_name({...})
app.integrations.linear.personal.function_name({...})
```

All functions are identical across accounts — only the credentials differ.
Metadata-derived Lua example
local result = app.integrations.linear.create_issue({team_id = "example_team_id", title = "example_title", description = "example_description", priority = 1, assignee_id = "example_assignee_id", label_ids = "example_label_ids", state_id = "example_state_id"})
print(result)

Functions

create_issue Write

Create a new issue in Linear. Requires a team ID and title. Optionally set description, priority (0=none, 1=urgent, 2=high, 3=medium, 4=low), assignee, labels, and initial state. Use linear_get_teams to find team IDs.

Lua path
app.integrations.linear.create_issue
Full name
linear.linear_create_issue
ParameterTypeRequiredDescription
team_id string yes Team ID to create the issue in.
title string yes Issue title.
description string no Issue description (markdown supported).
priority integer no Priority: 0=none, 1=urgent, 2=high, 3=medium, 4=low.
assignee_id string no User ID to assign the issue to.
label_ids string no Comma-separated label IDs to apply.
state_id string no Workflow state ID for the initial status.
get_issue Read

Get a single Linear issue by ID or identifier (e.g., "TEAM-123"). Returns full details including description, state, assignee, labels, team info, and comments.

Lua path
app.integrations.linear.get_issue
Full name
linear.linear_get_issue
ParameterTypeRequiredDescription
id string yes Issue ID or identifier (e.g., "TEAM-123").
update_issue Write

Update an existing Linear issue. Provide the issue ID or identifier and any fields to change. Only specified fields will be updated. Priority: 0=none, 1=urgent, 2=high, 3=medium, 4=low.

Lua path
app.integrations.linear.update_issue
Full name
linear.linear_update_issue
ParameterTypeRequiredDescription
id string yes Issue ID or identifier to update.
title string no New title.
description string no New description (markdown).
priority integer no Priority: 0=none, 1=urgent, 2=high, 3=medium, 4=low.
assignee_id string no User ID to assign.
state_id string no Workflow state ID to set.
label_ids string no Comma-separated label IDs to set (replaces existing labels).
search_issues Read

Search Linear issues using filter criteria. Supports filtering by text query, team, state name, assignee, and priority. Returns matching issues with pagination info.

Lua path
app.integrations.linear.search_issues
Full name
linear.linear_search_issues
ParameterTypeRequiredDescription
query string no Text to search in issue titles and descriptions.
team_id string no Filter by team ID.
state string no Filter by state name (e.g., "In Progress", "Done").
assignee_id string no Filter by assignee user ID.
priority integer no Filter by priority: 0=none, 1=urgent, 2=high, 3=medium, 4=low.
limit integer no Max results to return. Default: 20.
list_issues Read

List issues for a specific Linear team. Supports filtering by status, assignee, and cursor-based pagination. Use linear_get_teams to find team IDs.

Lua path
app.integrations.linear.list_issues
Full name
linear.linear_list_issues
ParameterTypeRequiredDescription
team_id string yes Team ID to list issues for.
status string no Filter by state name (e.g., "In Progress", "Backlog").
assignee_id string no Filter by assignee user ID.
limit integer no Results per page. Default: 25.
after string no Cursor for next page (from previous response endCursor).
delete_issue Write

Delete a Linear issue by ID or identifier. This action is irreversible.

Lua path
app.integrations.linear.delete_issue
Full name
linear.linear_delete_issue
ParameterTypeRequiredDescription
id string yes Issue ID or identifier to delete (e.g., "TEAM-123").
create_comment Write

Add a comment to a Linear issue. Supports markdown formatting. Provide the issue ID or identifier and the comment body.

Lua path
app.integrations.linear.create_comment
Full name
linear.linear_create_comment
ParameterTypeRequiredDescription
issue_id string yes Issue ID or identifier to comment on.
body string yes Comment body text (markdown supported).
list_comments Read

List all comments on a Linear issue, ordered chronologically. Provide the issue ID or identifier.

Lua path
app.integrations.linear.list_comments
Full name
linear.linear_list_comments
ParameterTypeRequiredDescription
issue_id string yes Issue ID or identifier to list comments for.
get_teams Read

Get all Linear teams the authenticated user has access to, including team name, key, description, and member list. Use this to discover team IDs needed for other tools.

Lua path
app.integrations.linear.get_teams
Full name
linear.linear_get_teams
ParameterTypeRequiredDescription
No parameters.
list_projects Read

List Linear projects with optional cursor-based pagination. Returns project details including state, dates, lead, and associated teams.

Lua path
app.integrations.linear.list_projects
Full name
linear.linear_list_projects
ParameterTypeRequiredDescription
limit integer no Results per page. Default: 25.
after string no Cursor for next page (from previous response endCursor).
create_project Write

Create a new Linear project. Requires a name and at least one team ID. Optionally set description, lead, and target dates. Use linear_get_teams to find team IDs.

Lua path
app.integrations.linear.create_project
Full name
linear.linear_create_project
ParameterTypeRequiredDescription
name string yes Project name.
description string no Project description.
team_ids string yes Comma-separated team IDs to associate.
lead_id string no User ID of the project lead.
update_project Write

Update a Linear project. Provide the project ID and any fields to change. Only specified fields will be updated.

Lua path
app.integrations.linear.update_project
Full name
linear.linear_update_project
ParameterTypeRequiredDescription
id string yes Project ID to update.
name string no New project name.
description string no New description.
state string no New project state (e.g., "planned", "active", "paused", "completed", "canceled").
list_initiatives Read

List Linear initiatives with optional limit. Returns initiative details including state, dates, and associated projects.

Lua path
app.integrations.linear.list_initiatives
Full name
linear.linear_list_initiatives
ParameterTypeRequiredDescription
limit integer no Max results to return. Default: 25.
create_initiative Write

Create a new Linear initiative. Initiatives group related projects together. Requires a name. Optionally include a description.

Lua path
app.integrations.linear.create_initiative
Full name
linear.linear_create_initiative
ParameterTypeRequiredDescription
name string yes Initiative name.
description string no Initiative description.
list_labels Read

List issue labels in Linear. Optionally filter by team. Returns label ID, name, color, and description.

Lua path
app.integrations.linear.list_labels
Full name
linear.linear_list_labels
ParameterTypeRequiredDescription
team_id string no Team ID to filter labels by.
add_label Write

Add a label to a Linear issue. Provide the issue ID or identifier and the label ID to add. The label will be appended to existing labels. Use linear_list_labels to find label IDs.

Lua path
app.integrations.linear.add_label
Full name
linear.linear_add_label
ParameterTypeRequiredDescription
issue_id string yes Issue ID or identifier.
label_id string yes Label ID to add.
remove_label Write

Remove a label from a Linear issue. Provide the issue ID or identifier and the label ID to remove. Other labels on the issue are preserved.

Lua path
app.integrations.linear.remove_label
Full name
linear.linear_remove_label
ParameterTypeRequiredDescription
issue_id string yes Issue ID or identifier.
label_id string yes Label ID to remove.
get_current_user Read

Get the currently authenticated Linear user's profile, including ID, name, email, and avatar URL.

Lua path
app.integrations.linear.get_current_user
Full name
linear.linear_get_current_user
ParameterTypeRequiredDescription
No parameters.
list_workflows Read

List workflow states for a Linear team. Shows all available statuses (e.g., Backlog, Todo, In Progress, Done) with their IDs, types, and colors. Optionally filter by team ID.

Lua path
app.integrations.linear.list_workflows
Full name
linear.linear_list_workflows
ParameterTypeRequiredDescription
team_id string no Team ID to filter workflow states by.
raw_query Read

Execute an arbitrary GraphQL query or mutation against the Linear API. Provide a GraphQL document and optional variables as JSON. Use this for advanced operations not covered by other tools.

Lua path
app.integrations.linear.raw_query
Full name
linear.linear_raw_query
ParameterTypeRequiredDescription
query string yes GraphQL query or mutation document.
variables string no Variables as a JSON object string.