@synapsor/runner 1.6.3 → 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 (97) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +72 -8
  3. package/CONTRIBUTING.md +10 -3
  4. package/README.md +61 -93
  5. package/SECURITY.md +7 -3
  6. package/THREAT_MODEL.md +37 -0
  7. package/dist/authoring.mjs +98 -13
  8. package/dist/cli.d.ts +12 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/local-ui.d.ts +60 -0
  11. package/dist/local-ui.d.ts.map +1 -1
  12. package/dist/runner.mjs +7321 -2000
  13. package/dist/runtime.mjs +528 -51
  14. package/docs/README.md +14 -0
  15. package/docs/agent-guided-setup.md +7 -7
  16. package/docs/aggregate-reads.md +14 -5
  17. package/docs/app-owned-executors.md +5 -6
  18. package/docs/auto-boundary-and-scoped-explore.md +58 -6
  19. package/docs/capability-authoring.md +2 -2
  20. package/docs/client-recipes.md +1 -1
  21. package/docs/cloud-mode.md +7 -7
  22. package/docs/conformance.md +6 -3
  23. package/docs/current-scope.md +13 -2
  24. package/docs/cursor-plugin.md +3 -3
  25. package/docs/database-enforced-scope.md +6 -0
  26. package/docs/dsl-reference.md +12 -1
  27. package/docs/fresh-developer-usability.md +6 -6
  28. package/docs/getting-started-own-database.md +41 -41
  29. package/docs/guided-onboarding.md +98 -30
  30. package/docs/limitations.md +34 -14
  31. package/docs/local-mode.md +20 -20
  32. package/docs/mcp-audit.md +14 -14
  33. package/docs/mcp-client-setup.md +11 -14
  34. package/docs/mcp-clients.md +1 -1
  35. package/docs/migrating-to-synapsor-spec.md +5 -1
  36. package/docs/openai-agents-sdk.md +2 -2
  37. package/docs/proposal-evidence-freshness.md +7 -7
  38. package/docs/recipes.md +6 -6
  39. package/docs/release-notes.md +86 -10
  40. package/docs/release-policy.md +20 -7
  41. package/docs/reversible-change-sets.md +1 -1
  42. package/docs/reviewed-database-views.md +132 -0
  43. package/docs/reviewed-relationships.md +245 -0
  44. package/docs/rfcs/006-reviewed-reversible-change-sets.md +1 -1
  45. package/docs/runner-bundles.md +7 -7
  46. package/docs/schema-api-candidates.md +1 -1
  47. package/docs/security-boundary.md +30 -0
  48. package/docs/troubleshooting-first-run.md +52 -12
  49. package/docs/use-your-own-database.md +6 -4
  50. package/docs/workbench-ask.md +279 -0
  51. package/docs/writeback-executors.md +7 -7
  52. package/examples/auto-boundary-churn/README.md +1 -1
  53. package/examples/community-solar-clean-room/README.md +7 -0
  54. package/examples/community-solar-clean-room/docker-compose.yml +16 -0
  55. package/examples/community-solar-clean-room/package.json +15 -0
  56. package/examples/community-solar-clean-room/prisma/schema.prisma +171 -0
  57. package/examples/community-solar-clean-room/seed/postgres.sql +571 -0
  58. package/examples/fitflow-guided-onboarding/README.md +2 -2
  59. package/examples/openai-agents-http/Makefile +1 -1
  60. package/examples/openai-agents-http/README.md +1 -1
  61. package/examples/openai-agents-stdio/Makefile +1 -1
  62. package/examples/openai-agents-stdio/README.md +2 -2
  63. package/examples/openai-agents-stdio/agent.py +1 -4
  64. package/examples/reference-support-billing-app/README.md +16 -16
  65. package/examples/retail-clean-room/README.md +7 -0
  66. package/examples/retail-clean-room/docker-compose.yml +16 -0
  67. package/examples/retail-clean-room/package.json +9 -0
  68. package/examples/retail-clean-room/prisma/schema.prisma +239 -0
  69. package/examples/retail-clean-room/seed/postgres.sql +781 -0
  70. package/examples/retail-clean-room/view-recipe/average-retained-revenue.synapsor.sql +21 -0
  71. package/examples/retail-clean-room/view-recipe/synapsor.runner.json +25 -0
  72. package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +1 -4
  73. package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +1 -4
  74. package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +1 -4
  75. package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +1 -4
  76. package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +1 -4
  77. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +1 -4
  78. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +1 -1
  79. package/examples/support-plan-credit/mcp-client-examples/google-adk.py +1 -1
  80. package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +1 -1
  81. package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +1 -1
  82. package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
  83. package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +1 -4
  84. package/fixtures/compatibility/published-1.6.3/manifest.json +76 -0
  85. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  86. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  87. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  88. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  89. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  90. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  91. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  92. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  93. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  94. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  95. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  96. package/llms.txt +10 -5
  97. package/package.json +8 -2
