---
title: "Linear"
description: "Reach your agent through Linear Agent Sessions, with native Agent Activities for progress, questions, and responses."
type: integration
---

The Linear channel uses Linear's Agent Session surface rather than ordinary comments. Users delegate work to the agent from Linear, eve receives `AgentSessionEvent` webhooks at `/eve/v1/linear`, and the channel replies with native Agent Activities, including `thought`, `action`, `elicitation`, `response`, and `error`. See [Channels](./overview) for the contract this builds on.

## Add the channel

```ts title="agent/channels/linear.ts"
import { linearChannel } from "eve/channels/linear";

export default linearChannel({
  credentials: {
    accessToken: process.env.LINEAR_AGENT_ACCESS_TOKEN,
    webhookSecret: process.env.LINEAR_WEBHOOK_SECRET,
  },
});
```

```bash
LINEAR_AGENT_ACCESS_TOKEN=lin_api_... # posts Agent Activities and creates proactive sessions
LINEAR_WEBHOOK_SECRET=...             # verifies Linear-Signature
```

The sample passes credentials explicitly. To rely on env vars instead, drop the `credentials` block: the access token falls back to `LINEAR_AGENT_ACCESS_TOKEN`, `LINEAR_ACCESS_TOKEN`, `LINEAR_API_KEY`, or `LINEAR_API_TOKEN`, and the webhook secret falls back to `LINEAR_WEBHOOK_SECRET`. Both fields also accept lazy resolver functions.

## Configure Linear

Create a Linear OAuth app, enable Agent Session events, and point the webhook URL at:

```text
https://<deployment>/eve/v1/linear
```

For Linear's agent surface, configure the OAuth authorize URL with `actor=app` and grant the app scopes that let it appear as an agent in Linear, including `app:assignable` and `app:mentionable`. Subscribe to the `AgentSessionEvent` webhook category so Linear sends `created` events when the agent is delegated or mentioned and `prompted` events when the user continues the session.

Linear sends webhook signatures in `Linear-Signature`; eve verifies the HMAC over the raw body and rejects stale `webhookTimestamp` values. If a trusted gateway verifies Linear before the request reaches eve, pass `credentials.webhookVerifier` instead of a webhook secret.

## How the channel handles messages

### Dispatch

The default hook dispatches `created` and `prompted` Agent Session events. eve adds a Linear context block with the agent session, issue, comment, and organization identifiers, then continues the same session with `agent-session:<id>`.

### Delivery

Turn start posts an ephemeral `thought`, tool calls post ephemeral `action` activities, final assistant text posts a durable `response`, and failures post `error` activities. When the model emits text before a tool call, eve buffers the first non-empty line and uses it as the next ephemeral Linear `thought`, mirroring Slack's typing-status behavior.

### Human-in-the-loop (HITL)

Human-in-the-loop (HITL) input requests render as Linear `elicitation` activities. When the user replies to the Agent Session, the channel resolves that prompt back to the pending eve input request and resumes with `inputResponses`.

### Proactive sessions

Start a session without an inbound webhook with `receive(linear, { target })`. See [Proactive sessions](#proactive-sessions) below for the target shape and examples.

### Attachments

Inbound file attachments are not supported on this channel today.

### API handle

Event handlers receive `channel.linear`, which exposes `createActivity`, `listActivities`, and `updateSession` for custom Agent Activity delivery and Agent Session metadata.

## Custom hooks

Return `{ auth }` to dispatch, or `null` to acknowledge without waking the agent.

```ts
import { defaultLinearAuth, linearChannel } from "eve/channels/linear";

export default linearChannel({
  onAgentSession: (_ctx, event) => {
    if (event.action !== "created" && event.action !== "prompted") return null;
    return { auth: defaultLinearAuth(event) };
  },
});
```

Restrict dispatch to a subset of Linear teams or projects by inspecting `event.agentSession.issue` in `onAgentSession`. Add extra context by returning `context` alongside `auth`.

```ts
import { defaultLinearAuth, linearChannel } from "eve/channels/linear";

export default linearChannel({
  onAgentSession: (_ctx, event) => {
    if (event.agentSession.issue?.identifier?.startsWith("OPS-") !== true) return null;
    return {
      auth: defaultLinearAuth(event),
      context: ["Only make reversible changes unless the issue says otherwise."],
    };
  },
});
```

Override event delivery when you want more specific Agent Activities.

```ts
import { linearChannel } from "eve/channels/linear";

export default linearChannel({
  events: {
    async "message.completed"(eventData, channel) {
      if (eventData.finishReason === "tool-calls" || !eventData.message) return;
      await channel.linear.createActivity({
        body: `Done.\n\n${eventData.message}`,
        type: "response",
      });
    },
    async "input.requested"(eventData, channel) {
      await channel.linear.createActivity({
        body: eventData.requests.map((request) => request.prompt).join("\n\n"),
        type: "elicitation",
      });
    },
  },
});
```

Add session-level links when your agent creates an external artifact.

```ts
await channel.linear.updateSession({
  addedExternalUrls: [{ label: "Run log", url: "https://example.com/runs/123" }],
});
```

## Proactive sessions

Use the channel's `receive` target to continue an existing Agent Session or create one from a Linear issue or root comment. The target accepts an existing `agentSessionId`, or an `issueId` or root `commentId` to create a new session before sending the message. The example below runs from a schedule; a route handler uses the same target shape through its own `receive` helper.

```ts
import { defineSchedule } from "eve/schedules";

import linear from "../channels/linear.js";

export default defineSchedule({
  cron: "0 14 * * 1",
  async run({ receive, waitUntil, appAuth }) {
    waitUntil(
      receive(linear, {
        auth: appAuth,
        message: "Post a concise status update with blockers and next actions.",
        target: {
          issueId: "EVE-123",
          initialActivity: "Preparing the status update.",
        },
      }),
    );
  },
});
```

For issue or comment targets, the channel calls Linear's proactive Agent Session mutations before starting the eve turn. For an existing `agentSessionId`, it skips session creation and only seeds the continuation token.

## What to read next

- [Channels overview](./overview): the channel contract and every built-in channel
- [MCP connections](../connections/mcp): use the Linear MCP connection when the agent needs to inspect or edit Linear data from another channel
