This guide walks you through setting up Cyrus completely self-hosted, including your own Linear OAuth application. This is the free, zero-cost option that gives you full control.
Tip: If you're using Claude, Cursor, or any AI coding agent, ask it to read this file and help you implement all the steps. Example: "Read docs/SELF_HOSTING.md and help me set up self-hosted Cyrus"
- Linear workspace with admin access (required to create OAuth apps)
- Node.js v18 or higher
- jq (for Claude Code parsing)
- A public URL for receiving Linear webhooks
macOS:
brew install jq gh
# Verify
jq --version # Should show version like jq-1.7
node --version # Should show v18 or higherLinux/Ubuntu:
apt install -y gh npm git jq
# Verify
jq --version # Should show version like jq-1.7
node --version # Should show v18 or higherYou'll complete these steps:
- Set up a public URL for webhooks
- Configure Claude Code authentication
- Create a Linear OAuth application
- Install Cyrus and complete your environment file
- Start Cyrus, authorize with Linear, and add repositories
Tip: Cyrus automatically loads environment variables from
~/.cyrus/.envon startup. You can override this path withcyrus --env-file=/path/to/your/env.
Linear needs to send webhooks to your Cyrus instance. Choose one option:
| Option | Best For | Persistence |
|---|---|---|
| Cloudflare Tunnel | Production | Permanent URL |
| ngrok | Development/testing | Changes on restart |
| Public server/domain | VPS or cloud hosting | Permanent URL |
| Reverse proxy (nginx/caddy) | Existing infrastructure | Permanent URL |
You'll need:
- A public URL (e.g.,
https://cyrus.yourdomain.com) - The URL must be accessible from the internet
Cyrus needs Claude Code credentials. Choose one option and add it to your env file (~/.cyrus/.env):
Option A: API Key (recommended)
ANTHROPIC_API_KEY=your-api-keyGet your API key from the Anthropic Console.
Option B: OAuth Token (for Max subscription users)
Run claude setup-token on any machine where you already have Claude Code installed (e.g., your laptop), then add to your env file:
CLAUDE_CODE_OAUTH_TOKEN=your-oauth-tokenOption C: Third-Party Providers
For Vertex AI, Azure, AWS Bedrock, and other providers, see the Third-Party Integrations documentation.
IMPORTANT: You must be a workspace admin in Linear.
- Go to Linear: https://linear.app
- Click your workspace name (top-left corner)
- Click Settings in the dropdown
- In the left sidebar, scroll down to Account section
- Click API
- Scroll down to OAuth Applications section
-
Click Create new OAuth Application button
-
Fill in the form:
- Name:
Cyrus - Description:
Self-hosted Cyrus agent for automated development - Callback URLs:
https://your-public-url.com/callback
- Name:
-
Enable Client credentials toggle
-
Enable Webhooks toggle
-
Configure Webhook Settings:
- Webhook URL:
https://your-public-url.com/webhook - App events - Check these boxes:
- Agent session events (REQUIRED - makes Cyrus appear as agent)
- Inbox notifications (recommended)
- Permission changes (recommended)
- Webhook URL:
-
Click Save
After saving, copy these values:
- Client ID - Long string like
client_id_27653g3h4y4ght3g4 - Client Secret - Another long string (may only be shown once!)
- Webhook Signing Secret - Found in webhook settings
Add these to your env file (~/.cyrus/.env):
# Linear OAuth configuration
LINEAR_DIRECT_WEBHOOKS=true
LINEAR_CLIENT_ID=client_id_27653g3h4y4ght3g4
LINEAR_CLIENT_SECRET=client_secret_shgd5a6jdk86823h
LINEAR_WEBHOOK_SECRET=lin_whs_s56dlmfhg72038474nmfojhsn7npm install -g cyrus-aiYour env file (~/.cyrus/.env) should now contain:
# Server configuration
LINEAR_DIRECT_WEBHOOKS=true
CYRUS_BASE_URL=https://your-public-url.com
CYRUS_SERVER_PORT=3456
# Linear OAuth
LINEAR_CLIENT_ID=your_client_id
LINEAR_CLIENT_SECRET=your_client_secret
LINEAR_WEBHOOK_SECRET=your_webhook_secret
# Claude Code authentication (choose one)
ANTHROPIC_API_KEY=your-api-key
# or: CLAUDE_CODE_OAUTH_TOKEN=your-oauth-token
# Optional: Cloudflare Tunnel
# CLOUDFLARE_TOKEN=your-cloudflare-tokencyrus self-authThis will:
- Start a temporary OAuth callback server
- Open your browser to Linear's OAuth authorization page
- After you click Authorize, redirect back and save the tokens to your config
cyrus self-add-repo https://github.com/yourorg/yourrepo.gitThis clones the repository to ~/.cyrus/repos/ and configures it with your Linear workspace credentials.
For multiple workspaces, specify which one:
cyrus self-add-repo https://github.com/yourorg/yourrepo.git "My Workspace"You can run cyrus self-add-repo at any time, even while Cyrus is running. No restart is required—Cyrus will automatically pick up the new repository configuration.
Once authorization is complete and repositories are added, start Cyrus:
cyrusCyrus automatically loads ~/.cyrus/.env on startup. You'll see Cyrus start up and show logs.
Note: To use a different env file location, use
cyrus --env-file=/path/to/your/env.
For Cyrus to create pull requests, configure Git and GitHub CLI authentication.
See the Git & GitHub Setup Guide for complete instructions.
For 24/7 availability, run Cyrus as a persistent process.
tmux new-session -s cyrus
cyrus
# Ctrl+B, D to detach
# tmux attach -t cyrus to reattachpm2 start cyrus --name cyrus
pm2 save
pm2 startupCreate /etc/systemd/system/cyrus.service:
[Unit]
Description=Cyrus AI Agent
After=network.target
[Service]
Type=simple
User=your-user
EnvironmentFile=/home/your-user/.cyrus/.env
ExecStart=/usr/local/bin/cyrus
Restart=always
[Install]
WantedBy=multi-user.targetThen:
sudo systemctl enable cyrus
sudo systemctl start cyrusCyrus stores its configuration in ~/.cyrus/config.json. You can customize tool permissions, issue routing rules, MCP server integrations, and label-based AI modes by editing this file. Cyrus watches the config file and automatically picks up changes—no restart required.
For detailed options, see the Configuration File Reference.
- Verify
CYRUS_BASE_URLmatches your Linear OAuth callback URL exactly - Check that your public URL is accessible from the internet
- Ensure all Linear environment variables are set
- Verify Linear webhook URL matches
CYRUS_BASE_URL/webhook - Check Cyrus logs for incoming webhook attempts
- Ensure your public URL is accessible
- Check that the repository is in your config (
~/.cyrus/config.json) - Verify Linear tokens are valid with
cyrus check-tokens - Ensure the issue is assigned to Cyrus in Linear
- Verify your Claude Code credentials are set in the env file
- For API key: Check it's valid at console.anthropic.com
- For OAuth token: Run
claude setup-tokenagain to refresh
If you're developing Cyrus from source:
cd /path/to/cyrus
pnpm install
cd apps/cli
pnpm link --global
# In a separate terminal
pnpm dev
# Then run cyrus normally
cyrus