@@ -1,6 +1,6 @@
1
1
  # Reviewed Reversible Change Sets
2
2
 
3
- Synapsor Runner 1.4 can capture a bounded inverse for an opt-in direct database
3
+ Synapsor Runner can capture a bounded inverse for an opt-in direct database
4
4
  write. This is **reviewed compensation**, not rollback or database time travel.
5
5
 
6
6
  The operator flow is deliberately two separate approval loops:
@@ -0,0 +1,132 @@
1
+ # Reviewed Database Views For Derived Measures
2
+
3
+ Scoped Explore deliberately has no formula or expression language. The model
4
+ cannot invent ratios, arithmetic, functions, subqueries, or joins. When a
5
+ useful measure needs reviewed database logic, put that logic in a
6
+ database-owned view and expose only the resulting typed column through a named
7
+ Synapsor capability.
8
+
9
+ The authority split is:
10
+
11
+ ```text
12
+ Database owner reviews formula, joins, cardinality, and base-table scope
13
+ -> view publishes a small typed row shape
14
+ -> contract author reviews the view columns and fixed predicate
15
+ -> Runner applies trusted scope and the named aggregate
16
+ -> model receives one scalar, never SQL or member rows
17
+ ```
18
+
19
+ This is an explicit escape hatch, not automatic generation. Auto Boundary
20
+ blocks a view whose row identity cannot be proven from catalog metadata. Review
21
+ the view definition, scope, uniqueness, and grants before hand-authoring a
22
+ capability.
23
+
24
+ ## PostgreSQL Hardened Pattern
25
+
26
+ Use a `security_invoker` view so PostgreSQL checks permissions and row-level
27
+ security (RLS) as the Runner read role, not as the view owner. A
28
+ `security_barrier` also prevents unsafe predicate movement across the view
29
+ boundary.
30
+
31
+ The retail clean-room fixture defines this reviewed ratio:
32
+
33
+ ```sql
34
+ CREATE VIEW public.reviewed_order_performance
35
+ WITH (security_barrier = true, security_invoker = true) AS
36
+ SELECT
37
+ orders.id AS order_id,
38
+ orders.merchant_id,
39
+ orders.assigned_manager_id,
40
+ orders.region_id,
41
+ ROUND(
42
+ (orders.net_revenue_cents::numeric /
43
+ NULLIF(orders.gross_revenue_cents, 0)) * 10000
44
+ )::integer AS net_revenue_retention_basis_points
45
+ FROM public.orders;
46
+ ```
47
+
48
+ The formula is fixed in a reviewed database migration. The model sees only
49
+ `net_revenue_retention_basis_points`. It cannot change the numerator,
50
+ denominator, scale, or source relation.
51
+
52
+ For `database_scope.mode = "postgres_rls"`, Runner accepts a read view only
53
+ when all of these checks pass:
54
+
55
+ - the target is a normal PostgreSQL view used for `SELECT`;
56
+ - both `security_invoker=true` and `security_barrier=true` are present;
57
+ - the Runner role is not the view owner, a superuser, or `BYPASSRLS`;
58
+ - every referenced table or nested view can be resolved from the catalog;
59
+ - every referenced base table independently passes the existing FORCE RLS,
60
+ role, policy-operation, and trusted-setting checks;
61
+ - every nested view passes the same view checks.
62
+
63
+ An ordinary owner-rights view, an unverifiable dependency, a missing RLS
64
+ setting, or any non-read operation fails closed before MCP serving.
65
+
66
+ ## Named Aggregate
67
+
68
+ The public DSL fixes the trusted scope, formula output, region, aggregate, and
69
+ minimum cohort:
70
+
71
+ ```sql
72
+ CREATE AGENT CONTEXT retail_analytics_context
73
+ BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
74
+ BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
75
+ TENANT BINDING tenant_id
76
+ PRINCIPAL BINDING principal
77
+ END
78
+
79
+ CREATE CAPABILITY retail.average_net_revenue_retention_pacific
80
+ DESCRIPTION 'Return the privacy-suppressed average net-to-gross revenue retention rate for Pacific orders assigned to the trusted manager.'
81
+ RETURNS HINT 'Returns one scalar average in basis points or a suppression result; never order rows.'
82
+ USING CONTEXT retail_analytics_context
83
+ SOURCE retail_postgres
84
+ ON public.reviewed_order_performance
85
+ PRIMARY KEY order_id
86
+ TENANT KEY merchant_id
87
+ PRINCIPAL SCOPE KEY assigned_manager_id
88
+ AGGREGATE READ AVG net_revenue_retention_basis_points
89
+ SELECT WHERE region_id = 'region-pacific'
90
+ MIN GROUP SIZE 5
91
+ REQUIRE EVIDENCE
92
+ END
93
+ ```
94
+
95
+ Validate, compile, validate the Runner config, and serve:
96
+
97
+ ```bash
98
+ npx -y @synapsor/runner dsl validate \
99
+ ./average-retained-revenue.synapsor.sql --strict
100
+
101
+ npx -y @synapsor/runner dsl compile \
102
+ ./average-retained-revenue.synapsor.sql \
103
+ --out ./average-retained-revenue.contract.json \
104
+ --strict
105
+
106
+ npx -y @synapsor/runner config validate \
107
+ --config ./synapsor.runner.json
108
+
109
+ npx -y @synapsor/runner mcp serve \
110
+ --config ./synapsor.runner.json
111
+ ```
112
+
113
+ The runnable packaged recipe is under
114
+ `examples/retail-clean-room/view-recipe/`. Its clean-room gate proves that the
115
+ result is exactly `9000` basis points for the trusted fixture scope, includes
116
+ no member rows, and does not change the source database.
117
+
118
+ ## Review Checklist
119
+
120
+ 1. Prove the view has one intended row per counted entity.
121
+ 2. Prove joins cannot multiply rows or silently double-count values.
122
+ 3. Apply tenant and, where required, principal scope to every base relation.
123
+ 4. Keep sensitive source columns out of the view output.
124
+ 5. Grant the Runner role only `SELECT` on the view and required base objects.
125
+ 6. Test same-tenant other-principal and cross-tenant denial.
126
+ 7. Test zero denominators, nulls, rounding, and numeric overflow.
127
+ 8. Keep cohort suppression and result limits in the Synapsor capability.
128
+ 9. Treat a changed view definition as reviewed authority drift.
129
+
130
+ For complex or ambiguous calculations, keep the capability disabled until the
131
+ database migration, contract, and expected results have all been reviewed
132
+ together.
@@ -0,0 +1,245 @@
1
+ # Reviewed Relationship Paths
2
+
3
+ Synapsor Runner can answer bounded aggregate questions across related tables
4
+ without exposing a general join planner or SQL. The relationship is authority:
5
+ Runner proposes it from database catalog evidence, a human reviews it, and the
6
+ activated boundary fixes its exact path and semantics.
7
+
8
+ This feature is part of local, development/staging-only Scoped Explore.
9
+ Production receives only named capabilities created through Protect This Query.
10
+
11
+ ## The Safety Rule
12
+
13
+ A model may select an already activated relationship **by name**. It cannot
14
+ provide a table name, join key, join type, relationship path, or SQL fragment.
15
+
16
+ Runner accepts only:
17
+
18
+ - one to three relationship paths in a protected capability;
19
+ - one or two links per path;
20
+ - inspected foreign-key links whose target key is unique;
21
+ - `many_to_one` cardinality with `max_fan_out: 1`;
22
+ - trusted tenant and, where configured, principal scope on every relation;
23
+ - an explicit human choice for missing related rows.
24
+
25
+ Runner refuses:
26
+
27
+ - one-to-many and many-to-many paths;
28
+ - relationships inferred only from similar column names;
29
+ - ambiguous or unproven cardinality;
30
+ - more than two links in one path;
31
+ - a plan using more than three reviewed paths;
32
+ - a relationship whose catalog proof or generation lock is stale;
33
+ - a related table whose trusted scope cannot be enforced;
34
+ - formulas, derived measures, free-form joins, and model-selected identifiers.
35
+
36
+ These limits permit reviewed star-style analysis. For example, a sales fact can
37
+ group by an activated store path and an activated category path without
38
+ multiplying the counted sales rows.
39
+
40
+ ## Why Fan-Out Matters
41
+
42
+ Suppose one `sales_facts` row points to one store. Joining the store cannot
43
+ create more sales rows, so the relationship is many-to-one and has a maximum
44
+ fan-out of one.
45
+
46
+ By contrast, joining a sale to all of its line items can turn one sale into
47
+ several rows. A naive `SUM(sales_facts.amount_cents)` would then overstate
48
+ revenue. Runner refuses that one-to-many path instead of silently returning a
49
+ plausible but wrong number.
50
+
51
+ ## Demand-Driven Review
52
+
53
+ Auto Boundary may discover more proven relationships than a developer needs.
54
+ They are not all activated automatically.
55
+
56
+ The intended flow is:
57
+
58
+ 1. Activate the small starter boundary.
59
+ 2. Ask a bounded aggregate question.
60
+ 3. If the question needs an inactive but catalog-proven path, Runner refuses the
61
+ plan and identifies the exact path and proof.
62
+ 4. Workbench shows that one relationship for operator review.
63
+ 5. The operator chooses missing-row semantics when required and activates the
64
+ exact new boundary digest.
65
+ 6. Retry the original question.
66
+
67
+ The model cannot trigger step 5. Adding the path creates new authority, so it is
68
+ an operator-plane action with a new digest. Existing unrelated confirmations
69
+ remain valid; only dependent review state is invalidated.
70
+
71
+ ## Nullable Links
72
+
73
+ An optional foreign key requires an explicit business decision:
74
+
75
+ - `UNMATCHED EXCLUDE`: omit a counted row when its related record is missing;
76
+ - `UNMATCHED KEEP NULL`: keep the counted row and return an empty/null group
77
+ value for the missing relationship.
78
+
79
+ This is not cosmetic. The choice can change totals and cohort sizes, so Runner
80
+ does not silently choose it. The decision is stored in the canonical contract
81
+ and bound into its digest.
82
+
83
+ ## DSL Syntax
84
+
85
+ The SQL-like Domain-Specific Language (DSL) supports a legacy one-hop form and
86
+ the additive path form. Existing legacy contracts retain their canonical bytes
87
+ and digest.
88
+
89
+ Legacy one-hop form:
90
+
91
+ ```sql
92
+ PROTECTED RELATIONSHIP store
93
+ ON store_id
94
+ REFERENCES public.stores.id
95
+ PRIMARY KEY id
96
+ TENANT KEY tenant_id
97
+ ```
98
+
99
+ Reviewed path form:
100
+
101
+ ```sql
102
+ PROTECTED RELATIONSHIP store LINK 1
103
+ ON store_id
104
+ REFERENCES public.stores.id
105
+ PRIMARY KEY id
106
+ TENANT KEY tenant_id
107
+ UNMATCHED EXCLUDE
108
+
109
+ PROTECTED RELATIONSHIP category LINK 1
110
+ ON product_id
111
+ REFERENCES public.products.id
112
+ PRIMARY KEY id
113
+ TENANT KEY tenant_id
114
+ UNMATCHED KEEP NULL
115
+
116
+ PROTECTED RELATIONSHIP category LINK 2
117
+ ON category_id
118
+ REFERENCES public.categories.id
119
+ PRIMARY KEY id
120
+ TENANT KEY tenant_id
121
+ UNMATCHED EXCLUDE
122
+ ```
123
+
124
+ In that example:
125
+
126
+ - `store` and `category` are user-defined path names;
127
+ - `LINK 1` and `LINK 2` are DSL keywords and ordered link numbers;
128
+ - `store_id`, `product_id`, and `category_id` are inspected local keys;
129
+ - `public.stores.id`, `public.products.id`, and `public.categories.id` are
130
+ fixed reviewed targets;
131
+ - `PRIMARY KEY`, `TENANT KEY`, `UNMATCHED EXCLUDE`, and
132
+ `UNMATCHED KEEP NULL` are DSL syntax;
133
+ - the two `category` declarations form one depth-two path.
134
+
135
+ Link declarations for one path must be contiguous and ordered. A protected read
136
+ cannot mix the legacy form with the path form.
137
+
138
+ ## Canonical Contract
139
+
140
+ The path form compiles to public, language-neutral JSON:
141
+
142
+ ```json
143
+ {
144
+ "protected_read": {
145
+ "mode": "aggregate",
146
+ "relationships": [
147
+ {
148
+ "name": "category",
149
+ "links": [
150
+ {
151
+ "local_key": "product_id",
152
+ "schema": "public",
153
+ "table": "products",
154
+ "target_key": "id",
155
+ "primary_key": "id",
156
+ "tenant_key": "tenant_id",
157
+ "cardinality": "many_to_one",
158
+ "max_fan_out": 1,
159
+ "unmatched_rows": "keep_null"
160
+ },
161
+ {
162
+ "local_key": "category_id",
163
+ "schema": "public",
164
+ "table": "categories",
165
+ "target_key": "id",
166
+ "primary_key": "id",
167
+ "tenant_key": "tenant_id",
168
+ "cardinality": "many_to_one",
169
+ "max_fan_out": 1,
170
+ "unmatched_rows": "exclude"
171
+ }
172
+ ]
173
+ }
174
+ ]
175
+ }
176
+ }
177
+ ```
178
+
179
+ Measures, dimensions, time buckets, and fixed predicates refer to the reviewed
180
+ path name. The canonical Spec is not a generic SQL or analytics Abstract Syntax
181
+ Tree (AST); it represents fixed reviewed authority.
182
+
183
+ ## Scope And Privacy
184
+
185
+ For every participating relation, Runner injects trusted tenant and configured
186
+ principal predicates outside model arguments. Scope on only the starting table
187
+ is insufficient.
188
+
189
+ Aggregate privacy controls continue to apply after relationships are added:
190
+
191
+ - minimum cohort suppression;
192
+ - maximum groups and response size;
193
+ - query, rate, extraction, and differencing budgets;
194
+ - fixed reviewed dimensions and measures;
195
+ - no pagination that bypasses the group bound.
196
+
197
+ Adding dimensions can make cohorts smaller, so suppression is evaluated on the
198
+ final grouped result. A relationship does not weaken kept-out fields: kept-out
199
+ fields cannot be selected, filtered, grouped, sorted, joined, or counted
200
+ distinctly.
201
+
202
+ ## Protect For Production
203
+
204
+ Protect This Query freezes the exact reviewed paths, measures, dimensions,
205
+ filters, ordering, limits, scope, and privacy controls into a disabled named
206
+ capability. A human activates its exact digest. Scoped Explore can then be
207
+ disabled; the protected capability remains available.
208
+
209
+ Production does not advertise broad Explore tools and does not permit the model
210
+ to add relationship authority.
211
+
212
+ ## When A View Is Better
213
+
214
+ Runner intentionally does not support:
215
+
216
+ - arbitrary relationship graphs;
217
+ - many-to-many analytics;
218
+ - derived formulas such as `revenue / capacity`;
219
+ - model-defined expressions;
220
+ - general-purpose join planning.
221
+
222
+ For those cases, create a database view that computes the reviewed business
223
+ meaning, grant Runner's reader access only to the safe projected columns, and
224
+ inspect the view as a new resource. See [Reviewed Database
225
+ Views](reviewed-database-views.md).
226
+
227
+ This keeps business formulas and complex joins under ordinary database and code
228
+ review while preserving Synapsor's field, scope, budget, proposal, and audit
229
+ boundary.
230
+
231
+ ## Verification
232
+
233
+ The repository release gates exercise:
234
+
235
+ ```bash
236
+ corepack pnpm test:reviewed-relationships
237
+ corepack pnpm test:auto-boundary-explore:packed
238
+ corepack pnpm test:clean-room:community-solar
239
+ corepack pnpm test:clean-room:retail
240
+ ```
241
+
242
+ The live PostgreSQL and MySQL relationship test proves direct star paths,
243
+ depth-two paths, both nullable-link choices, demand-driven activation, drift
244
+ refusal, per-relation tenant/principal scope, suppression, and rejection of a
245
+ deliberately wrong fan-out relationship.
@@ -1,6 +1,6 @@
1
1
  # RFC 006: Reviewed Reversible Change Sets
