@synapsor/runner 1.6.2 → 1.6.4

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 (116) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +141 -2
  3. package/CONTRIBUTING.md +10 -3
  4. package/README.md +65 -83
  5. package/SECURITY.md +14 -2
  6. package/THREAT_MODEL.md +64 -4
  7. package/dist/authoring.mjs +151 -16
  8. package/dist/cli.d.ts +31 -3
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/local-ui.d.ts +145 -1
  11. package/dist/local-ui.d.ts.map +1 -1
  12. package/dist/runner.mjs +37488 -19009
  13. package/dist/runtime.mjs +4056 -235
  14. package/dist/shadow.mjs +2423 -65
  15. package/docs/README.md +36 -2
  16. package/docs/agent-guided-setup.md +239 -0
  17. package/docs/aggregate-reads.md +14 -5
  18. package/docs/app-owned-executors.md +5 -6
  19. package/docs/approval-roles-and-operator-identity.md +353 -0
  20. package/docs/auto-boundary-and-scoped-explore.md +89 -11
  21. package/docs/capability-authoring.md +21 -2
  22. package/docs/client-recipes.md +1 -1
  23. package/docs/cloud-mode.md +7 -7
  24. package/docs/conformance.md +6 -3
  25. package/docs/current-scope.md +32 -2
  26. package/docs/cursor-plugin.md +3 -3
  27. package/docs/database-enforced-scope.md +6 -0
  28. package/docs/dsl-json-parity.md +75 -0
  29. package/docs/dsl-reference.md +22 -1
  30. package/docs/fresh-developer-usability.md +155 -80
  31. package/docs/getting-started-own-database.md +45 -44
  32. package/docs/guarded-crud-writeback.md +19 -0
  33. package/docs/guided-onboarding.md +399 -0
  34. package/docs/human-attention-notifications.md +367 -0
  35. package/docs/limitations.md +49 -13
  36. package/docs/local-mode.md +36 -22
  37. package/docs/mcp-audit.md +14 -14
  38. package/docs/mcp-client-setup.md +11 -14
  39. package/docs/mcp-clients.md +1 -1
  40. package/docs/migrating-to-synapsor-spec.md +42 -0
  41. package/docs/openai-agents-sdk.md +2 -2
  42. package/docs/production.md +39 -0
  43. package/docs/proposal-evidence-freshness.md +7 -7
  44. package/docs/recipes.md +6 -6
  45. package/docs/release-notes.md +144 -4
  46. package/docs/release-policy.md +20 -7
  47. package/docs/reversible-change-sets.md +1 -1
  48. package/docs/reviewed-database-views.md +132 -0
  49. package/docs/reviewed-relationships.md +245 -0
  50. package/docs/rfcs/006-reviewed-reversible-change-sets.md +1 -1
  51. package/docs/runner-bundles.md +7 -7
  52. package/docs/runner-config-reference.md +132 -0
  53. package/docs/running-a-runner-fleet.md +16 -1
  54. package/docs/schema-api-candidates.md +1 -1
  55. package/docs/security-boundary.md +54 -0
  56. package/docs/store-lifecycle.md +20 -1
  57. package/docs/supervised-automatic-apply.md +267 -0
  58. package/docs/troubleshooting-first-run.md +85 -10
  59. package/docs/use-your-own-database.md +6 -4
  60. package/docs/workbench-ask.md +279 -0
  61. package/docs/writeback-executors.md +7 -7
  62. package/examples/auto-boundary-churn/README.md +1 -1
  63. package/examples/community-solar-clean-room/README.md +7 -0
  64. package/examples/community-solar-clean-room/docker-compose.yml +16 -0
  65. package/examples/community-solar-clean-room/package.json +15 -0
  66. package/examples/community-solar-clean-room/prisma/schema.prisma +171 -0
  67. package/examples/community-solar-clean-room/seed/postgres.sql +571 -0
  68. package/examples/fitflow-guided-onboarding/README.md +43 -0
  69. package/examples/fitflow-guided-onboarding/app/page.tsx +8 -0
  70. package/examples/fitflow-guided-onboarding/docker-compose.yml +16 -0
  71. package/examples/fitflow-guided-onboarding/package.json +18 -0
  72. package/examples/fitflow-guided-onboarding/prisma/schema.prisma +98 -0
  73. package/examples/fitflow-guided-onboarding/seed/postgres.sql +401 -0
  74. package/examples/openai-agents-http/Makefile +1 -1
  75. package/examples/openai-agents-http/README.md +1 -1
  76. package/examples/openai-agents-stdio/Makefile +1 -1
  77. package/examples/openai-agents-stdio/README.md +2 -2
  78. package/examples/openai-agents-stdio/agent.py +1 -4
  79. package/examples/operator-oidc/issuer.mjs +188 -0
  80. package/examples/reference-support-billing-app/README.md +16 -16
  81. package/examples/retail-clean-room/README.md +7 -0
  82. package/examples/retail-clean-room/docker-compose.yml +16 -0
  83. package/examples/retail-clean-room/package.json +9 -0
  84. package/examples/retail-clean-room/prisma/schema.prisma +239 -0
  85. package/examples/retail-clean-room/seed/postgres.sql +781 -0
  86. package/examples/retail-clean-room/view-recipe/average-retained-revenue.synapsor.sql +21 -0
  87. package/examples/retail-clean-room/view-recipe/synapsor.runner.json +25 -0
  88. package/examples/support-plan-credit/README.md +6 -2
  89. package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +1 -4
  90. package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +1 -4
  91. package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +1 -4
  92. package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +1 -4
  93. package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +1 -4
  94. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +1 -4
  95. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +1 -1
  96. package/examples/support-plan-credit/mcp-client-examples/google-adk.py +1 -1
  97. package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +1 -1
  98. package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +1 -1
  99. package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
  100. package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +1 -4
  101. package/fixtures/compatibility/published-1.6.3/manifest.json +76 -0
  102. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  103. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  104. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  105. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  106. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  107. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  108. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  109. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  110. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  111. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  112. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  113. package/llms.txt +10 -5
  114. package/package.json +11 -3
  115. package/schemas/schema-candidate-review.schema.json +42 -0
  116. package/schemas/synapsor.runner.schema.json +227 -4
