@synapsor/runner 0.1.0-alpha.9 → 0.1.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 (67) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/README.md +388 -41
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/runner.mjs +2982 -238
  6. package/docs/README.md +40 -0
  7. package/docs/app-owned-executors.md +38 -0
  8. package/docs/capability-authoring.md +265 -0
  9. package/docs/cloud-mode.md +24 -0
  10. package/docs/current-scope.md +29 -0
  11. package/docs/dependency-license-inventory.md +35 -0
  12. package/docs/doctor.md +98 -0
  13. package/docs/getting-started-own-database.md +131 -46
  14. package/docs/handler-helper.md +228 -0
  15. package/docs/http-mcp.md +85 -17
  16. package/docs/licensing.md +36 -0
  17. package/docs/local-mode.md +44 -25
  18. package/docs/mcp-audit.md +8 -8
  19. package/docs/mcp-client-setup.md +59 -21
  20. package/docs/openai-agents-sdk.md +57 -0
  21. package/docs/recipes.md +6 -6
  22. package/docs/release-notes.md +327 -0
  23. package/docs/release-policy.md +125 -0
  24. package/docs/result-envelope-v2.md +151 -0
  25. package/docs/rfcs/001-result-envelope-v2.md +143 -0
  26. package/docs/rfcs/002-app-owned-handler-helper.md +161 -0
  27. package/docs/rfcs/003-integrator-feedback-teardown.md +97 -0
  28. package/docs/store-lifecycle.md +83 -0
  29. package/docs/troubleshooting-first-run.md +6 -6
  30. package/docs/use-your-own-database.md +18 -0
  31. package/docs/writeback-executors.md +92 -1
  32. package/examples/app-owned-writeback/README.md +128 -0
  33. package/examples/app-owned-writeback/business-actions.md +221 -0
  34. package/examples/app-owned-writeback/command-handler.mjs +55 -0
  35. package/examples/app-owned-writeback/node-fastify-handler.mjs +64 -0
  36. package/examples/app-owned-writeback/python-fastapi-handler.py +66 -0
  37. package/examples/mcp-postgres-billing-app-handler/README.md +94 -0
  38. package/examples/mcp-postgres-billing-app-handler/app-handler.mjs +123 -0
  39. package/examples/mcp-postgres-billing-app-handler/docker-compose.yml +13 -0
  40. package/examples/mcp-postgres-billing-app-handler/schema.sql +59 -0
  41. package/examples/mcp-postgres-billing-app-handler/scripts/run-demo.sh +100 -0
  42. package/examples/mcp-postgres-billing-app-handler/seed.sql +39 -0
  43. package/examples/mcp-postgres-billing-app-handler/synapsor-handler.mjs +437 -0
  44. package/examples/mcp-postgres-billing-app-handler/synapsor.runner.json +158 -0
  45. package/examples/openai-agents-http/README.md +19 -12
  46. package/examples/openai-agents-http/agent.py +29 -65
  47. package/examples/openai-agents-stdio/README.md +10 -6
  48. package/examples/openai-agents-stdio/agent.py +4 -2
  49. package/examples/reference-support-billing-app/README.md +16 -16
  50. package/examples/reference-support-billing-app/mcp-client.generic.json +1 -1
  51. package/fixtures/benchmark/mcp-efficiency.json +53 -0
  52. package/fixtures/benchmark/mcp-efficiency.txt +25 -0
  53. package/fixtures/protocol/MANIFEST.json +54 -0
  54. package/fixtures/protocol/change-set.late-fee-waiver.v1.json +72 -0
  55. package/fixtures/protocol/execution-receipt.applied.v1.json +14 -0
  56. package/fixtures/protocol/execution-receipt.conflict.v1.json +15 -0
  57. package/fixtures/protocol/runner-registration.v1.json +22 -0
  58. package/fixtures/protocol/writeback-job.late-fee-waiver.v1.json +44 -0
  59. package/package.json +6 -1
  60. package/schemas/change-set.v1.schema.json +140 -0
  61. package/schemas/execution-receipt.v1.schema.json +34 -0
  62. package/schemas/onboarding-selection.v1.schema.json +132 -0
  63. package/schemas/runner-registration.v1.schema.json +48 -0
  64. package/schemas/synapsor.app-handler-receipt.v1.json +39 -0
  65. package/schemas/synapsor.app-handler-request.v1.json +119 -0
  66. package/schemas/synapsor.runner.schema.json +415 -0
  67. package/schemas/writeback-job.v1.schema.json +121 -0
