Gareth Wilson Gareth Wilson

How to Run Claude Code as a Linear Agent with Cyrus and Hookdeck CLI

Published


Linear's agent platform lets you assign issues to AI coding agents the same way you'd assign them to a teammate. Cursor, GitHub Copilot, Codex, and Devin all have native integrations. Claude Code, however, doesn't have one yet.

When asked why, Linear explained that all their agent integrations are third-party built using Linear's Agent SDK. Anthropic just hasn't opted to build one yet.

That's a shame, but while we wait for an official agent, there is a solution: Cyrus.

Cyrus is an open-source agent runner that connects Claude Code to Linear's Agent SDK, so Claude shows up as an assignable agent in your workspace. And since Cyrus needs a publicly accessible webhook URL to receive events from Linear, Hookdeck CLI is a natural fit for getting it running locally without deploying infrastructure.

This guide walks through the full self-hosted setup.

What are Linear agents?

Linear agents are AI-powered teammates that live inside your workspace. You assign them issues, mention them in comments, and track their work — the same way you would with a human contributor. The human assignee stays primary, with the agent added as a contributor, so there's always accountability.

What makes this powerful is the workflow integration. You're not copy-pasting issue descriptions into a separate tool. The agent gets full context: issue description, comments, linked references, images. It works inside your existing project management flow and streams updates back into Linear as it goes.

Architecture

Here's how the pieces fit together:

Linear (webhook) → Hookdeck CLI → Cyrus → Claude Code

                                           Git branch + PR

                                           Linear update
  • Linear sends webhook events when issues are assigned to the Cyrus agent
  • Hookdeck CLI provides a stable public URL that forwards those webhooks to your local machine
  • Cyrus receives the events, creates an isolated git worktree, and spawns a Claude Code session
  • Claude Code reads the issue context, writes code, commits, and opens a pull request

Prerequisites

Install the dependencies:

# macOS
brew install jq gh hookdeck/hookdeck/hookdeck

# Linux/Ubuntu
apt install -y gh npm git jq
# See Hookdeck CLI docs for Linux install

Step 1: Start the Hookdeck CLI listener

Linear needs a publicly accessible URL to deliver webhooks. Hookdeck CLI creates a secure tunnel from a public URL to your local machine — no exposed ports, no infrastructure to manage.

hookdeck login
hookdeck listen 3456 cyrus

Hookdeck will output a URL like https://hkdk.events/abc123def456. Save this — you'll need it for the Linear OAuth app configuration.

Don't use the --path flag here. Cyrus handles multiple routes (/webhook, /callback, /github-webhook), and you need Hookdeck to preserve the original request path.

Also note that the OAuth callback is a browser redirect (GET request), but Hookdeck sources only allow POST/PUT/PATCH/DELETE by default. You'll need to enable GET requests on your Hookdeck source (either through the dashboard or the API).

Step 2: Install and configure Cyrus

npm install -g cyrus-ai
mkdir -p ~/.cyrus

Create your environment file at ~/.cyrus/.env:

# Server configuration
LINEAR_DIRECT_WEBHOOKS=true
CYRUS_BASE_URL=https://hkdk.events/your-hookdeck-url
CYRUS_SERVER_PORT=3456

# Claude Code authentication
ANTHROPIC_API_KEY=your-api-key

# Linear OAuth (filled in next step)
LINEAR_CLIENT_ID=
LINEAR_CLIENT_SECRET=
LINEAR_WEBHOOK_SECRET=

Step 3: Create a Linear OAuth application

This is the step that connects Cyrus to Linear's Agent SDK.

  1. In Linear, go to Settings → API → OAuth Applications
  2. Click Create new OAuth Application with these settings:
    • Name: Cyrus
    • Callback URL: https://hkdk.events/your-hookdeck-url/callback
    • Enable Client credentials
    • Enable Webhooks
    • Webhook URL: https://hkdk.events/your-hookdeck-url/webhook
    • Check Agent session events (required), Inbox notifications, and Permission changes
  3. Save, then copy the Client ID, Client Secret, and Webhook Signing Secret

Add these to your ~/.cyrus/.env file:

LINEAR_CLIENT_ID=your_client_id
LINEAR_CLIENT_SECRET=your_client_secret
LINEAR_WEBHOOK_SECRET=your_webhook_secret

Step 4: Authorize and add a repository

Start Cyrus once to generate the initial config, then authorize with Linear:

cyrus        # starts and creates ~/.cyrus/config.json, then Ctrl+C
cyrus self-auth

The auth command opens your browser for Linear OAuth authorization. After clicking Authorize, Cyrus saves the tokens to your config.

Then add your repository:

cyrus self-add-repo https://github.com/yourorg/yourrepo.git

This clones the repo to ~/.cyrus/repos/ and wires it up with your Linear workspace credentials.

Step 5: Start Cyrus

cyrus

Cyrus logs will show your configured repositories and confirm the webhook endpoint is listening. Head to Linear, assign an issue to Cyrus, and watch it work.

Running persistently

For anything beyond a quick test, you'll want Cyrus and Hookdeck running as managed processes. pm2 is the simplest option:

npm install -g pm2

pm2 start cyrus --name cyrus
pm2 start "hookdeck listen 3456 cyrus" --name hookdeck

pm2 save
pm2 startup   # follow the printed command for boot persistence

Gotchas and lessons learned

  • Watch your environment variables. If you start Cyrus from inside a Claude Code session or Claude Desktop, environment variables like CLAUDE_CODE_ENTRYPOINT and CLAUDECODE leak into the process. When Cyrus spawns Claude Code via the Agent SDK, these cause it to crash with exit code 1. If you're using pm2, create a wrapper script that unsets these variables before starting Cyrus:
#!/bin/bash
# ~/.cyrus/start-cyrus.sh
unset CLAUDECODE
unset CLAUDE_CODE_ENTRYPOINT
unset CLAUDE_CODE_EMIT_TOOL_USE_SUMMARIES
unset CLAUDE_CODE_ENABLE_ASK_USER_QUESTION_TOOL
unset CLAUDE_AGENT_SDK_VERSION
unset __CFBundleIdentifier

exec cyrus

Then: pm2 start ~/.cyrus/start-cyrus.sh --name cyrus --interpreter bash

  • The self-auth chicken-and-egg problem. cyrus self-auth saves tokens to existing repository entries in the config. If you haven't added any repos yet, the tokens are saved to nothing. Run cyrus first to generate the config, then add a stub repository entry before running self-auth. The self-hosting docs walk through the expected order, but if you hit "No Linear credentials found," this is likely why.

  • Configure commit and PR style with CLAUDE.md. Cyrus runs Claude Code under the hood, so it respects CLAUDE.md files. Drop one in ~/.cyrus/ for global settings or in your repository root for per-repo rules. This is where you control commit message format, branch naming conventions, and PR description structure.

Going further

  • Add multiple repositories with cyrus self-add-repo — Cyrus picks up new configs without restarting
  • Customize tool permissions and AI modes in ~/.cyrus/config.json (see the config reference)
  • Set up GitHub CLI auth so Cyrus can create pull requests (see the Git & GitHub guide)
  • Use the Hookdeck dashboard to inspect, retry, and debug webhook deliveries
  • Use our guide to build a Linear agent from scratch using Hookdeck CLI

Linear's agent platform is still early, and the ecosystem of supported agents is growing fast. If Claude Code is your tool of choice, Cyrus and Hookdeck CLI give you a way to plug it in today.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.