@plotday/twister 0.38.0 → 0.40.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 (118) hide show
  1. package/README.md +22 -16
  2. package/bin/commands/create.js +4 -4
  3. package/bin/commands/create.js.map +1 -1
  4. package/bin/index.js +1 -1
  5. package/bin/index.js.map +1 -1
  6. package/bin/templates/AGENTS.template.md +32 -0
  7. package/bin/templates/README.template.md +2 -2
  8. package/bin/utils/bundle.js +1 -1
  9. package/bin/utils/bundle.js.map +1 -1
  10. package/cli/templates/AGENTS.template.md +32 -0
  11. package/cli/templates/README.template.md +2 -2
  12. package/dist/{source.d.ts → connector.d.ts} +24 -22
  13. package/dist/connector.d.ts.map +1 -0
  14. package/dist/{source.js → connector.js} +23 -21
  15. package/dist/connector.js.map +1 -0
  16. package/dist/docs/assets/hierarchy.js +1 -1
  17. package/dist/docs/assets/navigation.js +1 -1
  18. package/dist/docs/assets/search.js +1 -1
  19. package/dist/docs/classes/{index.Source.html → index.Connector.html} +27 -27
  20. package/dist/docs/classes/index.Options.html +1 -1
  21. package/dist/docs/classes/tools_ai.AI.html +7 -3
  22. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  23. package/dist/docs/classes/tools_integrations.Integrations.html +15 -15
  24. package/dist/docs/classes/tools_network.Network.html +1 -1
  25. package/dist/docs/classes/tools_plot.Plot.html +23 -21
  26. package/dist/docs/classes/tools_store.Store.html +1 -1
  27. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  28. package/dist/docs/classes/tools_twists.Twists.html +3 -3
  29. package/dist/docs/classes/twist.Twist.html +1 -1
  30. package/dist/docs/documents/Building_Connectors.html +137 -0
  31. package/dist/docs/documents/Built-in_Tools.html +3 -3
  32. package/dist/docs/documents/Core_Concepts.html +5 -5
  33. package/dist/docs/documents/Getting_Started.html +1 -1
  34. package/dist/docs/enums/tools_ai.AIModel.html +2 -2
  35. package/dist/docs/enums/tools_integrations.AuthProvider.html +11 -11
  36. package/dist/docs/hierarchy.html +1 -1
  37. package/dist/docs/index.html +3 -3
  38. package/dist/docs/interfaces/tools_ai.AIRequest.html +11 -11
  39. package/dist/docs/interfaces/tools_ai.AIResponse.html +9 -9
  40. package/dist/docs/interfaces/tools_ai.FilePart.html +5 -5
  41. package/dist/docs/interfaces/tools_ai.ImagePart.html +4 -4
  42. package/dist/docs/interfaces/tools_ai.ReasoningPart.html +4 -4
  43. package/dist/docs/interfaces/tools_ai.RedactedReasoningPart.html +3 -3
  44. package/dist/docs/interfaces/tools_ai.TextPart.html +3 -3
  45. package/dist/docs/interfaces/tools_ai.ToolCallPart.html +5 -5
  46. package/dist/docs/interfaces/tools_ai.ToolExecutionOptions.html +4 -4
  47. package/dist/docs/interfaces/tools_ai.ToolResultPart.html +5 -5
  48. package/dist/docs/media/AGENTS.md +82 -65
  49. package/dist/docs/media/MULTI_USER_AUTH.md +1 -1
  50. package/dist/docs/media/SYNC_STRATEGIES.md +9 -9
  51. package/dist/docs/modules/index.html +1 -1
  52. package/dist/docs/modules/tools_ai.html +1 -1
  53. package/dist/docs/modules.html +1 -1
  54. package/dist/docs/types/tools_ai.AIAssistantMessage.html +2 -2
  55. package/dist/docs/types/tools_ai.AICapabilities.html +6 -0
  56. package/dist/docs/types/tools_ai.AIMessage.html +1 -1
  57. package/dist/docs/types/tools_ai.AIOptions.html +4 -0
  58. package/dist/docs/types/tools_ai.AISource.html +1 -1
  59. package/dist/docs/types/tools_ai.AISystemMessage.html +2 -2
  60. package/dist/docs/types/tools_ai.AITool.html +1 -1
  61. package/dist/docs/types/tools_ai.AIToolMessage.html +2 -2
  62. package/dist/docs/types/tools_ai.AIToolSet.html +1 -1
  63. package/dist/docs/types/tools_ai.AIUsage.html +5 -5
  64. package/dist/docs/types/tools_ai.AIUserMessage.html +2 -2
  65. package/dist/docs/types/tools_ai.DataContent.html +1 -1
  66. package/dist/docs/types/tools_ai.ModelPreferences.html +4 -4
  67. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  68. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  69. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  70. package/dist/docs/types/tools_integrations.Channel.html +5 -5
  71. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +11 -8
  72. package/dist/index.d.ts +1 -1
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +1 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/llm-docs/connector.d.ts +9 -0
  77. package/dist/llm-docs/connector.d.ts.map +1 -0
  78. package/dist/llm-docs/connector.js +8 -0
  79. package/dist/llm-docs/connector.js.map +1 -0
  80. package/dist/llm-docs/index.js +2 -2
  81. package/dist/llm-docs/index.js.map +1 -1
  82. package/dist/llm-docs/tools/ai.d.ts +1 -1
  83. package/dist/llm-docs/tools/ai.d.ts.map +1 -1
  84. package/dist/llm-docs/tools/ai.js +1 -1
  85. package/dist/llm-docs/tools/ai.js.map +1 -1
  86. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  87. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  88. package/dist/llm-docs/tools/integrations.js +1 -1
  89. package/dist/llm-docs/tools/integrations.js.map +1 -1
  90. package/dist/llm-docs/tools/plot.d.ts +1 -1
  91. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  92. package/dist/llm-docs/tools/plot.js +1 -1
  93. package/dist/llm-docs/tools/plot.js.map +1 -1
  94. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  95. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  96. package/dist/llm-docs/twist-guide-template.js +1 -1
  97. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  98. package/dist/tools/ai.d.ts +18 -0
  99. package/dist/tools/ai.d.ts.map +1 -1
  100. package/dist/tools/ai.js.map +1 -1
  101. package/dist/tools/integrations.d.ts +16 -11
  102. package/dist/tools/integrations.d.ts.map +1 -1
  103. package/dist/tools/integrations.js +3 -3
  104. package/dist/tools/integrations.js.map +1 -1
  105. package/dist/tools/plot.d.ts +4 -0
  106. package/dist/tools/plot.d.ts.map +1 -1
  107. package/dist/tools/plot.js.map +1 -1
  108. package/dist/twist-guide.d.ts +1 -1
  109. package/dist/twist-guide.d.ts.map +1 -1
  110. package/package.json +38 -38
  111. package/tsconfig.base.json +1 -1
  112. package/dist/docs/documents/Building_Sources.html +0 -137
  113. package/dist/llm-docs/source.d.ts +0 -9
  114. package/dist/llm-docs/source.d.ts.map +0 -1
  115. package/dist/llm-docs/source.js +0 -8
  116. package/dist/llm-docs/source.js.map +0 -1
  117. package/dist/source.d.ts.map +0 -1
  118. package/dist/source.js.map +0 -1
