Orchestrata Ultimate / Specs / 052-todoist-integration

052-todoist-integration: Todoist Integration

Bidirectional synchronization between Orchestrata tasks and Todoist using the Todoist REST API v2 and webhooks.

At a glance

Item Value
Spec directory specs/052-todoist-integration/
Status line in the spec Complete
Requirement IDs defined 73
With a @traces citation in src/ 0 (0.0%)
With a @traces citation in tests/ 0 (0.0%)
Tracked files 2
RTM page 052-todoist-integration

Reading this spec

This spec defines bidirectional synchronization between Orchestrata tasks and Todoist, so people can track tasks in the tool they prefer while agents work on the same items. It uses the Todoist REST API v2 for create, read, update and delete operations, webhooks for real-time change notification, custom fields to carry agent assignment, and timestamps to resolve conflicts.

Its three user stories are task synchronization, conflict resolution and webhook security. The functional requirements (FR-001 to FR-020) cover synchronization itself, authentication, webhook reception and signature verification, conflict detection and resolution (automatic and manual), rate-limit compliance, custom field mapping, priority, status and due-date synchronization, agent assignment, task deletion, audit logging, error handling, project mapping, bulk sync, a retry mechanism and notifications. Two data models, TodoistSyncState and SyncConflict, hold the sync state and the conflicts. All 73 requirement IDs are numbered REQ-052-NNN.

The main constraints are explicit. Tasks synchronize both ways within 1 second of a change. Non-critical conflicts resolve by last-write-wins, while critical conflicts go to manual resolution, and the sync state records which of the two modes applies. The system respects Todoist rate limits with exponential backoff, logs every sync operation for audit, and exposes POST /webhooks/todoist, which handles item added, updated, deleted and completed events. Conflict detection takes under 500 ms, webhook throughput is 100 per minute, a full sync queue drops its oldest entry and logs a warning, and alerts fire on a conflict rate above 10%, sync failures, webhook timeouts and rate-limit hits.

No code module cites this spec. The requirements traceability matrix lists every ID. The spec's own status line reads Complete and it tracks 2 files. No src/ symbol cites any of the 73 requirements, so measured trace coverage is 0.0%, and in tests/, 0 requirements are cited by a test-side @traces. All 73 requirements have no citing symbol; untraced means no @traces names the ID, and the behaviour may still exist in code that was never annotated.

Requirements

Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.