package/README.md CHANGED
@@ -7,24 +7,67 @@ Runner lets an MCP agent inspect scoped data and request database-backed
7
7
  business actions without receiving raw SQL, write credentials, approval tools,
8
8
  or commit tools.
9
9
 
10
- ## Alpha Operational Notes
10
+ ## The Five-Line Model
11
11
 
12
- These are current alpha requirements, not hidden behavior:
12
+ Your agent talks to Synapsor Runner, not directly to your database.
13
+ It can look: scoped reads through reviewed tools.
14
+ It can suggest: saved proposals with evidence and exact diffs.
15
+ It cannot commit: approval and writeback happen outside the model-facing tool.
16
+ After writeback, Runner keeps receipts and replay so you can inspect what happened.
13
17
 
14
- - Writeback with `--config ./synapsor.runner.json` reads the trusted writer
15
- connection from the source `write_url_env`, for example
16
- `SYNAPSOR_DATABASE_WRITE_URL`. `SYNAPSOR_DATABASE_URL` is only the legacy
17
- fallback when you run direct worker/apply flows without a local config.
18
- - `synapsor-runner mcp serve-http` is a small authenticated JSON-RPC endpoint
19
- for `tools/list`, `tools/call`, and `resources/read`. It is not full MCP
20
- Streamable HTTP and does not implement the `initialize`/SSE handshake. Use
21
- stdio MCP for standard local MCP clients, or wrap the HTTP endpoint like the
22
- OpenAI HTTP example.
23
- - Direct SQL writeback creates or writes `synapsor_writeback_receipts` for
24
- idempotency and replay. The trusted writer needs permission for that table,
25
- or an administrator must pre-create it and grant access. Use an app-owned
26
- `http_handler` or `command_handler` if Runner should not create receipt
27
- tables in your application schema.
18
+ ## Four Terms
19
+
20
+ - Capability: a tool you define in config, such as `billing.inspect_invoice`
21
+ or `billing.propose_late_fee_waiver`. The agent only sees capabilities.
22
+ - Proposal: the agent's suggested database-backed change. It is saved, not
23
+ applied.
24
+ - Writeback: the moment an approved proposal actually changes the database.
25
+ - Executor: your app's writeback handler for anything richer than a guarded
26
+ one-row update.
27
+
28
+ You install only `@synapsor/runner`. There is no separate handler package to
29
+ install. A handler is your app's endpoint or script for rich approved writes;
30
+ Runner includes templates and examples to help you build one.
31
+
32
+ ## Who Does What
33
+
34
+ You write the config: sources, trusted context, capabilities, visible fields,
35
+ proposal fields, and guards. For rich writes, you also write a small handler.
36
+
37
+ Synapsor Runner serves the MCP tools, stores evidence/proposals/receipts,
38
+ enforces tenant, column, version, and idempotency guards, routes writeback, and
39
+ keeps the replay log. You do not rebuild the safety loop yourself.
40
+
41
+ ## The Writeback Rule
42
+
43
+ One-row update to an existing row: Runner can do guarded direct writeback.
44
+ Anything else, such as inserting a row, touching two tables, or emitting an
45
+ event: your app-owned executor does it after approval.
46
+
47
+ ## How An External Handler Works
48
+
49
+ Some changes are too rich for Runner's one-row writeback: insert a credit row,
50
+ touch two tables, or emit an event. For those, you run a small endpoint. The
51
+ flow is:
52
+
53
+ ```text
54
+ agent proposes
55
+ -> human approves outside MCP
56
+ -> Runner POSTs the approved change to your endpoint
57
+ -> your code writes it in its own transaction and returns a receipt
58
+ ```
59
+
60
+ The model never touches this code. You are the last line of defense: Runner
61
+ hands you the tenant, expected row version, and idempotency key, and your
62
+ handler must re-check all three. Skipping those checks reintroduces
63
+ cross-tenant writes, lost updates, or duplicate writes. Start from
64
+ `synapsor-runner handler template ...` instead of hand-rolling the safety checks.
65
+
66
+ ## Deliberate Limits
67
+
68
+ Runner does not expose raw SQL, write credentials, approval tools, or commit
69
+ tools to the model. Direct Runner writeback does not do generic `INSERT`,
70
+ `DELETE`, `UPSERT`, DDL, or multi-row SQL. Those are app-owned executor jobs.
28
71
 
