@plotday/twister 0.57.0 → 0.59.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 +58 -17
  15. package/dist/connector.d.ts.map +1 -1
  16. package/dist/connector.js +51 -13
  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 +90 -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 +56 -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
@@ -29,17 +29,18 @@ Plot Twists are TypeScript classes that extend the `Twist` base class. Twists in
29
29
 
30
30
  1. **Always create Threads with an initial Note** - The title is just a summary; detailed content goes in Notes
31
31
  2. **Add Notes to existing Threads for updates** - Don't create a new Thread for each related message
32
- 3. **Use Thread.source and Note.key for automatic upserts (Recommended)** - Set Thread.source to the external item's URL for deduplication, and use Note.key for upsertable note content. No manual ID tracking needed.
32
+ 3. **Use source/key for automatic upserts (Recommended)** - External items are saved as links keyed by `source` (connectors call `integrations.saveLink()` with the item's canonical URL/ID), and `Note.key` enables upsertable note content. Reference an already-synced thread with `thread: { source }`. No manual ID tracking needed.
33
33
  4. **For advanced cases, use generated UUIDs** - Only when you need multiple Plot threads per external item (see SYNC_STRATEGIES.md)
34
- 5. **Most Threads should be `ThreadType.Note`** - Use `Action` only for tasks with `done`, use `Event` only for items with `start`/`end`
34
+ 5. **Thread `type` is an optional display sub-type** - One of `"action"`, `"notes"`, `"idea"`, `"goal"`, `"decision"`, `"discussion"`, `"announcement"`, `"ask"`. Omit it for the default (`"notes"` in private focuses, `"discussion"` in shared ones). Use `"action"` for tasks; events are threads with `schedules`.
35
35
 
36
36
  ### Recommended Decision Tree (Strategy 2: Upsert via Source/Key)
37
37
 
38
38
  ```
39
39
  New event/task/conversation from external system?
40
40
  ├─ Has stable URL or ID?
41
- │ └─ Yes → Set Thread.source to the canonical URL/ID
42
- Create Thread (Plot handles deduplication automatically)
41
+ │ └─ Yes → Save a link with `source` set to the canonical URL/ID
42
+ (connectors: integrations.saveLink() Plot handles
43
+ │ deduplication automatically)
43
44
  │ Use Note.key for different note types:
44
45
  │ - "description" for main content
45
46
  │ - "metadata" for status/priority/assignee
@@ -71,11 +72,9 @@ New event/task/conversation?
71
72
  import {
72
73
  type Thread,
73
74
  type NewThreadWithNotes,
74
- type ThreadFilter,
75
- type Priority,
75
+ type Note,
76
76
  type ToolBuilder,
77
77
  Twist,
78
- ThreadType,
79
78
  } from "@plotday/twister";
80
79
  import { ThreadAccess, Plot } from "@plotday/twister/tools/plot";
81
80
  // Import your sources or tools as needed
@@ -89,7 +88,7 @@ export default class MyTwist extends Twist<MyTwist> {
89
88
  };
90
89
  }
91
90
 
92
- async activate(_priority: Pick<Priority, "id">) {
91
+ async activate() {
93
92
  // Auth and resource selection handled in the twist edit modal.
94
93
  }
95
94
  }
@@ -119,11 +118,11 @@ For complete API documentation of built-in tools including all methods, types, a
119
118
 
120
119
  **Quick reference - Available tools:**
121
120
 
122
- - `@plotday/twister/tools/plot` - Core data layer (create/update activities, priorities, contacts)
121
+ - `@plotday/twister/tools/plot` - Core data layer (create/update threads, notes, focuses, contacts)
123
122
  - `@plotday/twister/tools/ai` - LLM integration (text generation, structured output, reasoning)
124
123
  - Use ModelPreferences to specify `speed` (fast/balanced/capable) and `cost` (low/medium/high)
125
124
  - `@plotday/twister/tools/store` - Persistent key-value storage (also via `this.set()`, `this.get()`)
126
- - `@plotday/twister/tools/tasks` - Queue batched work (also via `this.run()`)
125
+ - `@plotday/twister/tools/tasks` - Queue batched work (also via `this.runTask()`)
127
126
  - `@plotday/twister/tools/callbacks` - Persistent function references (also via `this.callback()`)
128
127
  - `@plotday/twister/tools/integrations` - OAuth2 authentication flows
129
128
  - `@plotday/twister/tools/network` - HTTP access permissions and webhook management
@@ -133,25 +132,24 @@ For complete API documentation of built-in tools including all methods, types, a
133
132
 
134
133
  ## Lifecycle Methods
135
134
 
136
- ### activate(priority: Pick<Priority, "id">)
135
+ ### activate(context?: { actor: Actor })
137
136
 
138
- Called when the twist is enabled for a priority. Auth and resource selection are handled automatically via the twist edit modal when using external tools with Integrations.
137
+ Called when the twist is installed by a user. Auth and resource selection are handled automatically via the twist edit modal when using external tools with Integrations.
139
138
 
140
139
  Most twists have an empty or minimal `activate()`:
141
140
 
142
141
  ```typescript
143
- async activate(_priority: Pick<Priority, "id">) {
142
+ async activate() {
144
143
  // Auth and resource selection are handled in the twist edit modal.
145
144
  // Only add custom initialization here if needed.
146
145
  }
147
146
  ```
148
147
 
149
- **Store Parent Thread for Later (optional):**
148
+ **Store Setup Thread for Later (optional):**
150
149
 
151
150
  ```typescript
152
- async activate(_priority: Pick<Priority, "id">) {
151
+ async activate() {
153
152
  const threadId = await this.tools.plot.createThread({
154
- type: ThreadType.Note,
155
153
  title: "Setup complete",
156
154
  notes: [{
157
155
  content: "Your twist is ready. Threads will appear as they sync.",
@@ -161,9 +159,9 @@ async activate(_priority: Pick<Priority, "id">) {
161
159
  }
162
160
  ```
163
161
 
164
- ### Event Callbacks (via build options)
162
+ ### Event Callbacks (lifecycle overrides)
165
163
 
166
- Twists respond to events through callbacks declared in `build()`:
164
+ Twists respond to events by overriding lifecycle methods inherited from the `Twist` base class. No registration is needed — declare Plot access in `build()` and the runtime routes events for threads your twist created:
167
165
 
168
166
  **React to thread changes (for two-way sync):**
169
167
 
@@ -171,20 +169,19 @@ Twists respond to events through callbacks declared in `build()`:
171
169
  plot: build(Plot, {
172
170
  thread: {
173
171
  access: ThreadAccess.Create,
174
- updated: this.onThreadUpdated,
175
- },
176
- note: {
177
- created: this.onNoteCreated,
178
172
  },
179
173
  }),
180
174
 
181
- async onThreadUpdated(thread: Thread, changes: { tagsAdded, tagsRemoved }): Promise<void> {
182
- const tool = this.getToolForThread(thread);
183
- if (tool?.updateIssue) await tool.updateIssue(thread);
175
+ // Called when a thread created by this twist is updated
176
+ async onThreadUpdated(thread: Thread, changes: { tagsAdded: Record<Tag, ActorId[]>; tagsRemoved: Record<Tag, ActorId[]> }): Promise<void> {
177
+ // Push the change to the external system
178
+ await externalApi.updateItem(thread.meta?.externalId, { title: thread.title });
184
179
  }
185
180
 
181
+ // Called when a note is created on a thread created by this twist.
182
+ // Notes created by the twist itself are filtered out automatically.
186
183
  async onNoteCreated(note: Note, thread: Thread): Promise<NoteWriteBackResult | void> {
187
- if (note.author.type === ActorType.Twist) return; // Prevent loops
184
+ if (note.author.type === ActorType.Twist) return; // Prevent loops with other twists
188
185
  // Sync note to external service as a comment. Return the external
189
186
  // system's id + stored content so the runtime can set note.key AND
190
187
  // record a sync baseline that preserves Plot's content on round-trip.
@@ -210,6 +207,8 @@ plot: build(Plot, {
210
207
  }),
211
208
  ```
212
209
 
210
+ For a fully conversational twist, set `note.handler` instead of `intents` — every mention is then routed directly to that one method (`(note: Note) => Promise<void>`), skipping intent matching. `handler` and `intents` are mutually exclusive.
211
+
213
212
  **Default mention on replies:**
214
213
 
215
214
  When your twist processes replies (two-way comment sync or conversational AI), set `defaultMention: true` so the user doesn't have to manually re-mention your twist on every note:
@@ -218,15 +217,11 @@ When your twist processes replies (two-way comment sync or conversational AI), s
218
217
  - `note.defaultMention` — Auto-mention on follow-up notes in threads where your twist was @-mentioned (e.g., conversational agents)
219
218
 
220
219
  ```typescript
221
- // Connector with two-way comment sync
220
+ // Connector with two-way comment sync (override onThreadUpdated / onNoteCreated)
222
221
  plot: build(Plot, {
223
222
  thread: {
224
223
  access: ThreadAccess.Create,
225
224
  defaultMention: true, // Users replying to synced threads will mention this twist by default
226
- updated: this.onThreadUpdated,
227
- },
228
- note: {
229
- created: this.onNoteCreated,
230
225
  },
231
226
  }),
232
227
 
@@ -256,8 +251,8 @@ const urlAction: Action = {
256
251
  url: "https://example.com",
257
252
  };
258
253
 
259
- // Callback action (uses Callbacks tool — use linkCallback, not callback)
260
- const token = await this.linkCallback(this.onActionClicked, "context");
254
+ // Callback action (uses Callbacks tool — use actionCallback, not callback)
255
+ const token = await this.actionCallback(this.onActionClicked, "context");
261
256
  const callbackAction: Action = {
262
257
  title: "Click me",
263
258
  type: ActionType.callback,
@@ -266,7 +261,6 @@ const callbackAction: Action = {
266
261
 
267
262
  // Add to thread note
268
263
  await this.tools.plot.createThread({
269
- type: ThreadType.Note,
270
264
  title: "Task with actions",
271
265
  notes: [
272
266
  {
@@ -284,27 +278,40 @@ async onActionClicked(action: Action, context: string): Promise<void> {
284
278
 
285
279
  ## Authentication Pattern
286
280
 
287
- Auth is handled automatically via the Integrations tool. Tools declare their OAuth provider in `build()`, and users connect in the twist edit modal. **You do not need to create auth activities manually.**
281
+ Auth is handled automatically via the Integrations tool. Connectors (twists that extend `Connector`) declare their OAuth provider and scopes as class properties, and users connect in the twist edit modal. **You do not need to create auth activities manually.**
288
282
 
289
283
  ```typescript
290
- // In your tool's build() method:
291
- build(build: ToolBuilder) {
292
- return {
293
- integrations: build(Integrations, {
294
- providers: [{
295
- provider: AuthProvider.Google,
296
- scopes: ["https://www.googleapis.com/auth/calendar"],
297
- getChannels: this.getChannels, // List available resources after auth
298
- onChannelEnabled: this.onChannelEnabled, // User enabled a resource
299
- onChannelDisabled: this.onChannelDisabled, // User disabled a resource
300
- }],
301
- }),
302
- // ...
303
- };
284
+ import { Connector, type ToolBuilder } from "@plotday/twister";
285
+ import {
286
+ AuthProvider,
287
+ type AuthToken,
288
+ type Authorization,
289
+ type Channel,
290
+ Integrations,
291
+ } from "@plotday/twister/tools/integrations";
292
+
293
+ export default class MyConnector extends Connector<MyConnector> {
294
+ readonly provider = AuthProvider.Google;
295
+ readonly scopes = ["https://www.googleapis.com/auth/calendar"];
296
+
297
+ build(build: ToolBuilder) {
298
+ return {
299
+ integrations: build(Integrations),
300
+ };
301
+ }
302
+
303
+ // List available resources after auth
304
+ async getChannels(auth: Authorization, token: AuthToken): Promise<Channel[]> { ... }
305
+
306
+ // User enabled a resource
307
+ async onChannelEnabled(channel: Channel): Promise<void> { ... }
308
+
309
+ // User disabled a resource
310
+ async onChannelDisabled(channel: Channel): Promise<void> { ... }
304
311
  }
305
312
 
306
313
  // Get a token for API calls:
307
- const token = await this.tools.integrations.get(AuthProvider.Google, channelId);
314
+ const token = await this.tools.integrations.get(channelId);
308
315
  if (!token) throw new Error("No auth token available");
309
316
  const client = new ApiClient({ accessToken: token.token });
310
317
  ```
@@ -321,28 +328,33 @@ is not dispatched.
321
328
 
322
329
  ### Upsert via Source/Key (Strategy 2)
323
330
 
324
- Use source/key for automatic upserts:
331
+ Use source/key for automatic upserts. Connectors save external items as links — `source` is the upsert key:
325
332
 
326
333
  ```typescript
327
334
  async handleEvent(event: ExternalEvent): Promise<void> {
328
- const thread: NewThreadWithNotes = {
329
- source: event.htmlLink, // Canonical URL for automatic deduplication
330
- type: ThreadType.Event,
335
+ // Create or update — Plot handles deduplication automatically
336
+ await this.tools.integrations.saveLink({
337
+ source: event.htmlLink, // Canonical URL/ID for automatic deduplication
338
+ type: "event",
331
339
  title: event.summary || "(No title)",
332
- notes: [],
333
- };
340
+ notes: event.description
341
+ ? [{
342
+ key: "description", // This key enables note-level upserts
343
+ content: event.description,
344
+ }]
345
+ : [],
346
+ });
347
+ }
348
+ ```
334
349
 
335
- if (event.description) {
336
- thread.notes.push({
337
- thread: { source: event.htmlLink },
338
- key: "description", // This key enables note-level upserts
339
- content: event.description,
340
- });
341
- }
350
+ `saveLink()` is available to Connectors only. A regular twist adding notes to an already-synced thread references it by source instead:
342
351
 
343
- // Create or update — Plot handles deduplication automatically
344
- await this.tools.plot.createThread(thread);
345
- }
352
+ ```typescript
353
+ await this.tools.plot.createNote({
354
+ thread: { source: event.htmlLink }, // Reference the synced thread
355
+ key: "summary",
356
+ content: "...",
357
+ });
346
358
  ```
347
359
 
348
360
  ### Advanced: Generate and Store IDs (Strategy 3)
@@ -391,10 +403,10 @@ async handleEventAdvanced(
391
403
 
392
404
  ## Resource Selection
393
405
 
394
- Resource selection (calendars, projects, channels) is handled automatically in the twist edit modal via the Integrations tool. Users see a list of available resources returned by your tool's `getChannels()` method and toggle them on/off. You do **not** need to build custom selection UI.
406
+ Resource selection (calendars, projects, channels) is handled automatically in the twist edit modal via the Integrations tool. Users see a list of available resources returned by your connector's `getChannels()` method and toggle them on/off. You do **not** need to build custom selection UI.
395
407
 
396
408
  ```typescript
397
- // In your tool:
409
+ // In your connector:
398
410
  async getChannels(_auth: Authorization, token: AuthToken): Promise<Channel[]> {
399
411
  const client = new ApiClient({ accessToken: token.token });
400
412
  const calendars = await client.listCalendars();
@@ -447,13 +459,11 @@ async syncBatch(resourceId: string): Promise<void> {
447
459
  // Process results using source/key pattern (automatic upserts, no manual tracking)
448
460
  // If each item makes ~10 requests, keep batch size ≤ 100 items to stay under limit
449
461
  for (const item of result.items) {
450
- // Each createThread may make ~5-10 requests depending on notes/links
451
- await this.tools.plot.createThread({
462
+ await this.tools.integrations.saveLink({
452
463
  source: item.url, // Use item's canonical URL for automatic deduplication
453
- type: ThreadType.Note,
464
+ type: "item",
454
465
  title: item.title,
455
466
  notes: [{
456
- activity: { source: item.url },
457
467
  key: "description", // Use key for upsertable notes
458
468
  content: item.description,
459
469
  }],
@@ -461,6 +471,8 @@ async syncBatch(resourceId: string): Promise<void> {
461
471
  ...(state.initialSync ? { archived: false } : {}), // unarchive on initial only
462
472
  });
463
473
  }
474
+ // Tip: integrations.saveLinks([...]) saves a whole page in one call,
475
+ // which counts as a single request against the execution budget.
464
476
 
465
477
  if (result.nextPageToken) {
466
478
  // Update state in Store for next batch
@@ -480,7 +492,6 @@ async syncBatch(resourceId: string): Promise<void> {
480
492
 
481
493
  // Optionally notify user of completion
482
494
  await this.tools.plot.createThread({
483
- type: ThreadType.Note,
484
495
  title: "Sync complete",
485
496
  notes: [
486
497
  {
@@ -507,25 +518,25 @@ All sync-based tools should distinguish between initial sync (first import) and
507
518
 
508
519
  **Example:**
509
520
  ```typescript
510
- const thread: NewThread = {
511
- type: ThreadType.Event,
521
+ await this.tools.integrations.saveLink({
512
522
  source: event.url,
523
+ type: "event",
513
524
  title: event.title,
514
525
  ...(initialSync ? { unread: false } : {}), // false for initial, omit for incremental
515
526
  ...(initialSync ? { archived: false } : {}), // unarchive on initial only
516
- };
527
+ });
517
528
  ```
518
529
 
519
530
  **Why this matters:**
520
- - **Initial sync**: Activities are unarchived and marked as read for all users, preventing spam from bulk historical imports
521
- - **Incremental sync**: Activities are auto-marked read for the author (twist owner), unread for everyone else. Archived state is preserved
522
- - **Reinstall**: Acts as initial sync, so previously archived activities are unarchived (fresh start)
531
+ - **Initial sync**: Threads are unarchived and marked as read for all users, preventing spam from bulk historical imports
532
+ - **Incremental sync**: Threads are auto-marked read for the author (twist owner), unread for everyone else. Archived state is preserved
533
+ - **Reinstall**: Acts as initial sync, so previously archived threads are unarchived (fresh start)
523
534
 
524
535
  ### Two-Way Sync: Avoiding Race Conditions
525
536
 
526
537
  When implementing two-way sync where items created in Plot are pushed to an external system (e.g. Notes becoming comments), a race condition can occur: the external system may send a webhook for the newly created item before you've updated the Thread/Note with the external key. The webhook handler won't find the item by external key and may create a duplicate.
527
538
 
528
- **Solution:** Embed the Plot `Thread.id` / `Note.id` in the external item's metadata when creating it, and update `Thread.source` / `Note.key` after creation. When processing webhooks, check for the Plot ID in metadata first.
539
+ **Solution:** Embed the Plot `Thread.id` / `Note.id` in the external item's metadata when creating it, and update `Note.key` after creation. When processing webhooks, check for the Plot ID in metadata first.
529
540
 
530
541
  ```typescript
531
542
  async pushNoteAsComment(note: Note, externalItemId: string): Promise<void> {
@@ -546,15 +557,21 @@ async pushNoteAsComment(note: Note, externalItemId: string): Promise<void> {
546
557
  async onWebhook(payload: WebhookPayload): Promise<void> {
547
558
  const comment = payload.comment;
548
559
 
549
- // Use Plot ID from metadata if present (handles race condition),
550
- // otherwise fall back to upserting by activity source and key
551
- await this.tools.plot.createNote({
552
- ...(comment.metadata?.plotNoteId
553
- ? { id: comment.metadata.plotNoteId }
554
- : { activity: { source: payload.itemUrl } }),
555
- key: `comment-${comment.id}`,
556
- content: comment.body,
557
- });
560
+ if (comment.metadata?.plotNoteId) {
561
+ // Plot ID in metadata: the note originated in Plot (handles the race)
562
+ await this.tools.plot.updateNote({
563
+ id: comment.metadata.plotNoteId,
564
+ key: `comment-${comment.id}`,
565
+ content: comment.body,
566
+ });
567
+ } else {
568
+ // Otherwise upsert by thread source and note key
569
+ await this.tools.plot.createNote({
570
+ thread: { source: payload.itemUrl },
571
+ key: `comment-${comment.id}`,
572
+ content: comment.body,
573
+ });
574
+ }
558
575
  }
559
576
  ```
560
577
 
@@ -569,7 +586,6 @@ try {
569
586
  console.error("Operation failed:", error);
570
587
 
571
588
  await this.tools.plot.createThread({
572
- type: ThreadType.Note,
573
589
  title: "Operation failed",
574
590
  notes: [
575
591
  {
@@ -583,15 +599,15 @@ try {
583
599
  ## Common Pitfalls
584
600
 
585
601
  - **Don't use instance variables for state** - Anything stored in memory is lost after function execution. Always use the Store tool for data that needs to persist.
586
- - **Processing self-created threads** - Other users may change a Thread created by the twist, resulting in a callback. Be sure to check the `changes === null` and/or `thread.author.id !== this.id` to avoid re-processing.
602
+ - **Processing self-created content** - `onNoteCreated` filters out notes created by the twist itself, but still guard against reacting to other automated actors (`note.author.type === ActorType.Twist`) to avoid loops.
587
603
  - **Always create Threads with Notes** - See "Understanding Threads and Notes" section above for the thread/message pattern and decision tree.
588
- - **Use correct Thread types** - Most should be `ThreadType.Note`. Only use `Action` for tasks with `done`, and `Event` for items with `start`/`end`.
589
- - **Use Thread.source and Note.key for automatic upserts (Recommended)** - Set Thread.source to the external item's URL for automatic deduplication. Only use UUID generation and storage for advanced cases (see SYNC_STRATEGIES.md).
604
+ - **Thread `type` is optional** - It's a display sub-type (`"action"`, `"notes"`, `"idea"`, `"goal"`, `"decision"`, `"discussion"`, `"announcement"`, `"ask"`). Omit it for the default; use `"action"` for tasks.
605
+ - **Use source/key for automatic upserts (Recommended)** - Save external items as links keyed by their canonical URL/ID (connectors: `integrations.saveLink()`) for automatic deduplication. Only use UUID generation and storage for advanced cases (see SYNC_STRATEGIES.md).
590
606
  - **Add Notes to existing Threads** - For source/key pattern, reference threads by source. For UUID pattern, look up stored mappings before creating new Threads. Think thread replies, not new threads.
591
607
  - Tools are declared in the `build` method and accessed via `this.tools.toolName` in twist methods.
592
608
  - **Don't forget request limits** - Each execution has ~1000 requests (HTTP requests, tool calls). Break long loops into batches with `this.runTask()` to get fresh request limits. Calculate requests per item to determine safe batch size (e.g., if each item needs ~10 requests, batch size = ~100 items).
593
609
  - **Always use Callbacks tool for persistent references** - Direct function references don't survive worker restarts.
594
- - **Store auth tokens** - Don't re-request authentication unnecessarily.
610
+ - **Don't cache auth tokens** - Fetch tokens with `this.tools.integrations.get(channelId)` when needed; the Integrations tool manages storage and refresh.
595
611
  - **Clean up callbacks and stored state** - Delete callbacks and Store entries when no longer needed.
596
612
  - **Handle missing auth gracefully** - Check for stored auth before operations.
597
613
  - **CRITICAL: Maintain callback backward compatibility** - All callbacks (webhooks, tasks, batch operations) automatically upgrade to new twist versions. You **must** maintain backward compatibility in callback method signatures. Only add optional parameters at the end, never remove or reorder parameters. For breaking changes, implement migration logic in the `upgrade()` lifecycle method to recreate affected callbacks.
@@ -5,9 +5,6 @@ A Plot twist that [describe what your twist does].
5
5
  ## Quick Start
6
6
 
7
7
  ```bash
8
- # Install dependencies
9
- {{packageManager}} install
10
-
11
8
  # Lint your code
12
9
  {{packageManager}} lint
13
10
 
@@ -15,6 +12,8 @@ A Plot twist that [describe what your twist does].
15
12
  {{packageManager}} deploy
16
13
  ```
17
14
 
15
+ Dependencies are installed automatically when the project is created.
16
+
18
17
  ## Development
19
18
 
20
19
  ### Project Structure
@@ -25,26 +24,28 @@ A Plot twist that [describe what your twist does].
25
24
  │ └── index.ts # Main twist implementation
26
25
  ├── package.json # twist metadata and dependencies
27
26
  ├── tsconfig.json # TypeScript configuration
27
+ ├── AGENTS.md # Implementation guide for AI assistants
28
+ ├── CLAUDE.md # Claude Code entry point (includes AGENTS.md)
28
29
  └── README.md # This file
29
30
  ```
30
31
 
31
32
  ### twist Lifecycle
32
33
 
33
- Your twist implements two key lifecycle methods:
34
+ Your twist overrides lifecycle methods from the `Twist` base class:
34
35
 
35
- #### `activate(priority: Pick<Priority, "id">)`
36
+ #### `activate(context?: { actor: Actor })`
36
37
 
37
- Called when the twist is enabled for a priority. This is where you typically:
38
- - Request authentication from external services
39
- - Create initial setup activities
38
+ Called when the twist is installed by a user. Authentication and resource selection are handled automatically in the twist edit modal, so this is where you typically:
39
+ - Seed initial threads
40
40
  - Initialize twist state
41
41
 
42
- #### `activity(activity: Activity)`
42
+ #### `onThreadUpdated(thread, changes)` / `onNoteCreated(note, thread)`
43
+
44
+ Called when a thread created by this twist is updated, or a note is added to one. Use these to:
45
+ - Implement two-way sync with external systems
46
+ - React to user replies and tag changes
43
47
 
44
- Called when an activity is routed to this twist. Use this to:
45
- - Process incoming activities
46
- - Create new activities based on external events
47
- - Update existing activities
48
+ Other hooks include `upgrade()` (new version deployed) and `deactivate()` (twist uninstalled).
48
49
 
49
50
  ### Using Tools
50
51
 
@@ -61,24 +62,25 @@ build(build: ToolBuilder) {
61
62
 
62
63
  #### Built-in Tools
63
64
 
64
- - **Plot**: Create, update, and delete activities
65
+ - **Plot**: Create and update threads, notes, and focuses
65
66
  - **Store**: Persist data across twist invocations
66
- - **Integrations**: Request OAuth authentication from external services
67
+ - **Integrations**: OAuth authentication and channel management for external services
67
68
  - **Tasks**: Queue background tasks and batch operations
68
69
  - **Callbacks**: Create persistent function references for webhooks
69
70
  - **Network**: HTTP access permissions and webhook management
71
+ - **AI**: LLM text generation and structured output
70
72
 
71
73
  #### Connectors
72
74
 
73
75
  External service integrations (Google Calendar, Slack, Linear, etc.) are built as Connectors. See the [Building Connectors](https://twist.plot.day/documents/Building_Connectors.html) guide.
74
76
 
75
- ### Activity Types
77
+ ### Thread Types
76
78
 
77
- Plot supports three activity types:
79
+ A thread's `type` is an optional display sub-type: `"action"`, `"notes"`, `"idea"`, `"goal"`, `"decision"`, `"discussion"`, `"announcement"`, or `"ask"`.
78
80
 
79
- - **ActivityType.Note**: Information without actionable requirements
80
- - **ActivityType.Action**: Actionable items that can be completed
81
- - **ActivityType.Event**: Scheduled occurrences with start/end times
81
+ - Omit it for the default (`"notes"` in private focuses, `"discussion"` in shared ones)
82
+ - Use `"action"` for tasks
83
+ - Scheduled events are threads with `schedules`
82
84
 
83
85
  ### State Management
84
86
 
@@ -99,8 +101,9 @@ const token = await this.get<string>("sync_token");
99
101
  **Important**: All twist and tool functions are executed in a sandboxed, ephemeral environment with limited resources:
100
102
 
101
103
  - **Memory is temporary**: Anything stored in memory (e.g. as a variable in the twist/tool object) is lost after the function completes. Use the Store tool instead. Only use memory for temporary caching.
102
- - **Limited CPU time**: Each execution has limited CPU time (typically 10 seconds) and memory (128MB)
103
- - **Use the Tasks tool**: Queue separate chunks of work with `this.run(callback)`
104
+ - **Limited requests per execution**: Each execution has ~1000 requests (HTTP requests, tool calls, database operations)
105
+ - **Limited CPU time**: Each execution has limited CPU time (typically ~60 seconds) and memory (128MB)
106
+ - **Use the Tasks tool**: Queue separate chunks of work with `this.runTask(callback)` — each task runs in a new execution with a fresh request limit
104
107
  - **Break long operations**: Split large operations into smaller batches that can be processed independently
105
108
  - **Store intermediate state**: Use the Store tool to persist state between batches
106
109
  - **Examples**: Syncing large datasets, processing many API calls, or performing batch operations
@@ -115,12 +118,12 @@ async startSync(calendarId: string): Promise<void> {
115
118
  batchNumber: 1,
116
119
  });
117
120
 
118
- // Queue first batch using run method
119
- const callback = await this.callback("syncBatch", { calendarId });
120
- await this.run(callback);
121
+ // Queue first batch as a task (new execution, fresh request limit)
122
+ const callback = await this.callback(this.syncBatch, calendarId);
123
+ await this.runTask(callback);
121
124
  }
122
125
 
123
- async syncBatch(args: any, context: { calendarId: string }): Promise<void> {
126
+ async syncBatch(calendarId: string): Promise<void> {
124
127
  // Load state from Store
125
128
  const state = await this.get(`sync_state_${calendarId}`);
126
129
 
@@ -129,16 +132,16 @@ async syncBatch(args: any, context: { calendarId: string }): Promise<void> {
129
132
 
130
133
  if (result.hasMore) {
131
134
  // Update state and queue next batch
132
- await this.set(`sync_state_${context.calendarId}`, {
135
+ await this.set(`sync_state_${calendarId}`, {
133
136
  nextPageToken: result.nextPageToken,
134
137
  batchNumber: state.batchNumber + 1,
135
138
  });
136
139
 
137
- const nextCallback = await this.callback("syncBatch", context);
138
- await this.run(nextCallback);
140
+ const nextCallback = await this.callback(this.syncBatch, calendarId);
141
+ await this.runTask(nextCallback);
139
142
  } else {
140
143
  // Cleanup when done
141
- await this.clear(`sync_state_${context.calendarId}`);
144
+ await this.clear(`sync_state_${calendarId}`);
142
145
  }
143
146
  }
144
147
  ```
@@ -157,9 +160,9 @@ Test your twist locally before deploying:
157
160
 
158
161
  ## Resources
159
162
 
160
- - [Plot twist Builder Documentation](https://github.com/plotday/plot)
161
- - [twist Examples](https://github.com/plotday/plot/tree/main/libs/twist/examples)
162
- - [Tool Documentation](https://github.com/plotday/plot/tree/main/libs/twist/tools)
163
+ - [Plot Twist Creator Documentation](https://twist.plot.day)
164
+ - [Connector Examples](https://github.com/plotday/plot/tree/main/connectors)
165
+ - [Tool Type Definitions](https://github.com/plotday/plot/tree/main/twister/src/tools)
163
166
 
164
167
  ## Support
165
168