@@ -0,0 +1,98 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model Organization {
11
+ id String @id
12
+ name String
13
+ locations Location[]
14
+ trainers Trainer[]
15
+ members Member[]
16
+ classes Class[]
17
+ checkIns CheckIn[]
18
+
19
+ @@map("organizations")
20
+ }
21
+
22
+ model Location {
23
+ id String @id
24
+ organizationId String @map("organization_id")
25
+ name String
26
+ region String
27
+ organization Organization @relation(fields: [organizationId], references: [id])
28
+ members Member[]
29
+ classes Class[]
30
+ checkIns CheckIn[]
31
+
32
+ @@unique([organizationId, name])
33
+ @@map("locations")
34
+ }
35
+
36
+ model Trainer {
37
+ id String @id
38
+ organizationId String @map("organization_id")
39
+ displayName String @map("display_name")
40
+ organization Organization @relation(fields: [organizationId], references: [id])
41
+ members Member[]
42
+ classes Class[]
43
+
44
+ @@map("trainers")
45
+ }
46
+
47
+ model Member {
48
+ id String @id
49
+ organizationId String @map("organization_id")
50
+ locationId String @map("location_id")
51
+ assignedTrainerId String @map("assigned_trainer_id")
52
+ membershipStatus String @map("membership_status")
53
+ membershipTier String @map("membership_tier")
54
+ loyaltyBalance Int @map("loyalty_balance")
55
+ version Int
56
+ paymentMethod String @map("payment_method")
57
+ homeAddress String @map("home_address")
58
+ medicalWaiverNotes String @map("medical_waiver_notes")
59
+ organization Organization @relation(fields: [organizationId], references: [id])
60
+ location Location @relation(fields: [locationId], references: [id])
61
+ assignedTrainer Trainer @relation(fields: [assignedTrainerId], references: [id])
62
+ checkIns CheckIn[]
63
+
64
+ @@index([organizationId, assignedTrainerId])
65
+ @@map("members")
66
+ }
67
+
68
+ model Class {
69
+ id String @id
70
+ organizationId String @map("organization_id")
71
+ locationId String @map("location_id")
72
+ trainerId String @map("trainer_id")
73
+ classType String @map("class_type")
74
+ startsAt DateTime @map("starts_at") @db.Timestamptz(6)
75
+ organization Organization @relation(fields: [organizationId], references: [id])
76
+ location Location @relation(fields: [locationId], references: [id])
77
+ trainer Trainer @relation(fields: [trainerId], references: [id])
78
+ checkIns CheckIn[]
79
+
80
+ @@map("classes")
81
+ }
82
+
83
+ model CheckIn {
84
+ id String @id
85
+ organizationId String @map("organization_id")
86
+ locationId String @map("location_id")
87
+ memberId String @map("member_id")
88
+ classId String @map("class_id")
89
+ outcome String
90
+ checkedInAt DateTime @map("checked_in_at") @db.Timestamptz(6)
91
+ organization Organization @relation(fields: [organizationId], references: [id])
92
+ location Location @relation(fields: [locationId], references: [id])
93
+ member Member @relation(fields: [memberId], references: [id])
94
+ fitnessClass Class @relation(fields: [classId], references: [id])
95
+
96
+ @@index([organizationId, checkedInAt])
97
+ @@map("check_ins")
98
+ }
@@ -0,0 +1,401 @@
1
+ DO $$
2
+ BEGIN
3
+ CREATE ROLE fitflow_analytics_reader LOGIN PASSWORD 'fitflow_analytics_reader_password';
4
+ EXCEPTION WHEN duplicate_object THEN NULL;
5
+ END
6
+ $$;
7
+
8
+ DO $$
9
+ BEGIN
10
+ CREATE ROLE fitflow_trainer_reader LOGIN PASSWORD 'fitflow_trainer_reader_password';
11
+ EXCEPTION WHEN duplicate_object THEN NULL;
12
+ END
13
+ $$;
14
+
15
+ DO $$
16
+ BEGIN
17
+ CREATE ROLE fitflow_writer LOGIN PASSWORD 'fitflow_writer_password';
18
+ EXCEPTION WHEN duplicate_object THEN NULL;
19
+ END
20
+ $$;
21
+
22
+ DO $$
23
+ BEGIN
24
+ CREATE ROLE fitflow_setup LOGIN PASSWORD 'fitflow_setup_password';
25
+ EXCEPTION WHEN duplicate_object THEN NULL;
26
+ END
27
+ $$;
28
+
29
+ ALTER ROLE fitflow_analytics_reader SET default_transaction_read_only = on;
30
+ ALTER ROLE fitflow_trainer_reader SET default_transaction_read_only = on;
31
+
32
+ CREATE TABLE public.organizations (
33
+ id text PRIMARY KEY,
34
+ name text NOT NULL
35
+ );
36
+
37
+ CREATE TABLE public.locations (
38
+ id text PRIMARY KEY,
39
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
40
+ name text NOT NULL,
41
+ region text NOT NULL CHECK (region IN ('central', 'east', 'north', 'south', 'west')),
42
+ UNIQUE (organization_id, name)
43
+ );
44
+
45
+ CREATE TABLE public.trainers (
46
+ id text PRIMARY KEY,
47
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
48
+ display_name text NOT NULL
49
+ );
50
+
51
+ CREATE TABLE public.members (
52
+ id text PRIMARY KEY,
53
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
54
+ location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
55
+ assigned_trainer_id text NOT NULL REFERENCES public.trainers(id) ON DELETE RESTRICT,
56
+ membership_status text NOT NULL CHECK (membership_status IN ('active', 'frozen', 'cancelled')),
57
+ membership_tier text NOT NULL CHECK (membership_tier IN ('basic', 'plus', 'elite')),
58
+ loyalty_balance integer NOT NULL CHECK (loyalty_balance BETWEEN 0 AND 10000),
59
+ version integer NOT NULL DEFAULT 1 CHECK (version >= 1),
60
+ payment_method text NOT NULL,
61
+ home_address text NOT NULL,
62
+ medical_waiver_notes text NOT NULL
63
+ );
64
+
65
+ CREATE INDEX members_trusted_scope_idx
66
+ ON public.members(organization_id, assigned_trainer_id);
67
+
68
+ CREATE TABLE public.classes (
69
+ id text PRIMARY KEY,
70
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
71
+ location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
72
+ trainer_id text NOT NULL REFERENCES public.trainers(id) ON DELETE RESTRICT,
73
+ class_type text NOT NULL CHECK (class_type IN ('cycling', 'strength', 'yoga')),
74
+ starts_at timestamptz NOT NULL
75
+ );
76
+
77
+ CREATE TABLE public.check_ins (
78
+ id text PRIMARY KEY,
79
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
80
+ location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
81
+ member_id text NOT NULL REFERENCES public.members(id) ON DELETE RESTRICT,
82
+ class_id text NOT NULL REFERENCES public.classes(id) ON DELETE RESTRICT,
83
+ outcome text NOT NULL CHECK (outcome IN ('attended', 'late_cancel', 'no_show')),
84
+ checked_in_at timestamptz NOT NULL
85
+ );
86
+
87
+ CREATE INDEX check_ins_tenant_time_idx
88
+ ON public.check_ins(organization_id, checked_in_at);
89
+
90
+ -- A realistic application has much more schema than the first agent pack
91
+ -- needs. These metadata-only subsystems exercise whole-application review
92
+ -- without adding irrelevant rows to the onboarding result.
93
+ DO $$
94
+ DECLARE
95
+ relation_name text;
96
+ BEGIN
97
+ FOREACH relation_name IN ARRAY ARRAY[
98
+ 'plans',
99
+ 'membership_events',
100
+ 'membership_freezes',
101
+ 'membership_cancellations',
102
+ 'class_bookings',
103
+ 'class_waitlists',
104
+ 'attendance_adjustments',
105
+ 'trainer_certifications',
106
+ 'trainer_schedules',
107
+ 'staff_users',
108
+ 'staff_roles',
109
+ 'location_hours',
110
+ 'rooms',
111
+ 'equipment',
112
+ 'equipment_maintenance',
113
+ 'workout_programs',
114
+ 'workout_exercises',
115
+ 'member_goals',
116
+ 'body_metrics',
117
+ 'health_flags',
118
+ 'waivers',
119
+ 'billing_accounts',
120
+ 'payment_methods',
121
+ 'invoices',
122
+ 'invoice_items',
123
+ 'payments',
124
+ 'refunds',
125
+ 'promo_codes',
126
+ 'member_promotions',
127
+ 'leads',
128
+ 'referrals',
129
+ 'campaigns',
130
+ 'notification_preferences',
131
+ 'support_tickets'
132
+ ]
133
+ LOOP
134
+ EXECUTE format(
135
+ 'CREATE TABLE public.%I (
136
+ id text PRIMARY KEY,
137
+ organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
138
+ status text NOT NULL,
139
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp()
140
+ )',
141
+ relation_name
142
+ );
143
+ END LOOP;
144
+ END
145
+ $$;
146
+
147
+ INSERT INTO public.organizations (id, name) VALUES
148
+ ('org-fitflow', 'FitFlow'),
149
+ ('org-other', 'Other Fitness');
150
+
151
+ INSERT INTO public.locations (id, organization_id, name, region) VALUES
152
+ ('loc-downtown', 'org-fitflow', 'Downtown', 'central'),
153
+ ('loc-east', 'org-fitflow', 'Eastside', 'east'),
154
+ ('loc-north', 'org-fitflow', 'North Loop', 'north'),
155
+ ('loc-other', 'org-other', 'Other Downtown', 'west');
156
+
157
+ INSERT INTO public.trainers (id, organization_id, display_name) VALUES
158
+ ('trainer-alex', 'org-fitflow', 'Alex'),
159
+ ('trainer-jordan', 'org-fitflow', 'Jordan'),
160
+ ('trainer-other', 'org-other', 'Other Trainer');
161
+
162
+ WITH member_rows AS (
163
+ SELECT
164
+ item,
165
+ CASE
166
+ WHEN item <= 12 THEN 'loc-downtown'
167
+ WHEN item <= 22 THEN 'loc-east'
168
+ ELSE 'loc-north'
169
+ END AS location_id,
170
+ CASE WHEN item % 2 = 0 THEN 'trainer-alex' ELSE 'trainer-jordan' END AS trainer_id,
171
+ CASE WHEN item % 7 = 0 THEN 'frozen' ELSE 'active' END AS status,
172
+ CASE WHEN item % 3 = 0 THEN 'elite' WHEN item % 2 = 0 THEN 'plus' ELSE 'basic' END AS tier
173
+ FROM generate_series(1, 30) AS item
174
+ )
175
+ INSERT INTO public.members (
176
+ id,
177
+ organization_id,
178
+ location_id,
179
+ assigned_trainer_id,
180
+ membership_status,
181
+ membership_tier,
182
+ loyalty_balance,
183
+ version,
184
+ payment_method,
185
+ home_address,
186
+ medical_waiver_notes
187
+ )
188
+ SELECT
189
+ 'member-' || lpad(item::text, 3, '0'),
190
+ 'org-fitflow',
191
+ location_id,
192
+ trainer_id,
193
+ status,
194
+ tier,
195
+ item * 10,
196
+ 1,
197
+ 'synthetic-card-token-' || item,
198
+ item || ' Synthetic Street',
199
+ 'synthetic private medical note ' || item
200
+ FROM member_rows;
201
+
202
+ INSERT INTO public.members (
203
+ id,
204
+ organization_id,
205
+ location_id,
206
+ assigned_trainer_id,
207
+ membership_status,
208
+ membership_tier,
209
+ loyalty_balance,
210
+ version,
211
+ payment_method,
212
+ home_address,
213
+ medical_waiver_notes
214
+ ) VALUES (
215
+ 'other-member-001',
216
+ 'org-other',
217
+ 'loc-other',
218
+ 'trainer-other',
219
+ 'active',
220
+ 'elite',
221
+ 9999,
222
+ 1,
223
+ 'other-secret-payment',
224
+ 'Other Tenant Address',
225
+ 'other tenant private medical note'
226
+ );
227
+
228
+ INSERT INTO public.classes (id, organization_id, location_id, trainer_id, class_type, starts_at) VALUES
229
+ ('class-downtown-w1', 'org-fitflow', 'loc-downtown', 'trainer-alex', 'strength', '2026-07-06T17:00:00Z'),
230
+ ('class-downtown-w2', 'org-fitflow', 'loc-downtown', 'trainer-alex', 'cycling', '2026-07-13T17:00:00Z'),
231
+ ('class-east-w1', 'org-fitflow', 'loc-east', 'trainer-jordan', 'yoga', '2026-07-06T18:00:00Z'),
232
+ ('class-north-w2', 'org-fitflow', 'loc-north', 'trainer-jordan', 'strength', '2026-07-13T18:00:00Z'),
233
+ ('class-other', 'org-other', 'loc-other', 'trainer-other', 'cycling', '2026-07-13T19:00:00Z');
234
+
235
+ WITH groups(prefix, organization_id, location_id, class_id, outcome, checked_in_at, first_member, group_size) AS (
236
+ VALUES
237
+ ('downtown-w1', 'org-fitflow', 'loc-downtown', 'class-downtown-w1', 'attended', '2026-07-06T17:00:00Z'::timestamptz, 1, 6),
238
+ ('downtown-w2', 'org-fitflow', 'loc-downtown', 'class-downtown-w2', 'attended', '2026-07-13T17:00:00Z'::timestamptz, 1, 9),
239
+ ('east-w1', 'org-fitflow', 'loc-east', 'class-east-w1', 'late_cancel', '2026-07-06T18:00:00Z'::timestamptz, 13, 5),
240
+ ('north-w2', 'org-fitflow', 'loc-north', 'class-north-w2', 'no_show', '2026-07-13T18:00:00Z'::timestamptz, 23, 2)
241
+ )
242
+ INSERT INTO public.check_ins (
243
+ id,
244
+ organization_id,
245
+ location_id,
246
+ member_id,
247
+ class_id,
248
+ outcome,
249
+ checked_in_at
250
+ )
251
+ SELECT
252
+ 'checkin-' || prefix || '-' || item,
253
+ organization_id,
254
+ location_id,
255
+ 'member-' || lpad((first_member + item - 1)::text, 3, '0'),
256
+ class_id,
257
+ outcome,
258
+ checked_in_at
259
+ FROM groups
260
+ CROSS JOIN LATERAL generate_series(1, group_size) AS item;
261
+
262
+ INSERT INTO public.check_ins (
263
+ id,
264
+ organization_id,
265
+ location_id,
266
+ member_id,
267
+ class_id,
268
+ outcome,
269
+ checked_in_at
270
+ )
271
+ SELECT
272
+ 'other-checkin-' || item,
273
+ 'org-other',
274
+ 'loc-other',
275
+ 'other-member-001',
276
+ 'class-other',
277
+ 'attended',
278
+ '2026-07-13T19:00:00Z'::timestamptz
279
+ FROM generate_series(1, 8) AS item;
280
+
281
+ ALTER TABLE public.organizations ENABLE ROW LEVEL SECURITY;
282
+ ALTER TABLE public.organizations FORCE ROW LEVEL SECURITY;
283
+ ALTER TABLE public.locations ENABLE ROW LEVEL SECURITY;
284
+ ALTER TABLE public.locations FORCE ROW LEVEL SECURITY;
285
+ ALTER TABLE public.trainers ENABLE ROW LEVEL SECURITY;
286
+ ALTER TABLE public.trainers FORCE ROW LEVEL SECURITY;
287
+ ALTER TABLE public.members ENABLE ROW LEVEL SECURITY;
288
+ ALTER TABLE public.members FORCE ROW LEVEL SECURITY;
289
+ ALTER TABLE public.classes ENABLE ROW LEVEL SECURITY;
290
+ ALTER TABLE public.classes FORCE ROW LEVEL SECURITY;
291
+ ALTER TABLE public.check_ins ENABLE ROW LEVEL SECURITY;
292
+ ALTER TABLE public.check_ins FORCE ROW LEVEL SECURITY;
293
+
294
+ CREATE POLICY organizations_org_read ON public.organizations
295
+ FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
296
+ USING (id = current_setting('app.tenant_id', true));
297
+
298
+ CREATE POLICY locations_org_read ON public.locations
299
+ FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
300
+ USING (organization_id = current_setting('app.tenant_id', true));
301
+
302
+ CREATE POLICY trainers_org_read ON public.trainers
303
+ FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
304
+ USING (organization_id = current_setting('app.tenant_id', true));
305
+
306
+ CREATE POLICY members_analytics_read ON public.members
307
+ FOR SELECT TO fitflow_analytics_reader
308
+ USING (organization_id = current_setting('app.tenant_id', true));
309
+
310
+ CREATE POLICY members_trainer_read ON public.members
311
+ FOR SELECT TO fitflow_trainer_reader, fitflow_writer
312
+ USING (
313
+ organization_id = current_setting('app.tenant_id', true)
314
+ AND assigned_trainer_id = current_setting('app.principal', true)
315
+ );
316
+
317
+ CREATE POLICY members_guarded_update ON public.members
318
+ FOR UPDATE TO fitflow_writer
319
+ USING (
320
+ organization_id = current_setting('app.tenant_id', true)
321
+ AND assigned_trainer_id = current_setting('app.principal', true)
322
+ )
323
+ WITH CHECK (
324
+ organization_id = current_setting('app.tenant_id', true)
325
+ AND assigned_trainer_id = current_setting('app.principal', true)
326
+ );
327
+
328
+ CREATE POLICY classes_org_read ON public.classes
329
+ FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
330
+ USING (organization_id = current_setting('app.tenant_id', true));
331
+
332
+ CREATE POLICY check_ins_org_read ON public.check_ins
333
+ FOR SELECT TO fitflow_analytics_reader
334
+ USING (organization_id = current_setting('app.tenant_id', true));
335
+
336
+ DO $$
337
+ DECLARE
338
+ relation_name text;
339
+ BEGIN
340
+ FOREACH relation_name IN ARRAY ARRAY[
341
+ 'plans',
342
+ 'membership_events',
343
+ 'membership_freezes',
344
+ 'membership_cancellations',
345
+ 'class_bookings',
346
+ 'class_waitlists',
347
+ 'attendance_adjustments',
348
+ 'trainer_certifications',
349
+ 'trainer_schedules',
350
+ 'staff_users',
351
+ 'staff_roles',
352
+ 'location_hours',
353
+ 'rooms',
354
+ 'equipment',
355
+ 'equipment_maintenance',
356
+ 'workout_programs',
357
+ 'workout_exercises',
358
+ 'member_goals',
359
+ 'body_metrics',
360
+ 'health_flags',
361
+ 'waivers',
362
+ 'billing_accounts',
363
+ 'payment_methods',
364
+ 'invoices',
365
+ 'invoice_items',
366
+ 'payments',
367
+ 'refunds',
368
+ 'promo_codes',
369
+ 'member_promotions',
370
+ 'leads',
371
+ 'referrals',
372
+ 'campaigns',
373
+ 'notification_preferences',
374
+ 'support_tickets'
375
+ ]
376
+ LOOP
377
+ EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', relation_name);
378
+ EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', relation_name);
379
+ EXECUTE format(
380
+ 'CREATE POLICY %I ON public.%I
381
+ FOR SELECT TO fitflow_analytics_reader
382
+ USING (organization_id = current_setting(''app.tenant_id'', true))',
383
+ relation_name || '_org_read',
384
+ relation_name
385
+ );
386
+ EXECUTE format('GRANT SELECT ON public.%I TO fitflow_analytics_reader', relation_name);
387
+ END LOOP;
388
+ END
389
+ $$;
390
+
391
+ GRANT CONNECT ON DATABASE fitflow TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer, fitflow_setup;
392
+ GRANT USAGE ON SCHEMA public TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer, fitflow_setup;
393
+ GRANT SELECT ON public.organizations, public.locations, public.trainers, public.members, public.classes, public.check_ins TO fitflow_analytics_reader;
394
+ GRANT SELECT ON public.organizations, public.locations, public.trainers, public.members, public.classes TO fitflow_trainer_reader;
395
+ GRANT SELECT, UPDATE (membership_status, loyalty_balance, version) ON public.members TO fitflow_writer;
396
+ GRANT CREATE ON SCHEMA public TO fitflow_setup;
397
+
398
+ CREATE TABLE public.synapsor_fixture_ready (
399
+ initialized_at timestamptz NOT NULL
400
+ );
401
+ INSERT INTO public.synapsor_fixture_ready (initialized_at) VALUES (clock_timestamp());
@@ -2,5 +2,5 @@
2
2
 