29
72
  ```text
30
73
  AI agent or MCP client
@@ -70,7 +113,7 @@ Run the guided quick demo first. It does not require Docker, a database, a
70
113
  config file, an MCP client, or a Synapsor Cloud account.
71
114
 
72
115
  ```bash
73
- npx -y -p @synapsor/runner@alpha synapsor-runner demo --quick
116
+ npx -y -p @synapsor/runner synapsor-runner demo --quick
74
117
  ```
75
118
 
76
119
  In a terminal, it walks through the safety model step by step. In CI, piped
@@ -82,7 +125,7 @@ It does not prove database connectivity. It shows the proposal, evidence, and
82
125
  replay flow without giving the runner a database URL.
83
126
 
84
127
  ```bash
85
- npx -y -p @synapsor/runner@alpha synapsor-runner demo inspect
128
+ npx -y -p @synapsor/runner synapsor-runner demo inspect
86
129
  ```
87
130
 
88
131
  Human output is concise by default. Use `--details` for reviewer metadata or
@@ -100,14 +143,69 @@ synapsor-runner demo inspect --npx
100
143
  Then choose one path:
101
144
 
102
145
  ```text
103
- Full disposable proof -> npx -y -p @synapsor/runner@alpha synapsor-runner demo
146
+ Full disposable proof -> npx -y -p @synapsor/runner synapsor-runner demo
104
147
  Your own staging DB -> export DATABASE_URL=... then run the inspect command below
105
- MCP risk review -> npx -y -p @synapsor/runner@alpha synapsor-runner audit --example dangerous-db-mcp
148
+ MCP risk review -> npx -y -p @synapsor/runner synapsor-runner audit --example dangerous-db-mcp
149
+ ```
150
+
151
+ For your own database, do this before wiring Claude, Cursor, OpenAI Agents SDK,
152
+ or another MCP client:
153
+
154
+ ```text
155
+ 1. Generate the config with start/init/onboard.
156
+ 2. Run tools preview to confirm no raw SQL or write credentials are exposed.
157
+ 3. Run smoke call against one generated inspect tool.
158
+ 4. Only then run up --serve or mcp serve.
106
159
  ```
107
160
 
108
161
  `synapsor-runner` is the public command for this OSS runner. `synapsor` is
109
162
  reserved for the Synapsor Cloud CLI.
110
163
 
164
+ Authoring reference:
165
+
166
+ - [Capability Authoring](docs/capability-authoring.md): read/proposal tools,
167
+ model-facing descriptions, result envelope v2, trusted context, and writeback
168
+ guards.
169
+ - [Result Envelope v2](docs/result-envelope-v2.md): stable
170
+ `ok`/`summary`/`data`/`proposal`/`error` MCP tool results.
171
+ - [JSON Schema](schemas/synapsor.runner.schema.json): editor validation for
172
+ `synapsor.runner.json`.
173
+
174
+ ## Current Alpha Details
175
+
176
+ These are current alpha requirements, not hidden behavior:
177
+
178
+ - Writeback with `--config ./synapsor.runner.json` reads the trusted writer
179
+ connection from the source `write_url_env`, for example
180
+ `SYNAPSOR_DATABASE_WRITE_URL`. `SYNAPSOR_DATABASE_URL` is only the legacy
181
+ fallback when you run direct worker/apply flows without a local config.
182
+ - `synapsor-runner mcp serve` is standard stdio MCP for local clients that can
183
+ launch Runner.
184
+ - `synapsor-runner mcp serve-streamable-http` is standard MCP Streamable HTTP
185
+ with `initialize` and in-memory session behavior for SDK/client HTTP MCP
186
+ integrations.
187
+ - OpenAI Agents SDK rejects dotted function/tool names. Use
188
+ `--alias-mode openai` or `--openai-tool-aliases` for OpenAI-facing MCP
189
+ transports. Runner exposes aliases such as `billing__inspect_invoice` and
190
+ keeps the canonical Synapsor capability name in tool metadata.
191
+ - `synapsor-runner mcp serve-http` is a small authenticated JSON-RPC bridge for
192
+ `tools/list`, `tools/call`, and `resources/read`. Use it only when you want a
193
+ simple app/server wrapper instead of full HTTP MCP.
194
+ - Direct SQL writeback creates or writes `synapsor_writeback_receipts` for
195
+ idempotency and replay. The trusted writer needs permission for that table,
196
+ or an administrator must pre-create it and grant access. Use an app-owned
197
+ `http_handler` or `command_handler` if Runner should not create receipt
198
+ tables in your application schema.
199
+ - Run `synapsor-runner doctor --config synapsor.runner.json --check-writeback`
200
+ after reviewing receipt-table DDL/grants to verify writer connectivity,
201
+ receipt-table permissions, and rollback-only target-table access. The probe
202
+ never mutates business rows, but it can create the receipt table if the
203
+ writer has permission.
204
+ - For app-owned `http_handler` executors, configure `signing_secret_env` to
205
+ have Runner sign writeback requests with `X-Synapsor-Signature`. Run
206
+ `synapsor-runner doctor --config synapsor.runner.json --check-handlers` to
207
+ check handler env vars and network reachability without applying a proposal.
208
+
111
209
  ## Connect Your Own Staging Database
112
210
 
113
211
  Put a read-only connection string in the environment:
@@ -120,17 +218,160 @@ For disposable dev RDS fixtures only, use `sslmode=no-verify` if your local
120
218
  Node/Postgres TLS stack cannot verify the test certificate chain. For real
121
219
  staging or production-like databases, keep certificate verification enabled.
122
220
 
123
- Inspect metadata:
221
+ Run the guided own-database path:
124
222
 
125
223
  ```bash