2
2
 
3
- Status: implemented and verified for the prepared Runner 1.4 release line
3
+ Status: implemented (originally verified for the Runner 1.4 release line)
4
4
 
5
5
  ## Problem
6
6
 
@@ -41,11 +41,11 @@ cd ./synapsor-runner-bundle
41
41
  cp .env.example .env
42
42
  set -a && . ./.env && set +a
43
43
 
44
- npx -y -p @synapsor/runner synapsor-runner contract validate ./synapsor.contract.json
45
- npx -y -p @synapsor/runner synapsor-runner config validate --config ./synapsor.runner.json
46
- npx -y -p @synapsor/runner synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
47
- npx -y -p @synapsor/runner synapsor-runner cloud connect --config ./synapsor.cloud.json
48
- npx -y -p @synapsor/runner synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
44
+ npx -y @synapsor/runner contract validate ./synapsor.contract.json
45
+ npx -y @synapsor/runner config validate --config ./synapsor.runner.json
46
+ npx -y @synapsor/runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
47
+ npx -y @synapsor/runner cloud connect --config ./synapsor.cloud.json
48
+ npx -y @synapsor/runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
49
49
  ```
50
50
 
51
51
  For proposal contracts, run the trusted worker in a separate
@@ -53,14 +53,14 @@ operator-controlled terminal:
53
53
 
54
54
  ```bash
