@plotday/twister 0.57.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/README.md +53 -44
  2. package/bin/commands/create.js +9 -14
  3. package/bin/commands/create.js.map +1 -1
  4. package/bin/commands/deploy.js +2 -0
  5. package/bin/commands/deploy.js.map +1 -1
  6. package/bin/commands/generate.js +8 -5
  7. package/bin/commands/generate.js.map +1 -1
  8. package/bin/index.js +2 -2
  9. package/bin/index.js.map +1 -1
  10. package/bin/templates/AGENTS.template.md +110 -94
  11. package/bin/templates/README.template.md +36 -33
  12. package/cli/templates/AGENTS.template.md +110 -94
  13. package/cli/templates/README.template.md +36 -33
  14. package/dist/connector.d.ts +24 -17
  15. package/dist/connector.d.ts.map +1 -1
  16. package/dist/connector.js +19 -12
  17. package/dist/connector.js.map +1 -1
  18. package/dist/docs/assets/hierarchy.js +1 -1
  19. package/dist/docs/assets/navigation.js +1 -1
  20. package/dist/docs/assets/search.js +1 -1
  21. package/dist/docs/classes/index.Connector.html +66 -60
  22. package/dist/docs/classes/index.FileNotFoundError.html +2 -2
  23. package/dist/docs/classes/index.Files.html +4 -4
  24. package/dist/docs/classes/index.Imap.html +10 -10
  25. package/dist/docs/classes/index.Options.html +2 -2
  26. package/dist/docs/classes/index.Smtp.html +6 -6
  27. package/dist/docs/classes/tool.ITool.html +2 -2
  28. package/dist/docs/classes/tool.Tool.html +23 -23
  29. package/dist/docs/classes/tools_ai.AI.html +5 -5
  30. package/dist/docs/classes/tools_callbacks.Callbacks.html +8 -8
  31. package/dist/docs/classes/tools_integrations.Integrations.html +15 -15
  32. package/dist/docs/classes/tools_network.Network.html +9 -9
  33. package/dist/docs/classes/tools_plot.Plot.html +34 -33
  34. package/dist/docs/classes/tools_store.Store.html +8 -8
  35. package/dist/docs/classes/tools_tasks.Tasks.html +6 -6
  36. package/dist/docs/classes/tools_twists.Twists.html +12 -11
  37. package/dist/docs/classes/twist.Twist.html +28 -28
  38. package/dist/docs/documents/Building_Connectors.html +42 -28
  39. package/dist/docs/documents/Built-in_Tools.html +170 -67
  40. package/dist/docs/documents/CLI_Reference.html +68 -47
  41. package/dist/docs/documents/Core_Concepts.html +52 -81
  42. package/dist/docs/documents/Getting_Started.html +28 -31
  43. package/dist/docs/documents/MULTI_USER_AUTH.html +45 -0
  44. package/dist/docs/documents/Runtime_Environment.html +13 -12
  45. package/dist/docs/documents/SYNC_STRATEGIES.html +373 -0
  46. package/dist/docs/enums/plot.ActionType.html +9 -9
  47. package/dist/docs/enums/plot.ActorType.html +4 -4
  48. package/dist/docs/enums/plot.ConferencingProvider.html +6 -6
  49. package/dist/docs/enums/plot.ThemeColor.html +9 -9
  50. package/dist/docs/enums/tag.Tag.html +3 -3
  51. package/dist/docs/enums/tools_ai.AIModel.html +3 -3
  52. package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
  53. package/dist/docs/enums/tools_plot.ContactAccess.html +2 -2
  54. package/dist/docs/enums/tools_plot.FocusAccess.html +3 -3
  55. package/dist/docs/enums/tools_plot.LinkAccess.html +3 -3
  56. package/dist/docs/enums/tools_plot.ThreadAccess.html +4 -4
  57. package/dist/docs/functions/index.Uuid.Generate.html +1 -1
  58. package/dist/docs/functions/utils_hash.quickHash.html +1 -1
  59. package/dist/docs/hierarchy.html +1 -1
  60. package/dist/docs/index.html +7 -8
  61. package/dist/docs/interfaces/tools_ai.AIRequest.html +13 -13
  62. package/dist/docs/interfaces/tools_ai.AIResponse.html +9 -9
  63. package/dist/docs/interfaces/tools_ai.FilePart.html +5 -5
  64. package/dist/docs/interfaces/tools_ai.ImagePart.html +4 -4
  65. package/dist/docs/interfaces/tools_ai.ReasoningPart.html +4 -4
  66. package/dist/docs/interfaces/tools_ai.RedactedReasoningPart.html +3 -3
  67. package/dist/docs/interfaces/tools_ai.TextPart.html +3 -3
  68. package/dist/docs/interfaces/tools_ai.ToolCallPart.html +5 -5
  69. package/dist/docs/interfaces/tools_ai.ToolExecutionOptions.html +4 -4
  70. package/dist/docs/interfaces/tools_ai.ToolResultPart.html +5 -5
  71. package/dist/docs/interfaces/tools_twists.TwistSource.html +3 -3
  72. package/dist/docs/interfaces/utils_types.ToolShed.html +5 -5
  73. package/dist/docs/media/AGENTS.md +101 -74
  74. package/dist/docs/modules.html +1 -1
  75. package/dist/docs/types/index.BooleanDef.html +2 -2
  76. package/dist/docs/types/index.CreateLinkDraft.html +9 -9
  77. package/dist/docs/types/index.ImapAddress.html +3 -3
  78. package/dist/docs/types/index.ImapConnectOptions.html +6 -6
  79. package/dist/docs/types/index.ImapFetchOptions.html +4 -4
  80. package/dist/docs/types/index.ImapFlagOperation.html +1 -1
  81. package/dist/docs/types/index.ImapMailbox.html +5 -5
  82. package/dist/docs/types/index.ImapMailboxStatus.html +7 -7
  83. package/dist/docs/types/index.ImapMessage.html +14 -14
  84. package/dist/docs/types/index.ImapSearchCriteria.html +9 -9
  85. package/dist/docs/types/index.ImapSession.html +1 -1
  86. package/dist/docs/types/index.NewSchedule.html +13 -13
  87. package/dist/docs/types/index.NewScheduleContact.html +2 -2
  88. package/dist/docs/types/index.NewScheduleOccurrence.html +1 -1
  89. package/dist/docs/types/index.NoteWriteBackResult.html +3 -3
  90. package/dist/docs/types/index.NumberDef.html +2 -2
  91. package/dist/docs/types/index.OptionDef.html +1 -1
  92. package/dist/docs/types/index.OptionalScopeGroup.html +6 -6
  93. package/dist/docs/types/index.OptionsSchema.html +1 -1
  94. package/dist/docs/types/index.ReactionCapabilities.html +1 -1
  95. package/dist/docs/types/index.ResolvedOptions.html +1 -1
  96. package/dist/docs/types/index.ResolvedRecipient.html +5 -5
  97. package/dist/docs/types/index.Schedule.html +12 -12
  98. package/dist/docs/types/index.ScheduleContact.html +2 -2
  99. package/dist/docs/types/index.ScheduleContactRole.html +1 -1
  100. package/dist/docs/types/index.ScheduleContactStatus.html +1 -1
  101. package/dist/docs/types/index.ScheduleOccurrence.html +6 -6
  102. package/dist/docs/types/index.ScheduleOccurrenceUpdate.html +1 -1
  103. package/dist/docs/types/index.ScopeConfig.html +3 -3
  104. package/dist/docs/types/index.SelectDef.html +2 -2
  105. package/dist/docs/types/index.Serializable.html +1 -1
  106. package/dist/docs/types/index.SmtpAddress.html +3 -3
  107. package/dist/docs/types/index.SmtpConnectOptions.html +7 -7
  108. package/dist/docs/types/index.SmtpMessage.html +12 -12
  109. package/dist/docs/types/index.SmtpSendResult.html +4 -4
  110. package/dist/docs/types/index.SmtpSession.html +1 -1
  111. package/dist/docs/types/index.TextDef.html +2 -2
  112. package/dist/docs/types/index.Uuid.html +1 -1
  113. package/dist/docs/types/plot.Action.html +1 -1
  114. package/dist/docs/types/plot.Actor.html +5 -5
  115. package/dist/docs/types/plot.ActorId.html +4 -4
  116. package/dist/docs/types/plot.Contact.html +4 -4
  117. package/dist/docs/types/plot.ContentType.html +1 -1
  118. package/dist/docs/types/plot.Focus.html +8 -8
  119. package/dist/docs/types/plot.FocusUpdate.html +1 -1
  120. package/dist/docs/types/plot.Link.html +17 -17
  121. package/dist/docs/types/plot.LinkUpdate.html +1 -1
  122. package/dist/docs/types/plot.NewActor.html +1 -1
  123. package/dist/docs/types/plot.NewContact.html +1 -1
  124. package/dist/docs/types/plot.NewFocus.html +1 -1
  125. package/dist/docs/types/plot.NewLink.html +5 -2
  126. package/dist/docs/types/plot.NewLinkWithNotes.html +1 -1
  127. package/dist/docs/types/plot.NewNote.html +1 -1
  128. package/dist/docs/types/plot.NewReactions.html +1 -1
  129. package/dist/docs/types/plot.NewTags.html +1 -1
  130. package/dist/docs/types/plot.NewThread.html +1 -1
  131. package/dist/docs/types/plot.NewThreadWithNotes.html +1 -1
  132. package/dist/docs/types/plot.Note.html +1 -1
  133. package/dist/docs/types/plot.NoteUpdate.html +1 -1
  134. package/dist/docs/types/plot.PlanOperation.html +1 -1
  135. package/dist/docs/types/plot.Reaction.html +3 -3
  136. package/dist/docs/types/plot.Reactions.html +1 -1
  137. package/dist/docs/types/plot.Tags.html +1 -1
  138. package/dist/docs/types/plot.Thread.html +1 -1
  139. package/dist/docs/types/plot.ThreadAccessLevel.html +1 -1
  140. package/dist/docs/types/plot.ThreadCommon.html +6 -6
  141. package/dist/docs/types/plot.ThreadFilter.html +2 -2
  142. package/dist/docs/types/plot.ThreadMeta.html +1 -1
  143. package/dist/docs/types/plot.ThreadType.html +1 -1
  144. package/dist/docs/types/plot.ThreadUpdate.html +1 -1
  145. package/dist/docs/types/plot.ThreadWithNotes.html +1 -1
  146. package/dist/docs/types/tools_ai.AIAssistantMessage.html +2 -2
  147. package/dist/docs/types/tools_ai.AICapabilities.html +4 -4
  148. package/dist/docs/types/tools_ai.AIMessage.html +1 -1
  149. package/dist/docs/types/tools_ai.AIOptions.html +2 -2
  150. package/dist/docs/types/tools_ai.AISource.html +1 -1
  151. package/dist/docs/types/tools_ai.AISystemMessage.html +2 -2
  152. package/dist/docs/types/tools_ai.AITool.html +1 -1
  153. package/dist/docs/types/tools_ai.AIToolMessage.html +2 -2
  154. package/dist/docs/types/tools_ai.AIToolSet.html +1 -1
  155. package/dist/docs/types/tools_ai.AIUsage.html +5 -5
  156. package/dist/docs/types/tools_ai.AIUserMessage.html +2 -2
  157. package/dist/docs/types/tools_ai.DataContent.html +1 -1
  158. package/dist/docs/types/tools_ai.ModelPreferences.html +5 -5
  159. package/dist/docs/types/tools_callbacks.Callback.html +2 -2
  160. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  161. package/dist/docs/types/tools_integrations.ArchiveNotesFilter.html +2 -2
  162. package/dist/docs/types/tools_integrations.AuthToken.html +6 -5
  163. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  164. package/dist/docs/types/tools_integrations.Channel.html +6 -6
  165. package/dist/docs/types/tools_integrations.ComposeConfig.html +4 -4
  166. package/dist/docs/types/tools_integrations.ContactRoleConfig.html +5 -5
  167. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +21 -21
  168. package/dist/docs/types/tools_integrations.NewCustomEmoji.html +8 -8
  169. package/dist/docs/types/tools_integrations.StatusIcon.html +1 -1
  170. package/dist/docs/types/tools_integrations.SyncContext.html +4 -4
  171. package/dist/docs/types/tools_network.WebhookRequest.html +6 -6
  172. package/dist/docs/types/tools_plot.LinkFilter.html +5 -5
  173. package/dist/docs/types/tools_plot.LinkSearchResult.html +1 -1
  174. package/dist/docs/types/tools_plot.NoteIntentHandler.html +4 -4
  175. package/dist/docs/types/tools_plot.NoteSearchResult.html +1 -1
  176. package/dist/docs/types/tools_plot.SearchOptions.html +4 -4
  177. package/dist/docs/types/tools_plot.SearchResult.html +1 -1
  178. package/dist/docs/types/tools_twists.Log.html +2 -2
  179. package/dist/docs/types/tools_twists.TwistPermissions.html +1 -1
  180. package/dist/docs/types/utils_types.BuiltInTools.html +2 -2
  181. package/dist/docs/types/utils_types.ExtractBuildReturn.html +1 -1
  182. package/dist/docs/types/utils_types.InferOptions.html +1 -1
  183. package/dist/docs/types/utils_types.InferTools.html +1 -1
  184. package/dist/docs/types/utils_types.JSONValue.html +1 -1
  185. package/dist/docs/types/utils_types.PromiseValues.html +1 -1
  186. package/dist/docs/types/utils_types.ToolBuilder.html +1 -1
  187. package/dist/docs/variables/tools_plot.SEARCH_DEFAULT_LIMIT.html +1 -1
  188. package/dist/docs/variables/tools_plot.SEARCH_MAX_LIMIT.html +1 -1
  189. package/dist/facets.d.ts +30 -0
  190. package/dist/facets.d.ts.map +1 -0
  191. package/dist/facets.js +16 -0
  192. package/dist/facets.js.map +1 -0
  193. package/dist/llm-docs/connector.d.ts +1 -1
  194. package/dist/llm-docs/connector.d.ts.map +1 -1
  195. package/dist/llm-docs/connector.js +1 -1
  196. package/dist/llm-docs/connector.js.map +1 -1
  197. package/dist/llm-docs/facets.d.ts +9 -0
  198. package/dist/llm-docs/facets.d.ts.map +1 -0
  199. package/dist/llm-docs/facets.js +8 -0
  200. package/dist/llm-docs/facets.js.map +1 -0
  201. package/dist/llm-docs/index.d.ts.map +1 -1
  202. package/dist/llm-docs/index.js +2 -0
  203. package/dist/llm-docs/index.js.map +1 -1
  204. package/dist/llm-docs/plot.d.ts +1 -1
  205. package/dist/llm-docs/plot.d.ts.map +1 -1
  206. package/dist/llm-docs/plot.js +1 -1
  207. package/dist/llm-docs/plot.js.map +1 -1
  208. package/dist/llm-docs/tool.d.ts +1 -1
  209. package/dist/llm-docs/tool.d.ts.map +1 -1
  210. package/dist/llm-docs/tool.js +1 -1
  211. package/dist/llm-docs/tool.js.map +1 -1
  212. package/dist/llm-docs/tools/ai.d.ts +1 -1
  213. package/dist/llm-docs/tools/ai.d.ts.map +1 -1
  214. package/dist/llm-docs/tools/ai.js +1 -1
  215. package/dist/llm-docs/tools/ai.js.map +1 -1
  216. package/dist/llm-docs/tools/callbacks.d.ts +1 -1
  217. package/dist/llm-docs/tools/callbacks.d.ts.map +1 -1
  218. package/dist/llm-docs/tools/callbacks.js +1 -1
  219. package/dist/llm-docs/tools/callbacks.js.map +1 -1
  220. package/dist/llm-docs/tools/files.d.ts +1 -1
  221. package/dist/llm-docs/tools/files.d.ts.map +1 -1
  222. package/dist/llm-docs/tools/files.js +1 -1
  223. package/dist/llm-docs/tools/files.js.map +1 -1
  224. package/dist/llm-docs/tools/imap.d.ts +1 -1
  225. package/dist/llm-docs/tools/imap.d.ts.map +1 -1
  226. package/dist/llm-docs/tools/imap.js +1 -1
  227. package/dist/llm-docs/tools/imap.js.map +1 -1
  228. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  229. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  230. package/dist/llm-docs/tools/integrations.js +1 -1
  231. package/dist/llm-docs/tools/integrations.js.map +1 -1
  232. package/dist/llm-docs/tools/network.d.ts +1 -1
  233. package/dist/llm-docs/tools/network.d.ts.map +1 -1
  234. package/dist/llm-docs/tools/network.js +1 -1
  235. package/dist/llm-docs/tools/network.js.map +1 -1
  236. package/dist/llm-docs/tools/plot.d.ts +1 -1
  237. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  238. package/dist/llm-docs/tools/plot.js +1 -1
  239. package/dist/llm-docs/tools/plot.js.map +1 -1
  240. package/dist/llm-docs/tools/smtp.d.ts +1 -1
  241. package/dist/llm-docs/tools/smtp.d.ts.map +1 -1
  242. package/dist/llm-docs/tools/smtp.js +1 -1
  243. package/dist/llm-docs/tools/smtp.js.map +1 -1
  244. package/dist/llm-docs/tools/tasks.d.ts +1 -1
  245. package/dist/llm-docs/tools/tasks.d.ts.map +1 -1
  246. package/dist/llm-docs/tools/tasks.js +1 -1
  247. package/dist/llm-docs/tools/tasks.js.map +1 -1
  248. package/dist/llm-docs/tools/twists.d.ts +1 -1
  249. package/dist/llm-docs/tools/twists.d.ts.map +1 -1
  250. package/dist/llm-docs/tools/twists.js +1 -1
  251. package/dist/llm-docs/tools/twists.js.map +1 -1
  252. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  253. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  254. package/dist/llm-docs/twist-guide-template.js +1 -1
  255. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  256. package/dist/llm-docs/twist.d.ts +1 -1
  257. package/dist/llm-docs/twist.d.ts.map +1 -1
  258. package/dist/llm-docs/twist.js +1 -1
  259. package/dist/llm-docs/twist.js.map +1 -1
  260. package/dist/plot.d.ts +15 -8
  261. package/dist/plot.d.ts.map +1 -1
  262. package/dist/plot.js.map +1 -1
  263. package/dist/tool.d.ts +4 -4
  264. package/dist/tool.js +4 -4
  265. package/dist/tools/ai.d.ts +12 -13
  266. package/dist/tools/ai.d.ts.map +1 -1
  267. package/dist/tools/ai.js +8 -9
  268. package/dist/tools/ai.js.map +1 -1
  269. package/dist/tools/callbacks.d.ts +1 -1
  270. package/dist/tools/files.d.ts +2 -2
  271. package/dist/tools/imap.d.ts +1 -1
  272. package/dist/tools/imap.js +1 -1
  273. package/dist/tools/integrations.d.ts +2 -1
  274. package/dist/tools/integrations.d.ts.map +1 -1
  275. package/dist/tools/network.d.ts +5 -5
  276. package/dist/tools/plot.d.ts +42 -37
  277. package/dist/tools/plot.d.ts.map +1 -1
  278. package/dist/tools/plot.js +16 -12
  279. package/dist/tools/plot.js.map +1 -1
  280. package/dist/tools/smtp.d.ts +1 -1
  281. package/dist/tools/smtp.js +1 -1
  282. package/dist/tools/tasks.d.ts +6 -8
  283. package/dist/tools/tasks.d.ts.map +1 -1
  284. package/dist/tools/tasks.js +5 -7
  285. package/dist/tools/tasks.js.map +1 -1
  286. package/dist/tools/twists.d.ts +15 -14
  287. package/dist/tools/twists.d.ts.map +1 -1
  288. package/dist/tools/twists.js +2 -2
  289. package/dist/tools/twists.js.map +1 -1
  290. package/dist/twist-guide.d.ts +1 -1
  291. package/dist/twist-guide.d.ts.map +1 -1
  292. package/dist/twist.d.ts +2 -2
  293. package/dist/twist.js +2 -2
  294. package/package.json +6 -1
  295. package/src/connector.ts +23 -16
  296. package/src/facets.ts +40 -0
  297. package/src/llm-docs/connector.ts +1 -1
  298. package/src/llm-docs/facets.ts +8 -0
  299. package/src/llm-docs/index.ts +2 -0
  300. package/src/llm-docs/plot.ts +1 -1
  301. package/src/llm-docs/tool.ts +1 -1
  302. package/src/llm-docs/tools/ai.ts +1 -1
  303. package/src/llm-docs/tools/callbacks.ts +1 -1
  304. package/src/llm-docs/tools/files.ts +1 -1
  305. package/src/llm-docs/tools/imap.ts +1 -1
  306. package/src/llm-docs/tools/integrations.ts +1 -1
  307. package/src/llm-docs/tools/network.ts +1 -1
  308. package/src/llm-docs/tools/plot.ts +1 -1
  309. package/src/llm-docs/tools/smtp.ts +1 -1
  310. package/src/llm-docs/tools/tasks.ts +1 -1
  311. package/src/llm-docs/tools/twists.ts +1 -1
  312. package/src/llm-docs/twist-guide-template.ts +1 -1
  313. package/src/llm-docs/twist.ts +1 -1
  314. package/src/plot.ts +15 -8
  315. package/src/tool.ts +4 -4
  316. package/src/tools/ai.ts +12 -13
  317. package/src/tools/callbacks.ts +1 -1
  318. package/src/tools/files.ts +2 -2
  319. package/src/tools/imap.ts +1 -1
  320. package/src/tools/integrations.ts +2 -1
  321. package/src/tools/network.ts +5 -5
  322. package/src/tools/plot.ts +42 -37
  323. package/src/tools/smtp.ts +1 -1
  324. package/src/tools/tasks.ts +6 -8
  325. package/src/tools/twists.ts +15 -14
  326. package/src/twist.ts +2 -2
  327. package/dist/docs/media/MULTI_USER_AUTH.md +0 -116
  328. package/dist/docs/media/SYNC_STRATEGIES.md +0 -818
