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
specs/052-todoist-integration/compliance-audit.md
Full spec text
Verbatim from specs/052-todoist-integration/spec.md; headings are pushed down two levels.
SPEC-052: Todoist Integration
Metadata
- Spec ID: 052-todoist-integration
- Title: Todoist Integration - Task Synchronization
- Author: Mohamed
- Status: Complete
- Created: 2026-04-08
- Last Updated: 2026-04-09
- Priority: P1
- Version: 1.0.0
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:
- Tasks created in either system appear in both
- Changes sync within 1 second
- Deletions are handled gracefully
- Deleted tasks can be recovered
US-002: Conflict Resolution
As a user, I want conflicts resolved automatically so I don't have to manually merge changes.
Acceptance Criteria:
- Last-write-wins for non-critical conflicts
- Manual resolution for critical conflicts
- Conflict history tracked in audit log
- User notified of conflicts requiring attention
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:
- HMAC-SHA256 signature verification
- Secret rotation support
- Invalid payloads rejected and logged
- Rate limiting on webhook endpoints
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
- One-way sync latency: <1 second
- Conflict detection latency: <500ms
- Webhook processing time: <100ms
- Bulk sync (1000 tasks): <10 seconds
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
- Sync success rate: >99.5%
- System availability: 99.9%
- Data loss: zero tolerance
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
- Concurrent sync operations: 10
- Webhook throughput: 100/minute
- API calls: 50/minute
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
- API keys encrypted at rest
- HMAC-SHA256 signature verification
- IP whitelisting for webhooks
- Secret rotation support
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
- Poll Todoist API or receive webhook
- Fetch Orchestrata tasks from Neo4j
- Compare task versions and detect conflicts
- Apply conflict resolution strategy
- Update both systems
- Log audit trail
Data Flow
- Task creation: Orchestrata → Sync Engine → Todoist API
- Task update: Bidirectional via webhooks and polling
- Conflict detection: Compare
updated_attimestamps - Resolution: Apply last-write-wins or queue for manual
State Management
- Sync state stored in Redis with TTL
- Checkpoint-based sync for recovery
- Optimistic locking with version vectors
Rate Limiting
Todoist API Rate Limits
- Requests per minute: 50 (personal), 150 (business)
- Burst: 10 requests
- Retry: Exponential backoff (1s, 2s, 4s, 8s, max 60s)
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
- Todoist API connectivity
- Webhook endpoint validation
- Sync conflict resolution
- Error handling and retries
REQ-052-113: Integration tests SHALL cover Todoist API connectivity, webhook endpoint validation, sync conflict resolution, and error handling and retries.
Test Coverage
- Unit: >80%
- Integration: >90%
- API contracts: 100%
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
- Sync operations require project:write permission
- Webhook endpoints require admin role
- All API calls audited
- Sensitive data handling policies
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
- Sync metadata: 90 days
- Conflict history: 1 year
- Audit logs: 7 years
- Webhook logs: 30 days
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
- One-way sync: <1 second
- Conflict detection: <500ms
- Webhook processing: <100ms
- Bulk sync: <10 seconds for 1000 tasks
Throughput
- Concurrent syncs: 10
- Webhooks per minute: 100
- API calls per minute: 50
Monitoring
Metrics
- Sync success rate
- Conflict frequency
- Webhook response time
- API error rate
- Sync latency percentiles
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
- High conflict rate (>10%)
- Sync failures
- Webhook timeout
- Rate limit exceeded
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
- Encrypt API keys at rest
- Rotate keys annually
- Monitor key usage
REQ-052-118: API keys SHALL be rotated annually.
REQ-052-119: The system SHALL monitor API key usage.
Webhook Security
- HMAC signature verification
- IP whitelisting
- Rate limiting per endpoint
- Secret rotation
Data Privacy
- Encrypt sync data
- Mask sensitive fields
- Comply with GDPR
- Data minimization
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
- Leverage Todoist's mature task management features
- Enable task tracking in user's preferred tool
- Support for projects, priorities, due dates
- Webhook-based real-time synchronization
How
- REST API v2 for CRUD operations
- Webhooks for real-time updates
- Custom fields for agent assignment
- Conflict resolution with timestamps
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
- Base URL: https://api.todoist.com/rest/v2
- Authentication: Bearer token (API token)
- Endpoints Used:
- GET/POST /tasks
- GET/PUT/DELETE /tasks/{id}
- GET /projects
- GET/POST /webhooks
Orchestrata Internal
- Neo4j: Task and project storage
- Redis: Rate limiting, sync state
- Message Queue: Event-driven sync triggers
External Webhooks
- Endpoint: POST /webhooks/todoist
- Verification: HMAC-SHA256 signature
- Events: item:added, item:updated, item:deleted, item:completed
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
- [ ] Tasks sync bidirectionally within 1 second
- [ ] All three user scenarios (US-001, US-002, US-003) work as specified
- [ ] Conflicts are detected and resolved per FR-005, FR-006, FR-007
- [ ] Webhooks are verified with HMAC-SHA256 per FR-004
- [ ] Rate limiting complies with Todoist API limits per FR-008
Quality Criteria
- [ ] Unit test coverage >80%
- [ ] Integration test coverage >90%
- [ ] API contract tests 100%
- [ ] All 17 error conditions handled gracefully
Operational Criteria
- [ ] Sync latency <1 second (one-way)
- [ ] Conflict detection <500ms
- [ ] Webhook processing <100ms
- [ ] System availability 99.9%
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 |