fullstackgtm 0.10.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 (77) hide show
  1. package/CHANGELOG.md +381 -0
  2. package/INSTALL_FOR_AGENTS.md +87 -0
  3. package/LICENSE +202 -0
  4. package/README.md +230 -0
  5. package/dist/audit.d.ts +7 -0
  6. package/dist/audit.js +202 -0
  7. package/dist/bin.d.ts +2 -0
  8. package/dist/bin.js +6 -0
  9. package/dist/cli.d.ts +38 -0
  10. package/dist/cli.js +915 -0
  11. package/dist/config.d.ts +36 -0
  12. package/dist/config.js +85 -0
  13. package/dist/connector.d.ts +30 -0
  14. package/dist/connector.js +94 -0
  15. package/dist/connectors/hubspot.d.ts +20 -0
  16. package/dist/connectors/hubspot.js +409 -0
  17. package/dist/connectors/hubspotAuth.d.ts +42 -0
  18. package/dist/connectors/hubspotAuth.js +189 -0
  19. package/dist/connectors/salesforce.d.ts +26 -0
  20. package/dist/connectors/salesforce.js +318 -0
  21. package/dist/connectors/salesforceAuth.d.ts +44 -0
  22. package/dist/connectors/salesforceAuth.js +120 -0
  23. package/dist/connectors/stripe.d.ts +27 -0
  24. package/dist/connectors/stripe.js +176 -0
  25. package/dist/credentials.d.ts +75 -0
  26. package/dist/credentials.js +197 -0
  27. package/dist/demo.d.ts +20 -0
  28. package/dist/demo.js +169 -0
  29. package/dist/diff.d.ts +46 -0
  30. package/dist/diff.js +107 -0
  31. package/dist/format.d.ts +3 -0
  32. package/dist/format.js +109 -0
  33. package/dist/index.d.ts +18 -0
  34. package/dist/index.js +17 -0
  35. package/dist/mappings.d.ts +8 -0
  36. package/dist/mappings.js +123 -0
  37. package/dist/mcp-bin.d.ts +2 -0
  38. package/dist/mcp-bin.js +33 -0
  39. package/dist/mcp.d.ts +1 -0
  40. package/dist/mcp.js +140 -0
  41. package/dist/merge.d.ts +48 -0
  42. package/dist/merge.js +145 -0
  43. package/dist/planStore.d.ts +31 -0
  44. package/dist/planStore.js +116 -0
  45. package/dist/rules.d.ts +24 -0
  46. package/dist/rules.js +512 -0
  47. package/dist/sampleData.d.ts +2 -0
  48. package/dist/sampleData.js +115 -0
  49. package/dist/types.d.ts +294 -0
  50. package/dist/types.js +8 -0
  51. package/docs/api.md +72 -0
  52. package/docs/roadmap-to-1.0.md +121 -0
  53. package/llms.txt +25 -0
  54. package/package.json +76 -0
  55. package/src/audit.ts +242 -0
  56. package/src/bin.ts +7 -0
  57. package/src/cli.ts +1042 -0
  58. package/src/config.ts +113 -0
  59. package/src/connector.ts +140 -0
  60. package/src/connectors/hubspot.ts +528 -0
  61. package/src/connectors/hubspotAuth.ts +246 -0
  62. package/src/connectors/salesforce.ts +420 -0
  63. package/src/connectors/salesforceAuth.ts +167 -0
  64. package/src/connectors/stripe.ts +215 -0
  65. package/src/credentials.ts +282 -0
  66. package/src/demo.ts +200 -0
  67. package/src/diff.ts +158 -0
  68. package/src/format.ts +162 -0
  69. package/src/index.ts +129 -0
  70. package/src/mappings.ts +157 -0
  71. package/src/mcp-bin.ts +32 -0
  72. package/src/mcp.ts +185 -0
  73. package/src/merge.ts +235 -0
  74. package/src/planStore.ts +155 -0
  75. package/src/rules.ts +539 -0
  76. package/src/sampleData.ts +117 -0
  77. package/src/types.ts +372 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Canonical GTM data model.
