Linear Sync

pending

by Samuel Ho

Bidirectional sync between Linear issues and notes with automatic file generation, multi-team support, and state-based organization.

Updated 4mo agoMITDiscovered via Obsidian Unofficial Plugins
View on GitHub

Obsidian Linear Sync Plugin v1.0.0

Bidirectional sync between Linear and Obsidian with intelligent template-based file generation and multi-team support

Version Obsidian Linear API Templater

📋 Overview

Bidirectional sync between Linear issues and Obsidian with automatic file generation, multi-team support, and state-based organization.

Key Features (v1.0)

  • 🔄 Bidirectional Sync: Sync changes between Obsidian and Linear (configurable direction)
  • 📥 Linear → Obsidian: Automatic issue sync with progressive template generation
  • 📤 Obsidian → Linear: Update Linear issues by editing frontmatter (state, priority, estimate, assignee, due date)
  • ⚡ Webhook Integration: Real-time updates via n8n webhook queue (file-based)
  • 🔀 Conflict Resolution: Configurable strategies (most-recent-wins, linear-wins, obsidian-wins)
  • 👥 Multi-Team Support: Sync multiple Linear teams with independent configurations
  • 📁 Automatic Organization: Issues organized by team and workflow state
  • 📝 Progressive Templates: Cumulative template generation as issues advance through states
  • 🎯 State-Based Mapping: Customizable directory structure per Linear workflow state
  • 📊 Kanban Board Generation: Auto-generated TRACKER.md kanban boards
  • 🔁 Sync Loop Prevention: Timestamp-based guards prevent infinite write cycles
  • 📱 Mobile Support: Platform-aware file watching and debouncing
  • 🎨 Templater Integration: Context-aware file generation with Linear data injection

🔮 Planned Features

  • v2.0: Advanced conflict resolution (vector clocks, CRDTs), enhanced webhook features
  • v3.0: Real-time HTTP webhooks (if Obsidian adds server capability), collaborative editing

🏗️ System Architecture (v1.0)

graph TB
    subgraph "Linear Platform"
        LA[Linear API<br/>GraphQL Mutations]
        LW[Linear Webhooks]
    end

    subgraph "n8n Integration"
        N8N[n8n Workflow<br/>Webhook Receiver]
        WQ[Webhook Queue<br/>.linear-webhook-queue.json]
    end

    subgraph "Obsidian Plugin"
        PS[Plugin Service<br/>Polling Sync]
        LC[LinearClient<br/>+ 5min Cache + Mutations]
        SO[SyncOrchestrator<br/>Linear → Obsidian]
        BS[BidirectionalSyncService<br/>Obsidian → Linear]
        WP[WebhookQueueProcessor<br/>Real-time Updates]
        DS[DirectorySyncService]
        TG[TemplateGenerationService]
        KB[KanbanBoardService]
        CD[ObsidianChangeDetector<br/>File Watcher]
    end

    subgraph "Obsidian Vault"
        TM[TRACKER.md<br/>Kanban Board]
        TD[Team Directories<br/>Per-Team Config]
        IF[Issue Files<br/>Markdown Docs]
        TF[Template Files<br/>Per-Team Templates]
    end

    subgraph "External Dependencies"
        TP[Templater Plugin<br/>Required]
    end

    %% Linear → Obsidian (Polling)
    LA -.->|Poll| LC
    LC --> SO
    PS --> SO
    SO --> DS
    SO --> TG
    SO --> KB

    %% Obsidian → Linear (Bidirectional)
    IF -.->|File Changes| CD
    CD --> BS
    BS --> LC
    LC -.->|Mutations| LA

    %% Webhook Flow
    LW -.->|HTTP POST| N8N
    N8N --> WQ
    WQ -.->|Poll Queue| WP
    WP --> SO

    %% Template Processing
    TG --> TP
    TP --> TF
    DS --> TD
    DS --> IF
    KB --> TM
    TF --> IF

    style LA fill:#5E6AD2
    style PS fill:#7C3AED
    style BS fill:#10B981
    style WP fill:#F59E0B
    style N8N fill:#FF6B6B