126
- npx -y -p @synapsor/runner@alpha synapsor-runner inspect \
127
- --engine auto \
224
+ npx -y -p @synapsor/runner synapsor-runner start \
128
225
  --from-env DATABASE_URL \
129
226
  --schema public
130
227
  ```
131
228
 
132
- Generate a reviewed read-only config first. The wizard creates this local
133
- flow:
229
+ `start --from-env` is the low-friction alias for `onboard db --from-env`. That
230
+ path inspects metadata, helps you choose one table/view, creates trusted
231
+ context bindings, generates semantic MCP tools, validates the tool boundary,
232
+ and prints the exact MCP/UI next commands. It does not require hand-authored
233
+ JSON. If you provide an optional real object id during the wizard, it also
234
+ writes `./.synapsor/smoke-input.json` so the first tool call can use an actual
235
+ row instead of guessed sample data. When the read URL env var and trusted
236
+ tenant/principal env vars are already set, onboarding also attempts that smoke
237
+ call immediately and stores the evidence/query audit in the local ledger. If
238
+ those env vars are missing, it prints the exact command to run after you set
239
+ them from `.env.example`.
240
+
241
+ The end-to-end shape is:
242
+
243
+ ```text
244
+ 1. Put your read-only DB URL in DATABASE_URL.
245
+ 2. Run start --from-env DATABASE_URL.
246
+ 3. Choose one table/view and the safe fields agents may see.
247
+ 4. Preview the generated capabilities.
248
+ 5. Serve them over MCP to Claude, Cursor, OpenAI Agents SDK, or your app.
249
+ 6. For writes, approve a proposal outside MCP before writeback.
250
+ ```
251
+
252
+ The generated config is just the safety contract. A small reviewed version
253
+ looks like this:
254
+
255
+ Bring the generated review-mode workspace up with one command:
256
+
257
+ ```bash
258
+ npx -y -p @synapsor/runner synapsor-runner up \
259
+ --serve \
260
+ --config ./synapsor.runner.json \
261
+ --store ./.synapsor/local.db
262
+ ```
263
+
264
+ `up` validates the config/store, summarizes model-facing tools, shows whether
265
+ proposal tools use direct SQL writeback or app-owned executors, checks active
266
+ store leases, and prints the next smoke, approve, apply, replay, UI, and doctor
267
+ commands. By default, `up` is guidance-only. Use `up --serve` to start the
268
+ standard Streamable HTTP MCP server after the checklist; use `--dry-run` to
269
+ rehearse without starting it. For app-owned executor configs, add
270
+ `--with-handler` to run the handler doctor before serving.
271
+
272
+ For CI, shell scripts, or an LLM driving the setup, use the prompt-free path:
273
+
274
+ ```bash
275
+ npx -y -p @synapsor/runner synapsor-runner onboard db \
276
+ --from-env DATABASE_URL \
277
+ --schema public \
278
+ --table invoices \
279
+ --mode review \
280
+ --tenant-column tenant_id \
281
+ --primary-key id \
282
+ --conflict-column updated_at \
283
+ --namespace billing \
284
+ --object-name invoice \
285
+ --id-arg invoice_id \
286
+ --visible-columns id,tenant_id,late_fee_cents,waiver_reason,updated_at \
287
+ --patch late_fee_cents=fixed:0,waiver_reason=arg:reason \
288
+ --patch-bounds late_fee_cents=0:5500 \
289
+ --write-url-env SYNAPSOR_DATABASE_WRITE_URL \
290
+ --yes
291
+ ```
292
+
293
+ If `--namespace` is omitted, Runner derives a namespace from the table name
294
+ instead of creating `source.*` tools. Use `--read-tool` and `--proposal-tool`
295
+ when you need exact model-facing names.
296
+
297
+ For app-owned writeback, replace `--write-url-env ...` with
298
+ `--writeback http_handler --handler-url-env APP_WRITEBACK_URL --emit-handler`.
299
+ Runner marks that source as read-only unless you explicitly pass a writer env,
300
+ so `config validate` does not warn that direct SQL writeback is disabled.
301
+ You can also pass `--answers ./answers.json --yes` for a fully declarative
302
+ setup file.
303
+
304
+ ```json
305
+ {
306
+ "version": 1,
307
+ "mode": "review",
308
+ "result_format": 2,
309
+ "sources": {
310
+ "app_postgres": {
311
+ "engine": "postgres",
312
+ "read_url_env": "DATABASE_URL",
313
+ "write_url_env": "SYNAPSOR_DATABASE_WRITE_URL"
314
+ }
315
+ },
316
+ "trusted_context": {
317
+ "provider": "environment",
318
+ "values": {
319
+ "tenant_id_env": "SYNAPSOR_TENANT_ID",
320
+ "principal_env": "SYNAPSOR_PRINCIPAL"
321
+ }
322
+ },
323
+ "capabilities": [
324
+ {
325
+ "name": "billing.inspect_invoice",
326
+ "kind": "read",
327
+ "source": "app_postgres",
328
+ "target": {
329
+ "schema": "public",
330
+ "table": "invoices",
331
+ "primary_key": "id",
332
+ "tenant_key": "tenant_id"
333
+ },
334
+ "args": {
335
+ "invoice_id": { "type": "string", "required": true }
336
+ },
337
+ "lookup": { "id_from_arg": "invoice_id" },
338
+ "visible_columns": ["id", "status", "late_fee_cents", "updated_at"],
339
+ "evidence": "required",
340
+ "max_rows": 1
341
+ },
342
+ {
343
+ "name": "billing.propose_late_fee_waiver",
344
+ "kind": "proposal",
345
+ "source": "app_postgres",
346
+ "target": {
347
+ "schema": "public",
348
+ "table": "invoices",
349
+ "primary_key": "id",
350
+ "tenant_key": "tenant_id"
351
+ },
352
+ "args": {
353
+ "invoice_id": { "type": "string", "required": true },
354
+ "reason": { "type": "string", "required": true }
355
+ },
356
+ "lookup": { "id_from_arg": "invoice_id" },
357
+ "visible_columns": ["id", "status", "late_fee_cents", "updated_at"],
358
+ "patch": {
359
+ "late_fee_cents": { "fixed": 0 },
360
+ "waiver_reason": { "from_arg": "reason" }
361
+ },
362
+ "allowed_columns": ["late_fee_cents", "waiver_reason"],
363
+ "conflict_guard": { "column": "updated_at" },
364
+ "approval": { "mode": "human", "required_role": "billing_lead" }
365
+ }
366
+ ]
367
+ }
368
+ ```
369
+
370
+ The agent sees `billing.inspect_invoice` and
371
+ `billing.propose_late_fee_waiver`. It does not see the database URL, writer
372
+ credential, raw SQL, approval command, or commit command.
373
+
374
+ The wizard creates this local flow:
134
375
 
135
376
  ```text
