Skip to content

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

License

samuelho-dev/obsidian-linear-sync

Repository files navigation

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
Loading

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
Loading

Phase Details

Phase Directory Linear States Templates Generated Purpose
Planning 01-planning Backlog, Triage 01-prd.md
02-architecture.md
Requirements & Design
Pending 02-pending Unstarted + 03-task.md Ready for Development
In Progress 03-in-progress Started + 04-audit.md Active Development
Review 04-review Started (Review) Same as Progress Code Review & QA
Staging 05-staging Completed + 05-changelog.md Pre-production
Closed 06-closed Done, Canceled All files Archived

🎯 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):

Command Description Hotkey
Sync from Linear Fetch and update all issues -
Sync to Linear Push local changes to Linear -
Batch sync all kanban files Sync files with auto_sync: true -
Create Linear issue from note Create new issue from current file -
Create kanban structure Generate folder structure for issue -
Test Linear connection Verify 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
Loading

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
Loading

🐛 Troubleshooting

Common Issues

Issue Cause Solution
No API Key Error Missing configuration Settings → Linear Sync → Add API key
Files Not Syncing Missing frontmatter Ensure linear_id and auto_sync: true
Templates Not Working Templater not configured Install and configure Templater plugin
State Not Updating File in wrong folder Check file is in recognized kanban folder
Connection Issues Network/API problems Use "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

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published