# Linear

**The Linear integration installs hlix as an agent in your Linear workspace.** Assign it an issue or mention it, and it opens an *agent session* — a thread in which it reports what it is doing and what it decided, and in which you can steer or stop it.

This is the only integration that both receives work and reports progress on the same surface.

## Prerequisites

- Agency `owner` or `admin` in the hlix workspace
- Permission to authorize an OAuth application in the target Linear workspace
- At least one hlix project the issue can be resolved to — see [what it needs to key on](#what-it-needs-from-an-issue)

## Connect it

1. **Start the install.** From the dashboard's integrations screen, or directly:

   ```bash
   curl -sS -i "$HLIX_BASE_URL/v1/api/integrations/linear/install" \
     -H "x-api-key: $HLIX_API_KEY" \
     -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
   ```

   Expected result: a `302` to `linear.app/oauth/authorize`, carrying an HMAC-signed state that binds the install to your workspace and user.

2. **Authorize in Linear.** hlix requests `read`, `write`, `app:assignable`, and `app:mentionable`, and installs with `actor=app` — so it becomes a workspace-level app user rather than acting as you. The two `app:` scopes are what make it assignable and mentionable at all.

3. **Land back on hlix.** The callback exchanges the code, reads the app user and workspace identity, and stores the installation with its refresh token and expiry.

   Expected result: a redirect to `…/integrations/linear?installed=1`.

4. **Verify.**

   ```bash
   curl -sS "$HLIX_BASE_URL/v1/api/integrations/linear" \
     -H "x-api-key: $HLIX_API_KEY" \
     -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
   ```

   Then, in Linear, assign the hlix agent to a test issue. A `thought` activity — *"Received — gathering context…"* — should appear in the session within seconds.

## What hlix writes back

Everything hlix says lands as an **agent activity** on the Linear session, not as an issue comment. Five kinds:

| Activity | Meaning |
| --- | --- |
| `thought` | intermediate reasoning. The immediate acknowledgement is one of these, and is ephemeral |
| `action` | a concrete step it took, with its parameter and result |
| `response` | its answer for this turn — a plan summary, a status, or the outcome |
| `elicitation` | a question for you. With options attached, Linear renders them as choices |
| `error` | the run failed, with the message |

The session's own status moves alongside: `awaitingInput` when it needs an answer, `complete` when the turn is finished, `error` when it is not. A session stays open only while something is actually going to report back.
**The acknowledgement is inline, on purpose:** Linear expects the first activity within ten seconds. hlix emits the acknowledgement **synchronously**, before returning `200` to the webhook, and dispatches the real run afterwards. If that acknowledgement call fails, the webhook still succeeds — the session row exists, so a follow-up event recovers.

## What it needs from an issue

hlix has to decide which project — and, for a multi-repository project, which repository — an issue belongs to. When it cannot, it does not guess. It sets the session to `awaitingInput` and asks once, listing the candidates, because running an agent against the wrong repository is worse than a question.

Two cases produce that question:

- **Nothing to key a project on.** The issue has no signal tying it to a hlix project.
- **The project has several repositories** and the issue never said which.

Answer in the thread and the session continues.

## Steering a running session

- **Prompt it again** by replying in the session. The agent reads the prior activity history, so the reply is a continuation rather than a fresh start.
- **Stop it** with Linear's stop signal. hlix honours it immediately, records the stop, replies *"Stopped as requested."*, and closes the session.

When hlix queues a cycle proposal it cannot hand to a live orchestrator, it says so and closes the turn rather than leaving the thread showing "Working…" indefinitely.

## Permissions and security

- The install uses `actor=app`, so the agent is its own workspace user. Actions are attributable to hlix, not to whoever installed it.
- Access tokens last 24 hours. hlix refreshes proactively within five minutes of expiry — but only **after** a webhook's signature has been verified, so a forged payload cannot trigger a token refresh or any database write.
- Every webhook is HMAC-verified against the OAuth app's signing secret before any side effect.
- A `PermissionChange` or unrecognised event type is acknowledged and ignored rather than processed on a guess.
- An `OAuthApp` revocation from Linear's side marks the installation revoked in hlix.
**The signing secret is not returned by the token exchange:** For an `actor=app` install, Linear does not include a webhook secret in the token response — it signs every webhook for the OAuth app with one app-scoped secret from the developer console. A deployment that enables the integration without configuring that secret **fails at boot**, deliberately: without it every webhook would 401, Linear would disable the webhook, and the integration would go silently dark.

## Disconnect

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/integrations/linear/$INSTALL_ID/revoke" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
```

`owner` or `admin` only. Revoke the OAuth application in Linear as well — that is the half that removes hlix's access.

## If Linear does not connect

- `500` — ``Linear OAuth not configured``. The deployment has no Linear OAuth credentials. Operator fix.
- Redirect with `error=missing_code_or_state` — the callback was opened without Linear's parameters. Restart from `/install`.
- Redirect with `error=invalid_state_…` — the signed state failed verification or expired. Restart the install.
- Redirect with `error=token_exchange_failed` — Linear refused the authorization code. Usually a redirect-URI mismatch in the OAuth app configuration.
- Redirect with `error=viewer_lookup_failed` — the token worked but the app user could not be read. Check the granted scopes include `read`.
- `401` on the webhook — ``unauthorized``. hlix answers this both when the signature does not verify AND when no installation matches the payload's app user, deliberately: the endpoint is unauthenticated, so a distinct "unknown installation" reply would let anyone probe which Linear workspaces hlix is installed in. To tell the two apart, read the backend log — it records `unknown appUserId` or `signature invalid` with the reason. Confirm the configured signing secret matches the OAuth app's Webhooks tab, and that you are pointing Linear at the right deployment; Linear disables a webhook that keeps failing.
- Nothing appears in the session thread — assignment and mention need the `app:assignable` and `app:mentionable` scopes. Reinstall if the original authorization predates them.
- The thread asks which project or repository — that is the design, not a failure. Answer in the thread.

## Next steps

[Cycles](/running/cycles/)
  [GitHub](/integrations/github/)
  [Approvals](/running/approvals/)
  [Integrations](/integrations/)