136
377
  trusted context -> capability -> MCP tool
@@ -138,10 +379,11 @@ trusted context -> capability -> MCP tool
138
379
 
139
380
  It asks which table/view backs the context, which tenant/scope column and
140
381
  backend session env vars are trusted, which fields are visible, and what
141
- semantic capability name to expose.
382
+ semantic capability name to expose. Before writing files, it shows a final
383
+ preview and lets you revise visible fields or capability names.
142
384
 
143
385
  ```bash
144
- npx -y -p @synapsor/runner@alpha synapsor-runner init \
386
+ npx -y -p @synapsor/runner synapsor-runner init \
145
387
  --wizard \
146
388
  --engine auto \
147
389
  --from-env DATABASE_URL \
@@ -152,15 +394,26 @@ npx -y -p @synapsor/runner@alpha synapsor-runner init \
152
394
  Preview and serve the semantic tools:
153
395
 
154
396
  ```bash
155
- npx -y -p @synapsor/runner@alpha synapsor-runner tools preview \
397
+ npx -y -p @synapsor/runner synapsor-runner tools preview \
156
398
  --config ./synapsor.runner.json \
157
399
  --store ./.synapsor/local.db
158
400
 
159
- npx -y -p @synapsor/runner@alpha synapsor-runner mcp serve \
401
+ npx -y -p @synapsor/runner synapsor-runner smoke call \
402
+ <generated.inspect_tool_name> \
403
+ --input ./.synapsor/smoke-input.json \
404
+ --config ./synapsor.runner.json \
405
+ --store ./.synapsor/local.db
406
+
407
+ npx -y -p @synapsor/runner synapsor-runner mcp serve \
160
408
  --config ./synapsor.runner.json \