ID Done Requirement Traced by
REQ-052-001 - The system SHALL resolve non-critical conflicts using the last-write-wins strategy. none
REQ-052-002 - The system SHALL route critical conflicts to manual resolution. none
REQ-052-003 - The system SHALL record conflict history in the audit log. none
REQ-052-004 - The system SHALL support rotation of the webhook signing secret. none
REQ-052-005 - The system SHALL enforce rate limiting on webhook endpoints. none
REQ-052-006 - The system SHALL persist sync state conforming to the TodoistSyncState schema, which requires project_id, last_sync and direction, where direction SHALL be one of orchestrata_to_todoist, todoist_to_orchestrata or bidirectional, and conflict_resolution SHALL be one of last_write_wins or manual. none
REQ-052-007 - The system SHALL represent every detected conflict conforming to the SyncConflict schema, which requires task_id, orchestrata_version and todoist_version, and which records the conflicting fields, whether the conflict is resolved, and the resolution applied. none
REQ-052-008 - The system MUST synchronize tasks bidirectionally between Orchestrata and Todoist within 1 second of any change. none
REQ-052-009 - The system MUST authenticate with Todoist API using OAuth 2.0 or API token-based authentication. none
REQ-052-010 - The system MUST receive and process webhooks from Todoist for real-time task updates. none
REQ-052-011 - The system MUST verify HMAC-SHA256 signatures on all incoming webhook payloads. none
REQ-052-012 - The system MUST detect conflicts when the same task is modified in both systems since last sync. none
REQ-052-013 - The system MUST automatically resolve conflicts using last-write-wins strategy when configured. none
REQ-052-014 - The system MUST provide a mechanism for users to manually resolve conflicts when configured. none
REQ-052-015 - The system MUST respect Todoist API rate limits and implement exponential backoff. none
REQ-052-016 - The system MUST map Orchestrata-specific fields to Todoist custom fields. none
REQ-052-017 - The system MUST synchronize task priorities between Orchestrata (P1-P4) and Todoist (1-4). none
REQ-052-018 - The system MUST synchronize task status between Orchestrata states and Todoist sections. none
REQ-052-019 - The system MUST handle due dates, including null dates and overdue tasks. none
REQ-052-020 - The system MUST sync agent assignments from Orchestrata to Todoist custom fields. none
REQ-052-021 - The system MUST handle task deletions gracefully, supporting soft delete and recovery. none
REQ-052-022 - The system MUST log all sync operations for audit purposes. none
REQ-052-023 - The system MUST handle all error conditions defined in the Error Conditions section. none
REQ-052-024 - The system MUST maintain a mapping between Orchestrata projects and Todoist projects. none
REQ-052-025 - The system MUST support bulk synchronization of up to 1000 tasks. none
REQ-052-026 - The system MUST retry failed operations with exponential backoff up to 60 seconds. none
REQ-052-027 - The system MUST notify users of conflicts and critical errors requiring attention. none
REQ-052-101 - One-way sync latency SHALL be under 1 second. none
REQ-052-102 - Conflict detection latency SHALL be under 500ms. none
REQ-052-103 - Webhook processing time SHALL be under 100ms. none
REQ-052-104 - Bulk sync of 1000 tasks SHALL complete in under 10 seconds. none
REQ-052-105 - The sync success rate SHALL exceed 99.5%. none
REQ-052-106 - System availability SHALL be 99.9%. none
REQ-052-107 - The system SHALL lose zero data. none
REQ-052-108 - The system SHALL support 10 concurrent sync operations. none
REQ-052-109 - The system SHALL sustain a webhook throughput of 100 per minute. none
REQ-052-110 - The system SHALL sustain 50 API calls per minute. none
REQ-052-111 - API keys SHALL be encrypted at rest. none
REQ-052-112 - Webhook endpoints SHALL enforce IP whitelisting. none
REQ-052-028 - On ERR-001 (Todoist API rate limit exceeded, severity MEDIUM), the system SHALL apply exponential backoff. none
REQ-052-029 - On ERR-002 (Todoist API unavailable, severity HIGH), the system SHALL queue the operation for retry and notify the user. none
REQ-052-030 - On ERR-003 (webhook signature invalid, severity HIGH), the system SHALL reject the payload, log it and raise an alert. none
REQ-052-031 - On ERR-004 (sync conflict detected, severity MEDIUM), the system SHALL queue the conflict for resolution and notify the user. none
REQ-052-032 - On ERR-005 (task not found in target system, severity LOW), the system SHALL create a new task. none
REQ-052-033 - On ERR-006 (invalid API key, severity HIGH), the system SHALL reject the sync and prompt for re-authentication. none
REQ-052-034 - On ERR-007 (network timeout, severity MEDIUM), the system SHALL retry with exponential backoff. none
REQ-052-035 - On ERR-008 (JSON parse error, severity MEDIUM), the system SHALL log the payload and reject it. none
REQ-052-036 - On ERR-009 (missing required field, severity LOW), the system SHALL log the error and skip the task. none
REQ-052-037 - On ERR-010 (circular dependency detected, severity HIGH), the system SHALL detect the cycle, break it and notify. none
REQ-052-038 - On ERR-011 (sync queue full, severity MEDIUM), the system SHALL drop the oldest entry and log a warning. none
REQ-052-039 - On ERR-012 (database connection error, severity HIGH), the system SHALL retry and fail over to standby. none
REQ-052-040 - On ERR-013 (invalid cron schedule, severity MEDIUM), the system SHALL reject the schedule and suggest a fix. none
REQ-052-041 - On ERR-014 (duplicate task ID, severity LOW), the system SHALL auto-merge or prompt the user. none
REQ-052-042 - On ERR-015 (budget exceeded, severity HIGH), the system SHALL pause sync and notify the administrator. none
REQ-052-043 - On ERR-016 (webhook payload too large, severity MEDIUM), the system SHALL reject the payload and log a warning. none
REQ-052-044 - On ERR-017 (invalid project mapping, severity HIGH), the system SHALL reject the sync and prompt for configuration. none
REQ-052-113 - Integration tests SHALL cover Todoist API connectivity, webhook endpoint validation, sync conflict resolution, and error handling and retries. none
REQ-052-114 - Test coverage SHALL exceed 80% for unit tests, exceed 90% for integration tests, and reach 100% for API contracts. none
REQ-052-045 - The system SHALL require the project:write permission for sync operations. none
REQ-052-046 - The system SHALL require the admin role for webhook endpoints. none
REQ-052-047 - The system SHALL audit all API calls. none
REQ-052-115 - The system SHALL retain sync metadata for 90 days, conflict history for 1 year, audit logs for 7 years and webhook logs for 30 days. none
REQ-052-116 - The system SHALL emit metrics for sync success rate, conflict frequency, webhook response time, API error rate and sync latency percentiles. none
REQ-052-117 - The system SHALL raise alerts on a conflict rate above 10%, on sync failures, on webhook timeouts and on rate limit exceeded. none
REQ-052-118 - API keys SHALL be rotated annually. none
REQ-052-119 - The system SHALL monitor API key usage. none
REQ-052-120 - Sync data SHALL be encrypted. none
REQ-052-121 - Sensitive fields SHALL be masked. none
REQ-052-122 - The system SHALL comply with GDPR. none
REQ-052-123 - The system SHALL apply data minimization to synchronized data. none
REQ-052-048 - The system SHALL expose the webhook endpoint POST /webhooks/todoist and SHALL process the item:added, item:updated, item:deleted and item:completed events. none
REQ-052-049 - Error responses SHALL conform to the ErrorResponse schema, which requires error, message and timestamp. none
REQ-052-050 - All APIs SHALL use path-based versioning (/api/v1/), and breaking changes SHALL increment the version to v2. none

