Linear Bridge Integration
August 21, 2026 · View on GitHub
DevPilot provides bidirectional synchronization with Linear for issue tracking.
Overview
The Linear integration enables:
- Outbound Sync: DevPilot sessions → Linear issues
- Inbound Sync: Linear webhooks → DevPilot dispatch (via hosted bridge)
- Status Updates: Progress synced in real-time
- Auto-Dispatch: Assign to bot user → automatic agent spawn
Everything below describes work DevPilot starts. For the other direction — agent sessions already running on your machine that DevPilot did not start, discovered and placed on the board — see docs/ADOPTION.md and
spec/trd/21-FLEET-INTROSPECTION.md.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ LINEAR │
└────────────────────────────────┬────────────────────────────────────┘
│ signed webhook (HMAC-SHA256, mandatory)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ HOSTED BRIDGE — Next.js on Vercel + Supabase Postgres │
│ │
│ verify signature → route by repo → ONE TRANSACTION: │
│ dispatch_sessions + session_events + dispatch_queue │
│ │
│ Realtime is a latency optimization. The GUARANTEE is the queue │
│ table: a client that reconnects sweeps for unclaimed rows. │
└────────────────────────────────┬────────────────────────────────────┘
│ claim = conditional UPDATE (the ack)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ YOUR MACHINE — devpilot bridge connect │
│ local orchestrator runs the agent · reports status + completion │
│ The control plane never clones a repo and never sees source. │
└─────────────────────────────────────────────────────────────────────┘
Superseded: this previously described GCP Cloud Run + CloudSQL + Pub/Sub. That design required every user's laptop to hold credentials into DevPilot's GCP project, which is why it was never completed. See
spec/trd/05-HOSTED-BRIDGE.md§3.2 for the full rationale.
Local Setup (Direct API)
1. Get Linear API Credentials
- Go to https://linear.app/settings/api
- Create a new API key with:
- Read access to issues
- Write access to issues and comments
- Read access to teams
2. Configure via CLI
# Interactive setup
devpilot setup
# Or manual configuration
devpilot config linear --api-key lin_api_xxxxx --team-id TEAM-xxxxx
# Test connection
devpilot config linear --test
3. Configuration File
Edit .devpilot/config.yaml:
integrations:
linear:
apiKey: lin_api_xxxxx
teamId: TEAM-xxxxx
teamName: My Team
teamKey: TEAM
defaultProjectId: proj_xxxxx # Optional
Outbound Sync (DevPilot → Linear)
Session Creation
When dispatching a horizon item, DevPilot creates/updates a Linear issue:
// packages/core/src/integrations/linear/sync.ts
await syncSessionToLinear({
sessionId: 'sess_123',
ticketTitle: 'Implement feature X',
repo: 'my-org/my-repo',
workstream: 'Backend',
estimatedMinutes: 60,
});
This:
- Creates a new Linear issue (or finds existing by title)
- Adds a comment with session details
- Returns the Linear issue ID for tracking
Progress Updates
During agent execution:
await syncProgressToLinear({
linearTicketId: 'LIN-123',
progressPercent: 45,
currentWorkstream: 'Writing tests',
filesModified: ['src/api.ts', 'tests/api.test.ts'],
status: 'running',
message: 'Implementing test cases',
});
This adds a progress comment to the Linear issue.
Completion Sync
When a session completes:
await syncCompletionToLinear({
linearTicketId: 'LIN-123',
success: true,
prUrl: 'https://github.com/org/repo/pull/456',
filesModified: ['src/api.ts', 'tests/api.test.ts'],
completionMessage: 'Implemented feature with full test coverage',
});
This:
- Adds a completion comment with PR link
- Moves the issue to "Done" state (if configured)
- Optionally closes the issue
Inbound Sync (Linear → DevPilot)
Local Webhook Handler
For development/testing, configure Linear webhooks to point to a public URL (e.g., via ngrok):
# Expose local server
ngrok http 3847
# Configure webhook in Linear:
# URL: https://xxxxx.ngrok.io/api/integrations/linear/webhook
Webhook Events Handled
| Event | Action |
|---|---|
Issue.create | Create horizon item |
Issue.update | Update item details |
Issue.assign | Check for bot user → dispatch |
Comment.create | Forward to agent session |
Auto-Dispatch via Bot User
- Create a Linear "bot" user for DevPilot
- Configure bot user ID in bridge settings
- Assign issues to bot user → automatic dispatch
# Bridge configuration
linear:
botUserId: user_xxxxx # DevPilot bot user
autoDispatch: true
autoDispatchLabels:
- devpilot
- ai-task
Cloud Bridge Setup
For production deployments with multiple orchestrators:
1. Connect a Linear workspace
packages/bridge is gone — the bridge is a Next.js app deployed on Vercel
(private repo devpilot-website), not a Cloud Run service.
In the dashboard: Settings → Linear → Connect a Linear workspace. Supply your Linear API key, bot user id and organization id. The key is encrypted with AES-256-GCM before it is stored and is never readable again — not by the dashboard, not by any browser-facing route.
You are shown a signing secret exactly once. Copy it.
2. Configure Linear Webhook
Point your Linear workspace webhook to the bridge:
URL: https://<your-devpilot-host>/api/webhooks/linear
Secret: the signing secret shown when you connected the workspace
Events: Issues
3. Connect Local Orchestrator
devpilot bridge connect \
--url https://devpilot-bridge-xxx.run.app \
--api-key dp_orch_xxxxx
4. Verify Connection
devpilot bridge status
Bridge Client Package
The @devpilot.sh/bridge-client package handles cloud connectivity:
import { createBridgeClient, type BridgeClientConfig } from '@devpilot.sh/bridge-client';
const client = createBridgeClient({
bridgeUrl: 'https://devpilot-bridge-xxx.run.app',
apiKey: 'dp_orch_xxxxx',
orchestratorId: 'orch_local_1',
});
// Start listening for dispatched tasks
await client.startListening({
onTask: async (task) => {
// Spawn agent for task
await orchestrator.dispatch(task);
},
onError: (error) => {
console.error('Bridge error:', error);
},
});
// Send heartbeat
await client.sendHeartbeat();
// Report session status
await client.reportStatus(sessionId, statusUpdate);
Webhook Signature Verification
Linear webhooks include a signature header for verification:
// packages/bridge/src/api/webhooks/verify.ts
import { createHmac, timingSafeEqual } from 'crypto';
export function verifyLinearWebhookSignature(
payload: string,
signature: string, // "sha256=..."
secret: string
): boolean {
const expected = createHmac('sha256', secret)
.update(payload)
.digest('hex');
const actual = signature.replace('sha256=', '');
return timingSafeEqual(
Buffer.from(expected),
Buffer.from(actual)
);
}
API Reference
Linear Client Methods
import { linear } from '@devpilot.sh/core';
// Initialize client
const client = linear.initLinearClient({
apiKey: 'lin_api_xxxxx',
teamId: 'TEAM-xxxxx',
});
// Get team info
const team = await client.getTeam();
// Create issue
const issue = await client.createIssue({
title: 'New feature',
description: 'Implement X',
priority: 2,
});
// Update issue
await client.updateIssue(issueId, { state: 'in-progress' });
// Add comment
await client.addComment(issueId, 'Progress update: 50% complete');
// Get issue
const issue = await client.getIssue(issueId);
// Search issues
const issues = await client.searchIssues({ query: 'bug' });
Sync Functions
import { linear } from '@devpilot.sh/core';
// Check if configured
const configured = linear.isLinearConfigured();
// Get client
const client = linear.getLinearClient();
// Sync session to Linear
await linear.syncSessionToLinear({ ... });
// Sync progress
await linear.syncProgressToLinear({ ... });
// Sync completion
await linear.syncCompletionToLinear({ ... });
// Handle webhook
const result = await linear.handleLinearWebhook(payload, options);
Environment Variables
# Required for Linear integration
LINEAR_API_KEY=lin_api_xxxxx
LINEAR_TEAM_ID=TEAM-xxxxx
# Optional
LINEAR_DEFAULT_PROJECT_ID=proj_xxxxx
LINEAR_BOT_USER_ID=user_xxxxx
# For bridge connection
DEVPILOT_BRIDGE_URL=https://devpilot-bridge-xxx.run.app
DEVPILOT_BRIDGE_API_KEY=dp_orch_xxxxx
Troubleshooting
Connection Failed
# Test connection
devpilot config linear --test
# Check API key permissions
# Ensure key has: read/write issues, read teams
Webhook Not Received
- Verify webhook URL is accessible
- Check Linear webhook settings for errors
- View webhook delivery logs in Linear
Sync Issues
Check the activity log in DevPilot UI for sync errors.
Next Steps
- API-REFERENCE.md - Full API documentation
- AO-INTEGRATION.md - Agent orchestrator setup