paperclip-plugin-writbase

March 31, 2026 · View on GitHub

Bidirectional sync between Paperclip issues and WritBase tasks.

Features

  • Event-driven sync — Paperclip issue events push to WritBase; WritBase webhooks push to Paperclip
  • Periodic reconciliation — Full sync every 15 minutes catches missed webhook events
  • Conflict resolution — Version-based optimistic concurrency with automatic retry
  • Echo suppression — Prevents sync loops via actor ID detection and per-entity cooldowns
  • Configurable direction — Pull (WritBase→Paperclip), push (Paperclip→WritBase), or bidirectional

Prerequisites

  • Paperclip instance (v2026.318.0+, plugin system required)
  • WritBase workspace with a manager-role agent key
  • Node.js 20+

Installation

npm install paperclip-plugin-writbase

Then register the plugin in your Paperclip instance.

Configuration

FieldRequiredDescription
writbaseUrlYesSupabase Edge Function base URL (e.g. https://your-project.supabase.co/functions/v1/mcp-server)
agentKeyYesWritBase agent key (wb_<key_id>_<secret>). Must have manager role.
projectYesWritBase project slug to sync with
companyIdYesPaperclip company ID for issue creation/listing
departmentNoWritBase department slug (required if workspace enforces department scoping)
syncDirectionNopull, push, or bidirectional (default: bidirectional)

Creating a WritBase Agent Key

npx writbase key create --name paperclip-sync --role manager

The key must have manager role to register webhook subscriptions.

Field Mapping

Status

WritBasePaperclipNotes
todotodo
in_progressin_progress
blockedblocked
donedone
cancelledcancelled
failedcancelledLossy — original status preserved in metadata
PaperclipWritBaseNotes
backlogtodoLossy
todotodo
in_progressin_progress
in_reviewin_progressLossy
donedone
blockedblocked
cancelledcancelled

Priority

Direct 1:1 mapping: low, medium, high, critical.

Fields

WritBasePaperclipDirection
description (first line)titleBoth
description (remaining) + notesdescriptionBoth
due_datemetadata in descriptionWritBase→Paperclip only
is_archivedhiddenAtBoth

Not mapped: blocked_by (DAG deps vs parentId hierarchy), assignee fields, labelIds, billingCode.

How It Works

Event-Driven Sync

  1. Paperclip → WritBase: Plugin subscribes to issue.created and issue.updated events via ctx.events.on(). Events are debounced (500ms) and serialized per entity to prevent version conflicts.

  2. WritBase → Paperclip: Plugin registers a webhook subscription on WritBase for task.created, task.updated, task.completed, task.failed events. Incoming webhooks are verified via Standard Webhooks HMAC-SHA256.

Reconciliation

A scheduled job runs every 15 minutes to catch events missed by webhooks (WritBase uses fire-and-forget delivery). It pages through all tasks updated since the last run (with a 60-second overlap window) and reconciles any unmapped or out-of-sync items.

Conflict Resolution

  • Every WritBase mutation stores the returned version in the sync mapping
  • On version_conflict, the plugin refetches the current task version and retries (up to 3 times)
  • No cross-system timestamp comparison (avoids clock skew issues)

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Type check
npm run lint

# Watch mode
npm run dev

License

Apache-2.0