Purvakalpa Studio

Docs / Tasker

Architecture

Layers, capability seams, the TaskStore facade and the rules that keep the engine headless and testable.

Layers

   SwiftUI app (iPhone, iPad, Mac, Watch, widgets)
        │
   TaskUI · TaskIntents · TaskAdapters
        │
   TaskCore  ── TaskStore facade ── SwiftData (+ CloudKit private database)
        │            │
        │            ├── Planning: DayPlanner, PlanRouter, TimeBlocker
        │            ├── AI: TaskNLParser, TaskToolkit, NLBackend
        │            ├── Agents: AgentGate, approvals, receipts, keys
        │            └── IO: .unkt bundles, .xlsx export
        │
   task-mcp (stdio, optional HTTP)

TaskCore links no SwiftUI or UIKit. Anything with a side effect on the operating system is injected through a protocol, so the core runs the same in the app, in tests and inside the MCP server.

Capability seams

ProtocolPurposeImplementations
TaskSyncProviderPush and pull changes with any backendCloudKitTaskSyncProvider; NoSyncProvider for local use and tests
TaskNotificationSchedulingDue-date and early-warning notificationsUserNotificationTaskScheduler in TaskAdapters
TaskGeofencingArrive and leave remindersCoreLocationGeofencer in TaskAdapters
AttachmentStoreAttachment bytes, kept outside the databaseFileAttachmentStore on the device; ICloudDriveAttachmentStore to sync bytes through your own iCloud Drive
AttachmentTransportOptional upload path for a team backendS3PresignedTransport and HTTPUploadTransport; the host signs URLs, so the engine never holds cloud credentials
CalendarProvidingFree and busy time for planningSupplied by the app from EventKit; EmptyCalendarProvider for tests
TemplateProvidingTask blueprintsDefaultTemplateStore
DayPlanProviderAn optional AI plannerApple Intelligence, a paired device, a local server or your own cloud key (see Planning)
NLBackendOptional language model for captureLLMTaskBackend (any OpenAI-compatible endpoint, your key)

The facade

Humans and agents use the same TaskStore. A minimal setup:

import TaskCore

let store = try TaskStore(
    configuration: .cloudKit(containerID: "iCloud.com.purvakalpa.Tasker"),
    syncProvider: CloudKitTaskSyncProvider(containerID: "iCloud.com.purvakalpa.Tasker"),
    crypto: TaskCrypto.fromKeychain())   // seals notes and page bodies, see Security

try store.bootstrap()            // default list, built-in workflow stages, personal workspace; idempotent
try await store.startSync()

let task = try store.createTask(TaskDraft(title: "Ship 1.2", estimatedMinutes: 90, priority: .high))
let plan = try await store.planDay(budgetMinutes: 180, preferredEnergy: .focused)

Configurations are .inMemory for tests and previews, .local() for on-device only, and .cloudKit(containerID:) for iCloud sync. An app that already owns a ModelContainer can splice in TaskSchema.models and pass its container instead. Notes and page bodies are encrypted by default when a TaskCrypto is supplied; attachment encryption is an opt-in flag.

Errors

Store operations throw TaskStoreError: notBootstrapped, listNotFound, taskNotFound, stageNotFound, cyclicParent, attachmentIngestFailed, syncUnavailable, importMalformed and persistence. Background sync never throws: failures surface on the syncStatus stream so the UI can show a badge. An explicit “Sync now” rethrows.

Concurrency and stability

  • Built for Swift 6 strict concurrency. Value types (TaskDraft, JSONValue, enums) are Sendable; @Model objects are not, so code passes IDs across actors, never models.
  • Semantic versioning. Before 1.0, minor versions may break the API; patch versions never do.
  • Persisted schemas are frozen per version and checked in CI (see Data and sync).

Tests

TaskCoreTests cover recurrence, the conflict resolvers, task hierarchy and cycle safety, store round-trips, the day planner and its router, time blocking, reviews and streaks, calendar free-window maths, geofence distance, the natural-language parser, the tool kit, crypto, schema locks, the agent gate matrix, scheduled delegation and MCP golden fixtures. They run with swift test on macOS; SwiftData, CloudKit and App Intents are not available on Linux.