161
409
  --store ./.synapsor/local.db
162
410
  ```
163
411
 
412
+ `smoke call` uses the same runtime as MCP, records evidence/query audit or a
413
+ proposal in the local store, and prints the evidence/proposal/replay commands
414
+ to inspect what happened. If you skipped the optional smoke input in the
415
+ wizard, pass `--json '{"<lookup_arg>":"<real_id>"}'` instead.
416
+
164
417
  ## Two Ways To Run MCP
165
418
 
166
419
  Use stdio when the MCP client runs locally and can launch Synapsor Runner. Use
@@ -175,26 +428,70 @@ synapsor-runner mcp serve \
175
428
  --store ./.synapsor/local.db
176
429
  ```
177
430
 
431
+ For OpenAI Agents SDK over stdio, add OpenAI-safe aliases:
432
+
433
+ ```bash
434
+ synapsor-runner mcp serve \
435
+ --config ./synapsor.runner.json \
436
+ --store ./.synapsor/local.db \
437
+ --alias-mode openai
438
+ ```
439
+
178
440
  App/server deployments:
179
441
 
180
442
  ```bash
181
443
  export SYNAPSOR_RUNNER_HTTP_TOKEN="dev-local-token"
182
444
 
445
+ synapsor-runner mcp serve-streamable-http \
446
+ --config ./synapsor.runner.json \
447
+ --store ./.synapsor/local.db \
448
+ --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
449
+ --alias-mode openai
450
+ ```
451
+
452
+ You can also start the same review-mode server through the safer startup
453
+ checklist:
454
+
455
+ ```bash
456
+ synapsor-runner up --serve \
457
+ --config ./synapsor.runner.json \
458
+ --store ./.synapsor/local.db \
459
+ --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
460
+ --alias-mode openai
461
+ ```
462
+
463
+ Equivalent unified command:
464
+
465
+ ```bash
466
+ synapsor-runner mcp serve \
467
+ --transport streamable-http \
468
+ --config ./synapsor.runner.json \
469
+ --store ./.synapsor/local.db \
470
+ --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
471
+ --alias-mode openai
472
+ ```
473
+
474
+ Streamable HTTP defaults to `127.0.0.1:8766`, requires bearer auth by default,
475
+ and should use private networking, TLS, and rate limits before being exposed
476
+ beyond a local machine. With `--alias-mode openai`, tools are exposed to
477
+ the model as OpenAI-safe aliases such as `billing__inspect_invoice`; `_meta`
478
+ still includes `synapsor.canonical_tool_name = billing.inspect_invoice`, and
479
+ Runner routes calls back to the canonical Synapsor capability. Use
480
+ `--alias-mode both` during migrations if one client still expects canonical
481
+ dotted names while another needs OpenAI-safe aliases.
482
+
483
+ Bridge mode:
484
+
485
+ ```bash
183
486
  synapsor-runner mcp serve-http \
184
487
  --config ./synapsor.runner.json \
185
488
  --store ./.synapsor/local.db \
186
489
  --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
187
490
  ```