@@ -6,14 +6,14 @@
6
6
  <hr>
7
7
  <h2 id="no-code-twists" class="tsd-anchor-link">No-Code Twists<a href="#no-code-twists" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Create twists using natural language descriptions - no programming required!</p>
8
8
  <h3 id="step-1-create-a-plot-twistmd-file" class="tsd-anchor-link">Step 1: Create a <a href="http://plot-twist.md">plot-twist.md</a> File<a href="#step-1-create-a-plot-twistmd-file" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Create a file named <code>plot-twist.md</code> in your project directory and describe what you want your twist to do:</p>
9
- <pre><code class="markdown"><span class="hl-9"># My Calendar Twist</span><br/><br/><span class="hl-1">I want a twist that:</span><br/><br/><span class="hl-10">-</span><span class="hl-1"> Syncs my Google Calendar events into Plot as activities</span><br/><span class="hl-10">-</span><span class="hl-1"> Creates tasks for upcoming meetings</span><br/><span class="hl-10">-</span><span class="hl-1"> Sends me a reminder 10 minutes before each meeting</span><br/><span class="hl-10">-</span><span class="hl-1"> Updates activity status when meetings are completed</span>
9
+ <pre><code class="markdown"><span class="hl-9"># My Calendar Twist</span><br/><br/><span class="hl-1">I want a twist that:</span><br/><br/><span class="hl-10">-</span><span class="hl-1"> Syncs my Google Calendar events into Plot as threads</span><br/><span class="hl-10">-</span><span class="hl-1"> Creates tasks for upcoming meetings</span><br/><span class="hl-10">-</span><span class="hl-1"> Sends me a reminder 10 minutes before each meeting</span><br/><span class="hl-10">-</span><span class="hl-1"> Updates thread status when meetings are completed</span>
10
10
  </code><button type="button">Copy</button></pre>
