---
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: `thought`, `action`, `elicitation`, `response`, and `error`.

## 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
```

If you'd rather not use env vars, pass the same values through `credentials: { accessToken, webhookSecret }`. Both fields also accept lazy resolver functions. The access token falls back to `LINEAR_AGENT_ACCESS_TOKEN`, `LINEAR_ACCESS_TOKEN`, `LINEAR_API_KEY`, or `LINEAR_API_TOKEN`; the webhook secret falls back to `LINEAR_WEBHOOK_SECRET`.

## 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.

## Affordances

**Agent Session 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>`.

**Native progress and replies.** 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 input.** Eve input requests are rendered 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`.

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

**Proactive sessions.** `receive(linear, { target })` accepts an existing `agentSessionId`, or can create a new Agent Session on an `issueId` or root `commentId` before sending the message.

```ts
await receive(linear, {
  auth: null,
  message: "Summarize the current status and risks.",
  target: { issueId: "issue-id" },
});
```

## 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"(event, channel) {
      if (event.finishReason === "tool-calls" || !event.message) return;
      await channel.linear.createActivity({
        body: `Done.\n\n${event.message}`,
        type: "response",
      });
    },
    async "input.requested"(event, channel) {
      await channel.linear.createActivity({
        body: event.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.

```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.",
        },
      }),
    );
  },
});
```

Route handlers can use the same target shape through their `receive` helper:

```ts
await receive(linear, {
  auth: null,
  message: "Post a concise status update with blockers and next actions.",
  target: {
    issueId: "EVE-123",
    initialActivity: "Preparing the status update.",
  },
});
```

For issue/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
- [Connections](../connections): use the Linear MCP connection when the agent needs to inspect or edit Linear data from another channel