3
3
  smoke:
4
4
  python3 -m py_compile agent.py
5
- npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http --help >/dev/null
5
+ npx -y @synapsor/runner mcp serve-streamable-http --help >/dev/null
6
6
  @printf '%s\n' "OpenAI Agents Streamable HTTP example smoke passed."
@@ -42,7 +42,7 @@ export SYNAPSOR_TENANT_ID="acme"
42
42
  export SYNAPSOR_PRINCIPAL="openai_agent_demo"
43
43
  export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
44
44
 
45
- npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
45
+ npx -y @synapsor/runner mcp serve-streamable-http \
46
46
  --config ./synapsor.runner.json \
47
47
  --store ./.synapsor/local.db \
48
48
  --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
@@ -2,5 +2,5 @@
2
2
 
3
3
  smoke:
4
4
  python3 -m py_compile agent.py
5
- npx -y -p @synapsor/runner synapsor-runner mcp serve --help >/dev/null
5
+ npx -y @synapsor/runner mcp serve --help >/dev/null
6
6
  @printf '%s\n' "OpenAI Agents stdio example smoke passed."
@@ -30,13 +30,13 @@ OpenAI Agents stdio example smoke passed.
30
30
  Generate `synapsor.runner.json` first:
31
31
 
32
32
  ```bash
33
- npx -y -p @synapsor/runner synapsor-runner demo
33
+ npx -y @synapsor/runner demo
34
34
  ```
35
35
 
36
36
  or connect your own staging database:
37
37
 
38
38
  ```bash
39
- npx -y -p @synapsor/runner synapsor-runner onboard db --from-env DATABASE_URL
39
+ npx -y @synapsor/runner onboard db --from-env DATABASE_URL
40
40
  ```
41
41
 
42
42
  Then install the Python dependencies:
@@ -25,10 +25,7 @@ async def main() -> None:
25
25
  params = {
26
26
  "command": "npx",
27
27
  "args": [
28
- "-y",
29
- "-p",
30
- "@synapsor/runner",
31
- "synapsor-runner",
28
+ "-y", "@synapsor/runner",
32
29
  "mcp",
33
30
  "serve",
34
31
  "--config",