11
11
 
12
12
  <p><strong>Be specific about:</strong></p>
13
13
  <ul>
14
14
  <li><strong>Data sources</strong> - Which services to connect (Google Calendar, GitHub, Slack, etc.)</li>
15
15
  <li><strong>Actions</strong> - What the twist should do (create tasks, send notifications, update status)</li>
16
- <li><strong>Triggers</strong> - When actions should happen (on new events, on schedule, when activities change)</li>
16
+ <li><strong>Triggers</strong> - When actions should happen (on new events, on schedule, when threads change)</li>
17
17
  </ul>
18
18
  <h3 id="step-2-deploy-your-twist" class="tsd-anchor-link">Step 2: Deploy Your Twist<a href="#step-2-deploy-your-twist" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>You'll need a <a href="https://plot.day">Plot account</a> to deploy twists.</p>
19
19
  <pre><code class="bash"><span class="hl-7"># Login to Plot</span><br/><span class="hl-6">npx</span><span class="hl-1"> </span><span class="hl-3">@plotday/twister</span><span class="hl-1"> </span><span class="hl-3">login</span><br/><br/><span class="hl-7"># Deploy directly from your spec</span><br/><span class="hl-6">npx</span><span class="hl-1"> </span><span class="hl-3">@plotday/twister</span><span class="hl-1"> </span><span class="hl-3">deploy</span>