Code that traces this spec

No src/ symbol cites a requirement of this spec.

Other tracked files

Full spec text

Verbatim from specs/052-todoist-integration/spec.md; headings are pushed down two levels.

SPEC-052: Todoist Integration

Metadata


User Scenarios

US-001: Task Synchronization

As a developer, I want tasks synced between Orchestrata and Todoist so I can use my preferred task management tool.

Acceptance Criteria:

US-002: Conflict Resolution

As a user, I want conflicts resolved automatically so I don't have to manually merge changes.

Acceptance Criteria:

REQ-052-001: The system SHALL resolve non-critical conflicts using the last-write-wins strategy.

REQ-052-002: The system SHALL route critical conflicts to manual resolution.

REQ-052-003: The system SHALL record conflict history in the audit log.

US-003: Webhook Security

As a security officer, I want webhook payloads verified so I can trust incoming updates.

Acceptance Criteria:

REQ-052-004: The system SHALL support rotation of the webhook signing secret.

REQ-052-005: The system SHALL enforce rate limiting on webhook endpoints.


Data Models

TodoistSyncState
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["project_id", "last_sync", "direction"],
  "properties": {
    "project_id": {
      "type": "string"
    },
    "todoist_project_id": {
      "type": "string"
    },
    "last_sync": {
      "type": "string",
      "format": "date-time"
    },
    "direction": {
      "type": "string",
      "enum": ["orchestrata_to_todoist", "todoist_to_orchestrata", "bidirectional"]
    },
    "conflict_resolution": {
      "type": "string",
      "enum": ["last_write_wins", "manual"]
    }
  }
}

REQ-052-006: The system SHALL persist sync state conforming to the TodoistSyncState schema, which requires project_id, last_sync and direction, where direction SHALL be one of orchestrata_to_todoist, todoist_to_orchestrata or bidirectional, and conflict_resolution SHALL be one of last_write_wins or manual.

SyncConflict
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["task_id", "orchestrata_version", "todoist_version"],
  "properties": {
    "task_id": {
      "type": "string"
    },
    "orchestrata_version": {
      "type": "object"
    },
    "todoist_version": {
      "type": "object"
    },
    "conflict_fields": {
      "type": "array",
      "items": {"type": "string"}
    },
    "resolved": {
      "type": "boolean"
    },
    "resolution": {
      "type": "string"
    }
  }
}

REQ-052-007: The system SHALL represent every detected conflict conforming to the SyncConflict schema, which requires task_id, orchestrata_version and todoist_version, and which records the conflicting fields, whether the conflict is resolved, and the resolution applied.


Functional Requirements

FR-001: Task Synchronization

REQ-052-008: The system MUST synchronize tasks bidirectionally between Orchestrata and Todoist within 1 second of any change.

FR-002: Authentication

REQ-052-009: The system MUST authenticate with Todoist API using OAuth 2.0 or API token-based authentication.

FR-003: Webhook Reception

REQ-052-010: The system MUST receive and process webhooks from Todoist for real-time task updates.

FR-004: Signature Verification

