> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auto.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Linear Events

> Linear issue events an agent trigger can listen on: payload shape, label and state filters, mention detection, and issue-bound routing.

Linear sends issue webhooks to auto, which normalizes them into two trigger events: `linear.issue.created` and `linear.issue.updated`. This page documents their payloads, the filters that make label-driven and mention-driven workflows work, and how sessions bind to the issues they own. A trigger on a `linear.*` event resolves against the project's Linear connection at apply time; name it with `connection:` when more than one exists.

## Event keys

| Event                  | Fires when                                                                                    |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| `linear.issue.created` | A Linear issue was created.                                                                   |
| `linear.issue.updated` | A Linear issue was updated — title, description, state, assignee, labels, or any other field. |

Only Linear `Issue` webhooks with action `create` or `update` are ingested; other actions and entity types are dropped at the ingress. Deliveries are verified with an HMAC-SHA256 signature over the raw body (Linear's `linear-signature` header) and deduplicated by a hash of the body, so webhook retries never double-fire a trigger.

<Note>
  Comment activity on Linear issues does not produce a trigger event today. Inbound Linear is `linear.issue.created` and `linear.issue.updated` only; a description edit arrives as `linear.issue.updated`. Sessions can still read and write comments through the [chat tools](/runtime/chat-tools) with target provider `linear`.
</Note>

## Payload

<ParamField path="artifact" type="object">
  The issue as a bindable artifact: `type: "linear.issue"` and `externalId` in the form `linear:<organizationId>:issue/<issueId>`. This is what `bind`-routed triggers and bind-at-spawn resolve against.
</ParamField>

<ParamField path="linear.action" type="string">
  `create` or `update`.
</ParamField>

<ParamField path="linear.issue" type="object">
  The issue snapshot: `id`, `identifier` (e.g. `ENG-123`), `title`, `description`, `url`, `state` (`{ id, name, type }`), `team` (`{ id, key, name }`), and `labelNames` — a flat array of the issue's current label names.
</ParamField>

<ParamField path="linear.actor" type="object">
  Who performed the change: `{ id, type, name }`.
</ParamField>

<ParamField path="linear.auto" type="object">
  Auto metadata: `authored` (the change was made by the Auto app user — all agents share one Linear app user, so this says "an Auto session did this", not which one), `mentioned` (the issue description @-mentions Auto), and `context.kind: "explicit_mention"` when mentioned.
</ParamField>

<ParamField path="linear.updatedFrom" type="object">
  On `linear.issue.updated`: the previous values Linear reported for the changed fields, augmented with `labelNames: { added: [...], removed: [...] }` — a computed diff of label names whenever labels changed.
</ParamField>

<ParamField path="linear.organizationId" type="string">
  The Linear organization id. `webhookId` and `webhookTimestamp` are also present.
</ParamField>

<ParamField path="raw" type="object">
  The raw Linear webhook payload.
</ParamField>

### Mention detection

`linear.auto.mentioned` is true when the issue **description** contains a Linear mention of the Auto app user — Linear renders mentions as `@[Display Name](userId)` markup, and auto matches the user id or display name. Mentions elsewhere (comments, other fields) are not detected.

## Template placeholders

```yaml theme={null}
initialPrompt: |
  Triage Linear issue {{linear.issue.identifier}}: {{linear.issue.title}}

  Trigger event: {{type}}
  Issue URL: {{linear.issue.url}}
  Current state: {{linear.issue.state.name}}
```

Objects and arrays render as JSON; missing paths render as empty strings. See [variables and templating](/reference/variables-and-templating).

## Filters

| Filter                                                               | Use                                                                                                           |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `$.linear.issue.labelNames: { contains: "auto-triage" }`             | The issue currently carries a label — the standard "label as request token" kickoff.                          |
| `$.linear.updatedFrom.labelNames.added: { contains: "auto-triage" }` | The label was added **in this update** — fires once at the moment of labeling instead of on every later edit. |
| `$.linear.auto.authored: false`                                      | Suppress echoes of the agent's own Linear writes.                                                             |
| `$.linear.auto.mentioned: true`                                      | The issue description mentions Auto.                                                                          |
| `$.linear.issue.state.name: "In Progress"`                           | Match the issue's current state by equality.                                                                  |
| `$.linear.issue.team.key: "ENG"`                                     | Pin to one team.                                                                                              |

<Warning>
  The `changedTo` filter operator does not work on Linear events: it looks for a sibling `previous.*` object in the payload, which Linear payloads do not carry. To react to a transition, combine an existence filter on the previous value under `$.linear.updatedFrom` with an equality filter on the current value — `linear.updatedFrom` holds exactly the fields Linear reported as changed.
</Warning>

Pair a `linear.issue.created` trigger with a `linear.issue.updated` trigger when you key off labels: creation with the label already set fires only `created`, and labeling an existing issue fires only `updated`.

## Routing

Both Linear events carry the issue as a `linear.issue` routing target, so:

* **`spawn`** starts a fresh session for the issue. Add `bind: { target: linear.issue }` when the session should own the issue, so later `linear.issue.updated` events can `bind`-route back to it.
* **`bind` with `target: linear.issue`** delivers follow-up updates into the session bound to that issue; `onUnmatched` (default `drop`) governs updates to issues no session owns.

## Example: label-driven triage

An agent that triages any issue labeled `auto-triage`, whether the label was set at creation or added later. Adapted from the [issue triage example](/examples/issue-triage).

```yaml .auto/agents/issue-triage.yaml theme={null}
name: issue-triage
systemPrompt: |
  You are the issue triage agent. Work from Linear as the source of
  truth, using chat.issue.get, chat.issue.update, chat.history, and
  chat.send with target provider `linear`. The `auto-triage` label is a
  one-shot request token — remove it once you have acted.
initialPrompt: |
  Triage Linear issue {{linear.issue.identifier}}: {{linear.issue.title}}

  Trigger event: {{type}}
  Issue URL: {{linear.issue.url}}

  Inspect the issue and related Linear context, then apply your triage
  instructions.
tools:
  auto:
    kind: local
    implementation: auto
  chat:
    kind: local
    implementation: chat
    auth:
      kind: connection
      provider: linear
      connection: linear
triggers:
  # Issue created with the label already applied.
  - event: linear.issue.created
    connection: linear
    where:
      $.linear.issue.labelNames:
        contains: auto-triage
    routing:
      kind: spawn
  # Label added to an existing issue.
  - event: linear.issue.updated
    connection: linear
    where:
      $.linear.updatedFrom.labelNames.added:
        contains: auto-triage
    routing:
      kind: spawn
```

To keep one durable session per issue instead of one per labeling, add `bind: { target: linear.issue }` to each spawn and a third trigger:

```yaml theme={null}
  - event: linear.issue.updated
    connection: linear
    where:
      $.linear.auto.authored: false
    routing:
      kind: bind
      target: linear.issue
      onUnmatched: drop
```

The spawn and bind triggers overlap on one edge: re-adding the label to an issue whose session is still bound fires both. Have the agent remove the label once it has acted (as the system prompt above instructs) to keep the label a one-shot token.

## See also

* [Triggers reference](/reference/triggers) — routing kinds, filter grammar, `optional` connections
* [Chat tools](/runtime/chat-tools) — `chat.issue.get`, `chat.issue.update`, and commenting on issues
* [GitHub events](/reference/events/github) — the equivalent catalog for GitHub