@@ -1,20 +1,20 @@
1
- # Source Development Guide
1
+ # Connector Development Guide
2
2
 
3
- This guide covers everything needed to build a Plot source correctly.
3
+ This guide covers everything needed to build a Plot connector correctly.
4
4
 
5
5
  **For twist development**: See `../twister/cli/templates/AGENTS.template.md`
6
6
  **For general navigation**: See `../AGENTS.md`
7
7
  **For type definitions**: See `../twister/src/tools/*.ts` (comprehensive JSDoc)
8
8
 
9
- ## Quick Start: Complete Source Scaffold
9
+ ## Quick Start: Complete Connector Scaffold
10
10
 
11
- Every source follows this structure:
11
+ Every connector follows this structure:
12
12
 
13
13
  ```
14
- sources/<name>/
14
+ connectors/<name>/
15
15
  src/
16
16
  index.ts # Re-exports: export { default, ClassName } from "./class-file"
17
- <class-name>.ts # Main Source class
17
+ <class-name>.ts # Main Connector class
18
18
  <api-name>.ts # (optional) Separate API client + transform functions
19
19
  package.json
20
20
  tsconfig.json
@@ -26,7 +26,7 @@ sources/<name>/
26
26
 
27
27
  ```json
28
28
  {
29
- "name": "@plotday/source-<name>",
29
+ "name": "@plotday/connector-<name>",
30
30
  "displayName": "Human Name",
31
31
  "description": "One-line purpose statement",
32
32
  "author": "Plot <team@plot.day> (https://plot.day)",
@@ -37,7 +37,7 @@ sources/<name>/
37
37
  "types": "./dist/index.d.ts",
38
38
  "exports": {
39
39
  ".": {
40
- "@plotday/source": "./src/index.ts",
40
+ "@plotday/connector": "./src/index.ts",
41
41
  "types": "./dist/index.d.ts",
42
42
  "default": "./dist/index.js"
43
43
  }
@@ -56,18 +56,18 @@ sources/<name>/
56
56
  "repository": {
57
57
  "type": "git",
58
58
  "url": "https://github.com/plotday/plot.git",
59
- "directory": "sources/<name>"
59
+ "directory": "connectors/<name>"
60
60
  },
61
61
  "homepage": "https://plot.day",
62
- "keywords": ["plot", "source", "<name>"],
62
+ "keywords": ["plot", "connector", "<name>"],
63
63
  "publishConfig": { "access": "public" }
64
64
  }
65
65
  ```
66
66
 
67
67
  **Notes:**
68
- - `"@plotday/source"` export condition resolves to TypeScript source during workspace development
68
+ - `"@plotday/connector"` export condition resolves to TypeScript source during workspace development
69
69
  - Add third-party SDKs to `dependencies` (e.g., `"@linear/sdk": "^72.0.0"`)
70
- - Add `@plotday/source-google-contacts` as `"workspace:^"` if your source syncs contacts (Google sources only)
70
+ - Add `@plotday/connector-google-contacts` as `"workspace:^"` if your connector syncs contacts (Google connectors only)
71
71
 
72
72
  ### tsconfig.json
73
73
 
@@ -85,10 +85,10 @@ sources/<name>/
85
85
  ### src/index.ts
86
86
 
87
87
  ```typescript
88
- export { default, SourceName } from "./source-name";
88
+ export { default, ConnectorName } from "./connector-name";
89
89
  ```
90
90
 
91
- ## Source Class Template
91
+ ## Connector Class Template
92
92
 
93
93
  ```typescript
94
94
  import {
@@ -98,8 +98,8 @@ import {
98
98
  type NewActivityWithNotes,
99
99
  type NewNote,
100
100
  type SyncToolOptions,
101
- Source,
102
- type SourceBuilder,
101
+ Connector,
102
+ type ConnectorBuilder,
103
103
  } from "@plotday/twister";
104
104
  import type { NewContact } from "@plotday/twister/plot";
105
105
  import { type Callback, Callbacks } from "@plotday/twister/tools/callbacks";
@@ -121,7 +121,7 @@ type SyncState = {
121
121
  initialSync: boolean;
122
122
  };
123
123
 
124
- export class MySource extends Source<MySource> {
124
+ export class MyConnector extends Connector<MyConnector> {
125
125
  // 1. Static constants
126
126
  static readonly PROVIDER = AuthProvider.Linear; // Use appropriate provider
127
127
  static readonly SCOPES = ["read", "write"];
@@ -129,12 +129,12 @@ export class MySource extends Source<MySource> {
129
129
  declare readonly Options: SyncToolOptions;
130
130
 
131
131
  // 2. Declare dependencies
132
- build(build: SourceBuilder) {
132
+ build(build: ConnectorBuilder) {
133
133
  return {
134
134
  integrations: build(Integrations, {
135
135
  providers: [{
136
- provider: MySource.PROVIDER,
137
- scopes: MySource.SCOPES,
136
+ provider: MyConnector.PROVIDER,
137
+ scopes: MyConnector.SCOPES,
138
138
  getChannels: this.getChannels,
139
139
  onChannelEnabled: this.onChannelEnabled,
140
140
  onChannelDisabled: this.onChannelDisabled,
@@ -149,7 +149,7 @@ export class MySource extends Source<MySource> {
149
149
 
150
150
  // 3. Create API client using channel-based auth
151
151
  private async getClient(channelId: string): Promise<any> {
152
- const token = await this.tools.integrations.get(MySource.PROVIDER, channelId);
152
+ const token = await this.tools.integrations.get(MyConnector.PROVIDER, channelId);
153
153
  if (!token) throw new Error("No authentication token available");
154
154
  return new SomeApiClient({ accessToken: token.token });
155
155
  }
@@ -371,16 +371,16 @@ export class MySource extends Source<MySource> {
371
371
  }
372
372
  }
373
373
 
374
- export default MySource;
374
+ export default MyConnector;
375
375
  ```
376
376
 
377
377
  ## The Integrations Pattern (Auth + Channels)
378
378
 
379
- **This is how ALL authentication works.** Auth is handled in the Flutter edit modal, not in code. Sources declare their provider config in `build()`.
379
+ **This is how ALL authentication works.** Auth is handled in the Flutter edit modal, not in code. Connectors declare their provider config in `build()`.
380
380
 
381
381
  ### How It Works
382
382
 
383
- 1. Source declares providers in `build()` with `getChannels`, `onChannelEnabled`, `onChannelDisabled` callbacks
383
+ 1. Connector declares providers in `build()` with `getChannels`, `onChannelEnabled`, `onChannelDisabled` callbacks
384
384
  2. User clicks "Connect" in the twist edit modal → OAuth flow happens automatically
385
385
  3. After auth, the runtime calls your `getChannels()` to list available resources
386
386
  4. User enables resources in the modal → `onChannelEnabled()` fires
@@ -397,7 +397,7 @@ For bidirectional sync where actions should be attributed to the acting user:
397
397
 
398
398
  ```typescript
399
399
  await this.tools.integrations.actAs(
400
- MySource.PROVIDER,
400
+ MyConnector.PROVIDER,
401
401
  actorId, // The user who performed the action
402
402
  activityId, // Activity to create auth prompt in (if user hasn't connected)
403
403
  this.performWriteBack,
@@ -411,20 +411,20 @@ async performWriteBack(token: AuthToken, ...extraArgs: any[]): Promise<void> {
411
411
  }
412
412
  ```
413
413
 
414
- ### Cross-Source Auth Sharing (Google Sources)
414
+ ### Cross-Connector Auth Sharing (Google Connectors)
415
415
 
416
- When building a Google source that should also sync contacts, merge scopes:
416
+ When building a Google connector that should also sync contacts, merge scopes:
417
417
 
418
418
  ```typescript
419
- import GoogleContacts from "@plotday/source-google-contacts";
419
+ import GoogleContacts from "@plotday/connector-google-contacts";
420
420
 
421
- build(build: SourceBuilder) {
421
+ build(build: ConnectorBuilder) {
422
422
  return {
423
423
  integrations: build(Integrations, {
424
424
  providers: [{
425
425
  provider: AuthProvider.Google,
426
426
  scopes: Integrations.MergeScopes(
427
- MyGoogleSource.SCOPES,
427
+ MyGoogleConnector.SCOPES,
428
428
  GoogleContacts.SCOPES
429
429
  ),
430
430
  getChannels: this.getChannels,
@@ -438,18 +438,18 @@ build(build: SourceBuilder) {
438
438
  }
439
439
  ```
440
440
 
441
- ## Architecture: Sources Save Directly
441
+ ## Architecture: Connectors Save Directly
442
442
 
443
- **Sources save data directly** via `integrations.saveLink()`. Sources build `NewLinkWithNotes` objects and save them, rather than passing them through a parent twist.
443
+ **Connectors save data directly** via `integrations.saveLink()`. Connectors build `NewLinkWithNotes` objects and save them, rather than passing them through a parent twist.
444
444
 
445
445
  This means:
446
- - Sources request `Plot` with `ContactAccess.Write` (for contacts on threads)
447
- - Sources declare providers via `Integrations` with lifecycle callbacks
448
- - Sources call save methods directly to persist synced data
446
+ - Connectors request `Plot` with `ContactAccess.Write` (for contacts on threads)
447
+ - Connectors declare providers via `Integrations` with lifecycle callbacks
448
+ - Connectors call save methods directly to persist synced data
449
449
 
450
450
  ## Critical: Callback Serialization Pattern
451
451
 
452
- **The #1 mistake when building sources is passing function references as callback arguments.** Functions cannot be serialized across worker boundaries.
452
+ **The #1 mistake when building connectors is passing function references as callback arguments.** Functions cannot be serialized across worker boundaries.
453
453
 
454
454
  ### ❌ WRONG - Passing Function as Callback Argument
455
455
 
@@ -500,7 +500,7 @@ async syncBatch(resourceId: string): Promise<void> {
500
500
 
501
501
  ## Callback Backward Compatibility
502
502
 
503
- **All callbacks automatically upgrade to new source versions on deployment.** You MUST maintain backward compatibility.
503
+ **All callbacks automatically upgrade to new connector versions on deployment.** You MUST maintain backward compatibility.
504
504
 
505
505
  - ❌ Don't change function signatures (remove/reorder params, change types)
506
506
  - ✅ Do add optional parameters at the end
@@ -533,7 +533,7 @@ async preUpgrade(): Promise<void> {
533
533
 
534
534
  ## Storage Key Conventions
535
535
 
536
- All sources use consistent key prefixes:
536
+ All connectors use consistent key prefixes:
537
537
 
538
538
  | Key Pattern | Purpose |
539
539
  |------------|---------|
@@ -545,7 +545,7 @@ All sources use consistent key prefixes:
545
545
  | `webhook_secret_<id>` | Webhook signing secret |
546
546
  | `watch_renewal_task_<id>` | Scheduled task token for webhook renewal |
547
547
 
548
- ## Source URL Conventions
548
+ ## Activity Source URL Conventions
549
549
 
550
550
  The `activity.source` field is the idempotency key for automatic upserts. Use a canonical format:
551
551
 
@@ -554,7 +554,7 @@ The `activity.source` field is the idempotency key for automatic upserts. Use a
554
554
  <provider>:<namespace>:<id> — When provider has multiple entity types
555
555
  ```
556
556
 
557
- Examples from existing sources:
557
+ Examples from existing connectors:
558
558
  ```
559
559
  linear:issue:<issueId>
560
560
  asana:task:<taskGid>
@@ -659,7 +659,7 @@ async onChannelDisabled(filter: ActivityFilter): Promise<void> {
659
659
 
660
660
  ## Initial vs. Incremental Sync (REQUIRED)
661
661
 
662
- **Every source MUST track whether it is performing an initial sync (first import) or an incremental sync (ongoing updates).** Omitting this causes notification spam from bulk historical imports.
662
+ **Every connector MUST track whether it is performing an initial sync (first import) or an incremental sync (ongoing updates).** Omitting this causes notification spam from bulk historical imports.
663
663
 
664
664
  | Field | Initial Sync | Incremental Sync | Reason |
665
665
  |-------|-------------|------------------|--------|
@@ -682,7 +682,7 @@ The `initialSync` flag must flow from the entry point (`onChannelEnabled` / `sta
682
682
 
683
683
  The scaffold's `SyncState` type includes `initialSync: boolean`. Set it to `true` in `startBatchSync`, read it in `syncBatch`, and preserve it across batches. Webhook/incremental handlers pass `false`.
684
684
 
685
- **Pattern B: Pass as callback argument** (used by sources like Gmail that don't store `initialSync` in state)
685
+ **Pattern B: Pass as callback argument** (used by connectors like Gmail that don't store `initialSync` in state)
686
686
 
687
687
  Pass `initialSync` as an explicit argument through `this.callback()`:
688
688
 
@@ -715,7 +715,7 @@ async syncBatch(
715
715
 
716
716
  ### Localhost Guard (REQUIRED)
717
717
 
718
- All sources MUST skip webhook registration in local development:
718
+ All connectors MUST skip webhook registration in local development:
719
719
 
720
720
  ```typescript
721
721
  const webhookUrl = await this.tools.network.createWebhook({}, this.onWebhook, resourceId);
@@ -754,7 +754,7 @@ private async scheduleWatchRenewal(resourceId: string): Promise<void> {
754
754
 
755
755
  ## Bidirectional Sync
756
756
 
757
- For sources that support write-backs (updating external items from Plot):
757
+ For connectors that support write-backs (updating external items from Plot):
758
758
 
759
759
  ### Issue/Task Updates (`updateIssue`)
760
760
 
@@ -789,16 +789,33 @@ async addIssueComment(meta: ActivityMeta, body: string, noteId?: string): Promis
789
789
  The parent twist prevents infinite loops by checking note authorship:
790
790
 
791
791
  ```typescript
792
- // In the twist (not the source):
792
+ // In the twist (not the connector):
793
793
  async onNoteCreated(note: Note): Promise<void> {
794
794
  if (note.author.type === ActorType.Twist) return; // Prevent loops
795
795
  // ... sync note to external service
796
796
  }
797
797
  ```
798
798
 
799
+ ### Default Mention on Replies
800
+
801
+ Connectors with bidirectional sync should set `thread.defaultMention: true` in their Plot tool options so replies to synced threads automatically mention the connector:
802
+
803
+ ```typescript
804
+ plot: build(Plot, {
805
+ thread: {
806
+ access: ThreadAccess.Create,
807
+ defaultMention: true, // Replies to synced threads mention this connector by default
808
+ updated: this.onThreadUpdated,
809
+ },
810
+ note: { created: this.onNoteCreated },
811
+ }),
812
+ ```
813
+
814
+ Without this, users must manually toggle the connector's mention chip on each reply. Connectors that don't process replies (e.g., read-only calendar sync) should NOT set this flag.
815
+
799
816
  ## Contacts Pattern
800
817
 
801
- Sources that sync user data should create contacts for authors and assignees:
818
+ Connectors that sync user data should create contacts for authors and assignees:
802
819
 
803
820
  ```typescript
804
821
  import type { NewContact } from "@plotday/twister/plot";
@@ -841,21 +858,21 @@ declare const Buffer: {
841
858
  ## Building and Testing
842
859
 
843
860
  ```bash
844
- # Build the source
845
- cd public/sources/<name> && pnpm build
861
+ # Build the connector
862
+ cd public/connectors/<name> && pnpm build
846
863
 
847
864
  # Type-check without building
848
- cd public/sources/<name> && pnpm exec tsc --noEmit
865
+ cd public/connectors/<name> && pnpm exec tsc --noEmit
849
866
 
850
867
  # Install dependencies (from repo root)
851
868
  pnpm install
852
869
  ```
853
870
 
854
- After creating a new source, add it to `pnpm-workspace.yaml` if not already covered by the glob pattern.
871
+ After creating a new connector, add it to `pnpm-workspace.yaml` if not already covered by the glob pattern.
855
872
 
856
- ## Source Development Checklist
873
+ ## Connector Development Checklist
857
874
 
858
- - [ ] Extend `Source<YourSource>`
875
+ - [ ] Extend `Connector<YourConnector>`
859
876
  - [ ] Declare `static readonly PROVIDER`, `static readonly SCOPES`
860
877
  - [ ] Declare `static readonly Options: SyncToolOptions` and `declare readonly Options: SyncToolOptions`
861
878
  - [ ] Declare all dependencies in `build()`: Integrations, Network, Callbacks, Tasks, Plot
@@ -875,7 +892,7 @@ After creating a new source, add it to `pnpm-workspace.yaml` if not already cove
875
892
  - [ ] Create contacts for authors/assignees with `NewContact`
876
893
  - [ ] Clean up all stored state and callbacks in `stopSync()` and `onChannelDisabled()`
877
894
  - [ ] Add `package.json` with correct structure, `tsconfig.json`, and `src/index.ts` re-export
878
- - [ ] Verify the source builds: `pnpm build`
895
+ - [ ] Verify the connector builds: `pnpm build`
879
896
 
880
897
  ## Common Pitfalls
881
898
 
@@ -887,7 +904,7 @@ After creating a new source, add it to `pnpm-workspace.yaml` if not already cove
887
904
  6. **❌ Using mutable IDs in `source`** — Use immutable IDs (Jira issue ID, not issue key)
888
905
  7. **❌ Not breaking loops into batches** — Each execution has ~1000 request limit
889
906
  8. **❌ Missing localhost guard** — Webhook registration fails silently on localhost
890
- 9. **❌ Calling `plot.createThread()` from a source** — Sources save data directly via `integrations.saveLink()`
907
+ 9. **❌ Calling `plot.createThread()` from a connector** — Connectors save data directly via `integrations.saveLink()`
891
908
  10. **❌ Breaking callback signatures** — Old callbacks auto-upgrade; add optional params at end only
892
909
  11. **❌ Passing `undefined` in serializable values** — Use `null` instead
893
910
  12. **❌ Forgetting to clean up on disable** — Delete callbacks, webhooks, and stored state
@@ -897,14 +914,14 @@ After creating a new source, add it to `pnpm-workspace.yaml` if not already cove
897
914
 
898
915
  ## Study These Examples
899
916
 
900
- | Source | Category | Key Patterns |
901
- |--------|----------|-------------|
902
- | `linear/` | ProjectSource | Clean reference implementation, webhook handling, bidirectional sync |
903
- | `google-calendar/` | CalendarSource | Recurring events, RSVP write-back, watch renewal, cross-source auth sharing |
904
- | `slack/` | MessagingSource | Team-sharded webhooks, thread model, Slack-specific auth |
905
- | `gmail/` | MessagingSource | PubSub webhooks, email thread transformation, HTML contentType, callback-arg initialSync pattern |
906
- | `google-drive/` | DocumentSource | Document comments, reply threading, file watching |
907
- | `jira/` | ProjectSource | Immutable vs mutable IDs, comment metadata for dedup |
908
- | `asana/` | ProjectSource | HMAC webhook verification, section-based projects |
909
- | `outlook-calendar/` | CalendarSource | Microsoft Graph API, subscription management |
910
- | `google-contacts/` | (Supporting) | Contact sync, cross-source `syncWithAuth()` pattern |
917
+ | Connector | Category | Key Patterns |
918
+ |-----------|----------|-------------|
919
+ | `linear/` | ProjectConnector | Clean reference implementation, webhook handling, bidirectional sync |
920
+ | `google-calendar/` | CalendarConnector | Recurring events, RSVP write-back, watch renewal, cross-connector auth sharing |
921
+ | `slack/` | MessagingConnector | Team-sharded webhooks, thread model, Slack-specific auth |
922
+ | `gmail/` | MessagingConnector | PubSub webhooks, email thread transformation, HTML contentType, callback-arg initialSync pattern |
923
+ | `google-drive/` | DocumentConnector | Document comments, reply threading, file watching |
924
+ | `jira/` | ProjectConnector | Immutable vs mutable IDs, comment metadata for dedup |
925
+ | `asana/` | ProjectConnector | HMAC webhook verification, section-based projects |
926
+ | `outlook-calendar/` | CalendarConnector | Microsoft Graph API, subscription management |
927
+ | `google-contacts/` | (Supporting) | Contact sync, cross-connector `syncWithAuth()` pattern |
@@ -1,6 +1,6 @@
1
1
  # Multi-User Priority Auth
2
2
 
3
- Twists and sources operating in shared priorities must handle authentication for multiple users. This guide covers the patterns for per-user auth and private auth activities.
3
+ Twists and connectors operating in shared priorities must handle authentication for multiple users. This guide covers the patterns for per-user auth and private auth activities.
4
4
 
5
5
  ## Auth Models
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Sync Strategies
2
2
 
3
- This guide explains good ways to build sources that sync other services with Plot. Choosing the right strategy depends on whether you need to update items, deduplicate them, or simply create them once.
3
+ This guide explains good ways to build connectors that sync other services with Plot. Choosing the right strategy depends on whether you need to update items, deduplicate them, or simply create them once.
4
4
 
5
5
  ## Table of Contents
6
6
 
@@ -115,7 +115,7 @@ interface Activity {
115
115
  ### Example: Calendar Event Sync
116
116
 
117
117
  ```typescript
118
- export default class GoogleCalendarSource extends Source<GoogleCalendarSource> {
118
+ export default class GoogleCalendarConnector extends Connector<GoogleCalendarConnector> {
119
119
  async syncEvent(event: calendar_v3.Schema$Event): Promise<void> {
120
120
  const activity: NewActivityWithNotes = {
121
121
  // Use the event's canonical URL as the source
@@ -168,7 +168,7 @@ export default class GoogleCalendarSource extends Source<GoogleCalendarSource> {
168
168
  ### Example: Task/Issue Sync
169
169
 
170
170
  ```typescript
171
- export default class LinearSource extends Source<LinearSource> {
171
+ export default class LinearConnector extends Connector<LinearConnector> {
172
172
  async syncIssue(issue: LinearIssue): Promise<void> {
173
173
  const activity: NewActivityWithNotes = {
174
174
  source: issue.url, // Linear provides stable URLs
@@ -274,7 +274,7 @@ Use this strategy when:
274
274
  ### Example: Multiple Activities from Single Source
275
275
 
276
276
  ```typescript
277
- export default class GmailSource extends Source<GmailSource> {
277
+ export default class GmailConnector extends Connector<GmailConnector> {
278
278
  /**
279
279
  * Creates separate activities for email threads and individual messages.
280
280
  * One email thread can have multiple Plot activities.
@@ -505,7 +505,7 @@ When syncing activities from external systems, it's critical to distinguish betw
505
505
 
506
506
  ### The `initialSync` Flag Pattern
507
507
 
508
- All sync-based tools should track whether they're performing an initial sync or incremental sync:
508
+ All sync-based connectors should track whether they're performing an initial sync or incremental sync:
509
509
 
510
510
  | Field | Initial Sync | Incremental Sync | Reason |
511
511
  |-------|--------------|------------------|---------|
@@ -588,7 +588,7 @@ async syncBatch(
588
588
  **Initial sync (first import):**
589
589
  - Activities are **unarchived** (`archived: false`) - gives user a fresh start
590
590
  - Activities are marked as **read** (`unread: false`) - prevents notification spam from bulk historical imports
591
- - Use case: When user first installs the tool or reconnects after disconnection
591
+ - Use case: When user first installs the connector or reconnects after disconnection
592
592
 
593
593
  **Incremental sync (ongoing updates):**
594
594
  - New activities appear as **unread** (`unread: true`) - user gets notified of new items
@@ -694,9 +694,9 @@ if (existingId) {
694
694
 
695
695
  ## Best Practices
696
696
 
697
- ### 1. Be Consistent Within a Source
697
+ ### 1. Be Consistent Within a Connector
698
698
 
699
- Choose one strategy per source and stick with it. Mixing strategies in the same source can lead to confusion and bugs.
699
+ Choose one strategy per connector and stick with it. Mixing strategies in the same connector can lead to confusion and bugs.
700
700
 
701
701
  ### 2. Use Descriptive Keys
702
702
 
@@ -805,4 +805,4 @@ For more information:
805
805
 
806
806
  - [Core Concepts](CORE_CONCEPTS.md) - Understanding activities, notes, and priorities
807
807
  - [Tools Guide](TOOLS_GUIDE.md) - Complete reference for the Plot tool
808
- - [Building Sources](BUILDING_SOURCES.md) - Creating external service integrations
808
+ - [Building Connectors](BUILDING_CONNECTORS.md) - Creating external service integrations