REQ-052-011: The system MUST verify HMAC-SHA256 signatures on all incoming webhook payloads.

FR-005: Conflict Detection

REQ-052-012: The system MUST detect conflicts when the same task is modified in both systems since last sync.

FR-006: Conflict Resolution - Automatic

REQ-052-013: The system MUST automatically resolve conflicts using last-write-wins strategy when configured.

FR-007: Conflict Resolution - Manual

REQ-052-014: The system MUST provide a mechanism for users to manually resolve conflicts when configured.

FR-008: Rate Limiting Compliance

REQ-052-015: The system MUST respect Todoist API rate limits and implement exponential backoff.

FR-009: Custom Field Mapping

REQ-052-016: The system MUST map Orchestrata-specific fields to Todoist custom fields.

FR-010: Priority Synchronization

REQ-052-017: The system MUST synchronize task priorities between Orchestrata (P1-P4) and Todoist (1-4).

FR-011: Status Synchronization

REQ-052-018: The system MUST synchronize task status between Orchestrata states and Todoist sections.

FR-012: Due Date Handling

REQ-052-019: The system MUST handle due dates, including null dates and overdue tasks.

FR-013: Agent Assignment

REQ-052-020: The system MUST sync agent assignments from Orchestrata to Todoist custom fields.

FR-014: Task Deletion

REQ-052-021: The system MUST handle task deletions gracefully, supporting soft delete and recovery.

FR-015: Audit Logging

REQ-052-022: The system MUST log all sync operations for audit purposes.

FR-016: Error Handling

REQ-052-023: The system MUST handle all error conditions defined in the Error Conditions section.

FR-017: Project Mapping

REQ-052-024: The system MUST maintain a mapping between Orchestrata projects and Todoist projects.

FR-018: Bulk Sync

REQ-052-025: The system MUST support bulk synchronization of up to 1000 tasks.

FR-019: Retry Mechanism

REQ-052-026: The system MUST retry failed operations with exponential backoff up to 60 seconds.

FR-020: Notification

REQ-052-027: The system MUST notify users of conflicts and critical errors requiring attention.


Non-Functional Requirements

Performance

REQ-052-101: One-way sync latency SHALL be under 1 second.

REQ-052-102: Conflict detection latency SHALL be under 500ms.

REQ-052-103: Webhook processing time SHALL be under 100ms.

REQ-052-104: Bulk sync of 1000 tasks SHALL complete in under 10 seconds.

Reliability

REQ-052-105: The sync success rate SHALL exceed 99.5%.

REQ-052-106: System availability SHALL be 99.9%.

REQ-052-107: The system SHALL lose zero data.

Scalability

REQ-052-108: The system SHALL support 10 concurrent sync operations.

REQ-052-109: The system SHALL sustain a webhook throughput of 100 per minute.

REQ-052-110: The system SHALL sustain 50 API calls per minute.

Security

REQ-052-111: API keys SHALL be encrypted at rest.

REQ-052-112: Webhook endpoints SHALL enforce IP whitelisting.


Technical Design

Architecture Components
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Orchestrata   │────▶│  Sync Engine    │────▶│    Todoist      │
│   Core System   │◀────│  (Python/Async) │◀────│    REST API     │
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │                        │                        │
        ▼                        ▼                        ▼
   ┌─────────┐            ┌───────────┐            ┌─────────┐
   │  Neo4j  │            │   Redis   │            │ Webhook │
   │   DB    │            │ Rate Limit│            │ Endpoint│
   └─────────┘            └───────────┘            └─────────┘
Sync Flow
  1. Poll Todoist API or receive webhook
  2. Fetch Orchestrata tasks from Neo4j
  3. Compare task versions and detect conflicts
  4. Apply conflict resolution strategy
  5. Update both systems
  6. Log audit trail
Data Flow
State Management

Rate Limiting

Todoist API Rate Limits
Implementation
class RateLimiter:
    def __init__(self, requests_per_minute: int = 50):
        self.requests_per_minute = requests_per_minute
        self.window = 60  # seconds
        self.burst = 10
    
    async def acquire(self):
        # Implement token bucket algorithm
        pass
    
    async def wait_if_needed(self):
        if not await self.acquire():
            wait_time = self.calculate_backoff()
            await asyncio.sleep(wait_time)

Conflict Resolution