3
+ *
4
+ * Amounts are expressed in major currency units (e.g. dollars), matching what
5
+ * CRM providers return natively. Adapters that store minor units (cents) must
6
+ * convert at their own boundary.
7
+ */
8
+ export type CrmProvider = "salesforce" | "hubspot" | "mock" | "unknown" | (string & {});
9
+ export type RiskLevel = "low" | "medium" | "high";
10
+ export type ApprovalStatus = "draft" | "needs_approval" | "approved" | "rejected" | "applied";
11
+ export type GtmObjectType = "account" | "contact" | "deal" | "user" | "activity";
12
+ export type GtmEvidenceSourceSystem = "salesforce" | "hubspot" | "gong" | "chorus" | "fathom" | "manual" | "csv" | "mock" | "unknown";
13
+ export type PatchOperationType = "set_field" | "clear_field" | "link_record" | "archive_record" | "create_task";
14
+ export type AuditFindingSeverity = "info" | "warning" | "critical";
15
+ /**
16
+ * One claim that a canonical record exists in an external system. A record
17
+ * merged from several providers carries one identity per provider.
18
+ */
19
+ export type ProviderIdentity = {
20
+ provider: CrmProvider;
21
+ externalId: string;
22
+ };
23
+ export type PipelineFindingType = "call_next_step_not_reflected_in_crm" | "deal_missing_next_step" | "deal_stale_activity" | "deal_past_close_date" | "deal_missing_owner" | "deal_missing_account";
24
+ export type PipelineFindingStatus = "open" | "planned" | "approved" | "applied" | "verified" | "dismissed" | "stale";
25
+ export type SourceFreshness = {
26
+ state: "fresh" | "stale" | "unknown";
27
+ checkedAt: string;
28
+ sourceUpdatedAt?: string;
29
+ ageDays?: number;
30
+ };
31
+ export type GtmEvidence = {
32
+ id: string;
33
+ sourceSystem: GtmEvidenceSourceSystem;
34
+ sourceObjectType: string;
35
+ sourceObjectId: string;
36
+ objectType?: GtmObjectType;
37
+ objectId?: string;
38
+ title?: string;
39
+ text: string;
40
+ observedAt?: string;
41
+ capturedAt?: string;
42
+ freshness?: SourceFreshness;
43
+ metadata?: Record<string, unknown>;
44
+ };
45
+ export type PipelineFinding = {
46
+ id: string;
47
+ type: PipelineFindingType;
48
+ objectType: GtmObjectType;
49
+ objectId: string;
50
+ severity: AuditFindingSeverity;
51
+ status: PipelineFindingStatus;
52
+ title: string;
53
+ summary: string;
54
+ recommendation: string;
55
+ evidenceIds: string[];
56
+ currentCrmValue?: unknown;
57
+ proposedValue?: unknown;
58
+ freshness: SourceFreshness;
59
+ patchEligibility: {
60
+ eligible: boolean;
61
+ operation?: PatchOperationType | "none";
62
+ field?: string;
63
+ reason: string;
64
+ approvalRequired: boolean;
65
+ };
66
+ };
67
+ export type PatchVerification = {
68
+ status: "not_started" | "pending" | "verified" | "failed" | "skipped";
69
+ checkedAt?: string;
70
+ sourceSystem?: GtmEvidenceSourceSystem;
71
+ expectedValue?: unknown;
72
+ observedValue?: unknown;
73
+ providerResult?: unknown;
74
+ auditText?: string;
75
+ };
76
+ export type CanonicalUser = {
77
+ id: string;
78
+ provider?: CrmProvider;
79
+ crmId?: string;
80
+ identities?: ProviderIdentity[];
81
+ name: string;
82
+ email?: string;
83
+ title?: string;
84
+ active?: boolean;
85
+ };
86
+ export type CanonicalAccount = {
87
+ id: string;
88
+ provider?: CrmProvider;
89
+ crmId?: string;
90
+ identities?: ProviderIdentity[];
91
+ name: string;
92
+ domain?: string;
93
+ industry?: string;
94
+ ownerId?: string;
95
+ employeeCount?: number;
96
+ annualRevenue?: number;
97
+ lastActivityAt?: string;
98
+ lastSyncAt?: string;
99
+ /** Provider-native payload escape hatch. Never read by audit rules. */
100
+ raw?: unknown;
101
+ };
102
+ export type CanonicalContact = {
103
+ id: string;
104
+ provider?: CrmProvider;
105
+ crmId?: string;
106
+ identities?: ProviderIdentity[];
107
+ accountId?: string;
108
+ firstName?: string;
109
+ lastName?: string;
110
+ email?: string;
111
+ phone?: string;
112
+ title?: string;
113
+ ownerId?: string;
114
+ lastActivityAt?: string;
115
+ lastSyncAt?: string;
116
+ /** Provider-native payload escape hatch. Never read by audit rules. */
117
+ raw?: unknown;
118
+ };
119
+ export type CanonicalDeal = {
120
+ id: string;
121
+ provider?: CrmProvider;
122
+ crmId?: string;
123
+ identities?: ProviderIdentity[];
124
+ accountId?: string;
125
+ ownerId?: string;
126
+ name: string;
127
+ amount?: number;
128
+ currency?: string;
129
+ stage?: string;
130
+ closeDate?: string;
131
+ /** Provider-native deal type string (e.g. HubSpot `dealtype`), unmapped. */
132
+ dealType?: string;
133
+ forecastCategory?: string;
134
+ nextStep?: string;
135
+ probability?: number;
136
+ isClosed?: boolean;
137
+ isWon?: boolean;
138
+ lastActivityAt?: string;
139
+ lastSyncAt?: string;
140
+ /** Provider-native payload escape hatch. Never read by audit rules. */
141
+ raw?: unknown;
142
+ };
143
+ export type CanonicalActivity = {
144
+ id: string;
145
+ provider?: CrmProvider;
146
+ crmId?: string;
147
+ identities?: ProviderIdentity[];
148
+ accountId?: string;
149
+ contactId?: string;
150
+ dealId?: string;
151
+ ownerId?: string;
152
+ type: "call" | "email" | "meeting" | "note" | "task" | "other";
153
+ occurredAt: string;
154
+ subject?: string;
155
+ };
156
+ export type CanonicalGtmSnapshot = {
157
+ generatedAt: string;
158
+ provider: CrmProvider;
159
+ users: CanonicalUser[];
160
+ accounts: CanonicalAccount[];
161
+ contacts: CanonicalContact[];
162
+ deals: CanonicalDeal[];
163
+ activities: CanonicalActivity[];
164
+ };
165
+ export type GtmPolicy = {
166
+ staleDealDays: number;
167
+ requireDealOwner: boolean;
168
+ requireAccountForDeal: boolean;
169
+ today: string;
170
+ /** Flag open deals without an amount (default true). */
171
+ requireDealAmount?: boolean;
172
+ /** Window ahead of today that counts as "closing soon" (default 14 days). */
173
+ closingSoonDays?: number;
174
+ /** Idle days that make a closing-soon deal a finding (default 7). */
175
+ closingSoonIdleDays?: number;
176
+ };
177
+ export type AuditFinding = {
178
+ id: string;
179
+ objectType: GtmObjectType;
180
+ objectId: string;
181
+ ruleId: string;
182
+ title: string;
183
+ severity: AuditFindingSeverity;
184
+ summary: string;
185
+ recommendation: string;
186
+ type?: PipelineFindingType;
187
+ evidenceIds?: string[];
188
+ currentCrmValue?: unknown;
189
+ proposedValue?: unknown;
190
+ freshness?: SourceFreshness;
191
+ patchEligible?: boolean;
192
+ };
193
+ export type PatchOperation = {
194
+ id: string;
195
+ objectType: GtmObjectType;
196
+ objectId: string;
197
+ operation: PatchOperationType;
198
+ field?: string;
199
+ beforeValue?: unknown;
200
+ afterValue?: unknown;
201
+ reason: string;
202
+ riskLevel: RiskLevel;
203
+ approvalRequired: boolean;
204
+ sourceRuleOrPolicy?: string;
205
+ rollback?: string;
206
+ evidenceIds?: string[];
207
+ findingIds?: string[];
208
+ verification?: PatchVerification;
209
+ };
210
+ /**
211
+ * A patch plan is always a dry-run proposal. Applying a plan never mutates
212
+ * the plan itself; the outcome is recorded separately as a `PatchPlanRun`.
213
+ */
214
+ export type PatchPlan = {
215
+ id: string;
216
+ title: string;
217
+ createdAt: string;
218
+ status: ApprovalStatus;
219
+ dryRun: true;
220
+ summary: string;
221
+ findings: AuditFinding[];
222
+ pipelineFindings?: PipelineFinding[];
223
+ evidence?: GtmEvidence[];
224
+ operations: PatchOperation[];
225
+ };
226
+ /** Pre-computed lookups shared by all rules so each rule stays O(n). */
227
+ export type GtmSnapshotIndex = {
228
+ usersById: Map<string, CanonicalUser>;
229
+ accountsById: Map<string, CanonicalAccount>;
230
+ contactsByAccountId: Map<string, CanonicalContact[]>;
231
+ dealsByAccountId: Map<string, CanonicalDeal[]>;
232
+ activitiesByDealId: Map<string, CanonicalActivity[]>;
233
+ };
234
+ export type GtmRuleContext = {
235
+ snapshot: CanonicalGtmSnapshot;
236
+ policy: GtmPolicy;
237
+ index: GtmSnapshotIndex;
238
+ };
239
+ export type GtmRuleResult = {
240
+ findings: AuditFinding[];
241
+ operations: PatchOperation[];
242
+ };
243
+ /**
244
+ * A deterministic audit rule. Rules read the snapshot through the context and
245
+ * return findings plus dry-run patch operations; they never perform writes.
246
+ */
247
+ export type GtmAuditRule = {
248
+ id: string;
249
+ title: string;
250
+ description: string;
251
+ /** Grouping for docs and discovery, e.g. "hygiene", "forecast", "coverage". */
252
+ category?: string;
253
+ evaluate: (context: GtmRuleContext) => GtmRuleResult;
254
+ };
255
+ export type PatchOperationResult = {
256
+ operationId: string;
257
+ /** `conflict`: the provider value drifted since the plan was proposed; nothing was written. */
258
+ status: "applied" | "failed" | "skipped" | "conflict";
259
+ detail?: string;
260
+ providerData?: unknown;
261
+ };
262
+ export type PatchPlanRunStatus = "applied" | "partial" | "failed" | "rejected";
263
+ /** The record of one attempt to apply an approved patch plan. */
264
+ export type PatchPlanRun = {
265
+ planId: string;
266
+ provider: CrmProvider;
267
+ startedAt: string;
268
+ finishedAt: string;
269
+ status: PatchPlanRunStatus;
270
+ results: PatchOperationResult[];
271
+ };
272
+ /**
273
+ * The provider contract. Reads produce a canonical snapshot; writes accept a
274
+ * single patch operation and report the outcome. Connectors without
275
+ * `applyOperation` are read-only.
276
+ */
277
+ export type GtmConnector = {
278
+ provider: CrmProvider;
279
+ fetchSnapshot: () => Promise<CanonicalGtmSnapshot>;
280
+ applyOperation?: (operation: PatchOperation) => Promise<PatchOperationResult>;
281
+ /**
282
+ * Read the live value of one canonical field, used for compare-and-set:
283
+ * apply orchestration refuses to write over values that drifted since the
284
+ * plan was proposed.
285
+ */
286
+ readField?: (objectType: GtmObjectType, objectId: string, field: string) => Promise<unknown>;
287
+ /**
288
+ * Records modified since the given ISO timestamp, as a partial snapshot —
289
+ * the incremental alternative to `fetchSnapshot` for frequent syncs.
290
+ * Provider change feeds may omit cross-record associations; consumers
291
+ * merging deltas must preserve associations from the last full snapshot.
292
+ */
293
+ fetchChanges?: (sinceIso: string) => Promise<CanonicalGtmSnapshot>;
294
+ };
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Canonical GTM data model.
3
+ *
4
+ * Amounts are expressed in major currency units (e.g. dollars), matching what
5
+ * CRM providers return natively. Adapters that store minor units (cents) must
6
+ * convert at their own boundary.
7
+ */
8
+ export {};
package/docs/api.md ADDED
@@ -0,0 +1,72 @@
1
+ # fullstackgtm — API surface (1.0 contract candidate)
2
+
3
+ Everything listed here is the intended 1.0 contract. While the package is in
4
+ beta (0.x), these surfaces are settling and breaking changes may still land
5
+ in minor releases — each one is called out in the CHANGELOG. At 1.0 they
6
+ freeze: breaking changes will require a major version. Anything *not* listed
7
+ (internal helpers, file layouts, exact message strings) may change in any
8
+ release.
9
+
10
+ ## Canonical data model (`types.ts`)
11
+
12
+ - `CanonicalGtmSnapshot` — `{ generatedAt, provider, users, accounts, contacts, deals, activities }`
13
+ - `CanonicalUser`, `CanonicalAccount`, `CanonicalContact`, `CanonicalDeal`, `CanonicalActivity`
14
+ - Amounts are **major currency units**; adapters storing minor units convert at their boundary.
15
+ - `identities: ProviderIdentity[]` — `(provider, externalId)` claims; one per source system.
16
+ - `raw` — provider payload escape hatch; never read by audit rules.
17
+ - `GtmPolicy` — thresholds with optional extensions (`requireDealAmount`, `closingSoonDays`, `closingSoonIdleDays`).
18
+
19
+ ## Audit engine
20
+
21
+ - `GtmAuditRule` — `{ id, title, description, category?, evaluate(context) }`; the public extension point.
22
+ - `GtmRuleContext` — `{ snapshot, policy, index }` with the prebuilt O(n) `GtmSnapshotIndex`.
23
+ - `auditSnapshot(snapshot, policy?, rules?)` → `PatchPlan`.
24
+ - `builtinAuditRules` (11 rules) plus each rule exported individually.
25
+ - **Determinism guarantee**: identical inputs produce identical findings and operations with identical ids (`auditFindingId`, `patchOperationId` are stable hashes of rule + record).
26
+
27
+ ## Patch plans and application
28
+
29
+ - `PatchPlan` — immutable dry-run proposal (`dryRun: true` always).
30
+ - `PatchOperation` — typed write: objectType, objectId, operation kind, field, before/after, reason, riskLevel, approvalRequired.
31
+ - `applyPatchPlan(connector, plan, options)` → `PatchPlanRun`. The safety contract:
32
+ 1. only operation ids in `approvedOperationIds` are written;
33
+ 2. `requires_human_*` placeholder values are never written without a `valueOverrides` entry;
34
+ 3. compare-and-set: with `readField` support, drifted values produce `conflict` results instead of writes (`checkConflicts: false` opts out);
35
+ 4. every operation yields a `PatchOperationResult` (`applied | failed | skipped | conflict`).
36
+ - `PlanStore` / `createFilePlanStore` — durable lifecycle: save → approve operations (+ value overrides) → record runs.
37
+
38
+ ## Connectors
39
+
40
+ - `GtmConnector` — `{ provider, fetchSnapshot(), applyOperation?, readField?, fetchChanges? }`.
41
+ - Connectors never silently drop unresolvable records; audits surface them.
42
+ - `fetchChanges(sinceIso)` returns a partial snapshot; change feeds may omit associations.
43
+ - `createHubspotConnector(options)` — read/write/readField/fetchChanges. `applyOperation` implements every `PatchOperationType`: `set_field`, `clear_field`, `link_record`, `create_task`, `archive_record`.
44
+ - `createSalesforceConnector(options)` — read/write/readField/fetchChanges; probabilities normalized to 0..1; `applyOperation` implements every operation type.
45
+ - `createStripeConnector(options)` — read-only billing by design (`applyOperation` returns `skipped`); email domains are the cross-system merge keys. Implements `fetchChanges` (incremental via `created[gte]`).
46
+
47
+ ## Multi-system operations
48
+
49
+ - `mergeSnapshots(snapshots)` → `{ snapshot, report }` — entity resolution on email/domain/name keys; identities accumulate; first source wins on conflicts and every conflict is reported.
50
+ - `diffSnapshots(before, after)` → record/field-level changes; `diffFindings(beforePlan, afterPlan)` → hygiene drift on stable ids.
51
+
52
+ ## Configuration
53
+
54
+ - `fullstackgtm.config.json`: `{ policy?, rules?: { enabled?, disabled? }, rulePackages? }`.
55
+ - Rule packages export `rules: GtmAuditRule[]`.
56
+ - Precedence: CLI flags > config file > defaults.
57
+
58
+ ## CLI
59
+
60
+ Commands: `login` / `logout`, `snapshot`, `audit`, `diff`, `merge`, `plans`, `apply`, `rules`.
61
+ Exit codes: `0` success · `1` error · `2` findings/regressions at the requested gate
62
+ (`--fail-on`, `--fail-on-new-findings`). `--json` everywhere; JSON output shapes are stable.
63
+
64
+ Credential resolution ladder: explicit `--token-env` → ambient env
65
+ (`HUBSPOT_ACCESS_TOKEN`, `SALESFORCE_ACCESS_TOKEN`+`SALESFORCE_INSTANCE_URL`,
66
+ `STRIPE_SECRET_KEY`) → stored login (`~/.fullstackgtm`, `FSGTM_HOME` override)
67
+ → broker pairing (`login --via`).
68
+
69
+ ## MCP
70
+
71
+ Tools: `fullstackgtm_audit`, `fullstackgtm_rules`, `fullstackgtm_apply`
72
+ (requires explicit `approvedOperationIds`). Input schemas are stable.
@@ -0,0 +1,121 @@
1
+ # fullstackgtm: 0.1 → 1.0
2
+
3
+ The planned, versioned path from first publish to a stable 1.0. Each milestone
4
+ is shippable on its own, ordered so that every step consolidates the
5
+ architecture before the next step expands it. The invariants that hold at
6
+ every version:
7
+
8
+ 1. **The package is the product; the app is an adapter.** Anything the app
9
+ needs from a provider goes through the package connector. New capability
10
+ lands in the package first.
11
+ 2. **Reads are free, writes are patch plans.** No code path may mutate a
12
+ provider except `applyPatchPlan` / `applyOperation` with explicit approval.
13
+ 3. **Deterministic and diffable.** Same inputs produce the same findings with
14
+ the same ids. Golden tests over the demo dataset enforce this.
15
+ 4. **Zero-dependency core.** Connectors use `fetch`; optional integrations
16
+ (MCP) stay optional peers.
17
+
18
+ ## 0.1.0 — The loop exists (done)
19
+
20
+ Canonical model, pluggable rule engine, patch plans, safe apply, HubSpot
21
+ connector, CLI/MCP, demo dataset, CLI auth (private app token, loopback
22
+ OAuth), broker pairing against a hosted deployment, CI + tag-publish
23
+ automation.
24
+
25
+ ## 0.2.0 — Provider parity and operational trust (done)
26
+
27
+ - **Salesforce connector** behind the same `GtmConnector` contract: SOQL with
28
+ cursor pagination, PATCH write-back, probabilities normalized to canonical
29
+ 0..1, never drops unresolvable records.
30
+ - **Salesforce CLI auth**: native device flow (code on any device, no client
31
+ secret, silent refresh) plus manual token + instance URL.
32
+ - **Broker mint for Salesforce**: paired CLIs receive `accessToken +
33
+ instanceUrl + fieldMappings` from the org's stored credentials.
34
+ - **CLI token observability**: paired-CLI list with last-used timestamps and
35
+ one-click revoke in the dashboard.
36
+ - App consolidation: `convex/salesforceActions.ts` collapses onto the package
37
+ connector like the HubSpot path did.
38
+
39
+ ## 0.3.0 — One patch-plan vocabulary (done)
40
+
41
+ The last internal duplication: the app's durable `patchPlans` tables speak
42
+ `verb`/`operation` strings while the package speaks typed `PatchOperation`s.
43
+
44
+ - Package: add a `PlanStore` interface (persist plan → approve operations →
45
+ record runs) so durable workflows are a first-class framework concern, not
46
+ an app concern.
47
+ - App: migrate `patchPlans`/`patchOperations` rows to the package types
48
+ (schema migration with a compatibility window), route
49
+ `patchPlanActions.apply` through `applyPatchPlan`.
50
+ - Exit criterion: the dashboard review queue and `fullstackgtm apply` operate
51
+ on byte-identical plan documents.
52
+
53
+ ## 0.4.0 — Policy as config, rules as packages (done)
54
+
55
+ Make the rule engine the community surface.
56
+
57
+ - `fullstackgtm.config.json` (or `.ts`): policy thresholds, enabled rules,
58
+ per-rule severity overrides, custom rule module paths.
59
+ - Rule metadata: category, default severity, docs URL; `fullstackgtm rules`
60
+ becomes generated documentation.
61
+ - 10–15 additional built-in rules drawn from real RevOps pain: duplicate
62
+ accounts by domain, contacts without owners, deals closing this quarter
63
+ with no activity in 14 days, stage/probability drift, currency mismatches.
64
+ - Exit criterion: a third party can publish an npm package of rules and a
65
+ user can enable it from config without forking.
66
+
67
+ ## 0.5.0 — Time: snapshot history and drift (done)
68
+
69
+ - Snapshot archive conventions (local directory or any mounted/S3-backed
70
+ path) with `fullstackgtm snapshot --archive`.
71
+ - `fullstackgtm diff <a> <b>`: what changed between snapshots — records,
72
+ fields, and *findings* (hygiene drift), built on the stable-id property.
73
+ - Audit trends in the hosted app (the observability layer earns its keep).
74
+ - Exit criterion: a nightly CI job can fail on hygiene regression, not just
75
+ hygiene presence.
76
+
77
+ ## 0.6.0 — Many systems, one entity (done — Stripe is the first non-CRM connector)
78
+
79
+ The original thesis: GTM data disagrees across systems.
80
+
81
+ - Entity resolution over `identities` claims: merge canonical records from
82
+ multiple snapshots (CRM + marketing + billing) by domain/email/external-id
83
+ heuristics, with explicit confidence and human-reviewable merge plans (the
84
+ patch-plan safety model applied to identity).
85
+ - Cross-system audit rules: "account exists in billing but not CRM",
86
+ "marketing-qualified contact has no CRM owner".
87
+ - First non-CRM connector (likely billing — Stripe — or marketing) to prove
88
+ the contract generalizes.
89
+ - Exit criterion: one audit over a merged snapshot from two live systems.
90
+
91
+ ## 0.7.0 — Sync maturity (done)
92
+
93
+ - Incremental fetch: provider cursors (HubSpot `updatedAfter` search,
94
+ Salesforce `SystemModstamp` filters) behind an optional
95
+ `fetchChanges(since)` connector capability.
96
+ - Conflict surfacing: when a provider value changed under an unapplied patch
97
+ operation, the plan flags it instead of writing blind (compare-and-set).
98
+ - Exit criterion: hourly sync of a 100k-record org without full re-pulls.
99
+
100
+ ## 0.8–0.9 — Hardening and freeze (done)
101
+
102
+ - API review and freeze of `types.ts`, connector contract, CLI flags, MCP
103
+ schemas; deprecations resolved.
104
+ - Security review of the auth surfaces (credential store, broker endpoints,
105
+ token lifecycle); rate limiting on the device-flow endpoints.
106
+ - Docs site with the operating-model registry as browsable reference.
107
+ - Performance pass: streaming snapshots for very large orgs.
108
+
109
+ ## 1.0.0 — The contract (reached)
110
+
111
+ Semver stability commitment on the canonical model, rule interface, connector
112
+ contract, plan format, CLI, and MCP tools. From here, new providers and new
113
+ rules are minor releases; the model only breaks at 2.0.
114
+
115
+ ## Deliberately out of scope until after 1.0
116
+
117
+ - Hosted multi-org analytics across customers
118
+ - Non-deterministic (LLM-scored) rules — they can *propose*, but the
119
+ deterministic engine stays the system of record for findings
120
+ - Workflow orchestration (sequences, cadences) — adjacent product, not
121
+ framework
package/llms.txt ADDED
@@ -0,0 +1,25 @@
1
+ # fullstackgtm
2
+
3
+ > Plan/apply for your GTM stack: canonical CRM/GTM data model, deterministic
4
+ > hygiene audits, reviewable dry-run patch plans, and approval-gated
5
+ > write-back to HubSpot, Salesforce, and Stripe (read-only). Think
6
+ > `terraform plan` for your CRM. Apache-2.0.
7
+
8
+ CLI quick check: `fullstackgtm doctor --json`. Zero-credential demo:
9
+ `fullstackgtm audit --demo --json`. Audits are read-only; `apply` writes only
10
+ explicitly approved operation ids. Exit codes: 0 success, 1 error, 2 findings
11
+ at/above `--fail-on`.
12
+
13
+ ## Docs
14
+
15
+ - [README](https://github.com/fullstackgtm/core/blob/main/README.md): install, five-minute loop, auth ladder, MCP setup, programmatic use
16
+ - [INSTALL_FOR_AGENTS](https://github.com/fullstackgtm/core/blob/main/INSTALL_FOR_AGENTS.md): deterministic install-and-verify steps with expected outputs
17
+ - [API reference](https://github.com/fullstackgtm/core/blob/main/docs/api.md): semver-covered surfaces — canonical model, rule interface, plan/apply contract, connector contract, config, CLI, MCP tools
18
+ - [CHANGELOG](https://github.com/fullstackgtm/core/blob/main/CHANGELOG.md): release history
19
+
20
+ ## Key invariants
21
+
22
+ - Reads are safe by default; nothing is written without explicit `--approve`
23
+ - `requires_human_*` placeholder values are refused without a `--value` override
24
+ - Finding/operation ids are stable hashes of rule + record (diffable across runs)
25
+ - Secrets are never accepted as argv flags; stdin or env only
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "fullstackgtm",
3
+ "version": "0.10.0",
4
+ "description": "Open-source agentic GTM ops framework: canonical GTM data model, pluggable deterministic audits, reviewable dry-run patch plans, approval-gated write-back with conflict detection, and cross-system entity resolution. HubSpot, Salesforce, and Stripe connectors included.",
5
+ "license": "Apache-2.0",
6
+ "author": "Full Stack GTM",
7
+ "homepage": "https://github.com/fullstackgtm/core#readme",
8
+ "bugs": {
9
+ "url": "https://github.com/fullstackgtm/core/issues"
10
+ },
11
+ "type": "module",
12
+ "sideEffects": false,
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "bin": {
22
+ "fullstackgtm": "dist/bin.js",
23
+ "fullstackgtm-mcp": "dist/mcp-bin.js"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "src",
28
+ "docs",
29
+ "README.md",
30
+ "CHANGELOG.md",
31
+ "INSTALL_FOR_AGENTS.md",
32
+ "llms.txt",
33
+ "LICENSE"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "test": "node --experimental-strip-types --test tests/*.test.ts",
38
+ "prepublishOnly": "npm run build"
39
+ },
40
+ "devDependencies": {
41
+ "@modelcontextprotocol/sdk": "^1.29.0",
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.9.0",
44
+ "zod": "^4.4.2"
45
+ },
46
+ "keywords": [
47
+ "gtm",
48
+ "revops",
49
+ "crm",
50
+ "salesforce",
51
+ "hubspot",
52
+ "audit",
53
+ "agent",
54
+ "mcp",
55
+ "patch-plan"
56
+ ],
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/fullstackgtm/core.git"
60
+ },
61
+ "engines": {
62
+ "node": ">=20"
63
+ },
64
+ "peerDependencies": {
65
+ "@modelcontextprotocol/sdk": "^1.29.0",
66
+ "zod": "^4.4.2"
67
+ },
68
+ "peerDependenciesMeta": {
69
+ "@modelcontextprotocol/sdk": {
70
+ "optional": true
71
+ },
72
+ "zod": {
73
+ "optional": true
74
+ }
75
+ }
76
+ }