55
55
  set -a && . ./.env && set +a
56
- npx -y -p @synapsor/runner synapsor-runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
56
+ npx -y @synapsor/runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
57
57
  ```
58
58
 
59
59
  After an MCP tool creates a local proposal, sync its reviewed diff and safe
60
60
  references to Cloud:
61
61
 
62
62
  ```bash
63
- npx -y -p @synapsor/runner synapsor-runner cloud sync latest \
63
+ npx -y @synapsor/runner cloud sync latest \
64
64
  --config ./synapsor.cloud.json \
65
65
  --store ./.synapsor/local.db
66
66
  ```
@@ -1,6 +1,6 @@
1
1
  # Reviewed Candidates From Prisma, Drizzle, And OpenAPI
2
2
 
3
- Runner 1.6.0 uses these same bounded static parsers as evidence in the
3
+ Runner 1.6.4 uses these same bounded static parsers as evidence in the
4
4
  whole-application [Auto Boundary](auto-boundary-and-scoped-explore.md) flow.
5
5
  The database catalog remains authoritative for database structure; Prisma,
6
6
  Drizzle, OpenAPI, and existing Synapsor definitions contribute deterministic
@@ -42,6 +42,36 @@ The model does not receive:
42
42
  - MCP endpoint tokens, JWTs, refresh tokens, client secrets, or TLS keys;
43
43
  - trusted tenant or principal authority as ordinary model arguments.
44
44
 
45
+ ## Optional Workbench model client
46
+
47
+ Workbench Ask is a local client of that same reviewed surface, not another
48
+ policy engine. It is available only from authenticated loopback Workbench in an
49
+ explicit development/staging profile. Its provider may request only the exact
50
+ active named capabilities plus valid local authoring tools. The request is
51
+ dispatched through the official MCP SDK and the existing typed-plan/runtime
52
+ validators; there is no parallel query or mutation executor.
53
+
54
+ The operator chooses provider, model, endpoint, and credential source and
55
+ acknowledges direct egress for the current authority digest. No model output can
56
+ change those values. Provider credentials and bounded conversation state stay
57
+ in local server memory and are not written to the project, ledger, browser
58
+ storage, logs, evidence, receipts, or replay. Reviewed tool results may be sent
59
+ directly to the provider after consent; Synapsor does not relay them.
60
+
61
+ Official remote providers use fixed HTTPS origins. Custom remote endpoints
62
+ require HTTPS; plaintext is restricted to loopback. Redirects are refused,
63
+ resolved destinations are checked and pinned on every connection, and
64
+ private/link-local/metadata/special remote addresses are blocked. Unknown
65
+ tools, malformed arguments/responses, authority drift, oversized data, time or
66
+ tool-loop exhaustion, and reported source mutation fail closed.
67
+
68
+ Provider prose remains untrusted. A write tool can create only the normal inert
69
+ proposal, and the Workbench directs the human to the separate operator path.
70
+ Ask never receives activation, Protect, approval, apply, worker, notification,
71
+ attention, or reconciliation tools. It is absent from production,
72
+ unknown-profile, shared, remote, and non-loopback surfaces. See [Workbench Ask
73
+ With Your Model](workbench-ask.md).
74
+
45
75
  ## Network transport and identity
46
76
 
47
77
  Local stdio is the preferred one-client path. The MCP client launches Runner and
@@ -3,26 +3,26 @@
3
3
  Run the friendly doctor first:
4
4
 
5
5
  ```bash