@@ -37,19 +37,19 @@
37
37
  <li><strong>Display name</strong> (human-readable, e.g., &quot;My Calendar Twist&quot;)</li>
38
38
  </ul>
39
39
  <p>This creates a new directory with:</p>
40
- <pre><code><span class="hl-2">my</span><span class="hl-1">-</span><span class="hl-2">calendar</span><span class="hl-1">-</span><span class="hl-2">twist</span><span class="hl-1">/</span><br/><span class="hl-1">├── </span><span class="hl-2">src</span><span class="hl-1">/</span><br/><span class="hl-1">│ └── </span><span class="hl-2">index</span><span class="hl-1">.</span><span class="hl-2">ts</span><span class="hl-1"> # </span><span class="hl-2">Your</span><span class="hl-1"> </span><span class="hl-2">twist</span><span class="hl-1"> </span><span class="hl-2">code</span><br/><span class="hl-1">├── </span><span class="hl-2">package</span><span class="hl-1">.</span><span class="hl-2">json</span><br/><span class="hl-1">├── </span><span class="hl-2">tsconfig</span><span class="hl-1">.</span><span class="hl-2">json</span><br/><span class="hl-1">└── </span><span class="hl-2">plot</span><span class="hl-1">-</span><span class="hl-2">twist</span><span class="hl-1">.</span><span class="hl-2">json</span><span class="hl-1"> # </span><span class="hl-2">Twist</span><span class="hl-1"> </span><span class="hl-2">configuration</span>
40
+ <pre><code><span class="hl-2">my</span><span class="hl-1">-</span><span class="hl-2">calendar</span><span class="hl-1">-</span><span class="hl-2">twist</span><span class="hl-1">/</span><br/><span class="hl-1">├── </span><span class="hl-2">src</span><span class="hl-1">/</span><br/><span class="hl-1">│ └── </span><span class="hl-2">index</span><span class="hl-1">.</span><span class="hl-2">ts</span><span class="hl-1"> # </span><span class="hl-2">Your</span><span class="hl-1"> </span><span class="hl-2">twist</span><span class="hl-1"> </span><span class="hl-2">code</span><br/><span class="hl-1">├── </span><span class="hl-2">package</span><span class="hl-1">.</span><span class="hl-2">json</span><span class="hl-1"> # </span><span class="hl-2">Twist</span><span class="hl-1"> </span><span class="hl-2">metadata</span><span class="hl-1"> </span><span class="hl-2">and</span><span class="hl-1"> </span><span class="hl-2">dependencies</span><br/><span class="hl-1">├── </span><span class="hl-2">tsconfig</span><span class="hl-1">.</span><span class="hl-2">json</span><br/><span class="hl-1">├── </span><span class="hl-8">README</span><span class="hl-1">.</span><span class="hl-2">md</span><br/><span class="hl-1">├── </span><span class="hl-8">AGENTS</span><span class="hl-1">.</span><span class="hl-2">md</span><span class="hl-1"> # </span><span class="hl-2">Guide</span><span class="hl-1"> </span><span class="hl-2">for</span><span class="hl-1"> </span><span class="hl-8">AI</span><span class="hl-1"> </span><span class="hl-2">coding</span><span class="hl-1"> </span><span class="hl-2">assistants</span><br/><span class="hl-1">└── </span><span class="hl-8">CLAUDE</span><span class="hl-1">.</span><span class="hl-2">md</span>
41
41
  </code><button>Copy</button></pre>
42
42
 
43
43
  <h3 id="step-2-implement-your-twist" class="tsd-anchor-link">Step 2: Implement Your Twist<a href="#step-2-implement-your-twist" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Edit <code>src/index.ts</code> to add your twist logic:</p>
44
- <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">Activity</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">Priority</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">Twist</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Plot</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/plot&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-0">default</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Twist</span><span class="hl-1">&lt;</span><span class="hl-5">MyTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Declare tool dependencies</span><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">plot:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Plot</span><span class="hl-1">),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Called when the twist is activated for a priority</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">(</span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-5">Pick</span><span class="hl-1">&lt;</span><span class="hl-5">Priority</span><span class="hl-1">, </span><span class="hl-3">&quot;id&quot;</span><span class="hl-1">&gt;) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Note</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Welcome! Your twist is now active.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Your twist is ready to use. You can now start creating activities and automating your workflow.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Called when an activity is routed to this twist</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activity</span><span class="hl-1">(</span><span class="hl-2">activity</span><span class="hl-1">: </span><span class="hl-5">Activity</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-3">&quot;Processing activity:&quot;</span><span class="hl-1">, </span><span class="hl-2">activity</span><span class="hl-1">.</span><span class="hl-2">title</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
44
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">Note</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1">, </span><span class="hl-2">Twist</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Plot</span><span class="hl-1">, </span><span class="hl-2">ThreadAccess</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/plot&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-0">default</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Twist</span><span class="hl-1">&lt;</span><span class="hl-5">MyTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Declare tool dependencies</span><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">plot:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Plot</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">thread:</span><span class="hl-1"> { </span><span class="hl-2">access:</span><span class="hl-1"> </span><span class="hl-2">ThreadAccess</span><span class="hl-1">.</span><span class="hl-2">Create</span><span class="hl-1"> },</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Called when the twist is installed</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Welcome! Your twist is now active.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Your twist is ready to use. You can now start creating threads and automating your workflow.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Called when a note is created on a thread this twist created</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">onNoteCreated</span><span class="hl-1">(</span><span class="hl-2">note</span><span class="hl-1">: </span><span class="hl-5">Note</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-3">&quot;Processing note:&quot;</span><span class="hl-1">, </span><span class="hl-2">note</span><span class="hl-1">.</span><span class="hl-2">content</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
45
45
  </code><button type="button">Copy</button></pre>
46
46
 
47
- <h3 id="step-3-test-locally" class="tsd-anchor-link">Step 3: Test Locally<a href="#step-3-test-locally" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Build and check for errors:</p>
48
- <pre><code class="bash"><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">build</span><br/><span class="hl-7"># or</span><br/><span class="hl-6">pnpm</span><span class="hl-1"> </span><span class="hl-3">build</span>
47
+ <h3 id="step-3-test-locally" class="tsd-anchor-link">Step 3: Test Locally<a href="#step-3-test-locally" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Check for build and lint errors:</p>
48
+ <pre><code class="bash"><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">lint</span><br/><span class="hl-7"># or</span><br/><span class="hl-6">pnpm</span><span class="hl-1"> </span><span class="hl-3">lint</span>
49
49
  </code><button type="button">Copy</button></pre>
50
50
 
51
51
  <h3 id="step-4-deploy" class="tsd-anchor-link">Step 4: Deploy<a href="#step-4-deploy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>You'll need a <a href="https://plot.day">Plot account</a> to deploy twists.</p>
52
- <pre><code class="bash"><span class="hl-7"># Login to Plot</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">plot</span><span class="hl-1"> </span><span class="hl-3">login</span><br/><br/><span class="hl-7"># Deploy your twist</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">deploy</span>
52
+ <pre><code class="bash"><span class="hl-7"># Login to Plot</span><br/><span class="hl-6">npx</span><span class="hl-1"> </span><span class="hl-3">plot</span><span class="hl-1"> </span><span class="hl-3">login</span><br/><br/><span class="hl-7"># Deploy your twist</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">deploy</span>
53
53
  </code><button type="button">Copy</button></pre>
54
54
 
55
55
  <p>Your twist is now deployed and ready to activate in Plot!</p>
@@ -57,12 +57,12 @@
57
57
  <h2 id="understanding-the-project-structure" class="tsd-anchor-link">Understanding the Project Structure<a href="#understanding-the-project-structure" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="twist-file-srcindexts" class="tsd-anchor-link">Twist File (src/index.ts)<a href="#twist-file-srcindexts" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Your twist extends the <code>Twist</code> class and implements:</p>
58
58
  <ul>
59
59
  <li><strong><code>build()</code></strong> - Declares tool dependencies</li>
60
- <li><strong><code>activate()</code></strong> - Initialization when added to a priority</li>
61
- <li><strong><code>deactivate()</code></strong> - Cleanup when removed from a priority</li>
60
+ <li><strong><code>activate()</code></strong> - Initialization when the twist is installed</li>
61
+ <li><strong><code>deactivate()</code></strong> - Cleanup when the twist is uninstalled</li>
62
62
  <li><strong><code>upgrade()</code></strong> - Migration when deploying a new version</li>
63
63
  </ul>
64
- <h3 id="configuration-plot-twistjson" class="tsd-anchor-link">Configuration (plot-twist.json)<a href="#configuration-plot-twistjson" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Contains twist metadata:</p>
65
- <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;my-calendar-twist&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;displayName&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;My Calendar Twist&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;version&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;1.0.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;description&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;Syncs calendar events to Plot&quot;</span><br/><span class="hl-1">}</span>
64
+ <h3 id="configuration-packagejson" class="tsd-anchor-link">Configuration (package.json)<a href="#configuration-packagejson" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Twist metadata lives in <code>package.json</code>, including a generated <code>plotTwistId</code> that identifies your twist for deployment:</p>
65
+ <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;my-calendar-twist&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;displayName&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;My Calendar Twist&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;description&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;Syncs calendar events to Plot&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;plotTwistId&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;generated-uuid&quot;</span><br/><span class="hl-1">}</span>
66
66
  </code><button type="button">Copy</button></pre>