Key Architecture Features:

  • Bidirectional Sync: Linear ↔ Obsidian with configurable conflict resolution
  • Webhook Integration: Real-time updates via n8n file-based queue
  • Sync Loop Prevention: Timestamp guards prevent infinite write cycles
  • Mobile Support: Platform-aware file watching with optimized debouncing

🚀 Quick Start

Prerequisites

  1. Obsidian v1.0.0 or higher
  2. Templater Plugin installed and configured
  3. Linear API Key from Linear Settings → API
  4. Folder Structure (auto-created on first sync)

Installation

  1. Install the Plugin

    # The plugin is located at:
    docs/automation/plugins/obsidian-linear-sync/
    
    # Symlinked to Obsidian plugins:
    .obsidian/plugins/obsidian-linear-sync/
    
  2. Configure Settings

    • Open Settings → Linear Sync
    • Enter your Linear API key
    • Set template folder path: templates/kanban-template
    • Test connection

    ⚠️ SECURITY WARNING: Never commit your data.json file to version control! It contains your Linear API key. This file is already in .gitignore, but double-check before pushing to any repository. If you accidentally commit your API key:

    1. Immediately revoke the key in Linear Settings → API
    2. Remove the file from git history using git filter-branch or BFG Repo-Cleaner
    3. Generate a new API key and configure the plugin again
  3. First Sync

    • Run command: "Linear Sync: Sync from Linear"
    • Plugin creates folder structure automatically

🔗 Webhook Setup (Optional)

For real-time webhook updates instead of polling:

Prerequisites

  • Local REST API Plugin - Install from Obsidian community plugins
  • Public tunnel - ngrok, Cloudflare Tunnel, or localtunnel to expose localhost

Setup Steps

1. Install Local REST API Plugin:

  • Open Obsidian Settings → Community plugins
  • Search for "Local REST API"
  • Install and enable
  • Note the API key from Local REST API settings

2. Set Up Tunnel (Choose one):

Option A: ngrok (Recommended)

# Install ngrok: https://ngrok.com/download
# Get free authtoken: https://dashboard.ngrok.com/get-started/your-authtoken
ngrok config add-authtoken YOUR_AUTHTOKEN

# Start tunnel to Local REST API port
ngrok http 27123

Option B: Cloudflare Tunnel

# Install cloudflared: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
cloudflared tunnel --url http://localhost:27123

Option C: localtunnel

npx localtunnel --port 27123