6
- npx -y -p @synapsor/runner synapsor-runner doctor --first-run
6
+ npx -y @synapsor/runner doctor --first-run
7
7
  ```
8
8
 
9
9
  Use JSON for automation:
10
10
 
11
11
  ```bash
12
- npx -y -p @synapsor/runner synapsor-runner doctor --first-run --json
12
+ npx -y @synapsor/runner doctor --first-run --json
13
13
  ```
14
14
 
15
15
  ## Guided Recovery Contract
16
16
 
17
- Runner 1.6.3 failures should tell you what failed, why the boundary stopped,
17
+ Runner 1.6.4 failures should tell you what failed, why the boundary stopped,
18
18
  what state remains, and one next action. Do not delete the project or add
19
19
  `--force` merely to recover.
20
20
 
21
21
  | Failure | State preserved | One next action |
22
22
  | --- | --- | --- |
23
- | Database connection or metadata inspection failed | Existing project/review files and source rows | Fix the exported URL/network without printing the credential, then rerun `npx -y @synapsor/runner@latest start --from-env DATABASE_URL`. |
23
+ | Database connection or metadata inspection failed | Existing project/review files and source rows | Fix the URL/network without printing the credential, then rerun `npx -y @synapsor/runner start`. |
24
24
  | Read role is writable, owner, superuser, `BYPASSRLS`, or unverifiable | Disabled metadata draft; no source-row Explore | Supply a verifiably SELECT-only non-owner staging role, then rerun the same `start` command. |
25
- | Schema or project choice is ambiguous | Existing files; no authority activation | Rerun with the exact reviewed schema, for example `npx -y @synapsor/runner@latest start --from-env DATABASE_URL --schema public`. |
25
+ | Schema or project choice is ambiguous | Existing files; no authority activation | Rerun with the exact reviewed schema, for example `npx -y @synapsor/runner start --schema public`. |
26
26
  | Tenant or principal scope is unresolved | Conservative blocked resource decisions | Open the same Workbench URL and resolve the highlighted scope exception. |
27
27
  | Sensitive field remains unresolved | Field stays kept out; active tools unchanged | Open Workbench **Exceptions** and record one reviewed field decision. |
28
28
  | Row identifier is missing/composite/ambiguous | Resource remains blocked | Select a source-proven single-column primary/unique identity or keep the resource blocked. |
@@ -33,6 +33,9 @@ what state remains, and one next action. Do not delete the project or add
33
33
  | Config mode is missing/invalid | Config and source database are unchanged | Set `mode` to `read_only`, `shadow`, `review`, or `cloud`, then rerun `synapsor-runner config validate --json`. |
34
34
  | Config contains an unknown field | Config and source database are unchanged | Remove or correct the reported JSON path, then rerun `synapsor-runner config validate --json`. |
35
35
  | Workbench port is occupied | Review files, ledger, and source database | Rerun `synapsor-runner ui --open`; the default selects a free loopback port. |
36
+ | Workbench Ask is missing | Reviewed project remains usable through no-model Workbench/CLI/MCP | Use authenticated loopback Workbench with an explicit development/staging profile and at least one active reviewed tool. |
37
+ | Ask provider/key fails | Boundary, no-model composer, and external MCP remain usable | Check the exported key name, provider/model access, and local DNS/TLS; then retry without changing authority. |
38
+ | Ask says authority changed | Previous consent is invalid; active reviewed tools remain unchanged | Inspect the new tool/digest summary and acknowledge direct egress again. |
36
39
  | Writeback setup fails | Config and reviewed plan; transactional setup rolls back | Rerun `synapsor-runner writeback setup --profile staging --json` and review the reported prerequisite. |
37
40
  | Writer role/setup URL is missing | No DDL or grant was applied | Rerun the preview with `--writer-role <role> --setup-url-env <ADMIN_URL_ENV>`. |
38
41
  | No supported write candidate exists | Read boundary remains active; no write authority | Use **Add a safe action** on a writable base table with a proven identity/version field, or retain read-only mode. |
@@ -49,9 +52,10 @@ outcome; inspect the durable receipt/reconciliation state rather than guessing.
49
52
 
50
53
  ## Fresh Start Did Not Enter Auto Boundary
51
54
 
52
- Auto Boundary is the default only for a fresh interactive `start --from-env`
53
- with no existing config, selector, answers file, machine-output flag, or other
54
- automation input. This preserves every established 1.x route.
55
+ Auto Boundary is the default only for a fresh interactive `start` with no
56
+ existing config, selector, answers file, machine-output flag, or other
57
+ automation input. An exported `DATABASE_URL` is implied; explicit connection
58
+ and schema flags still win. This preserves every established 1.x route.
55
59
 
56
60
  Check the generated state:
57
61
 
@@ -93,6 +97,42 @@ A write-capable, owner, superuser, `BYPASSRLS`, or unverifiable credential may
93
97
  still inspect metadata with a warning. It cannot enable source-row Explore.
94
98
  Use a dedicated staging reader instead of weakening this check.
95
99
 
100
+ ## Workbench Ask Is Missing Or Refused
101
+
102
+ Ask is optional and follows a stricter local profile boundary. It appears only
103
+ in authenticated loopback Workbench for explicit `development` or `staging`
104
+ projects with at least one reviewed tool. Production, unknown, shared, remote,
105
+ and non-loopback surfaces intentionally omit it.
106
+
107
+ Normal Runner and MCP execution do not automatically source `.env`. Fresh
108
+ interactive `start` may read a regular project `.env` only after explicit
109
+ consent and keeps the selected database URL in that process. For the optional
110
+ model provider, export the key in the same shell that launches Workbench, then
111
+ select **Read an environment variable** and enter only the variable name. A
112
+ session-only masked paste is also supported.
113
+
114
+ Provider errors are redacted and do not disable the no-model composer:
115
+
116
+ - `ASK_KEY_REQUIRED`: export the selected key or use the masked session paste;
117
+ - `ASK_AUTHORITY_CHANGED`: review the current tools/digest and acknowledge
118
+ direct egress again;
119
+ - `ASK_PROVIDER_UNAVAILABLE`: verify provider availability, key/model access,
120
+ and local DNS/TLS, then retry;
121
+ - `ASK_PROVIDER_REDIRECT_REFUSED`: use the final fixed endpoint; Runner never
122
+ forwards credentials across redirects;
123
+ - `ASK_PROVIDER_DESTINATION_REFUSED`: the host resolved to a private, special,
124
+ metadata, or otherwise disallowed remote address;
125
+ - `ASK_REMOTE_HTTPS_REQUIRED`: remote custom endpoints require HTTPS; HTTP is
126
+ accepted only on loopback;
127
+ - `ASK_TOOL_REQUIRED`: the provider answered from prose without using a
128
+ reviewed Synapsor tool;
129
+ - `ASK_UNKNOWN_TOOL` or `ASK_OPERATOR_TOOL_REFUSED`: the provider requested
130
+ authority outside the displayed tool surface.
131
+
132
+ Select **Clear** after a session to cancel active work and discard in-memory
133
+ provider configuration/history. See [Workbench Ask With Your
134
+ Model](workbench-ask.md).
135
+
96
136
  ## Cursor Has Production Tools Instead Of Authoring Tools
97
137
 
98
138
  Install the managed local authoring entry only after boundary activation:
@@ -327,13 +367,13 @@ Own-database MCP setup needs a reviewed config before serving tools.
327
367
  Fix:
328
368
 
329
369
  ```bash