188
491
 
189
- HTTP defaults to `127.0.0.1:8765`, requires bearer auth by default, and should
190
- use private networking, TLS, and rate limits before being exposed beyond a
191
- local machine.
192
-
193
- HTTP alpha scope: `serve-http` is a JSON-RPC endpoint for `tools/list`,
194
- `tools/call`, and `resources/read`. It is not full MCP Streamable HTTP and does
195
- not implement `initialize`/SSE. If an SDK HTTP MCP client expects that
196
- handshake, use stdio mode or wrap the HTTP endpoint like the OpenAI HTTP
197
- example.
492
+ Bridge HTTP defaults to `127.0.0.1:8765` and supports only JSON-RPC
493
+ `tools/list`, `tools/call`, and `resources/read`. It does not implement MCP
494
+ Streamable HTTP `initialize`/session behavior.
198
495
 
199
496
  OpenAI Agents SDK examples:
200
497
 
@@ -214,6 +511,15 @@ Before asking an agent to solve a real task, confirm it can call a Runner tool:
214
511
  synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
215
512
  ```
216
513
 
514
+ For OpenAI-facing clients:
515
+
516
+ ```bash
517
+ synapsor-runner tools preview \
518
+ --config ./synapsor.runner.json \
519
+ --store ./.synapsor/local.db \
520
+ --alias-mode openai
521
+ ```
522
+
217
523
  Then ask the agent:
218
524
 
219
525
  ```text
@@ -236,12 +542,25 @@ The disposable reference app includes proposal-first write examples for:
236
542
  Each tool creates evidence, a before/after diff, and a proposal. The source
237
543
  database remains unchanged until approval outside MCP and guarded writeback.
238
544
 
239
- For a longer local session, you can install the alpha package explicitly:
545
+ For a longer local session, you can install the package globally:
240
546
 
241
547
  ```bash
242
- npm install -g @synapsor/runner@alpha
548
+ npm install -g @synapsor/runner
243
549
  ```
244
550
 
551
+ ## Stable Compatibility Promise
552
+
553
+ Starting with `0.1.0`, Synapsor Runner keeps the documented `synapsor-runner`
554
+ binary, `synapsor.runner.json` schema version `1`, result envelope v2, stdio
555
+ MCP, Streamable HTTP MCP, MCP client snippets, proposal/approval/writeback
556
+ inspection commands, direct SQL writeback contract, and app-owned executor
557
+ contract compatible through the `0.1.x` line unless a release note marks a
558
+ deprecation first.
559
+
560
+ Stable does not mean production SLA, hosted Cloud features, compliance
561
+ certification, physical Postgres/MySQL branching, generic SQL writeback, or
562
+ support for undocumented local SQLite internals.
563
+
245
564
  ## Runtime Flow
246
565
 
247
566
  The local runner keeps the model-facing tool call separate from approval and
@@ -326,6 +645,8 @@ relying on `latest`:
326
645
 
327
646
  ```bash
328
647
  synapsor-runner activity search --tenant acme --object invoice:INV-3001
648
+ synapsor-runner events tail --store ./.synapsor/local.db
649
+ synapsor-runner events webhook --url http://127.0.0.1:8788/synapsor/events --kind proposal_created --store ./.synapsor/local.db
329
650
  synapsor-runner proposals list --tenant acme --object invoice:INV-3001 --status approved
330
651
  synapsor-runner evidence show ev_...
331
652
  synapsor-runner query-audit list --evidence ev_...
@@ -351,16 +672,24 @@ Create a redacted local diagnostic report:
351
672
 
352
673
  ```bash
353
674
  synapsor-runner doctor --config synapsor.runner.json --report --redact --output synapsor-doctor.md
675
+ synapsor-runner doctor --config synapsor.runner.json --check-writeback
354
676
  ```
355
677
 
356
678
  Inspect or compact the local ledger:
357
679
 
358
680
  ```bash
359
681
  synapsor-runner store stats --store ./.synapsor/local.db
682
+ synapsor-runner events tail --store ./.synapsor/local.db --follow
683
+ synapsor-runner events webhook --url-env SYNAPSOR_EVENT_WEBHOOK_URL --auth-token-env SYNAPSOR_EVENT_WEBHOOK_TOKEN --follow --store ./.synapsor/local.db
360
684
  synapsor-runner store vacuum --store ./.synapsor/local.db