67
67
 
68
68
  <h3 id="typescript-config-tsconfigjson" class="tsd-anchor-link">TypeScript Config (tsconfig.json)<a href="#typescript-config-tsconfigjson" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Extends the Twist Creator's base configuration:</p>
@@ -77,41 +77,38 @@
77
77
  <li><strong><a href="Building_Connectors.html">Building Connectors</a></strong> - Build external service integrations</li>
78
78
  <li><strong><a href="Runtime_Environment.html">Runtime Environment</a></strong> - Understand execution constraints and optimization</li>
79
79
  </ul>
80
- <h2 id="common-first-tasks" class="tsd-anchor-link">Common First Tasks<a href="#common-first-tasks" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="understanding-activities-and-notes" class="tsd-anchor-link">Understanding Activities and Notes<a href="#understanding-activities-and-notes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p><strong>Activity</strong> represents something done or to be done (a task, event, or conversation), while <strong>Notes</strong> represent the updates and details on that activity.</p>
81
- <p>Think of an <strong>Activity as a thread</strong> on a messaging platform, and <strong>Notes as the messages in that thread</strong>. Always create activities with an initial note, and add notes for updates rather than creating new activities.</p>
82
- <h3 id="creating-activities" class="tsd-anchor-link">Creating Activities<a href="#creating-activities" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Always create activities with an initial note. The <code>notes</code> array can contain multiple notes (messages in the thread).</p>
83
- <p><strong>Data Sync Tip:</strong> When syncing from external systems, use <code>Activity.source</code> for automatic deduplication and <code>Note.key</code> for upsertable notes. See the <a href="../media/SYNC_STRATEGIES.md">Sync Strategies</a> guide for detailed patterns.</p>
84
- <pre><code class="typescript"><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">source:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://github.com/org/repo/pull/123&quot;</span><span class="hl-1">, </span><span class="hl-7">// Enables automatic upserts</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Review pull request&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">activity:</span><span class="hl-1"> { </span><span class="hl-2">source:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://github.com/org/repo/pull/123&quot;</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">&quot;description&quot;</span><span class="hl-1">, </span><span class="hl-7">// Using key enables upserts</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Please review the authentication changes and ensure they follow security best practices.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">links:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityLinkType</span><span class="hl-1">.</span><span class="hl-2">external</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;View PR&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">url:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://github.com/org/repo/pull/123&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">});</span>
80
+ <h2 id="common-first-tasks" class="tsd-anchor-link">Common First Tasks<a href="#common-first-tasks" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="understanding-threads-and-notes" class="tsd-anchor-link">Understanding Threads and Notes<a href="#understanding-threads-and-notes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>A <strong>Thread</strong> represents something done or to be done (a task, event, or conversation), while <strong>Notes</strong> represent the updates and details on that thread.</p>
81
+ <p>Think of a <strong>Thread as a thread</strong> on a messaging platform, and <strong>Notes as the messages in that thread</strong>. Always create threads with an initial note, and add notes for updates rather than creating new threads.</p>
82
+ <h3 id="creating-threads" class="tsd-anchor-link">Creating Threads<a href="#creating-threads" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Always create threads with an initial note. The <code>notes</code> array can contain multiple notes (messages in the thread).</p>
83
+ <p><strong>Data Sync Tip:</strong> When syncing from external systems, build a connector and use <code>Link.sources</code> for automatic deduplication and <code>Note.key</code> for upsertable notes. See the <a href="SYNC_STRATEGIES.html">Sync Strategies</a> guide for detailed patterns.</p>
84
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">ActionType</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Review pull request&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">&quot;description&quot;</span><span class="hl-1">, </span><span class="hl-7">// Using key enables upserts</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Please review the authentication changes and ensure they follow security best practices.&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">actions:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActionType</span><span class="hl-1">.</span><span class="hl-2">external</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;View PR&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">url:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://github.com/org/repo/pull/123&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">});</span>
85
85
  </code><button type="button">Copy</button></pre>
86
86
 
87
- <h4 id="scheduling-states-for-actions" class="tsd-anchor-link">Scheduling States for Actions<a href="#scheduling-states-for-actions" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p><strong>Important:</strong> When creating Actions (tasks), the <code>start</code> field determines how they appear in Plot. By default, omitting <code>start</code> creates a &quot;Do Now&quot; task. For most integrations, you should explicitly set <code>start: null</code> to create backlog items.</p>
88
- <pre><code class="typescript"><span class="hl-7">// &quot;Do Now&quot; - Actionable today (DEFAULT when start is omitted)</span><br/><span class="hl-7">// Use for urgent tasks or items actively in progress</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Fix critical bug in production&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{ </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Users reporting login failures&quot;</span><span class="hl-1"> }],</span><br/><span class="hl-1"> </span><span class="hl-7">// Omitting start defaults to current time</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// &quot;Do Someday&quot; - Backlog item (RECOMMENDED for most synced tasks)</span><br/><span class="hl-7">// Use for task backlog, future ideas, non-urgent items</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Refactor authentication module&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">start:</span><span class="hl-1"> </span><span class="hl-4">null</span><span class="hl-1">, </span><span class="hl-7">// Explicitly set to null for backlog</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{ </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Technical debt item to address later&quot;</span><span class="hl-1"> }],</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// &quot;Do Later&quot; - Scheduled for specific date</span><br/><span class="hl-7">// Use when task has a specific due date</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Submit expense report&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">start:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-3">&quot;2025-01-31&quot;</span><span class="hl-1">), </span><span class="hl-7">// Due date</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{ </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;December expenses need to be submitted by end of month&quot;</span><span class="hl-1"> }],</span><br/><span class="hl-1">});</span>
87
+ <h4 id="scheduling-threads" class="tsd-anchor-link">Scheduling Threads<a href="#scheduling-threads" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>Threads appear on the user's agenda when they have a schedule. Pass <code>schedules</code> when creating the thread, or call <code>createSchedule()</code> later:</p>
88
+ <pre><code class="typescript"><span class="hl-7">// Scheduled (recurring) event</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Team standup&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{ </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Daily sync meeting&quot;</span><span class="hl-1"> }],</span><br/><span class="hl-1"> </span><span class="hl-2">schedules:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">start:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-3">&quot;2025-02-01T10:00:00Z&quot;</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-2">end:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-3">&quot;2025-02-01T10:30:00Z&quot;</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-2">recurrenceRule:</span><span class="hl-1"> </span><span class="hl-3">&quot;FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">});</span>
89
89
  </code><button type="button">Copy</button></pre>
90
90
 
91
91
  <h3 id="storing-data" class="tsd-anchor-link">Storing Data<a href="#storing-data" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-7">// Save</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">&quot;last_sync&quot;</span><span class="hl-1">, </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">().</span><span class="hl-6">toISOString</span><span class="hl-1">());</span><br/><br/><span class="hl-7">// Retrieve</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">lastSync</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt;(</span><span class="hl-3">&quot;last_sync&quot;</span><span class="hl-1">);</span>
92
92
  </code><button type="button">Copy</button></pre>
93
93
 
94
- <h3 id="scheduling-tasks" class="tsd-anchor-link">Scheduling Tasks<a href="#scheduling-tasks" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-7">// Run immediately</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">callback</span><span class="hl-1">(</span><span class="hl-3">&quot;processData&quot;</span><span class="hl-1">);</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">);</span><br/><br/><span class="hl-7">// Schedule for later</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">runAt:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-3">&quot;2025-02-01T10:00:00Z&quot;</span><span class="hl-1">),</span><br/><span class="hl-1">});</span>
94
+ <h3 id="scheduling-tasks" class="tsd-anchor-link">Scheduling Tasks<a href="#scheduling-tasks" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-7">// Run immediately (in a new execution with a fresh request limit)</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">callback</span><span class="hl-1">(</span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">processData</span><span class="hl-1">);</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">);</span><br/><br/><span class="hl-7">// Schedule for later</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">runAt:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-3">&quot;2025-02-01T10:00:00Z&quot;</span><span class="hl-1">),</span><br/><span class="hl-1">});</span>
95
95
  </code><button type="button">Copy</button></pre>
96
96
 
97
- <h3 id="best-practices" class="tsd-anchor-link">Best Practices<a href="#best-practices" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><h4 id="always-include-notes-with-activities" class="tsd-anchor-link">Always Include Notes with Activities<a href="#always-include-notes-with-activities" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p><strong>Important:</strong> Always create Activities with at least one initial Note. The <code>title</code> and <code>preview</code> are brief summaries that may be truncated in the UI. Detailed information should go in Notes.</p>
98
- <pre><code class="typescript"><span class="hl-7">// ✅ Good - Activity with detailed Note</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deploy v2.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">note:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deployment checklist:</span><span class="hl-12">\n</span><span class="hl-3">- Run database migrations</span><span class="hl-12">\n</span><span class="hl-3">- Update environment variables</span><span class="hl-12">\n</span><span class="hl-3">- Deploy backend services</span><span class="hl-12">\n</span><span class="hl-3">- Deploy frontend</span><span class="hl-12">\n</span><span class="hl-3">- Run smoke tests&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">links:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityLinkType</span><span class="hl-1">.</span><span class="hl-2">external</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deployment Guide&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">url:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://docs.example.com/deploy&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// ❌ Bad - No detailed information</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Action</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deploy v2.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-7">// Missing Notes with context and steps</span><br/><span class="hl-1">});</span>
97
+ <h3 id="best-practices" class="tsd-anchor-link">Best Practices<a href="#best-practices" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><h4 id="always-include-notes-with-threads" class="tsd-anchor-link">Always Include Notes with Threads<a href="#always-include-notes-with-threads" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p><strong>Important:</strong> Always create Threads with at least one initial Note. The <code>title</code> and <code>preview</code> are brief summaries that may be truncated in the UI. Detailed information should go in Notes.</p>
98
+ <pre><code class="typescript"><span class="hl-7">// ✅ Good - Thread with detailed Note</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deploy v2.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deployment checklist:</span><span class="hl-12">\n</span><span class="hl-3">- Run database migrations</span><span class="hl-12">\n</span><span class="hl-3">- Update environment variables</span><span class="hl-12">\n</span><span class="hl-3">- Deploy backend services</span><span class="hl-12">\n</span><span class="hl-3">- Deploy frontend</span><span class="hl-12">\n</span><span class="hl-3">- Run smoke tests&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">actions:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActionType</span><span class="hl-1">.</span><span class="hl-2">external</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deployment Guide&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">url:</span><span class="hl-1"> </span><span class="hl-3">&quot;https://docs.example.com/deploy&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// ❌ Bad - No detailed information</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;Deploy v2.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-7">// Missing Notes with context and steps</span><br/><span class="hl-1">});</span>
99
99
  </code><button type="button">Copy</button></pre>
100
100
 
101
- <h4 id="add-notes-to-existing-activities-for-related-content" class="tsd-anchor-link">Add Notes to Existing Activities for Related Content<a href="#add-notes-to-existing-activities-for-related-content" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>For conversations, email threads, or workflows, add Notes to the existing Activity instead of creating new Activities.</p>
102
- <p><strong>Recommended Pattern:</strong> Use <code>Activity.source</code> and <code>Note.key</code> for automatic upserts - no need to check if the activity exists first:</p>
103
- <pre><code class="typescript"><span class="hl-7">// Simply create - Plot handles deduplication automatically via source</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">conversationUrl</span><span class="hl-1"> = </span><span class="hl-3">`https://app.example.com/conversations/</span><span class="hl-4">${</span><span class="hl-2">conversationId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">;</span><br/><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createNote</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">activity:</span><span class="hl-1"> { </span><span class="hl-2">source:</span><span class="hl-1"> </span><span class="hl-2">conversationUrl</span><span class="hl-1"> }, </span><span class="hl-7">// References activity by source</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">`message-</span><span class="hl-4">${</span><span class="hl-2">messageId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, </span><span class="hl-7">// Use unique key per message for upserts</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">newMessage</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// If the activity doesn&#39;t exist yet, create it with source</span><br/><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">source:</span><span class="hl-1"> </span><span class="hl-2">conversationUrl</span><span class="hl-1">, </span><span class="hl-7">// Same source for deduplication</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Note</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;New conversation&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{</span><br/><span class="hl-1"> </span><span class="hl-2">activity:</span><span class="hl-1"> { </span><span class="hl-2">source:</span><span class="hl-1"> </span><span class="hl-2">conversationUrl</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">`message-</span><span class="hl-4">${</span><span class="hl-2">messageId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">newMessage</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1"> }],</span><br/><span class="hl-1">});</span>
101
+ <h4 id="add-notes-to-existing-threads-for-related-content" class="tsd-anchor-link">Add Notes to Existing Threads for Related Content<a href="#add-notes-to-existing-threads-for-related-content" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>For conversations, email threads, or workflows, add Notes to the existing Thread instead of creating new Threads.</p>
102
+ <p><strong>Recommended Pattern:</strong> Store the thread ID when you create the thread, then add notes by ID. A unique <code>Note.key</code> per message makes note writes upserts, so re-processing the same message never creates duplicates:</p>
103
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">onNewMessage</span><span class="hl-1">(</span><span class="hl-2">message</span><span class="hl-1">: </span><span class="hl-2">Message</span><span class="hl-1">, </span><span class="hl-2">conversationId</span><span class="hl-1">: </span><span class="hl-2">string</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// Look up the thread for this conversation (created earlier)</span><br/><span class="hl-1"> </span><span class="hl-4">let</span><span class="hl-1"> </span><span class="hl-2">threadId</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">Uuid</span><span class="hl-1">&gt;(</span><span class="hl-3">`thread_</span><span class="hl-4">${</span><span class="hl-2">conversationId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">threadId</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// First message - create the thread with the message as its initial note</span><br/><span class="hl-1"> </span><span class="hl-2">threadId</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createThread</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-2">message</span><span class="hl-1">.</span><span class="hl-2">subject</span><span class="hl-1"> || </span><span class="hl-3">&quot;New conversation&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">`message-</span><span class="hl-4">${</span><span class="hl-2">message</span><span class="hl-13">.</span><span class="hl-2">id</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, </span><span class="hl-7">// Unique key per message enables upserts</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">message</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">`thread_</span><span class="hl-4">${</span><span class="hl-2">conversationId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, </span><span class="hl-2">threadId</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Follow-up message - add a note to the existing thread</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createNote</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">thread:</span><span class="hl-1"> { </span><span class="hl-2">id:</span><span class="hl-1"> </span><span class="hl-2">threadId</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">key:</span><span class="hl-1"> </span><span class="hl-3">`message-</span><span class="hl-4">${</span><span class="hl-2">message</span><span class="hl-13">.</span><span class="hl-2">id</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">message</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span>
104
104
  </code><button type="button">Copy</button></pre>
105
105
 
106
- <p><strong>Alternative Pattern</strong> (for advanced cases): Use <code>getActivityBySource</code> to check existence:</p>
107
- <pre><code class="typescript"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">existing</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">getActivityBySource</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">conversation_id:</span><span class="hl-1"> </span><span class="hl-2">conversationId</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">existing</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createNote</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">activity:</span><span class="hl-1"> { </span><span class="hl-2">id:</span><span class="hl-1"> </span><span class="hl-2">existing</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">newMessage</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">} </span><span class="hl-0">else</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Note</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;New conversation&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">meta:</span><span class="hl-1"> { </span><span class="hl-2">conversation_id:</span><span class="hl-1"> </span><span class="hl-2">conversationId</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">notes:</span><span class="hl-1"> [{ </span><span class="hl-2">content:</span><span class="hl-1"> </span><span class="hl-2">newMessage</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1"> }],</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span>
108
- </code><button type="button">Copy</button></pre>
109
-
110
- <p>See <a href="../media/SYNC_STRATEGIES.md">Sync Strategies</a> for more patterns and guidance on choosing the right approach.</p>
111
- <p>See <a href="Core_Concepts.html#best-practices-for-activities-and-notes">Core Concepts - Best Practices</a> for more details.</p>
106
+ <p><strong>For connectors:</strong> When syncing from an external service, you don't need to store thread IDs at all — save links with <code>integrations.saveLink()</code> using <code>Link.sources</code> for deduplication, and reference threads by source (<code>thread: { source: ... }</code>) when creating notes.</p>
107
+ <p>See <a href="SYNC_STRATEGIES.html">Sync Strategies</a> for more patterns and guidance on choosing the right approach.</p>
108
+ <p>See <a href="Core_Concepts.html#best-practices-for-threads-and-notes">Core Concepts - Best Practices</a> for more details.</p>
112
109
  <h2 id="need-help" class="tsd-anchor-link">Need Help?<a href="#need-help" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
113
110
  <li><strong>Documentation</strong>: Continue reading the guides</li>
114
111
  <li><strong>Examples</strong>: Check the <a href="https://github.com/plotday/plot/tree/main/twists">examples directory</a></li>
115
112
  <li><strong>Issues</strong>: <a href="https://github.com/plotday/plot/issues">Report bugs or request features</a></li>
116
113
  </ul>
117
- </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#getting-started-with-plot-twists"><span>Getting <wbr/>Started with <wbr/>Plot <wbr/>Twists</span></a><ul><li><a href="#choose-your-path"><span>Choose <wbr/>Your <wbr/>Path</span></a></li><li><a href="#no-code-twists"><span>No-<wbr/>Code <wbr/>Twists</span></a></li><li><ul><li><a href="#step-1-create-a-plot-twistmd-file"><span>Step 1: <wbr/>Create a plot-<wbr/>twist.md <wbr/>File</span></a></li><li><a href="#step-2-deploy-your-twist"><span>Step 2: <wbr/>Deploy <wbr/>Your <wbr/>Twist</span></a></li><li><a href="#optional-generate-code-first"><span>Optional: <wbr/>Generate <wbr/>Code <wbr/>First</span></a></li></ul></li><li><a href="#developer-twists"><span>Developer <wbr/>Twists</span></a></li><li><ul><li><a href="#step-1-create-a-new-twist-project"><span>Step 1: <wbr/>Create a <wbr/>New <wbr/>Twist <wbr/>Project</span></a></li><li><a href="#step-2-implement-your-twist"><span>Step 2: <wbr/>Implement <wbr/>Your <wbr/>Twist</span></a></li><li><a href="#step-3-test-locally"><span>Step 3: <wbr/>Test <wbr/>Locally</span></a></li><li><a href="#step-4-deploy"><span>Step 4: <wbr/>Deploy</span></a></li></ul></li><li><a href="#understanding-the-project-structure"><span>Understanding the <wbr/>Project <wbr/>Structure</span></a></li><li><ul><li><a href="#twist-file-srcindexts"><span>Twist <wbr/>File (src/index.ts)</span></a></li><li><a href="#configuration-plot-twistjson"><span>Configuration (plot-<wbr/>twist.json)</span></a></li><li><a href="#typescript-config-tsconfigjson"><span>Type<wbr/>Script <wbr/>Config (tsconfig.json)</span></a></li></ul></li><li><a href="#next-steps"><span>Next <wbr/>Steps</span></a></li><li><a href="#common-first-tasks"><span>Common <wbr/>First <wbr/>Tasks</span></a></li><li><ul><li><a href="#understanding-activities-and-notes"><span>Understanding <wbr/>Activities and <wbr/>Notes</span></a></li><li><a href="#creating-activities"><span>Creating <wbr/>Activities</span></a></li><li><ul><li><a href="#scheduling-states-for-actions"><span>Scheduling <wbr/>States for <wbr/>Actions</span></a></li></ul></li><li><a href="#storing-data"><span>Storing <wbr/>Data</span></a></li><li><a href="#scheduling-tasks"><span>Scheduling <wbr/>Tasks</span></a></li><li><a href="#best-practices"><span>Best <wbr/>Practices</span></a></li><li><ul><li><a href="#always-include-notes-with-activities"><span>Always <wbr/>Include <wbr/>Notes with <wbr/>Activities</span></a></li><li><a href="#add-notes-to-existing-activities-for-related-content"><span>Add <wbr/>Notes to <wbr/>Existing <wbr/>Activities for <wbr/>Related <wbr/>Content</span></a></li></ul></li></ul></li><li><a href="#need-help"><span>Need <wbr/>Help?</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
114
+ </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#getting-started-with-plot-twists"><span>Getting <wbr/>Started with <wbr/>Plot <wbr/>Twists</span></a><ul><li><a href="#choose-your-path"><span>Choose <wbr/>Your <wbr/>Path</span></a></li><li><a href="#no-code-twists"><span>No-<wbr/>Code <wbr/>Twists</span></a></li><li><ul><li><a href="#step-1-create-a-plot-twistmd-file"><span>Step 1: <wbr/>Create a plot-<wbr/>twist.md <wbr/>File</span></a></li><li><a href="#step-2-deploy-your-twist"><span>Step 2: <wbr/>Deploy <wbr/>Your <wbr/>Twist</span></a></li><li><a href="#optional-generate-code-first"><span>Optional: <wbr/>Generate <wbr/>Code <wbr/>First</span></a></li></ul></li><li><a href="#developer-twists"><span>Developer <wbr/>Twists</span></a></li><li><ul><li><a href="#step-1-create-a-new-twist-project"><span>Step 1: <wbr/>Create a <wbr/>New <wbr/>Twist <wbr/>Project</span></a></li><li><a href="#step-2-implement-your-twist"><span>Step 2: <wbr/>Implement <wbr/>Your <wbr/>Twist</span></a></li><li><a href="#step-3-test-locally"><span>Step 3: <wbr/>Test <wbr/>Locally</span></a></li><li><a href="#step-4-deploy"><span>Step 4: <wbr/>Deploy</span></a></li></ul></li><li><a href="#understanding-the-project-structure"><span>Understanding the <wbr/>Project <wbr/>Structure</span></a></li><li><ul><li><a href="#twist-file-srcindexts"><span>Twist <wbr/>File (src/index.ts)</span></a></li><li><a href="#configuration-packagejson"><span>Configuration (package.json)</span></a></li><li><a href="#typescript-config-tsconfigjson"><span>Type<wbr/>Script <wbr/>Config (tsconfig.json)</span></a></li></ul></li><li><a href="#next-steps"><span>Next <wbr/>Steps</span></a></li><li><a href="#common-first-tasks"><span>Common <wbr/>First <wbr/>Tasks</span></a></li><li><ul><li><a href="#understanding-threads-and-notes"><span>Understanding <wbr/>Threads and <wbr/>Notes</span></a></li><li><a href="#creating-threads"><span>Creating <wbr/>Threads</span></a></li><li><ul><li><a href="#scheduling-threads"><span>Scheduling <wbr/>Threads</span></a></li></ul></li><li><a href="#storing-data"><span>Storing <wbr/>Data</span></a></li><li><a href="#scheduling-tasks"><span>Scheduling <wbr/>Tasks</span></a></li><li><a href="#best-practices"><span>Best <wbr/>Practices</span></a></li><li><ul><li><a href="#always-include-notes-with-threads"><span>Always <wbr/>Include <wbr/>Notes with <wbr/>Threads</span></a></li><li><a href="#add-notes-to-existing-threads-for-related-content"><span>Add <wbr/>Notes to <wbr/>Existing <wbr/>Threads for <wbr/>Related <wbr/>Content</span></a></li></ul></li></ul></li><li><a href="#need-help"><span>Need <wbr/>Help?</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>MULTI_USER_AUTH | Creating Plot Twists</title><link rel="icon" href="../assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for Creating Plot Twists"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="/" class="title">Creating Plot Twists</a><div id="tsd-toolbar-links"><a href="https://plot.day">Plot</a><a href="https://github.com/plotday/plot">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister">NPM</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">MULTI_USER_AUTH</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="multi-user-auth" class="tsd-anchor-link">Multi-User Auth<a href="#multi-user-auth" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Connectors operate on threads that are often shared across users — the same Gmail thread, calendar event, or Linear issue appears as a single Plot thread for everyone involved. This guide covers the auth models and how the runtime routes per-user write-backs.</p>
2
+ <h2 id="auth-models" class="tsd-anchor-link">Auth Models<a href="#auth-models" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><table>
3
+ <thead>
4
+ <tr>
5
+ <th>Model</th>
6
+ <th>Use case</th>
7
+ <th>Example</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <tr>
12
+ <td>No auth</td>
13
+ <td>Twist doesn't need external credentials</td>
14
+ <td>Text-only twist</td>
15
+ </tr>
16
+ <tr>
17
+ <td>Individual auth (default)</td>
18
+ <td>Each user connects their own account</td>
19
+ <td>Google Calendar, Gmail, Linear</td>
20
+ </tr>
21
+ <tr>
22
+ <td>Shared auth (<code>shared: true</code>)</td>
23
+ <td>One credential, entered by the installer, used workspace-wide</td>
24
+ <td>Slack bot token, workspace API key</td>
25
+ </tr>
26
+ </tbody>
27
+ </table>
28
+ <h2 id="declaring-auth" class="tsd-anchor-link">Declaring Auth<a href="#declaring-auth" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Connectors never build their own auth UI. Declare the provider and scopes as class properties and the runtime drives the OAuth flow from the connection setup modal:</p>
29
+ <pre><code class="typescript"><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">LinearConnector</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Connector</span><span class="hl-1">&lt;</span><span class="hl-5">LinearConnector</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">readonly</span><span class="hl-1"> </span><span class="hl-2">provider</span><span class="hl-1"> = </span><span class="hl-2">AuthProvider</span><span class="hl-1">.</span><span class="hl-2">Linear</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-4">readonly</span><span class="hl-1"> </span><span class="hl-2">scopes</span><span class="hl-1"> = [</span><span class="hl-3">&quot;read&quot;</span><span class="hl-1">, </span><span class="hl-3">&quot;write&quot;</span><span class="hl-1">];</span><br/><span class="hl-1"> </span><span class="hl-7">// ...</span><br/><span class="hl-1">}</span>
30
+ </code><button type="button">Copy</button></pre>
31
+
32
+ <p>Key points:</p>
33
+ <ul>
34
+ <li><code>shared = true</code> — one credential is shared across all users in the workspace, entered once by the installer. The default (<code>false</code>) is per-user auth: each user connects their own account.</li>
35
+ <li><code>keyOption</code> — set to the name of a <code>secure: true</code> Options field to use API-key auth instead of OAuth. For individual connectors the key is stored per-user.</li>
36
+ <li>Read tokens with <code>this.tools.integrations.get(channelId)</code> — returns the token of the user who enabled sync on that channel, or <code>null</code> if the channel isn't enabled or the token is invalid.</li>
37
+ </ul>
38
+ <h2 id="per-user-auth-for-write-backs" class="tsd-anchor-link">Per-User Auth for Write-Backs<a href="#per-user-auth-for-write-backs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>When a user acts on a shared thread — replying with a note, adding a reaction, changing a to-do or RSVP status — the runtime dispatches the change to <strong>the acting user's own connector instance</strong>, which is the only instance holding their OAuth token. Your callback (<code>onNoteCreated</code>, <code>onNoteUpdated</code>, <code>onNoteReactionChanged</code>, <code>onThreadToDo</code>, …) already runs under the acting user's auth: fetch the token through the connector's normal path and the external write is attributed to them automatically. No actor-switching step is required.</p>
39
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">onNoteCreated</span><span class="hl-1">(</span><span class="hl-2">note</span><span class="hl-1">: </span><span class="hl-2">Note</span><span class="hl-1">, </span><span class="hl-2">thread</span><span class="hl-1">: </span><span class="hl-2">Thread</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">NoteWriteBackResult</span><span class="hl-1"> | </span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// This instance belongs to the user who wrote the note, so this token is theirs.</span><br/><span class="hl-1"> const </span><span class="hl-2">token</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">integrations</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">(</span><span class="hl-2">thread</span><span class="hl-1">.</span><span class="hl-2">meta</span><span class="hl-1">?.</span><span class="hl-2">channelId</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (!</span><span class="hl-2">token</span><span class="hl-1">) return;</span><br/><br/><span class="hl-1"> const </span><span class="hl-2">comment</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">addIssueComment</span><span class="hl-1">(</span><span class="hl-2">token</span><span class="hl-1">, </span><span class="hl-2">thread</span><span class="hl-1">.</span><span class="hl-2">meta</span><span class="hl-1">, </span><span class="hl-2">note</span><span class="hl-1">.</span><span class="hl-2">content</span><span class="hl-1"> ?? </span><span class="hl-3">&quot;&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">// Returning { key, externalContent } lets the runtime set note.key AND</span><br/><span class="hl-1"> </span><span class="hl-7">// record the sync baseline so future re-syncs preserve Plot&#39;s markdown.</span><br/><span class="hl-1"> return { </span><span class="hl-15">key</span><span class="hl-1">: </span><span class="hl-3">`comment-</span><span class="hl-4">${</span><span class="hl-2">comment</span><span class="hl-13">.</span><span class="hl-2">id</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, </span><span class="hl-15">externalContent</span><span class="hl-1">: </span><span class="hl-2">comment</span><span class="hl-1">.</span><span class="hl-2">body</span><span class="hl-1"> };</span><br/><span class="hl-1">}</span>
40
+ </code><button type="button">Copy</button></pre>
41
+
42
+ <h3 id="when-the-acting-user-has-no-connection" class="tsd-anchor-link">When the Acting User Has No Connection<a href="#when-the-acting-user-has-no-connection" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>If the acting user has no connection of this type, the change is saved in Plot but no write-back dispatch fires — there is no connector instance with their credentials to deliver it to. The thread stays consistent in Plot; the external system simply doesn't receive that user's change.</p>
43
+ <p>This also means connectors don't need a &quot;fall back to the installer's credentials&quot; code path: dispatch routing already guarantees a write-back callback only runs with the acting user's own credentials.</p>
44
+ <h2 id="cross-user-thread-sharing" class="tsd-anchor-link">Cross-User Thread Sharing<a href="#cross-user-thread-sharing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Auth is per-user, but the synced data converges: when several users' connectors sync the same external item (the same <code>source</code>), they share a single Plot thread. Each user gains access when their own connector instance syncs the item — populating <code>thread.contacts</code> with recipients does not by itself admit them. See <code>connectors/AGENTS.md</code> → &quot;<code>source</code> — idempotency + cross-user dedup&quot; and &quot;Attestation-based visibility&quot; for the full contract.</p>
45
+ </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#multi-user-auth"><span>Multi-<wbr/>User <wbr/>Auth</span></a><ul><li><a href="#auth-models"><span>Auth <wbr/>Models</span></a></li><li><a href="#declaring-auth"><span>Declaring <wbr/>Auth</span></a></li><li><a href="#per-user-auth-for-write-backs"><span>Per-<wbr/>User <wbr/>Auth for <wbr/>Write-<wbr/>Backs</span></a></li><li><ul><li><a href="#when-the-acting-user-has-no-connection"><span>When the <wbr/>Acting <wbr/>User <wbr/>Has <wbr/>No <wbr/>Connection</span></a></li></ul></li><li><a href="#cross-user-thread-sharing"><span>Cross-<wbr/>User <wbr/>Thread <wbr/>Sharing</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>