330
- npx -y -p @synapsor/runner synapsor-runner init --from-env DATABASE_URL --mode review --wizard
370
+ npx -y @synapsor/runner init --from-env DATABASE_URL --mode review --wizard
331
371
  ```
332
372
 
333
373
  Or pass an example config:
334
374
 
335
375
  ```bash
336
- npx -y -p @synapsor/runner synapsor-runner tools preview --config ./examples/mcp-postgres-billing/synapsor.runner.json --store ./.synapsor/local.db
376
+ npx -y @synapsor/runner tools preview --config ./examples/mcp-postgres-billing/synapsor.runner.json --store ./.synapsor/local.db
337
377
  ```
338
378
 
339
379
  ## SQLite Store Missing
@@ -379,7 +419,7 @@ Fix:
379
419
 
380
420
  ```bash
381
421
  export SYNAPSOR_DATABASE_READ_URL="<read-only-url>"
382
- npx -y -p @synapsor/runner synapsor-runner doctor --config synapsor.runner.json
422
+ npx -y @synapsor/runner doctor --config synapsor.runner.json
383
423
  ```
384
424
 
385
425
  ## Read/Write Credential Split Failed
@@ -491,7 +531,7 @@ Fix:
491
531
  Regenerate the snippet:
492
532
 
493
533
  ```bash
494
- npx -y -p @synapsor/runner synapsor-runner mcp config claude-desktop \
534
+ npx -y @synapsor/runner mcp config claude-desktop \
495
535
  --absolute-paths \
496
536
  --config ./synapsor.runner.json \
497
537
  --store ./.synapsor/local.db
@@ -10,9 +10,11 @@ model.
10
10
  Short path:
11
11
 
12
12
  ```bash
13
- export DATABASE_URL="postgresql://readonly_user:password@host:5432/app?sslmode=require"
14
- npx -y -p @synapsor/runner synapsor-runner start --from-env DATABASE_URL --schema public
13
+ npx -y @synapsor/runner start
15
14
  ```
16
15
 
17
- Runner stores environment-variable names in `synapsor.runner.json`, not database
18
- URLs. Keep credentials in your shell, process manager, or secret manager.
16
+ Paste a read-only URL into the hidden prompt, explicitly approve a regular
17
+ project `.env` file for this process, or export `DATABASE_URL`. PostgreSQL
18
+ defaults to `public`; explicit `--from-env`, `--schema`, and `--project-root`
19
+ flags remain available and always win. Runner stores environment-variable names
20
+ in `synapsor.runner.json`, not database URLs.