361
685
  synapsor-runner store prune --store ./.synapsor/local.db --older-than 30d --dry-run
686
+ synapsor-runner store reset --store ./.synapsor/local.db --yes
362
687
  ```
363
688
 
689
+ `events webhook` is a local/dev/staging convenience for review UIs, Slack
690
+ bridges, or app-local notifications. It POSTs one redacted local event envelope
691
+ per lifecycle event; it is not a hosted central ledger.
692
+
364
693
  This is local indexed search for local/dev/staging usage. It is not external
365
694
  database time travel, not cross-runner search, and not hosted compliance
366
695
  retention.
@@ -372,6 +701,24 @@ your application service already owns business writes, configure an
372
701
  `http_handler` or `command_handler` executor. Approval still happens outside
373
702
  MCP, and the handler returns an applied/conflict/failed receipt for replay.
374
703
 
704
+ > **Important:** your app handler owns the final business write. Runner creates
705
+ > the proposal and calls your handler only after approval, but your handler must
706
+ > still enforce tenant/scope checks, expected-version or conflict guards,
707
+ > idempotency keys, allowed business actions, transaction/rollback, and safe
708
+ > error receipts. If you skip those checks, you can reintroduce cross-tenant
709
+ > writes, lost updates, or duplicate writes. Keep handler credentials out of MCP.
710
+
711
+ Starter handlers are included under `examples/app-owned-writeback`.
712
+ The packaged app-owned billing example also includes a bundled
713
+ `synapsor-handler.mjs` helper shim. There is no separate handler package to
714
+ install.
715
+ You can also generate a starter handler directly:
716
+
717
+ ```bash
718
+ npx -y -p @synapsor/runner synapsor-runner handler template node-fastify \
719
+ --output ./synapsor-writeback-handler.mjs
720
+ ```
721
+
375
722
  For direct SQL writeback, set the writer env var named by the source
376
723
  `write_url_env`, for example `SYNAPSOR_DATABASE_WRITE_URL`. Runner also creates
377
724
  or writes `synapsor_writeback_receipts` for idempotency/replay, so the writer
@@ -391,4 +738,4 @@ Synapsor DBMS, not a physical branch engine for Postgres/MySQL, and not a
391
738
  general MCP security platform.
392
739
 
393
740
  See the full repository README and docs for Docker demos, MCP client setup,
394
- configuration recipes, and security boundaries.
741
+ configuration recipes, security boundaries, and release notes.
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type DbRowReader } from "@synapsor-runner/mcp-server";
2
3
  import { type WritebackJob } from "@synapsor-runner/protocol";
3
4
  import { type SchemaInspection } from "@synapsor-runner/schema-inspector";
4
5
  export declare function main(argv: string[]): Promise<number>;
@@ -7,6 +8,7 @@ export declare function runInitWizard(args: string[], options?: {
7
8
  ask?: WizardAsk;
8
9
  env?: NodeJS.ProcessEnv;
9
10
  inspection?: SchemaInspection;
11
+ readRow?: DbRowReader;
10
12
  stdout?: Pick<NodeJS.WriteStream, "write">;
11
13
  }): Promise<number>;
12
14
  export declare function resolveSqlWriteDatabaseUrl(job: WritebackJob, configPath: string, env: NodeJS.ProcessEnv): Promise<string>;
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8BA,OAAO,EAA6G,KAAK,YAAY,EAAwB,MAAM,2BAA2B,CAAC;AAC/L,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,mCAAmC,CAAC;AA4H3C,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8C1D;AA0DD,KAAK,SAAS,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9E,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CACvC,GACL,OAAO,CAAC,MAAM,CAAC,CAiLjB;AAsyCD,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/H"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAYA,OAAO,EAAqG,KAAK,WAAW,EAA2F,MAAM,6BAA6B,CAAC;AAmB3P,OAAO,EAA6G,KAAK,YAAY,EAAwB,MAAM,2BAA2B,CAAC;AAC/L,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,mCAAmC,CAAC;AA4U3C,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmD1D;AA+DD,KAAK,SAAS,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9E,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CACvC,GACL,OAAO,CAAC,MAAM,CAAC,CA2TjB;AAo7DD,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/H"}