3. Configure Plugin:

  • Open Settings → Linear Sync → Sync Configuration
  • Set "Sync Method" to "Webhook"
  • Copy your tunnel URL (e.g., https://abc123.ngrok.io)
  • Paste into "Webhook Public URL" field
  • Copy the full webhook URL displayed below (includes endpoint path)

4. Configure Linear Webhook:

  • Open Linear Settings → API → Webhooks
  • Click "New Webhook"
  • Paste the full webhook URL from plugin settings
  • Select event types: Issue (all events)
  • Optional: Set webhook secret (must match in plugin settings)
  • Save

5. Test:

  • Create or update an issue in Linear
  • Check Obsidian - changes should appear within seconds!

Troubleshooting

Webhooks not received:

  • Verify tunnel is running and URL is accessible
  • Check webhook URL in Linear matches the full URL from plugin settings
  • Verify Local REST API plugin is enabled
  • Check HMAC secret matches if configured
  • Enable Local REST API plugin logs for debugging

Tunnel disconnected:

  • Restart your tunnel command
  • Update the public URL in plugin settings
  • Update webhook URL in Linear if it changed

📂 Phase Mapping System

The plugin uses a 6-phase workflow with progressive documentation:

stateDiagram-v2
    [*] --> Planning
    Planning --> Pending
    Pending --> InProgress
    InProgress --> Review
    Review --> Staging
    Staging --> Closed

    Planning: 01-planning<br/>PRD + Architecture
    Pending: 02-pending<br/>+ Task Planning
    InProgress: 03-in-progress<br/>+ Implementation
    Review: 04-review<br/>+ Audit Checklist
    Staging: 05-staging<br/>+ Changelog
    Closed: 06-closed<br/>Archived

Phase Details

PhaseDirectoryLinear StatesTemplates GeneratedPurpose
Planning01-planningBacklog, Triage01-prd.md
02-architecture.md
Requirements & Design
Pending02-pendingUnstarted+ 03-task.mdReady for Development
In Progress03-in-progressStarted+ 04-audit.mdActive Development
Review04-reviewStarted (Review)Same as ProgressCode Review & QA
Staging05-stagingCompleted+ 05-changelog.mdPre-production
Closed06-closedDone, CanceledAll filesArchived

🎯 Template System

Templates use Templater variables for dynamic content:

Available Variables

// Linear Issue Data
<% linear.id %>           // Issue ID
<% linear.identifier %>   // Issue key (e.g., ENG-123)
<% linear.title %>        // Issue title
<% linear.description %>  // Issue description
<% linear.state %>        // Current state
<% linear.priority %>     // Priority level
<% linear.assignee %>     // Assigned user
<% linear.due_date %>     // Due date
<% linear.project %>      // Project name
<% linear.labels %>       // Issue labels
<% linear.url %>          // Linear URL

// Metadata
<% tp.date.now("YYYY-MM-DD HH:mm") %>  // Current timestamp
<% phase %>                             // Current phase

Template Files

  1. 01-prd.md - Product Requirements Document
  2. 02-architecture.md - Technical Architecture
  3. 03-task.md - Implementation Tasks
  4. 04-audit.md - Review Checklist
  5. 05-changelog.md - Release Notes

⚙️ Configuration

Plugin Settings

# Settings accessible via Obsidian Settings → Linear Sync

# Authentication
apiKey: 'lin_api_...' # Your Linear API key

# Sync Configuration
# Choose sync method: polling or webhook (mutually exclusive)
syncMethod: 'polling' # polling | webhook

# Polling Configuration (only used when syncMethod = polling)
pollingConfig:
  intervalMinutes: 5 # Minutes between polling syncs

# Webhook Configuration (only used when syncMethod = webhook)
# Requires Local REST API plugin to be installed
webhookConfig:
  endpointPath: '/linear/webhook' # Webhook endpoint path
  linearWebhookSecret: '' # Optional HMAC secret (must match Linear webhook secret)
  batchSize: 10 # Processing batch size
  maxRetries: 3 # Max retry attempts for failed events

# Sync Direction
syncDirection: 'linear-to-obsidian' # linear-to-obsidian | bidirectional | obsidian-to-linear
conflictResolution: 'most-recent-wins' # most-recent-wins | linear-wins | obsidian-wins (only for bidirectional)

# Field Sync
syncPriority: true # Sync priority field
syncEstimate: true # Sync estimate points
syncDueDate: true # Sync due dates

File Frontmatter

Synced files include metadata:

---
# Linear Metadata
linear_id: abc-123-def
linear_identifier: ENG-123
linear_url: https://linear.app/team/issue/ENG-123
linear_state: In Progress
linear_state_id: uuid
linear_priority: 2
linear_estimate: 3
linear_due_date: 2024-01-15
linear_team_id: uuid
linear_assignee_id: uuid

# Sync Settings
auto_sync: true # Enable bidirectional sync for this file
last_sync: 2024-01-10T10:30:00Z

# Template Metadata
template_type: prd
template_version: 4.0.0
phase: 03-in-progress
---

Bidirectional Sync Fields: Edit these frontmatter fields to update Linear:

  • linear_state - Change issue state
  • priority - Update priority (0-4)
  • estimate - Update estimate points
  • due_date - Update due date
  • assignee - Update assignee by name

Webhook Setup

Prerequisites:

  1. Install Local REST API plugin from Community Plugins
  2. Enable Local REST API plugin
  3. Note the API key from Local REST API settings

Configuration:

  1. Linear Sync Settings:

    • Set Sync Method to "Webhook"
    • Copy the webhook URL displayed (e.g., https://localhost:27123/linear/webhook?api=YOUR_KEY)
    • (Optional) Set Linear webhook secret for HMAC verification
  2. Linear Settings:

    • Go to Linear → Settings → API → Webhooks
    • Create new webhook
    • Paste the URL from Linear Sync
    • Enter the same secret (if using)
    • Subscribe to: Issue created, updated, deleted
  3. For Remote Access (Optional):

    # Use ngrok or similar tunnel
    ngrok http 27123
    
    # Use tunnel URL in Linear
    https://abc123.ngrok.io/linear/webhook?api=YOUR_KEY
    

🔧 Commands

Access via Command Palette (Cmd/Ctrl + P):

CommandDescriptionHotkey
Sync from LinearFetch and update all issues-
Sync to LinearPush local changes to Linear-
Batch sync all kanban filesSync files with auto_sync: true-
Create Linear issue from noteCreate new issue from current file-
Create kanban structureGenerate folder structure for issue-
Test Linear connectionVerify API key and connection-

🔄 Data Flow

Linear → Obsidian (Polling & Webhooks)

sequenceDiagram
    participant L as Linear
    participant N as n8n
    participant W as Webhook Queue
    participant P as Plugin
    participant V as Vault
    participant T as Templater

    Note over L,P: Polling Sync (Every 5 min)
    L->>P: Fetch Issues (GraphQL)
    P->>P: Check Cache (5min TTL)
    P->>V: Find/Create Directory
    P->>T: Request Template
    T-->>P: Rendered Template
    P->>P: Mark Plugin Write
    P->>V: Write/Update Files
    P->>V: Update TRACKER.md

    Note over L,V: Webhook Flow (Real-time)
    L->>N: Webhook Event
    N->>W: Write to Queue File
    P->>W: Poll Queue (Every 5s)
    P->>P: Process Event
    P->>L: Fetch Updated Issue
    P->>V: Update Files

Obsidian → Linear (Bidirectional Sync)

sequenceDiagram
    participant U as User
    participant V as Vault
    participant P as Plugin
    participant L as Linear

    Note over U,L: User Edits Frontmatter
    U->>V: Edit File (state, priority, etc.)
    V->>P: File Change Event
    P->>P: Check Sync Loop Guard
    P->>P: Detect Frontmatter Changes
    P->>P: Debounce (300ms desktop)

    alt Has Syncable Changes
        P->>L: Update Issue (GraphQL Mutation)
        L-->>P: Confirm Update
        P->>P: Update Cache
        Note over V,L: ✓ Synced to Linear
    else No Changes
        P->>P: Skip (No sync needed)
    end

🐛 Troubleshooting

Common Issues

IssueCauseSolution
No API Key ErrorMissing configurationSettings → Linear Sync → Add API key
Files Not SyncingMissing frontmatterEnsure linear_id and auto_sync: true
Templates Not WorkingTemplater not configuredInstall and configure Templater plugin
State Not UpdatingFile in wrong folderCheck file is in recognized kanban folder
Connection IssuesNetwork/API problemsUse "Test connection" in settings

Debug Mode

  1. Open Developer Console: Ctrl+Shift+I (Windows/Linux) or Cmd+Opt+I (Mac)
  2. Filter by "Linear Sync" for plugin logs
  3. Check for GraphQL errors or template issues

🔗 Integration

This plugin integrates with the automation stack:

  • n8n Workflows: Webhook processing at http://localhost:5678
  • Cyrus AI Agent: Linear automation at http://localhost:3456
  • Docker Services: See INTEGRATION.md

📚 Documentation

🤝 Contributing

  1. Fork the repository
  2. Create feature branch
  3. Test with mock Linear data
  4. Submit pull request

📄 License

MIT License - See LICENSE file

🙏 Credits

  • Author: Samuel Ho
  • Website: https://samuelho.space
  • Dependencies: Obsidian API, Templater Plugin
  • API: Linear GraphQL API

Last Updated: 2024-08-29 | Version: 1.0.0 | Requires: Obsidian 1.0.0+, Templater

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.