Resolution Strategies
async def resolve_conflict(conflict: SyncConflict) -> dict:
    """Resolve sync conflict based on strategy."""
    
    if conflict.conflict_resolution == "last_write_wins":
        # Compare timestamps
        if conflict.orchestrata_version["updated_at"] > conflict.todoist_version["updated_at"]:
            return conflict.orchestrata_version
        else:
            return conflict.todoist_version
    
    elif conflict.conflict_resolution == "manual":
        # Return both versions for user decision
        return {
            "status": "needs_resolution",
            "orchestrata": conflict.orchestrata_version,
            "todoist": conflict.todoist_version
        }

Webhook Security

HMAC Verification
import hmac
import hashlib

async def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    """Verify webhook HMAC signature."""
    expected = hmac.new(
        key=secret.encode(),
        msg=payload,
        digestmod=hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(signature, expected)

@app.post("/webhooks/todoist")
async def handle_webhook(
    request: Request,
    x_todoist_signature: str = Header(None)
):
    payload = await request.body()
    
    if not verify_webhook(payload, x_todoist_signature, WEBHOOK_SECRET):
        raise HTTPException(401, "Invalid signature")
    
    # Process webhook
    event = json.loads(payload)
    await process_todoist_event(event)

Error Conditions

ID Condition Handling Severity
ERR-001 Todoist API rate limit exceeded Exponential backoff MEDIUM
ERR-002 Todoist API unavailable Queue for retry, notify user HIGH
ERR-003 Webhook signature invalid Reject, log, alert HIGH
ERR-004 Sync conflict detected Queue for resolution, notify user MEDIUM
ERR-005 Task not found in target system Create new task LOW
ERR-006 Invalid API key Reject sync, prompt re-authentication HIGH
ERR-007 Network timeout Retry with exponential backoff MEDIUM
ERR-008 JSON parse error Log payload, reject MEDIUM
ERR-009 Missing required field Log error, skip task LOW
ERR-010 Circular dependency detected Detect, break cycle, notify HIGH
ERR-011 Sync queue full Drop oldest, log warning MEDIUM
ERR-012 Database connection error Retry, failover to standby HIGH
ERR-013 Invalid cron schedule Reject, suggest fix MEDIUM
ERR-014 Duplicate task ID Auto-merge or prompt user LOW
ERR-015 Budget exceeded Pause sync, notify admin HIGH
ERR-016 Webhook payload too large Reject, log warning MEDIUM
ERR-017 Invalid project mapping Reject sync, prompt configuration HIGH

REQ-052-028: On ERR-001 (Todoist API rate limit exceeded, severity MEDIUM), the system SHALL apply exponential backoff.

REQ-052-029: On ERR-002 (Todoist API unavailable, severity HIGH), the system SHALL queue the operation for retry and notify the user.

REQ-052-030: On ERR-003 (webhook signature invalid, severity HIGH), the system SHALL reject the payload, log it and raise an alert.

REQ-052-031: On ERR-004 (sync conflict detected, severity MEDIUM), the system SHALL queue the conflict for resolution and notify the user.

REQ-052-032: On ERR-005 (task not found in target system, severity LOW), the system SHALL create a new task.

REQ-052-033: On ERR-006 (invalid API key, severity HIGH), the system SHALL reject the sync and prompt for re-authentication.

REQ-052-034: On ERR-007 (network timeout, severity MEDIUM), the system SHALL retry with exponential backoff.

REQ-052-035: On ERR-008 (JSON parse error, severity MEDIUM), the system SHALL log the payload and reject it.

REQ-052-036: On ERR-009 (missing required field, severity LOW), the system SHALL log the error and skip the task.

REQ-052-037: On ERR-010 (circular dependency detected, severity HIGH), the system SHALL detect the cycle, break it and notify.

REQ-052-038: On ERR-011 (sync queue full, severity MEDIUM), the system SHALL drop the oldest entry and log a warning.

REQ-052-039: On ERR-012 (database connection error, severity HIGH), the system SHALL retry and fail over to standby.

REQ-052-040: On ERR-013 (invalid cron schedule, severity MEDIUM), the system SHALL reject the schedule and suggest a fix.

REQ-052-041: On ERR-014 (duplicate task ID, severity LOW), the system SHALL auto-merge or prompt the user.

REQ-052-042: On ERR-015 (budget exceeded, severity HIGH), the system SHALL pause sync and notify the administrator.

REQ-052-043: On ERR-016 (webhook payload too large, severity MEDIUM), the system SHALL reject the payload and log a warning.

REQ-052-044: On ERR-017 (invalid project mapping, severity HIGH), the system SHALL reject the sync and prompt for configuration.


Visual Architecture

Class Diagram

Diagram source shown as text: Mermaid could not parse it (Error: Parse error on line 36:).

classDiagram-direction LR
    class CheetahClawsTUI {
        +__init__()
        #_load_commands(): dict[str, Any]
        +async create_checkpoint(name: str): dict[str, Any]
        +async rewind(steps: int = 1): dict[str, Any]
        +async query_memory(query: str, depth: int = 1): dict[str, Any]
        +async edit_file(file_path: str, old_string: str, new_string: str): dict[str, Any]
        +async search_files(pattern: str, path: str = '.'): list[str]
        +async execute_command(command: str, args: list[str] | None = None): dict[str, Any]
    }
    class OpenRouterProvider {
        +__init__(api_key: str | None = None)
        +async chat_completion(model: str, messages: list[dict[str, str]], **kwargs): dict[str, Any]
        +get_available_models(): list[str]
        +get_model_cost(model: str): float
    }
    class TodoistIntegration {
        +__init__(api_key: str | None = None)
        +is_configured(): bool
        +async create_project(name: str): str
        +async create_task(project_id: str, title: str, **kwargs): str
        +async sync_tasks(project_id: str): list[dict[str, Any]]
        +async close()
    }
    class VizIntWebUI {
        +__init__(host: str = 'localhost', port: int = 8765)
        +async start()
        +async shutdown()
        +async add_project(project_data: dict[str, Any])
        +async broadcast_edit_complete(file_path: str, result: dict[str, Any])
        +async update_task_status(task_id: str, status: str)
        +async get_projects(): list[dict[str, Any]]
    }
Unit Tests
class TestTodoistSync:
    async def test_sync_tasks_bidirectional(self):
        sync_manager = TodoistSyncManager()
        result = await sync_manager.sync_all(project)
        assert result.conflicts == []
    
    async def test_resolve_conflict_last_write_wins(self):
        conflict = SyncConflict(...)
        resolution = await sync_manager.resolve_conflict(conflict)
        assert resolution["status"] == "resolved"
Integration Tests

REQ-052-113: Integration tests SHALL cover Todoist API connectivity, webhook endpoint validation, sync conflict resolution, and error handling and retries.

Test Coverage

REQ-052-114: Test coverage SHALL exceed 80% for unit tests, exceed 90% for integration tests, and reach 100% for API contracts.


Governance (PAM++)

Policy Enforcement

REQ-052-045: The system SHALL require the project:write permission for sync operations.

REQ-052-046: The system SHALL require the admin role for webhook endpoints.

REQ-052-047: The system SHALL audit all API calls.

Audit Logging
async def log_sync_action(action: str, details: dict):
    await audit_log({
        "event_type": "todoist_sync",
        "action": action,
        "details": details,
        "user": request.user.id,
        "timestamp": datetime.utcnow()
    })
Data Retention

REQ-052-115: The system SHALL retain sync metadata for 90 days, conflict history for 1 year, audit logs for 7 years and webhook logs for 30 days.


Performance Targets

Sync Latency
Throughput

Monitoring

Metrics

REQ-052-116: The system SHALL emit metrics for sync success rate, conflict frequency, webhook response time, API error rate and sync latency percentiles.

Alerts

REQ-052-117: The system SHALL raise alerts on a conflict rate above 10%, on sync failures, on webhook timeouts and on rate limit exceeded.


Security

API Key Protection

REQ-052-118: API keys SHALL be rotated annually.

REQ-052-119: The system SHALL monitor API key usage.

Webhook Security
Data Privacy

REQ-052-120: Sync data SHALL be encrypted.

REQ-052-121: Sensitive fields SHALL be masked.

REQ-052-122: The system SHALL comply with GDPR.

REQ-052-123: The system SHALL apply data minimization to synchronized data.


Overview

Bidirectional synchronization between Orchestrata tasks and Todoist using the Todoist REST API v2 and webhooks.

What

Integration enabling seamless task management across both Todoist and Orchestrata, with agent assignment, priority sync, and real-time updates.

Why
How

Terminology

Term Definition
Bidirectional Sync Synchronization of data in both directions between two systems
Sync Conflict When the same task is modified in both systems since last synchronization
Last-Write-Wins Conflict resolution strategy where the most recent change takes precedence
Webhook HTTP callback for real-time event notifications from Todoist
HMAC-SHA256 Hash-based message authentication code using SHA-256
Custom Fields User-defined fields in Todoist for storing Orchestrata-specific data
Rate Limiting API request throttling to comply with service limits
Exponential Backoff Retry strategy with increasing wait times between attempts
Soft Delete Marking data as deleted without permanent removal
Sync State Metadata tracking the last synchronization timestamp and direction

API Integration

Authentication
from todoist.api import TodoistAPI

class UltimateTodoistIntegration:
    def __init__(self, api_token: str):
        self.api = TodoistAPI(api_token)
        self.webhook_secret = «redacted»
    
    async def sync_tasks(self, project: UltimateProject) -> list[UltimateTask]:
        """Fetch tasks from Todoist for project."""
        todoist_project = self.api.projects.get_by_id(project.todoist_project_id)
        tasks = todoist_project.get_tasks()
        
        return [self._convert_todoist_task(t) for t in tasks]
Custom Fields
TODOIST_CUSTOM_FIELDS = {
    "orchestrata_id": "Orchestrata Task ID",
    "assigned_agent": "U:Cd, U:Qa, etc.",
    "project_id": "Ultimate Project ID",
    "estimated_hours": "Estimated effort",
    "depends_on": "Dependencies (comma-separated IDs)"
}

Sync Implementation

Bidirectional Sync
class TodoistSyncManager:
    """Manages bidirectional task synchronization."""
    
    async def sync_all(self, project: UltimateProject) -> SyncResult:
        """Sync all tasks between systems."""
        # Fetch from both systems
        orchestrata_tasks = await self.orchestrator.get_tasks(project.id)
        todoist_tasks = await self.todoist.get_tasks(project.todoist_project_id)
        
        # Find conflicts and missing tasks
        conflicts = self._find_conflicts(orchestrata_tasks, todoist_tasks)
        orchestrata_only = self._find_orchestrata_only(orchestrata_tasks, todoist_tasks)
        todoist_only = self._find_todoist_only(orchestrata_tasks, todoist_tasks)
        
        # Resolve conflicts (last-write-wins)
        for conflict in conflicts:
            await self._resolve_conflict(conflict)
        
        # Sync missing tasks
        for task in orchestrata_only:
            await self._create_todoist_task(task)
        
        for task in todoist_only:
            await self._create_orchestrata_task(task)
        
        return SyncResult(
            conflicts_resolved=len(conflicts),
            orchestrata_created=len(orchestrata_only),
            todoist_created=len(todoist_only)
        )
Webhook Handler
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhooks/todoist")
async def todoist_webhook(request: Request):
    """Handle Todoist webhooks."""
    payload = await request.json()
    event_type = payload['event_type']
    
    if event_type == 'item:added':
        await self._handle_task_created(payload)
    elif event_type == 'item:updated':
        await self._handle_task_updated(payload)
    elif event_type == 'item:deleted':
        await self._handle_task_deleted(payload)
    elif event_type == 'item:completed':
        await self._handle_task_completed(payload)
    
    return {"status": "processed"}

Task Mapping

Status Mapping
STATUS_MAPPING = {
    'orchestrata_to_todoist': {
        'pending': 'inbox',
        'in_progress': 'today',
        'completed': 'completed',
        'cancelled': 'deleted'
    },
    'todoist_to_orchestrata': {
        'inbox': 'pending',
        'today': 'in_progress',
        'completed': 'completed',
        'deleted': 'cancelled'
    }
}
Priority Mapping
PRIORITY_MAPPING = {
    'orchestrata_to_todoist': {
        1: 4,  # P1 -> Priority 4 (highest)
        2: 3,  # P2 -> Priority 3
        3: 2,  # P3 -> Priority 2
        4: 1   # P4 -> Priority 1 (lowest)
    },
    'todoist_to_orchestrata': {
        4: 1,  # Priority 4 -> P1
        3: 2,  # Priority 3 -> P2
        2: 3,  # Priority 2 -> P3
        1: 4   # Priority 1 -> P4
    }
}

Integration Points

Todoist REST API v2
Orchestrata Internal
External Webhooks

REQ-052-048: The system SHALL expose the webhook endpoint POST /webhooks/todoist and SHALL process the item:added, item:updated, item:deleted and item:completed events.


Implementation Examples

Create Task
async def create_task(task: UltimateTask) -> str:
    """Create task in Todoist."""
    todoist_task = self.api.tasks.add(
        content=task.title,
        project_id=task.project_id,
        priority=PRIORITY_MAPPING['orchestrata_to_todoist'][task.priority],
        due_date=task.due_date.isoformat() if task.due_date else None,
        description=task.description
    )
    
    # Add custom fields
    todoist_task.custom_fields.update({
        'orchestrata_id': task.id,
        'assigned_agent': task.assigned_volk,
        'project_id': task.project_id
    })
    
    return todoist_task.id
Update Task
async def update_task(task: UltimateTask):
    """Update task in Todoist."""
    todoist_task = self.api.tasks.get_by_id(task.todoist_id)
    
    todoist_task.update(
        content=task.title,
        priority=PRIORITY_MAPPING['orchestrata_to_todoist'][task.priority],
        due_date=task.due_date.isoformat() if task.due_date else None
    )
    
    todoist_task.custom_fields.update({
        'status': task.status,
        'assigned_agent': task.assigned_volk
    })

Examples

Example 1: Full Task Sync
from orchestrata.integrations.todoist import TodoistSyncManager

sync_manager = TodoistSyncManager(
    api_token=«redacted»
    webhook_secret=«redacted»
)

project = await orchestrata.get_project("proj_123")
result = await sync_manager.sync_all(project)

print(f"Conflicts resolved: {result.conflicts_resolved}")
print(f"Tasks created in Todoist: {result.todoist_created}")
print(f"Tasks created in Orchestrata: {result.orchestrata_created}")
Example 2: Handle Webhook Event
from fastapi import FastAPI, Request, Header

app = FastAPI()

@app.post("/webhooks/todoist")
async def handle_todoist_webhook(
    request: Request,
    x_todoist_signature: str = Header(None)
):
    payload = await request.json()
    
    if payload["event_type"] == "item:updated":
        task_id = payload["data"]["id"]
        await orchestrata.update_task_from_todoist(task_id, payload["data"])
        return {"status": "synced"}
    
    return {"status": "ignored"}
Example 3: Manual Conflict Resolution
conflict = await sync_manager.get_conflict("task_456")

resolution = await sync_manager.resolve_conflict_manually(
    conflict_id="conflict_789",
    choice="orchestrata",
    user_id="user_001"
)

print(f"Conflict resolved: {resolution['status']}")
Example 4: Configure Custom Field Mapping
from todoist.api import TodoistAPI

api = TodoistAPI("your_api_token")

project = api.projects.get_by_id("project_123")
project.custom_fields.add({
    "name": "Orchestrata ID",
    "type": "string",
    "value": ""
})

field = project.custom_fields.get_by_name("Orchestrata ID")
print(f"Custom field ID: {field.id}")
Example 5: Rate Limited Sync
rate_limiter = RateLimiter(requests_per_minute=50)

for task in bulk_tasks:
    await rate_limiter.wait_if_needed()
    await sync_manager.sync_task(task)

Workflow

Todoist ←→ Orchestrata ←→ Agents ←→ Neo4j
    ↓          ↓           ↓         ↓
Webhook    CXP       Multi-Agent   Knowledge
 Updates   Protocol   Coordination   Graph

Success Criteria

Functional Criteria
Quality Criteria
Operational Criteria

Conclusion

Todoist integration enables seamless task management across systems, with real-time synchronization and agent assignment support.


API Contracts

REST API Endpoints
# Example endpoint definition
GET /api/v1/resource/{id}
Response (200):
  type: object
  required:
    - id
    - name
  properties:
    id: { type: string }
    name: { type: string }
Response (404):
  $ref: '#/components/schemas/ErrorResponse'
Error Response Schema
components:
  schemas:
    ErrorResponse:
      type: object
      required:
        - error
        - message
        - timestamp
      properties:
        error: { type: string }
        message: { type: string }
        timestamp: { type: string, format: date-time }
        request_id: { type: string }
        trace_id: { type: string }
        details: { type: array, items: { type: object } }

REQ-052-049: Error responses SHALL conform to the ErrorResponse schema, which requires error, message and timestamp.

API Versioning

All APIs use path-based versioning (/api/v1/). Breaking changes require increment to v2.

REQ-052-050: All APIs SHALL use path-based versioning (/api/v1/), and breaking changes SHALL increment the version to v2.


Revision History

Version Date Author Changes
1.0.0 2026-04-09 Mohamed Initial complete specification
0.1.0 2026-04-08 Mohamed Draft with basic structure