@synapsor/runner 0.1.12 → 0.1.13

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.
package/README.md CHANGED
@@ -4,614 +4,92 @@
4
4
  [![license: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
5
5
  [![ci](https://github.com/Synapsor/Synapsor-Runner/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Synapsor/Synapsor-Runner/actions/workflows/ci.yml?query=branch%3Amain)
6
6
 
7
- Stop giving AI agents `execute_sql()`. Give them reviewed business actions.
7
+ Stop giving AI agents `execute_sql`. Give them reviewed business actions.
8
8
 
9
- Synapsor Runner is an open-source, local-first MCP server that exposes reviewed semantic
10
- capabilities over Postgres and MySQL, stages risky writes as proposals, and
11
- keeps evidence and replay for agent actions. It sits between Claude, Cursor,
12
- OpenAI Agents SDK, or another MCP client and your database so the model does
13
- not receive raw SQL, write credentials, approval tools, or commit authority.
9
+ Synapsor Runner is an open-source, local-first MCP runtime for Postgres and
10
+ MySQL. It exposes semantic tools such as `billing.inspect_invoice` and
11
+ `billing.propose_late_fee_waiver`, saves risky changes as proposals, and keeps
12
+ database credentials, approval, and writeback outside the model-facing tool
13
+ surface.
14
14
 
15
- ```text
16
- Without Synapsor:
17
- agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")
18
- # raw write path, model-controlled scope, easy tenant mistake
15
+ ## Prove It In 60 Seconds
16
+
17
+ First, inspect the risk in a typical raw-SQL database MCP server. This works
18
+ even if you never adopt Runner:
19
19
 
20
- With Synapsor Runner:
21
- agent -> billing.propose_late_fee_waiver(invoice_id, reason)
22
- # proposal only
23
- human approves -> guarded writeback applies exactly one change
20
+ ```bash
21
+ npx -y @synapsor/runner audit --example dangerous-db-mcp
24
22
  ```
25
23
 
26
- Try the no-database quick demo:
24
+ Then see the proposal, approval boundary, evidence, and replay loop. It needs no
25
+ database, Docker, config file, MCP client, or Synapsor account:
27
26
 
28
27
  ```bash
29
28
  npx -y @synapsor/runner demo --quick
30
29
  ```
31
30
 
32
- You will see semantic tools instead of raw SQL, an exact proposal rather than
33
- an immediate write, approval/apply outside MCP, and a receipt/replay record.
34
-
35
- ## The Five-Line Model
31
+ The quick demo creates a fixture ledger at `./.synapsor/quick-demo.db`. It
32
+ teaches the boundary; it does not claim to test your database connection.
36
33
 
37
- Your agent talks to Synapsor Runner, not directly to your database.
38
- It can look: scoped reads through reviewed tools.
39
- It can suggest: saved proposals with evidence and exact diffs.
40
- It cannot commit: approval and writeback happen outside the model-facing tool.
41
- After writeback, Runner keeps receipts and replay so you can inspect what happened.
34
+ ## Safety Model
42
35
 
43
36
  ```text
44
37
  AI agent or MCP client
45
- (Claude, Cursor, OpenAI Agents SDK, LangGraph)
46
38
  |
47
- | calls reviewed MCP tool
39
+ | reviewed semantic tool
48
40
  v
49
41
  +--------------------------------+
50
42
  | Synapsor Runner MCP |
51
- | semantic capabilities only |
52
- | trusted tenant/principal ctx |
43
+ | trusted tenant/principal scope |
53
44
  | evidence + query audit |
45
+ | proposals, not direct writes |
54
46
  +--------------------------------+
55
47
  |
56
- | scoped read / guarded proposal
48
+ | scoped read / approved guarded writeback
57
49
  v
58
50
  +--------------------------------+
59
51
  | Your Postgres or MySQL |
60
52
  | source of truth |
61
53
  +--------------------------------+
62
54
 
63
- Local Runner store:
64
- evidence · query audit · proposals · receipts · replay
65
- ```
66
-
67
- Your database stays the source of truth. Synapsor Runner owns the
68
- model-facing boundary: what the agent can read, what it can propose, what
69
- evidence is saved, and what can later be reviewed or replayed.
70
-
71
- ## Start Here
72
-
73
- Run the guided quick demo first. It does not require Docker, a database, a
74
- config file, an MCP client, or a Synapsor Cloud account.
75
-
76
- ```bash
77
- npx -y @synapsor/runner demo --quick
78
- ```
79
-
80
- In a terminal, it walks through the safety model step by step. In CI, piped
81
- output, or other non-interactive mode, it prints a short summary and exits
82
- without waiting for Enter.
83
-
84
- That command creates a local ledger fixture at `./.synapsor/quick-demo.db`.
85
- It does not prove database connectivity. It shows the proposal, evidence, and
86
- replay flow without giving the runner a database URL.
87
-
88
- ```bash
89
- npx -y @synapsor/runner demo inspect
90
- ```
91
-
92
- Then choose one path:
93
-
94
- ```text
95
- Full disposable proof -> npx -y -p @synapsor/runner synapsor-runner demo
96
- Inspect MCP risk -> npx -y -p @synapsor/runner synapsor-runner audit --example dangerous-db-mcp
97
- ```
98
-
99
- Flagship example: [`examples/support-plan-credit`](examples/support-plan-credit)
100
- shows the contract policy path end to end: `$25` auto-approved by policy,
101
- `$100` held for local review, and `$1000` rejected by the reviewed bound before
102
- any proposal row exists.
103
-
104
- ## Why Not Just Build This Yourself?
105
-
106
- You can build the outline in an afternoon:
107
-
108
- ```text
109
- model calls a function
110
- -> app stores a pending change
111
- -> human approves
112
- -> app runs SQL
113
- ```
114
-
115
- That is useful, but it is not the safety layer. The repeated hard parts are
116
- tenant scope, no raw SQL exposure, evidence, query audit, exact diffs,
117
- approval outside the model-facing tool surface, idempotency, stale-row conflict
118
- checks, affected-row checks, receipts, and replay.
119
-
120
- Synapsor Runner gives you those pieces as a local runtime:
121
-
122
- - reviewed semantic capabilities instead of `execute_sql`;
123
- - trusted tenant/principal/object bindings from your server-side context;
124
- - scoped reads with evidence handles and query audit;
125
- - saved proposals with exact before/after changes;
126
- - approval and writeback commands that are not exposed to the model;
127
- - guarded direct writeback for one-row updates;
128
- - app-owned executors for richer writes;
129
- - idempotency receipts and replay so you can inspect what happened later.
130
-
131
- If all you need is restricted reads, a read-only database user and safe views
132
- are a good start. Use Runner when you need the agent-facing boundary around
133
- those reads, or when database-backed actions must become proposals before any
134
- durable write happens.
135
-
136
- ## More Than A Tool Proxy
137
-
138
- Synapsor is intentionally more than an MCP wrapper. The public packages include
139
- a versioned contract, DSL compiler, schema validation, conformance fixtures,
140
- Runner enforcement, proposal/evidence/replay artifacts, Cloud registry push,
141
- and C++/Cloud round-trip verification.
142
-
143
- ## Connect Your Postgres Or MySQL
144
-
145
- Use a staging or disposable database first:
146
-
147
- ```bash
148
- export DATABASE_URL="postgres://readonly:...@localhost:5432/app"
149
- npx -y -p @synapsor/runner synapsor-runner start --from-env DATABASE_URL
150
- ```
151
-
152
- The first-run path is:
153
-
154
- ```text
155
- 1. Inspect schema and generate a reviewed 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. Start review mode with up --serve or mcp serve.
159
- 5. Inspect, propose, approve, apply, and replay from the local ledger.
160
- ```
161
-
162
- Useful commands after setup:
163
-
164
- ```bash
165
- synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
166
- synapsor-runner smoke call --config ./synapsor.runner.json --store ./.synapsor/local.db
167
- synapsor-runner up --serve --config ./synapsor.runner.json --store ./.synapsor/local.db
168
- ```
169
-
170
- If you already have a canonical `synapsor.contract.json` from the DSL, Cloud,
171
- or the C++ exporter, keep it as the source of truth and reference it from local
172
- runner wiring:
173
-
174
- ```json
175
- {
176
- "version": 1,
177
- "mode": "review",
178
- "contracts": ["./synapsor.contract.json"],
179
- "sources": {
180
- "local_postgres": {
181
- "engine": "postgres",
182
- "read_url_env": "DATABASE_URL"
183
- }
184
- },
185
- "storage": {
186
- "sqlite_path": "./.synapsor/local.db"
187
- }
188
- }
189
- ```
190
-
191
- Preview the model-facing tool surface before connecting an MCP client:
192
-
193
- ```bash
194
- synapsor-runner contract validate ./synapsor.contract.json
195
- synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
55
+ Local SQLite ledger:
56
+ evidence -> proposal -> approval -> receipt -> replay
196
57
  ```
197
58
 
198
- ## What Runner Does
199
-
200
- When an agent uses Runner:
59
+ The model can inspect scoped data and propose an exact change. It cannot call
60
+ approval or apply tools. A human or trusted operator approves outside MCP, then
61
+ Runner either performs one guarded row update or routes the approved proposal
62
+ to an app-owned executor.
201
63
 
202
- - the model gets reviewed capabilities, not raw database authority;
203
- - reads produce evidence handles and query audit;
204
- - writes become proposals, not direct mutations;
205
- - approval and writeback happen outside the model-facing MCP surface;
206
- - replay shows what the agent saw, proposed, and what was applied or blocked.
207
-
208
- ## Four Terms
209
-
210
- - Capability: a tool you define in config, such as `billing.inspect_invoice`
211
- or `billing.propose_late_fee_waiver`. The agent only sees capabilities.
212
- - Proposal: the agent's suggested database-backed change. It is saved, not
213
- applied.
214
- - Writeback: the moment an approved proposal actually changes the database.
215
- - Executor: your app's writeback handler for anything richer than a guarded
216
- one-row update.
217
-
218
- You install only `@synapsor/runner`. There is no separate handler package to
219
- install. A handler is your app's endpoint or script for rich approved writes;
220
- Runner includes templates and examples to help you build one.
221
-
222
- ## Packages
223
-
224
- | Package | What it is |
225
- | --- | --- |
226
- | `@synapsor/runner` | The local runtime: CLI, MCP server, local store, evidence, proposals, approval, writeback, replay, and audit tools. |
227
- | `@synapsor/spec` | The canonical portable contract package for contexts, resources, capabilities, workflows, evidence, proposals, receipts, and replay. |
228
- | `@synapsor/dsl` | A SQL-like authoring layer that compiles `CREATE AGENT CONTEXT`, `CREATE CAPABILITY`, and `CREATE AGENT WORKFLOW` into `@synapsor/spec` JSON. |
229
-
230
- Use the runner when you want something to execute locally. Use the spec when
231
- you want a portable contract that Runner, Cloud, and the C++ engine can agree
232
- on. Use the DSL when you want to author that contract in a reviewable,
233
- database-style format.
234
-
235
- ## Author Your Contract
236
-
237
- For new capabilities, prefer the portable contract path:
238
-
239
- ```text
240
- contract.synapsor -> synapsor.contract.json -> synapsor.runner.json
241
- ```
64
+ ## Connect A Staging Database
242
65
 
243
- Example DSL:
244
-
245
- ```sql
246
- CREATE AGENT CONTEXT local_operator
247
- BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
248
- BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
249
- TENANT BINDING tenant_id
250
- PRINCIPAL BINDING principal
251
- END
252
-
253
- CREATE CAPABILITY billing.inspect_invoice
254
- DESCRIPTION 'Inspect one invoice in the trusted tenant before proposing a waiver.'
255
- RETURNS HINT 'Returns reviewed invoice fields plus evidence/query-audit handles.'
256
- USING CONTEXT local_operator
257
- SOURCE local_postgres
258
- ON public.invoices
259
- PRIMARY KEY id
260
- TENANT KEY tenant_id
261
- CONFLICT GUARD updated_at
262
- LOOKUP invoice_id BY id
263
- ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id such as INV-3001.'
264
- ALLOW READ id, tenant_id, status, late_fee_cents, updated_at
265
- REQUIRE EVIDENCE
266
- MAX ROWS 1
267
- END
268
-
269
- CREATE CAPABILITY billing.propose_late_fee_waiver
270
- DESCRIPTION 'Propose waiving one invoice late fee after inspecting invoice and policy evidence.'
271
- RETURNS HINT 'Returns a review-required proposal id, exact diff, evidence handle, and source_database_changed:false.'
272
- USING CONTEXT local_operator
273
- SOURCE local_postgres
274
- ON public.invoices
275
- PRIMARY KEY id
276
- TENANT KEY tenant_id
277
- CONFLICT GUARD updated_at
278
- LOOKUP invoice_id BY id
279
- ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id such as INV-3001.'
280
- ARG reason TEXT REQUIRED MAX LENGTH 500 DESCRIPTION 'Business reason for the proposed waiver.'
281
- ALLOW READ id, tenant_id, status, late_fee_cents, waiver_reason, updated_at
282
- REQUIRE EVIDENCE
283
- MAX ROWS 1
284
- PROPOSE ACTION waive_late_fee
285
- ALLOW WRITE late_fee_cents, waiver_reason
286
- PATCH late_fee_cents = 0
287
- PATCH waiver_reason = ARG reason
288
- BOUND late_fee_cents 0..10000
289
- APPROVAL ROLE billing_lead
290
- WRITEBACK DIRECT SQL
291
- END
292
- ```
293
-
294
- Compile, validate, and serve it:
295
-
296
- ```bash
297
- synapsor-runner dsl compile ./contract.synapsor --out ./synapsor.contract.json --strict
298
- synapsor-runner contract validate ./synapsor.contract.json
299
- synapsor-runner contract bundle ./synapsor.contract.json --out ./synapsor-runner-bundle
300
- synapsor-runner cloud push ./synapsor.contract.json --dry-run
301
- synapsor-runner cloud push ./synapsor.contract.json \
302
- --api-url "$SYNAPSOR_CLOUD_BASE_URL" \
303
- --token "$SYNAPSOR_CLOUD_TOKEN" \
304
- --workspace "$SYNAPSOR_PROJECT_ID" \
305
- --name billing-late-fee
306
- cd ./synapsor-runner-bundle
307
- cp .env.example .env # fill in and export your read-only database values
308
- synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
309
- ```
310
-
311
- `--strict` treats DSL safety warnings as errors, so CI catches proposal
312
- capabilities that are missing descriptions, returns hints, or numeric patch
313
- bounds.
314
-
315
- The `contract bundle` step generates `synapsor.runner.json` (with env-var
316
- placeholders) inside the bundle directory, which is why `mcp serve` runs from
317
- there. The server keeps stdout clean for MCP protocol frames and prints its
318
- ready line on stderr.
319
-
320
- See [`docs/dsl-json-parity.md`](docs/dsl-json-parity.md) for the current
321
- field-by-field support matrix across JSON spec, DSL, runner enforcement,
322
- C++/Cloud compatibility, and Cloud push.
323
-
324
- After a real push, open **Contract registry** in Synapsor Cloud to inspect the
325
- immutable version, semantic capabilities, workflows, visible and kept-out
326
- fields, policy references, warnings, and registry audit events. Downloading a
327
- runner bundle returns the same normalized contract with placeholder local
328
- wiring and ready-to-copy MCP configs.
329
-
330
- - [Cloud push](docs/cloud-push.md)
331
- - [Runner bundles](docs/runner-bundles.md)
332
- - [MCP client configs](docs/mcp-clients.md)
333
-
334
- Your `synapsor.runner.json` supplies local wiring: database env var names,
335
- SQLite store path, MCP transport settings, and local debug options. The
336
- contract supplies the portable meaning: contexts, capabilities, evidence,
337
- proposal shape, and writeback intent.
338
-
339
- ## Who Does What
340
-
341
- You write the config: sources, trusted context, capabilities, visible fields,
342
- proposal fields, and guards. For rich writes, you also write a small handler.
343
-
344
- Synapsor Runner serves the MCP tools, stores evidence/proposals/receipts,
345
- enforces tenant, column, version, and idempotency guards, routes writeback, and
346
- keeps the replay log. You do not rebuild the safety loop yourself.
347
-
348
- ## The Writeback Rule
349
-
350
- One-row update to an existing row: Runner can do guarded direct writeback.
351
- Anything else, such as inserting a row, touching two tables, or emitting an
352
- event: your app-owned executor does it after approval.
353
-
354
- ## How An External Handler Works
355
-
356
- Some changes are too rich for Runner's one-row writeback: insert a credit row,
357
- touch two tables, or emit an event. For those, you run a small endpoint. The
358
- flow is:
359
-
360
- ```text
361
- agent proposes
362
- -> human approves outside MCP
363
- -> Runner POSTs the approved change to your endpoint
364
- -> your code writes it in its own transaction and returns a receipt
365
- ```
366
-
367
- The model never touches this code. You are the last line of defense: Runner
368
- hands you the tenant, expected row version, and idempotency key, and your
369
- handler must re-check all three. Skipping those checks reintroduces
370
- cross-tenant writes, lost updates, or duplicate writes. Start from
371
- `synapsor-runner handler template ...` instead of hand-rolling the safety checks.
372
-
373
- ## Deliberate Limits
374
-
375
- Runner does not expose raw SQL, write credentials, approval tools, or commit
376
- tools to the model. Direct Runner writeback does not do generic `INSERT`,
377
- `DELETE`, `UPSERT`, DDL, or multi-row SQL. Those are app-owned executor jobs.
378
-
379
- ## Command Name
66
+ Start with a staging or disposable database and a read-only credential. Keep
67
+ database permissions, restricted views, and row-level security in place.
380
68
 
381
69
  ```bash
382
70
  npm install -g @synapsor/runner
383
- synapsor-runner demo --quick
384
- ```
385
-
386
- `synapsor-runner` is the public command for this OSS runner. `synapsor` is
387
- reserved for the Synapsor Cloud CLI. If you install the package globally, you
388
- can drop the `npx -y -p @synapsor/runner` prefix.
389
-
390
- Contributor note: during development, test local changes with
391
- `./bin/synapsor-runner ...` or a packed tarball. `npx -p @synapsor/runner ...`
392
- only tests the currently published package, not unpublished local source
393
- changes.
394
-
395
- Authoring reference:
396
-
397
- - [Migrating To `@synapsor/spec`](docs/migrating-to-synapsor-spec.md):
398
- split portable contract semantics from local runner wiring.
399
- - [Conformance Fixtures](docs/conformance.md): how the shared fixture suite
400
- keeps Runner and Cloud/C++ contract semantics from drifting.
401
- - [Capability Authoring](docs/capability-authoring.md): read/proposal tools,
402
- model-facing descriptions, result envelope v2, trusted context, and writeback
403
- guards.
404
- - [Result Envelope v2](docs/result-envelope-v2.md): stable
405
- `ok`/`summary`/`data`/`proposal`/`error` MCP tool results.
406
- - [JSON Schema](schemas/synapsor.runner.schema.json): editor validation for
407
- `synapsor.runner.json`.
408
-
409
- ## Operational Details
410
-
411
- These are current alpha requirements, not hidden behavior:
412
-
413
- - Writeback with `--config ./synapsor.runner.json` reads the trusted writer
414
- connection from the source `write_url_env`, for example
415
- `SYNAPSOR_DATABASE_WRITE_URL`. `SYNAPSOR_DATABASE_URL` is only the legacy
416
- fallback when you run direct worker/apply flows without a local config.
417
- - `synapsor-runner mcp serve` is standard stdio MCP for local clients that can
418
- launch Runner.
419
- - `synapsor-runner mcp serve-streamable-http` is standard MCP Streamable HTTP
420
- with `initialize` and in-memory session behavior for SDK/client HTTP MCP
421
- integrations.
422
- - OpenAI Agents SDK rejects dotted function/tool names. Use
423
- `--alias-mode openai` or `--openai-tool-aliases` for OpenAI-facing MCP
424
- transports. Runner exposes aliases such as `billing__inspect_invoice` and
425
- keeps the canonical Synapsor capability name in tool metadata.
426
- - `synapsor-runner mcp serve-http` is a small authenticated JSON-RPC bridge for
427
- `tools/list`, `tools/call`, and `resources/read`. Use it only when you want a
428
- simple app/server wrapper instead of full HTTP MCP.
429
- - Direct SQL writeback creates or writes `synapsor_writeback_receipts` for
430
- idempotency and replay. The trusted writer needs permission for that table,
431
- or an administrator must pre-create it and grant access. Use an app-owned
432
- `http_handler` or `command_handler` if Runner should not create receipt
433
- tables in your application schema.
434
- - Run `synapsor-runner doctor --config synapsor.runner.json --check-writeback`
435
- after reviewing receipt-table DDL/grants to verify writer connectivity,
436
- receipt-table permissions, and rollback-only target-table access. The probe
437
- never mutates business rows, but it can create the receipt table if the
438
- writer has permission.
439
- - For app-owned `http_handler` executors, configure `signing_secret_env` to
440
- have Runner sign writeback requests with `X-Synapsor-Signature`. Run
441
- `synapsor-runner doctor --config synapsor.runner.json --check-handlers` to
442
- check handler env vars and network reachability without applying a proposal.
443
-
444
- ## Run The Full Disposable Demo
445
-
446
- The full demo requires Docker. It starts a disposable local Postgres-backed app
447
- and proves the proposal-first write path:
448
-
449
- ```bash
450
- npx -y -p @synapsor/runner synapsor-runner demo
451
- ```
452
-
453
- For contributor/release verification from a checkout, the live apply smoke uses
454
- four disposable Postgres/MySQL scenarios and the official MCP stdio client
455
- transport:
456
-
457
- ```bash
458
- corepack pnpm test:live-apply
459
- ```
460
-
461
- It verifies semantic tool listing, proposal diffs, source rows unchanged before
462
- approval, guarded writeback, idempotent retry, stale-row conflict, receipts,
463
- replay, and the support-plan-credit policy tiers. See
464
- [`docs/local-mode.md`](docs/local-mode.md#local-mcp-smoke) for prerequisites and
465
- expected output.
466
-
467
- After the demo prints its generated config and store path, run the happy path it
468
- prints. The shape is:
469
-
470
- ```bash
471
- synapsor-runner propose billing.propose_late_fee_waiver --sample
472
- synapsor-runner proposals show latest
473
- synapsor-runner proposals approve latest --yes
474
- synapsor-runner apply latest
475
- synapsor-runner replay show latest
476
- synapsor-runner replay show latest --details
477
- ```
478
-
479
- What you should see:
480
-
481
- ```text
482
- Agent called:
483
- billing.propose_late_fee_waiver
484
-
485
- Proposal created:
486
- invoice.late_fee_cents
487
- 5500 -> 0
488
-
489
- Source DB changed:
490
- no
491
-
492
- Approval:
493
- required outside MCP
494
-
495
- After approval:
496
- guarded writeback applied
497
-
498
- Replay:
499
- saved
500
- ```
501
-
502
- That is the core point: the model can ask for a database-backed business
503
- change, but durable state changes only after reviewed approval and guarded
504
- writeback.
505
-
506
- ## Connect Your Own Staging Database
507
-
508
- Use this after the quick demo makes sense. Start with staging, a disposable
509
- database, or a least-privilege view. Do not start with your most sensitive
510
- production database.
511
-
512
- Put the read-only connection string in an environment variable:
513
-
514
- ```bash
515
- export DATABASE_URL="postgresql://readonly_user:password@host:5432/app?sslmode=require"
516
- ```
517
-
518
- For disposable dev RDS fixtures only, use `sslmode=no-verify` if your local
519
- Node/Postgres TLS stack cannot verify the test certificate chain. For real
520
- staging or production-like databases, keep certificate verification enabled.
521
-
522
- Run the guided own-database path:
523
-
524
- ```bash
525
- npx -y -p @synapsor/runner synapsor-runner start \
526
- --from-env DATABASE_URL \
527
- --schema public
528
- ```
529
-
530
- `start --from-env` is the low-friction alias for `onboard db --from-env`. That
531
- path inspects metadata, helps you choose one table/view, creates trusted
532
- context bindings, generates semantic MCP tools, validates the tool boundary,
533
- and prints the exact MCP/UI next commands. It does not require hand-authored
534
- JSON. If you provide an optional real object id during the wizard, it also
535
- writes `./.synapsor/smoke-input.json` so the first tool call can use an actual
536
- row instead of guessed sample data. When the read URL env var and trusted
537
- tenant/principal env vars are already set, onboarding also attempts that smoke
538
- call immediately and stores the evidence/query audit in the local ledger. If
539
- those env vars are missing, it prints the exact command to run after you set
540
- them from `.env.example`.
541
-
542
- Bring the generated review-mode workspace up with one command:
543
-
544
- ```bash
545
- npx -y -p @synapsor/runner synapsor-runner up \
546
- --serve \
547
- --config ./synapsor.runner.json \
548
- --store ./.synapsor/local.db
71
+ export DATABASE_URL="postgresql://runner_reader:REPLACE_ME@db.example.com:5432/app?sslmode=require"
72
+ synapsor-runner start --from-env DATABASE_URL --schema public
549
73
  ```
550
74
 
551
- `up` validates the config/store, summarizes model-facing tools, shows whether
552
- proposal tools use direct SQL writeback or app-owned executors, checks active
553
- store leases, and prints the next smoke, approve, apply, replay, UI, and doctor
554
- commands. By default, `up` is guidance-only. Use `up --serve` to start the
555
- standard Streamable HTTP MCP server after the checklist; use `--dry-run` to
556
- rehearse without starting it. For app-owned executor configs, add
557
- `--with-handler` to run the handler doctor before serving.
75
+ The guided command inspects metadata, asks you to choose one table or view,
76
+ creates trusted context, generates reviewed capabilities, previews the MCP tool
77
+ surface, and prints the next smoke and serve commands. It stores environment
78
+ variable names, not connection strings.
558
79
 
559
- For CI, shell scripts, or an LLM driving the setup, use the prompt-free path:
560
-
561
- ```bash
562
- npx -y -p @synapsor/runner synapsor-runner onboard db \
563
- --from-env DATABASE_URL \
564
- --schema public \
565
- --table invoices \
566
- --mode review \
567
- --tenant-column tenant_id \
568
- --primary-key id \
569
- --conflict-column updated_at \
570
- --namespace billing \
571
- --object-name invoice \
572
- --id-arg invoice_id \
573
- --visible-columns id,tenant_id,late_fee_cents,waiver_reason,updated_at \
574
- --patch late_fee_cents=fixed:0,waiver_reason=arg:reason \
575
- --patch-bounds late_fee_cents=0:5500 \
576
- --write-url-env SYNAPSOR_DATABASE_WRITE_URL \
577
- --yes
578
- ```
579
-
580
- If `--namespace` is omitted, Runner derives a namespace from the table name
581
- instead of creating `source.*` tools. Use `--read-tool` and `--proposal-tool`
582
- when you need exact model-facing names.
583
-
584
- For app-owned writeback, replace `--write-url-env ...` with
585
- `--writeback http_handler --handler-url-env APP_WRITEBACK_URL --emit-handler`.
586
- Runner marks that source as read-only unless you explicitly pass a writer env,
587
- so `config validate` does not warn that direct SQL writeback is disabled.
588
- You can also pass `--answers ./answers.json --yes` for a fully declarative
589
- setup file.
590
-
591
- The end-to-end shape is:
592
-
593
- ```text
594
- 1. Put your read-only DB URL in DATABASE_URL.
595
- 2. Run start --from-env DATABASE_URL.
596
- 3. Choose one table/view and the safe fields agents may see.
597
- 4. Preview the generated capabilities.
598
- 5. Serve them over MCP to Claude, Cursor, OpenAI Agents SDK, or your app.
599
- 6. For writes, approve a proposal outside MCP before writeback.
600
- ```
601
-
602
- The generated config is just the safety contract. A small reviewed version
603
- looks like this:
80
+ A minimal generated read-only configuration looks like this:
604
81
 
605
82
  ```json
606
83
  {
607
84
  "version": 1,
608
- "mode": "review",
85
+ "mode": "read_only",
609
86
  "result_format": 2,
87
+ "storage": { "sqlite_path": "./.synapsor/local.db" },
610
88
  "sources": {
611
89
  "app_postgres": {
612
90
  "engine": "postgres",
613
91
  "read_url_env": "DATABASE_URL",
614
- "write_url_env": "SYNAPSOR_DATABASE_WRITE_URL"
92
+ "statement_timeout_ms": 3000
615
93
  }
616
94
  },
617
95
  "trusted_context": {
@@ -633,783 +111,89 @@ looks like this:
633
111
  "tenant_key": "tenant_id"
634
112
  },
635
113
  "args": {
636
- "invoice_id": { "type": "string", "required": true }
114
+ "invoice_id": { "type": "string", "required": true, "max_length": 128 }
637
115
  },
638
116
  "lookup": { "id_from_arg": "invoice_id" },
639
- "visible_columns": ["id", "status", "late_fee_cents", "updated_at"],
117
+ "visible_columns": ["id", "tenant_id", "status", "late_fee_cents", "updated_at"],
640
118
  "evidence": "required",
641
119
  "max_rows": 1
642
- },
643
- {
644
- "name": "billing.propose_late_fee_waiver",
645
- "kind": "proposal",
646
- "source": "app_postgres",
647
- "target": {
648
- "schema": "public",
649
- "table": "invoices",
650
- "primary_key": "id",
651
- "tenant_key": "tenant_id"
652
- },
653
- "args": {
654
- "invoice_id": { "type": "string", "required": true },
655
- "reason": { "type": "string", "required": true }
656
- },
657
- "lookup": { "id_from_arg": "invoice_id" },
658
- "visible_columns": ["id", "status", "late_fee_cents", "updated_at"],
659
- "patch": {
660
- "late_fee_cents": { "fixed": 0 },
661
- "waiver_reason": { "from_arg": "reason" }
662
- },
663
- "allowed_columns": ["late_fee_cents", "waiver_reason"],
664
- "conflict_guard": { "column": "updated_at" },
665
- "approval": { "mode": "human", "required_role": "billing_lead" }
666
120
  }
667
121
  ]
668
122
  }
669
123
  ```
670
124
 
671
- The agent sees `billing.inspect_invoice` and
672
- `billing.propose_late_fee_waiver`. It does not see the database URL, writer
673
- credential, raw SQL, approval command, or commit command.
674
-
675
- Prefer the step-by-step commands if you want to inspect each stage manually:
676
-
677
- ```bash
678
- npx -y -p @synapsor/runner synapsor-runner inspect \
679
- --engine auto \
680
- --from-env DATABASE_URL \
681
- --schema public
682
-
683
- npx -y -p @synapsor/runner synapsor-runner init --wizard --from-env DATABASE_URL --mode read_only
684
- ```
685
-
686
- The wizard creates this local flow:
687
-
688
- ```text
689
- trusted context -> capability -> MCP tool
690
- ```
691
-
692
- It asks which table/view backs the context, which tenant/scope column and
693
- backend session env vars are trusted, which fields are visible, and what
694
- semantic capability name to expose. Before writing files, it shows a final
695
- preview and lets you revise visible fields or capability names. It writes
696
- `synapsor.runner.json`, `.env.example`, and MCP client snippets. It does not put
697
- your database URL in the MCP client config.
698
-
699
- Preview the tools:
700
-
701
- ```bash
702
- npx -y -p @synapsor/runner synapsor-runner tools preview \
703
- --config ./synapsor.runner.json \
704
- --store ./.synapsor/local.db
705
- ```
706
-
707
- Call one generated tool locally before wiring an MCP client:
708
-
709
- ```bash
710
- npx -y -p @synapsor/runner synapsor-runner smoke call \
711
- <generated.inspect_tool_name> \
712
- --input ./.synapsor/smoke-input.json \
713
- --config ./synapsor.runner.json \
714
- --store ./.synapsor/local.db
715
- ```
716
-
717
- `smoke call` uses the same runtime as MCP, records evidence/query audit or a
718
- proposal in the local store, and then prints the evidence/proposal/replay
719
- commands to inspect what happened. If you skipped the optional smoke input in
720
- the wizard, pass one real row id instead:
721
-
722
- ```bash
723
- npx -y -p @synapsor/runner synapsor-runner smoke call \
724
- <generated.inspect_tool_name> \
725
- --json '{"<lookup_arg>":"<real_id>"}' \
726
- --config ./synapsor.runner.json \
727
- --store ./.synapsor/local.db
728
- ```
729
-
730
- Serve the semantic MCP tools locally:
731
-
732
- ```bash
733
- npx -y -p @synapsor/runner synapsor-runner mcp serve \
734
- --config ./synapsor.runner.json \
735
- --store ./.synapsor/local.db
736
- ```
737
-
738
- ## Three Ways To Run MCP
739
-
740
- Use stdio when the MCP client runs locally and can launch Synapsor Runner. Use
741
- Streamable HTTP when a standard HTTP MCP client connects to a long-running
742
- Runner process. Use the JSON-RPC bridge only when you want simple POST calls
743
- from your own app/server wrapper.
744
-
745
- Local MCP clients:
746
-
747
- ```bash
748
- synapsor-runner mcp serve \
749
- --config ./synapsor.runner.json \
750
- --store ./.synapsor/local.db
751
- ```
752
-
753
- For OpenAI Agents SDK over stdio, add OpenAI-safe aliases:
754
-
755
- ```bash
756
- synapsor-runner mcp serve \
757
- --config ./synapsor.runner.json \
758
- --store ./.synapsor/local.db \
759
- --alias-mode openai
760
- ```
761
-
762
- App/server deployments:
763
-
764
- ```bash
765
- export SYNAPSOR_RUNNER_HTTP_TOKEN="dev-local-token"
766
-
767
- synapsor-runner mcp serve-streamable-http \
768
- --config ./synapsor.runner.json \
769
- --store ./.synapsor/local.db \
770
- --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
771
- --alias-mode openai
772
- ```
773
-
774
- You can also start the same review-mode server through the safer startup
775
- checklist:
776
-
777
- ```bash
778
- synapsor-runner up --serve \
779
- --config ./synapsor.runner.json \
780
- --store ./.synapsor/local.db \
781
- --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
782
- --alias-mode openai
783
- ```
784
-
785
- The same Streamable HTTP server can also be started through the unified serve
786
- command:
787
-
788
- ```bash
789
- synapsor-runner mcp serve \
790
- --transport streamable-http \
791
- --config ./synapsor.runner.json \
792
- --store ./.synapsor/local.db \
793
- --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
794
- --alias-mode openai
795
- ```
796
-
797
- Streamable HTTP defaults to `127.0.0.1:8766`, requires bearer auth by default,
798
- and should use private networking, TLS, and rate limits before being exposed
799
- beyond a local machine. With `--alias-mode openai`, tools are exposed to
800
- the model as OpenAI-safe aliases such as `billing__inspect_invoice`; `_meta`
801
- still includes `synapsor.canonical_tool_name = billing.inspect_invoice`, and
802
- Runner routes calls back to the canonical Synapsor capability. Use
803
- `--alias-mode both` during migrations if one client still expects canonical
804
- dotted names while another needs OpenAI-safe aliases.
805
-
806
- Bridge mode:
807
-
808
- ```bash
809
- synapsor-runner mcp serve-http \
810
- --config ./synapsor.runner.json \
811
- --store ./.synapsor/local.db \
812
- --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
813
- ```
814
-
815
- Bridge HTTP defaults to `127.0.0.1:8765` and supports only JSON-RPC
816
- `tools/list`, `tools/call`, and `resources/read`. It does not implement MCP
817
- Streamable HTTP `initialize`/session behavior.
818
-
819
- OpenAI Agents SDK examples:
820
-
821
- ```text
822
- examples/openai-agents-stdio/
823
- examples/openai-agents-http/
824
- ```
825
-
826
- Detailed setup: [docs/openai-agents-sdk.md](docs/openai-agents-sdk.md).
827
-
828
- Use `--mode review` only when you are ready to create proposal tools and test
829
- guarded writeback. Review mode needs an approved write path and a separate
830
- trusted write credential; the model-facing read URL should stay least
831
- privilege.
832
-
833
- ## Audit Your MCP Database Tools
834
-
835
- `synapsor-runner audit` is a static MCP/database risk review. It is useful even before
836
- you adopt the full runner.
837
-
838
- ```bash
839
- synapsor-runner audit --example dangerous-db-mcp
840
- synapsor-runner audit --example dangerous-db-mcp --format markdown
841
- synapsor-runner audit ./synapsor.runner.json
842
- synapsor-runner audit --mcp-config ./claude_desktop_config.json
843
- synapsor-runner audit --stdio "node ./my-db-mcp-server.js"
844
- ```
845
-
846
- The built-in example runs without cloning this repository or downloading an
847
- examples file. File-based audits still work when you have your own exported MCP
848
- tool manifest.
849
-
850
- It looks for patterns such as:
851
-
852
- - arbitrary SQL tools;
853
- - broad database write tools;
854
- - model-facing approval/commit tools;
855
- - missing tenant/principal context;
856
- - dangerous tool names;
857
- - unclear parameter schemas;
858
- - mutation tools without proposal/approval.
859
-
860
- Example finding:
861
-
862
- ```text
863
- Risk: high
864
-
865
- Found:
866
- - execute_sql appears to expose arbitrary database access.
867
- - approve_refund appears to let the model approve a durable write.
868
- - update_customer appears to mutate state without a proposal boundary.
869
- - No trusted tenant/principal context was detected.
870
-
871
- Suggested safer shape:
872
- - billing.inspect_invoice
873
- - billing.propose_late_fee_waiver
874
- - approval outside MCP
875
- - guarded writeback after approval
876
-
877
- Note:
878
- This is a static risk review, not a security guarantee.
879
- ```
880
-
881
- ## Why Not Just Use A Read-Only Database User?
882
-
883
- You should use one.
884
-
885
- Synapsor Runner is not a replacement for least-privilege database permissions.
886
- Start with a read-only user, restricted views, row-level security, and staging
887
- data where appropriate.
888
-
889
- The difference is that database permissions protect the connection. Synapsor
890
- Runner shapes the model-facing interface.
891
-
892
- Instead of exposing `execute_sql`, `query_database`, table names, or
893
- model-controlled tenant filters, Synapsor exposes reviewed business
894
- capabilities such as `billing.inspect_invoice` and
895
- `billing.propose_late_fee_waiver`.
896
-
897
- For read-only use cases, Runner provides scoped semantic tools, trusted context
898
- binding, evidence handles, query audit, and local inspection. Proposal
899
- workflows add full replay across evidence, approval, writeback receipts, and
900
- events.
901
-
902
- If all you need is restricted reads, database permissions are a good start.
903
- Use Synapsor Runner when you also want the agent-facing layer: semantic tools,
904
- trusted context, evidence handles, query audit, local inspection, and
905
- proposal-first writes.
906
-
907
- ## Find Evidence And Replay
908
-
909
- The commands in this section require this checkout or an alpha package that
910
- includes the local-ledger CLI surface.
911
-
912
- Synapsor Runner writes a local evidence/replay ledger to SQLite. Use it to
913
- answer questions such as:
914
-
915
- ```text
916
- What did the agent see and do for invoice INV-3001?
917
- ```
918
-
919
- Search the local activity ledger:
920
-
921
- ```bash
922
- synapsor-runner activity search --tenant acme --object invoice:INV-3001
923
- synapsor-runner activity search --capability billing.propose_late_fee_waiver --from 2026-06-01 --to 2026-06-23
924
- synapsor-runner events tail --store ./.synapsor/local.db
925
- synapsor-runner events webhook --url http://127.0.0.1:8788/synapsor/events --kind proposal_created --store ./.synapsor/local.db
926
- ```
927
-
928
- Inspect the linked records:
929
-
930
- ```bash
931
- synapsor-runner proposals list --tenant acme --object invoice:INV-3001 --status approved
932
- synapsor-runner evidence show ev_...
933
- synapsor-runner query-audit list --evidence ev_...
934
- synapsor-runner receipts list --proposal wrp_...
935
- synapsor-runner receipts show <receipt_id>
936
- synapsor-runner replay show --proposal wrp_...
937
- synapsor-runner replay show --replay replay_wrp_...
938
- ```
939
-
940
- The default views answer what happened, whether the source DB changed, the
941
- current status, and the next command to run. Add `--details` when you need
942
- target URIs, primary keys, proposal hash/version, conflict guards, query
943
- fingerprints, event timestamps, or receipt internals.
944
-
945
- Export replay or evidence for review:
946
-
947
- ```bash
948
- synapsor-runner replay export --proposal wrp_... --format json --output replay.json
949
- synapsor-runner replay export --proposal wrp_... --format markdown --output replay.md
950
- synapsor-runner evidence export ev_... --format markdown --output evidence.md
951
- ```
952
-
953
- Create a redacted local diagnostic report:
954
-
955
- ```bash
956
- synapsor-runner doctor --config synapsor.runner.json --report --redact --output synapsor-doctor.md
957
- synapsor-runner doctor --config synapsor.runner.json --check-writeback
958
- ```
959
-
960
- Inspect or compact the local ledger:
961
-
962
- ```bash
963
- synapsor-runner store stats --store ./.synapsor/local.db
964
- synapsor-runner events tail --store ./.synapsor/local.db --follow
965
- synapsor-runner events webhook --url-env SYNAPSOR_EVENT_WEBHOOK_URL --auth-token-env SYNAPSOR_EVENT_WEBHOOK_TOKEN --follow --store ./.synapsor/local.db
966
- synapsor-runner store vacuum --store ./.synapsor/local.db
967
- synapsor-runner store prune --store ./.synapsor/local.db --older-than 30d --dry-run
968
- synapsor-runner store reset --store ./.synapsor/local.db --yes
969
- ```
970
-
971
- `events webhook` is a local/dev/staging convenience for review UIs, Slack
972
- bridges, or app-local notifications. It POSTs one redacted local event envelope
973
- per lifecycle event; it is not a hosted central ledger.
974
-
975
- This is local indexed search for local/dev/staging usage. It is not a hosted
976
- central ledger, not RBAC/SSO, not cross-runner search, and not compliance
977
- retention. Synapsor Cloud adds a shared contract registry and enabled hosted
978
- activity/evidence surfaces; confirm retention and production operations for
979
- the specific design-partner deployment.
980
-
981
- ## Connect Claude, Cursor, Or Another MCP Client
982
-
983
- Generate a local MCP client snippet:
984
-
985
- ```bash
986
- synapsor-runner mcp config --config ./synapsor.runner.json --store ./.synapsor/local.db
987
- ```
988
-
989
- Use a specific client shape when needed:
990
-
991
- ```bash
992
- synapsor-runner mcp config cursor --config ./synapsor.runner.json --store ./.synapsor/local.db
993
- synapsor-runner mcp config vscode --config ./synapsor.runner.json --store ./.synapsor/local.db
994
- synapsor-runner mcp config generic --config ./synapsor.runner.json --store ./.synapsor/local.db
995
- synapsor-runner mcp client-config --client openai-agents --config ./synapsor.runner.json --store ./.synapsor/local.db
996
- ```
997
-
998
- The generated config references the local runner command. It does not include:
999
-
1000
- - database URL;
1001
- - database password;
1002
- - write credentials;
1003
- - approval tools;
1004
- - commit/apply tools.
1005
-
1006
- ## Sanity Check The Agent Connection
1007
-
1008
- After you connect Claude, Cursor, OpenAI Agents SDK, or another MCP client, run
1009
- one tiny tool-call test before asking the agent to solve a real task.
1010
-
1011
- First preview the tools Runner will expose:
125
+ Set the trusted values in the process that launches Runner, then validate and
126
+ preview the exact model-facing boundary before connecting an MCP client:
1012
127
 
1013
128
  ```bash
129
+ export SYNAPSOR_TENANT_ID="acme"
130
+ export SYNAPSOR_PRINCIPAL="local-developer"
131
+ synapsor-runner config validate --config ./synapsor.runner.json
1014
132
  synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
133
+ synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
1015
134
  ```
1016
135
 
1017
- For OpenAI-facing clients, preview the model-visible aliases:
1018
-
1019
- ```bash
1020
- synapsor-runner tools preview \
1021
- --config ./synapsor.runner.json \
1022
- --store ./.synapsor/local.db \
1023
- --alias-mode openai
1024
- ```
1025
-
1026
- Example:
1027
-
1028
- ```text
1029
- Exposed to MCP:
1030
- - billing__inspect_invoice -> billing.inspect_invoice
1031
- ```
1032
-
1033
- Then ask the agent:
1034
-
1035
- ```text
1036
- Use the Synapsor Runner MCP tool to inspect invoice INV-3001.
1037
- Do not answer from memory.
1038
- Return the tool name called, the evidence handle, and whether raw SQL was available.
1039
- ```
1040
-
1041
- For your own database, replace `invoice INV-3001` with one real object ID and
1042
- the semantic tool name from `tools preview`.
1043
-
1044
- Expected result:
1045
-
1046
- - the agent calls a Synapsor Runner tool such as `billing.inspect_invoice`;
1047
- - the response includes an evidence handle or local ledger reference;
1048
- - the agent says raw SQL/write/approval tools were not available.
1049
-
1050
- If the agent gives generic advice, a freeform summary, or unrelated planning
1051
- text without a tool call or evidence handle, Runner is not in the loop yet. Fix
1052
- the MCP client config, restart the client, confirm trusted context environment
1053
- variables are set, and rerun `synapsor-runner tools preview`.
1054
-
1055
- ## What The Model Gets
1056
-
1057
- The model gets reviewed semantic capabilities from `synapsor.runner.json`, for
1058
- example:
1059
-
1060
- ```text
1061
- billing.inspect_invoice
1062
- billing.propose_late_fee_waiver
1063
- support.inspect_ticket
1064
- support.propose_plan_credit
1065
- orders.inspect_order
1066
- orders.propose_status_change
1067
- ```
1068
-
1069
- These are business tools with trusted scope, visible fields, evidence rules,
1070
- proposal boundaries, and writeback guards.
1071
-
1072
- ## Fixture Benchmark
1073
-
1074
- Run the included MCP efficiency fixture:
1075
-
1076
- ```bash
1077
- synapsor-runner benchmark mcp-efficiency
1078
- ```
1079
-
1080
- Current fixture result for the late-fee-waiver workflow:
1081
-
1082
- ```text
1083
- Generic database MCP reference:
1084
- exposed tools: 4
1085
- scripted tool calls: 5
1086
- raw SQL exposed: yes
1087
- approval separated: no
1088
- stale-row conflict checked: no
1089
-
1090
- Synapsor Runner semantic path:
1091
- exposed tools: 2
1092
- scripted tool calls: 2
1093
- raw SQL exposed: no
1094
- approval separated: yes
1095
- stale-row conflict checked: yes
1096
- ```
1097
-
1098
- The fixture tokenizer is deterministic and repeatable for this repo. It is not
1099
- a model billing tokenizer and not a universal token-savings claim.
1100
-
1101
- ## Safe Write Examples
1102
-
1103
- The disposable reference app includes three proposal-first write shapes:
1104
-
1105
- - `billing.propose_late_fee_waiver`: waive a late fee after evidence and review.
1106
- - `support.propose_plan_credit`: propose a bounded customer credit for a support case.
1107
- - `orders.propose_status_change`: move an order through an allowlisted status transition.
1108
-
1109
- Each tool creates evidence, a before/after diff, and a local proposal. The
1110
- source database is unchanged until approval outside MCP and guarded writeback.
1111
-
1112
- ## What The Model Never Gets
1113
-
1114
- Synapsor Runner does not expose:
1115
-
1116
- ```text
1117
- execute_sql
1118
- raw_sql
1119
- query_database
1120
- database URLs
1121
- write credentials
1122
- approval tools
1123
- commit/apply tools
1124
- arbitrary table names
1125
- arbitrary column names
1126
- model-controlled tenant authority
1127
- direct write access
1128
- ```
1129
-
1130
- Approval and writeback stay outside the model-facing MCP tool surface.
1131
-
1132
- ## App-Owned Writeback
1133
-
1134
- Direct guarded DB writeback is useful for local/staging demos and simple
1135
- single-row updates. If your application service already owns business writes,
1136
- configure an `http_handler` or `command_handler` executor instead.
1137
-
1138
- The flow stays the same: model-facing MCP creates a proposal, approval happens
1139
- outside MCP, Synapsor Runner sends an approved job to your app handler, and the
1140
- handler returns an applied/conflict/failed receipt for replay.
1141
-
1142
- > **Important:** your app handler owns the final business write. Runner creates
1143
- > the proposal and calls your handler only after approval, but your handler must
1144
- > still enforce tenant/scope checks, expected-version or conflict guards,
1145
- > idempotency keys, allowed business actions, transaction/rollback, and safe
1146
- > error receipts. If you skip those checks, you can reintroduce cross-tenant
1147
- > writes, lost updates, or duplicate writes. Keep handler credentials out of MCP.
1148
-
1149
- Details: [docs/writeback-executors.md](docs/writeback-executors.md). Starter
1150
- handlers live in [examples/app-owned-writeback](examples/app-owned-writeback).
1151
- The runner npm package includes handler templates and the
1152
- `examples/mcp-postgres-billing-app-handler/synapsor-handler.mjs` bundled helper
1153
- shim. These show bearer/HMAC auth, tenant scope, expected-version guards,
1154
- idempotency, transaction rollback, and safe receipts around your business
1155
- effect. There is no separate handler package to install.
1156
- The full Postgres billing example in
1157
- [examples/mcp-postgres-billing-app-handler](examples/mcp-postgres-billing-app-handler)
1158
- shows `billing.propose_account_credit` creating a proposal first, then inserting
1159
- an `account_credits` row through an app-owned HTTP handler after approval.
1160
- You can also generate a starter handler directly:
1161
-
1162
- ```bash
1163
- npx -y -p @synapsor/runner synapsor-runner handler template node-fastify \
1164
- --output ./synapsor-writeback-handler.mjs
1165
- ```
1166
-
1167
- For direct SQL writeback, set the writer env var named by the source
1168
- `write_url_env`, for example `SYNAPSOR_DATABASE_WRITE_URL`. Runner also creates
1169
- or writes `synapsor_writeback_receipts` for idempotency/replay, so the writer
1170
- needs permission for that receipt table or an administrator must pre-create and
1171
- grant it. Use app-owned handlers when you do not want Runner creating receipt
1172
- tables in your application schema.
1173
-
1174
- ## Safety Model
1175
-
1176
- ```text
1177
- MCP client
1178
- -> Synapsor Runner
1179
- -> semantic capability
1180
- -> trusted tenant/principal context
1181
- -> scoped DB read
1182
- -> evidence-backed proposal
1183
- -> approval outside MCP
1184
- -> guarded writeback
1185
- -> receipt and replay
1186
- ```
1187
-
1188
- Current boundaries:
1189
-
1190
- - no generic SQL tools;
1191
- - no model-facing approval or apply tools;
1192
- - tenant/principal scoping is enforced;
1193
- - allowed columns are enforced;
1194
- - primary-key targeting is required;
1195
- - conflict/version guards are available;
1196
- - idempotency keys are used;
1197
- - affected row count is checked;
1198
- - direct DB writeback is limited to guarded single-row `UPDATE`.
136
+ For proposal capabilities and writes, follow the
137
+ [complete own-database guide](docs/getting-started-own-database.md). One-row
138
+ updates can use Runner's guarded direct writeback. Inserts, multiple tables, or
139
+ external effects go through an [app-owned executor](docs/writeback-executors.md)
140
+ after approval.
1199
141
 
1200
- ## Safety Checks It Catches
142
+ ## Trust And Verification
1201
143
 
1202
- After the happy path, use the demo and tests to inspect failure cases:
144
+ Start with the **[Threat Model](THREAT_MODEL.md)**. It defines protected assets,
145
+ trust boundaries, covered threats, non-goals, and required operator controls.
1203
146
 
1204
- - stale-row conflict;
1205
- - missing tenant context;
1206
- - disallowed write column;
1207
- - model-facing commit or approval tool;
1208
- - arbitrary SQL tool.
147
+ - [Conformance fixtures](docs/conformance.md) prove trusted context, scoped
148
+ reads, kept-out fields, proposal boundaries, approval, receipts, and replay
149
+ behavior rather than only validating JSON shape.
150
+ - `corepack pnpm test:live-apply` runs disposable Postgres and MySQL scenarios.
151
+ It proves source rows stay unchanged before approval, guarded writeback
152
+ applies once, idempotent retry does not duplicate the effect, and a stale row
153
+ returns a conflict.
154
+ - The C++/Cloud round-trip verifier exports normalized contracts, validates
155
+ them with `@synapsor/spec`, and loads them in Runner. The shared contract and
156
+ verification commands are documented in [Conformance](docs/conformance.md).
1209
157
 
1210
- The important stale-row case:
1211
-
1212
- ```text
1213
- The row changed after the agent saw it.
1214
- Result: conflict
1215
- Source DB changed by Synapsor: no
1216
- ```
158
+ Runner is a narrow agent/database safety boundary, not a replacement for
159
+ least-privilege database access, host security, or application authorization.
160
+ See [Security Boundary](docs/security-boundary.md) and
161
+ [Current Limitations](docs/limitations.md).
1217
162
 
1218
- Conflict handling is a safety check, not the first demo payoff.
1219
-
1220
- ## Local Features
163
+ ## Packages
1221
164
 
1222
- | Feature | Runner version |
165
+ | Package | Purpose |
1223
166
  | --- | --- |
1224
- | Context bindings | Trusted tenant/principal from env, static dev config, HTTP claims, or cloud session |
1225
- | Capabilities | Local semantic MCP tools from `synapsor.runner.json` |
1226
- | Evidence | Local evidence bundles and query audit records |
1227
- | Proposals | Local before/after change sets |
1228
- | Approval | Local CLI/UI approval outside MCP |
1229
- | Writeback | Guarded single-row `UPDATE` for Postgres/MySQL |
1230
- | Replay | Local replay of proposal, evidence, events, receipts, and query audit |
1231
- | MCP audit | Static risk review for MCP database tools |
1232
-
1233
- The runner intentionally does not include full Synapsor Cloud/DBMS features such
1234
- as workflow DAGs, native branches, time travel, settlement policies, governed
1235
- memory, RBAC/SSO, hosted evidence ledger, managed runners, CDC, or C++ DBMS
1236
- internals.
1237
-
1238
- ## Local Runner Vs Synapsor Cloud
1239
-
1240
- | Need | Synapsor Runner | Synapsor Cloud |
1241
- | --- | --- | --- |
1242
- | Local MCP server | Yes | Contracts export back to Runner; a managed fleet is not claimed |
1243
- | Local trusted context bindings | Yes | Contract bindings are registered; hosted session behavior is pilot-specific |
1244
- | Local semantic capabilities | Yes | Hosted registry + versioning |
1245
- | Local evidence/proposal/replay | Yes | Central searchable ledger |
1246
- | Local approval | CLI/UI | Existing team approval surfaces where enabled for a pilot |
1247
- | Writeback | Guarded single-row `UPDATE` | Cloud-linked jobs exist; managed production orchestration is not claimed |
1248
- | MCP risk audit | Static/local | Continuous/org-wide |
1249
- | RBAC/SSO | No | RBAC where configured; SAML/SCIM are not in this beta |
1250
- | Policy packs | Local reviewed subset | Registry preserves policies; hosted enforcement is not implied |
1251
- | Workflow builder | No | Existing Cloud authoring surfaces; full public DAG parity is not claimed |
1252
- | Native branches/time travel | No | Yes |
1253
- | Settlement policies | No | Yes |
1254
- | Compliance exports | No | Audit/retention primitives exist; legal hold/certification are not claimed |
1255
- | Production support/SLA | No | Design-partner support; no enterprise SLA is claimed |
1256
-
1257
- The runner is useful by itself for local/staging safety. Synapsor Cloud adds a
1258
- shared contract registry, immutable versions, downloadable Runner bundles, and
1259
- existing team activity/evidence/approval surfaces where enabled. Managed
1260
- runners, SAML/SCIM, legal hold, and an enterprise SLA remain future work.
1261
-
1262
- Portable contracts can be checked locally before Cloud import:
1263
-
1264
- ```bash
1265
- synapsor-runner contract validate ./synapsor.contract.json
1266
- synapsor-runner contract bundle ./synapsor.contract.json --out ./synapsor-runner-bundle
1267
- synapsor-runner cloud push ./synapsor.contract.json --dry-run
1268
- synapsor-runner cloud push ./synapsor.contract.json \
1269
- --api-url "$SYNAPSOR_CLOUD_BASE_URL" \
1270
- --token "$SYNAPSOR_CLOUD_TOKEN" \
1271
- --workspace "$SYNAPSOR_PROJECT_ID" \
1272
- --name billing-late-fee
1273
- ```
1274
-
1275
- ## Current Limitations
1276
-
1277
- Supported in the current `0.1.x` line:
1278
-
1279
- - stdio MCP server;
1280
- - authenticated HTTP MCP server for app/server deployments;
1281
- - Postgres/MySQL inspection;
1282
- - semantic read tools;
1283
- - evidence-backed proposals;
1284
- - local approval outside MCP;
1285
- - guarded single-row `UPDATE`;
1286
- - local SQLite evidence/proposal/replay store;
1287
- - tenant, primary-key, allowed-column, idempotency, and conflict guards;
1288
- - static MCP risk audit.
1289
-
1290
- Not supported:
1291
-
1292
- - raw `execute_sql`;
1293
- - model-generated SQL;
1294
- - DDL;
1295
- - INSERT;
1296
- - DELETE;
1297
- - UPSERT;
1298
- - multi-row writes;
1299
- - stored procedures;
1300
- - physical branching of external Postgres/MySQL;
1301
- - full Synapsor workflow DAG execution;
1302
- - Synapsor SQL generation;
1303
- - auto-merge or settlement-policy semantics;
1304
- - model-callable approval or commit tools;
1305
- - general prompt-injection prevention;
1306
- - production SLA or compliance certification.
1307
-
1308
- Contract and DSL authoring can declare workflows and allowed capabilities with
1309
- `CREATE AGENT WORKFLOW`. Runner 0.1 validates, bundles, and surfaces those
1310
- contracts, but it does not execute full Synapsor Cloud workflow DAGs,
1311
- auto-merge, settlement policies, or native branching.
1312
-
1313
- Complete limits: [docs/limitations.md](docs/limitations.md).
1314
-
1315
- Security boundary: [docs/security-boundary.md](docs/security-boundary.md).
167
+ | `@synapsor/runner` | CLI, MCP runtime, local ledger, proposals, approval, guarded writeback, replay, and MCP audit. |
168
+ | `@synapsor/spec` | Canonical portable contracts for contexts, capabilities, workflows, evidence, proposals, receipts, and replay. |
169
+ | `@synapsor/dsl` | SQL-like authoring that compiles contexts, capabilities, and workflow declarations into canonical contract JSON. |
1316
170
 
1317
- Single-node production-candidate runbook:
1318
- [docs/production.md](docs/production.md).
171
+ Runner executes locally. The spec is the portable contract shared by Runner
172
+ and Cloud/C++. The DSL gives that contract a reviewable source format. Start
173
+ with [Capability Authoring](docs/capability-authoring.md).
1319
174
 
1320
- Release notes and stable-tag policy:
1321
- [docs/release-notes.md](docs/release-notes.md).
175
+ ## OSS And Cloud
1322
176
 
1323
- ## Stable Compatibility Promise
177
+ Synapsor Runner works by itself for local and single-node deployments: your
178
+ database remains the source of truth and the local SQLite ledger stores review
179
+ artifacts. Synapsor Cloud adds a shared contract registry, immutable versions,
180
+ downloadable Runner bundles, and team activity, evidence, and approval
181
+ surfaces. See [OSS Runner vs Synapsor Cloud](docs/oss-vs-cloud.md) for the
182
+ detailed boundary.
1324
183
 
1325
- Starting with `0.1.0`, Synapsor Runner keeps the following surfaces compatible
1326
- through the `0.1.x` line unless a release note explicitly marks a deprecation
1327
- first:
184
+ ## Next Steps
1328
185
 
1329
- - the `synapsor-runner` binary name and README quickstart commands;
1330
- - `synapsor.runner.json` schema version `1` for documented fields;
1331
- - result envelope v2 for new configs, with the documented v1 opt-out;
1332
- - stdio MCP and Streamable HTTP MCP command surfaces;
1333
- - generated MCP client snippets for documented clients;
1334
- - proposal, approval, guarded writeback, receipt, evidence, query-audit, and
1335
- replay inspection commands;
1336
- - direct SQL writeback and app-owned executor contracts documented in this
1337
- README and `docs/writeback-executors.md`.
1338
-
1339
- Stable does not mean production SLA, hosted Cloud features, compliance
1340
- certification, physical Postgres/MySQL branching, generic SQL writeback, or
1341
- support for undocumented local SQLite internals. Those limits remain explicit
1342
- in [docs/limitations.md](docs/limitations.md).
186
+ - Run the [`support-plan-credit` flagship example](examples/support-plan-credit).
187
+ - Connect [Claude, Cursor, OpenAI Agents SDK, or another MCP client](docs/mcp-clients.md).
188
+ - Author and [push a validated contract to Cloud](docs/cloud-push.md).
189
+ - Browse the [task-first documentation index](docs/README.md).
190
+ - Report bugs or request features through [GitHub Issues](https://github.com/Synapsor/Synapsor-Runner/issues).
1343
191
 
1344
192
  ## License
1345
193
 
1346
- Synapsor Runner is open source under the Apache License 2.0 (`Apache-2.0`).
1347
-
1348
- Apache-2.0 applies to this runner repo. It does not grant rights to the
1349
- Synapsor name, logo, hosted cloud service, or proprietary Synapsor platform
1350
- features. See [docs/licensing.md](docs/licensing.md) and
1351
- [TRADEMARKS.md](TRADEMARKS.md).
1352
-
1353
- Synapsor Cloud, hosted governance, advanced policy/workflow engines, enterprise
1354
- controls, and native Synapsor DBMS/C++ internals are outside this Apache-2.0
1355
- repository. Managed runners and other hosted features, where offered, are
1356
- proprietary and are not implied by the OSS package.
1357
-
1358
- ## Developer And Contributor Commands
1359
-
1360
- Public docs use `synapsor-runner`. During source-checkout development, if the
1361
- global binary is not linked yet, use `./bin/synapsor-runner ...` or
1362
- `corepack pnpm runner ...`.
1363
-
1364
- Helper scripts are wrappers and development conveniences, not the main product
1365
- interface:
1366
-
1367
- ```bash
1368
- ./scripts/try-synapsor.sh
1369
- ./scripts/demo-docker.sh
1370
- ./scripts/open-demo-ui.sh
1371
- ./scripts/use-your-db.sh
1372
- ./scripts/mcp-config.sh
1373
- ```
1374
-
1375
- Contributor checks:
1376
-
1377
- ```bash
1378
- corepack pnpm install
1379
- ./scripts/verify-release-gate.sh
1380
- ```
1381
-
1382
- After a manual alpha publish, verify the public npm package:
1383
-
1384
- ```bash
1385
- VERIFY_PUBLISHED_ALPHA=1 ./scripts/verify-release-gate.sh 0.1.0-alpha.17
1386
- ```
1387
-
1388
- After a manual stable publish/promotion, verify `latest`:
1389
-
1390
- ```bash
1391
- ./scripts/verify-published-stable.sh 0.1.0
1392
- ```
1393
-
1394
- ## Repository Map
1395
-
1396
- - `apps/runner`: CLI entrypoint and local UI.
1397
- - `packages/spec`: canonical portable contract schemas, normalization, CLI, and conformance fixtures.
1398
- - `packages/dsl`: SQL-like contract authoring for contexts, capabilities, and workflow declarations.
1399
- - `packages/mcp-server`: stdio/HTTP MCP server and configured tool runtime.
1400
- - `packages/schema-inspector`: Postgres/MySQL metadata inspection and config generation.
1401
- - `packages/proposal-store`: local SQLite evidence/proposal/replay store.
1402
- - `packages/postgres`, `packages/mysql`: guarded writeback adapters.
1403
- - `packages/worker-core`: shared runner orchestration.
1404
- - `recipes`: optional starter contracts.
1405
- - `examples`: disposable local demos and reference app.
1406
- - `docs`: focused setup, MCP, security, troubleshooting, and limitation docs.
1407
-
1408
- ## Community
1409
-
1410
- Synapsor Runner is maintained by Synapsor.
194
+ Synapsor Runner is open source under the Apache License 2.0 (`Apache-2.0`). See
195
+ [Licensing](docs/licensing.md) and [Trademarks](TRADEMARKS.md). Synapsor Cloud
196
+ and proprietary Synapsor platform components are outside this repository.
1411
197
 
1412
- - Website: https://synapsor.ai
1413
- - Docs: https://synapsor.ai/docs
1414
- - License: Apache License 2.0 (`Apache-2.0`)
1415
- - Issues: use GitHub Issues
198
+ Maintainer and contributor workflows live in [CONTRIBUTING.md](CONTRIBUTING.md)
199
+ and [AGENTS.md](AGENTS.md).