Purvakalpa Studio

Docs / Storyline

Architecture

One multiplatform app over five Swift package modules, a SwiftData model mirrored to your CloudKit private database, the branch contract for AI writes, and the persona lexicon.

Layers

SwiftUI app: one multiplatform target for iPhone, iPad and Mac
  │
  └─ StorylinePackages (Swift package)
       ├─ StorylineUI          views, design system, AppEnvironment
       ├─ StorylineCore        models, vault, audit chain, egress funnel, peer types
       ├─ StorylineAI          model providers, agents and tools, MasterAgent
       ├─ StorylineResearch    ingestion, cleaning, chunking, embeddings, web search
       └─ StorylineSync        CloudKit pipeline, conflicts, encrypted assets
  │
SwiftData (NSPersistentCloudKitContainer) ──── your CloudKit private database

There is no Storyline server anywhere in this picture. The only persistent infrastructure is your own iCloud account, and any flow that would need a server is out of scope by design.

Modules

ModuleWhat it holds
StorylineCoreDomain models; the security primitives (CryptoVault, KDFScheme, AuditChainSigner, EncryptedBundle, PrivilegedProcessingSession); the egress funnel and leak guard; device pairing and the encrypted peer channel
StorylineUIThe SwiftUI views, the design system, and AppEnvironment, the dependency container
StorylineAIThe model providers, agent tooling (ToolRegistry, AgentLoop, MCPToolBridge) and the MasterAgent orchestrator
StorylineResearchResearchService, ReadabilityCleaner, Chunker, EmbeddingStore, WebSearchBackend, PDFTextExtractor
StorylineSyncSyncCoordinator, BackgroundSyncService, ConflictDetector, EncryptedAssetService, SharedProjectService

Data model

All persisted state is SwiftData. The container is built with cloudKitDatabase: .private(…), so NSPersistentCloudKitContainer mirrors every @Model to your CloudKit private database.

GroupModels
WritingProject, Chapter, Scene, Block, Character, Place, PlotBeat, WritingSession, Snippet
VersionsSnapshot, Branch, SceneEditEvent
ResearchResearchNote, Clip, ResearchRunStep, EgressRecord
AIAIAgent, AIPreset, AITask, TaskResult, TaskUnit, AIInteraction, AISuggestion, ConversationTurn, CustomEndpoint
SecurityAuditEntry, VaultCompartment
Devices and sharingDeviceProfile, FamilyPairing, SharedProjectMetadata

The model names are fiction words, but what you see depends on the project’s profession (see the registers below). A project holds many documents: in the model a document is a Scene and a folder is a Chapter. The project’s kind picks the editor: a block editor for document-shaped writing such as session notes, memos and briefs, or a single text view for long-form work.

Storage and sync

  • Your iCloud, nobody else’s. A CloudKit private database belongs to one Apple ID and never exchanges records with another. Sharing a project with a different Apple ID uses a CKShare in CloudKit’s shared database, with editor or viewer roles. Sharing a privileged project is refused, and the refusal is logged.
  • Live updates. SyncCoordinator watches remote-change notifications so open screens see CloudKit imports without a restart. Refreshes are coalesced, rate-capped and held while a full-screen editor is open, so an import never tears down a writing session.
  • Background work. BackgroundSyncService registers its background task handler at launch, before the first scene is built, and a CloudKit database subscription delivers silent pushes that wake the app.
  • Conflicts become branches. ConflictDetector compares incoming changes with a per-device record of recent edits. A conflicting edit becomes a Branch of kind .syncConflict, so neither side’s words are lost.
  • Encrypted assets. Large sealed files travel as EncryptedBundles inside CloudKit assets in their own zone, so Apple stores only ciphertext. See Security.
  • It always launches. If the CloudKit-backed store cannot open, start-up falls back to a local-only store, then an in-memory one. A reversible cloud-sync pause stops a stuck export while keeping every local record, and “Quit to repair” rebuilds the local store and re-imports from iCloud.

How the AI is layered

Every AI surface has a named lane, such as coauthor.draft or research.curate. Every model call goes through AIService, which applies the project’s policy before it chooses a provider, and the output passes an output contract before it is saved. AI routing has the detail.

The branch contract

AI suggestions land as a Branch, never directly in the document. Adopting, discarding and reverting are the branch system’s job, which keeps every suggestion reversible and auditable. Research inserts, which you preview and place yourself, follow the same idea in a lighter form: each takes a restore point first and records what was selected and what was inserted.

  • AutoSnapshotService takes a snapshot after every three minutes of active editing, every 500 characters of change and every document switch.
  • SceneEditEvent records who edited what, from which device, when, and the word delta, merged into one event per writing session per device. In privileged projects these sessions are also stamped into the audit chain.
  • The output contract wraps every agent’s system prompt in a house-style preamble, strips chat filler where output is stored, and fails any generation that echoes its prompt, so model input never becomes document content.

Professional registers

Each project carries one of ten registers: Healthcare, Legal, Journalism, Academic, Founder, General, Fiction, Screenwriting, Marketing or Technical. The register belongs to the project, not to you. It seeds the starter agents, snippet library, templates, vocabulary and theme colour, plus citation and privacy defaults: Healthcare uses AMA, Legal uses Bluebook and Academic uses APA.

Vocabulary is presentation only. Lexicon maps eight concept keys (TermKey) to words for each register, and a key can be hidden. Views and the prompt strings sent to agents resolve terms through the register, so a legal agent is never asked to write “the scene”.

Concept keyFictionTechnical
.projectmanuscriptproject
.scenescenepage
.chapterchaptersection
.charactercharactersubject
.placeplacehidden
.plotBeatplot beatrequirement
.biblestory biblereference
.branchbranchalternate

A lawyer sees sections, parties and issues; a clinician sees notes and people. Field editors follow suit: a legal party shows party type and identification, and a clinical record shows relationship and background. The models keep their slots and the register decides labels and visibility, so serving ten professions needs no data migration.