@synapsor/runner 0.1.0 → 0.1.2

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 (33) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +750 -245
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/runner.mjs +1621 -163
  5. package/docs/README.md +85 -47
  6. package/docs/conformance.md +91 -0
  7. package/docs/migrating-to-synapsor-spec.md +191 -0
  8. package/docs/production.md +289 -0
  9. package/docs/release-notes.md +32 -0
  10. package/examples/app-owned-writeback/command-handler.mjs +0 -0
  11. package/examples/claude-desktop-postgres/Makefile +6 -0
  12. package/examples/claude-desktop-postgres/README.md +40 -0
  13. package/examples/cursor-postgres/Makefile +6 -0
  14. package/examples/cursor-postgres/README.md +30 -0
  15. package/examples/mcp-postgres-billing-app-handler/scripts/run-demo.sh +0 -0
  16. package/examples/mysql-refund-agent/Makefile +4 -0
  17. package/examples/mysql-refund-agent/README.md +36 -0
  18. package/examples/openai-agents-http/Makefile +6 -0
  19. package/examples/openai-agents-http/README.md +14 -0
  20. package/examples/openai-agents-stdio/Makefile +6 -0
  21. package/examples/openai-agents-stdio/README.md +14 -0
  22. package/examples/raw-sql-vs-synapsor/Makefile +11 -0
  23. package/examples/raw-sql-vs-synapsor/README.md +41 -0
  24. package/examples/reference-support-billing-app/scripts/run-demo.sh +0 -0
  25. package/examples/support-billing-agent/Makefile +19 -0
  26. package/examples/support-billing-agent/README.md +89 -0
  27. package/examples/support-billing-agent/app/README.md +13 -0
  28. package/examples/support-billing-agent/db/schema.sql +91 -0
  29. package/examples/support-billing-agent/db/seed.sql +43 -0
  30. package/examples/support-billing-agent/docker-compose.yml +13 -0
  31. package/examples/support-billing-agent/scripts/run-demo.sh +15 -0
  32. package/examples/support-billing-agent/synapsor.runner.json +233 -0
  33. package/package.json +27 -10
@@ -0,0 +1,289 @@
1
+ # Production-Candidate Guide
2
+
3
+ Synapsor Runner is not self-hosted Synapsor Cloud. This guide is for the
4
+ narrow OSS production-candidate shape:
5
+
6
+ ```text
7
+ MCP agent
8
+ -> reviewed semantic capability
9
+ -> trusted tenant/principal context
10
+ -> scoped Postgres/MySQL read
11
+ -> evidence/query audit/proposal
12
+ -> approval outside MCP
13
+ -> guarded one-row update or app-owned executor
14
+ -> receipt/replay
15
+ ```
16
+
17
+ Use this only for bounded database workflows where you can accept a single-node
18
+ local ledger and local/operator approval. Use Synapsor Cloud when you need HA,
19
+ central audit, RBAC/SSO, multi-reviewer approvals, hosted retention, managed
20
+ runners, policy packs, or production support/SLA.
21
+
22
+ ## Supported Scope
23
+
24
+ Production-candidate OSS scope:
25
+
26
+ - Postgres/MySQL reads through fixed semantic MCP tools;
27
+ - trusted context from environment/session values, not model arguments;
28
+ - local SQLite ledger for evidence, query audit, proposals, receipts, replay,
29
+ and lifecycle events;
30
+ - direct guarded single-row `UPDATE` for simple approved edits;
31
+ - app-owned `http_handler` or `command_handler` executors for richer approved
32
+ business transactions;
33
+ - stdio MCP and Streamable HTTP MCP.
34
+
35
+ Out of scope:
36
+
37
+ - raw `execute_sql` or model-generated SQL;
38
+ - generic direct `INSERT`, `DELETE`, `UPSERT`, DDL, or multi-row SQL writeback;
39
+ - physical branching of external Postgres/MySQL;
40
+ - workflow DAGs, auto-merge/settlement, RBAC/SSO, HA ledger, or compliance
41
+ retention;
42
+ - making prompt injection impossible.
43
+
44
+ ## Database Roles
45
+
46
+ Use separate read and write credentials.
47
+
48
+ Read credential:
49
+
50
+ - can connect to the selected database;
51
+ - can inspect metadata for selected schemas;
52
+ - can `SELECT` only the tables/views used by capabilities;
53
+ - should be restricted by views/RLS where possible.
54
+
55
+ Write credential for direct `sql_update`:
56
+
57
+ - can update only the allowed business columns;
58
+ - cannot modify primary-key or tenant columns;
59
+ - can create/write the `synapsor_writeback_receipts` table, or the table is
60
+ pre-created and granted by an administrator;
61
+ - is never exposed to MCP clients.
62
+
63
+ Example config:
64
+
65
+ ```json
66
+ {
67
+ "sources": {
68
+ "billing_postgres": {
69
+ "engine": "postgres",
70
+ "read_url_env": "SYNAPSOR_DATABASE_READ_URL",
71
+ "write_url_env": "SYNAPSOR_DATABASE_WRITE_URL"
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ `synapsor-runner apply --config ...` reads the writer env var named by
78
+ `write_url_env`. `SYNAPSOR_DATABASE_URL` is only a legacy fallback for direct
79
+ worker flows that do not pass a local config.
80
+
81
+ ## Receipt Table
82
+
83
+ Direct SQL writeback stores idempotency receipts in the source database. Runner
84
+ creates this table if allowed:
85
+
86
+ ```sql
87
+ CREATE TABLE IF NOT EXISTS synapsor_writeback_receipts (...);
88
+ ```
89
+
90
+ Before using direct writeback in staging or production-like environments:
91
+
92
+ ```bash
93
+ synapsor-runner writeback migration --engine postgres
94
+ synapsor-runner writeback grants --engine postgres --writer-role app_writer
95
+ synapsor-runner doctor --config synapsor.runner.json --check-writeback
96
+ ```
97
+
98
+ For MySQL, replace `postgres` with `mysql`.
99
+
100
+ If the writer should not create application-schema tables, pre-create the
101
+ receipt table with an administrator role, grant only the needed receipt-table
102
+ permissions to the writer, or use an app-owned executor that stores receipts in
103
+ your application boundary.
104
+
105
+ ## Direct Writeback Vs App-Owned Executor
106
+
107
+ Use direct `sql_update` when the approved change is:
108
+
109
+ ```text
110
+ one existing row -> one allowed-column patch -> one guarded UPDATE
111
+ ```
112
+
113
+ Use an app-owned executor when the change is richer:
114
+
115
+ - insert a credit/refund/review row;
116
+ - update more than one row;
117
+ - touch more than one table;
118
+ - emit an event or call another internal service;
119
+ - enforce business logic that belongs in your app.
120
+
121
+ Handlers must re-check tenant/scope, expected version, idempotency, allowed
122
+ business action, transaction boundaries, and safe errors. See
123
+ [Writeback Executors](writeback-executors.md) and
124
+ [Handler Helper](handler-helper.md).
125
+
126
+ ## Local Ledger
127
+
128
+ Default local ledger path:
129
+
130
+ ```text
131
+ ./.synapsor/local.db
132
+ ```
133
+
134
+ This SQLite file stores local evidence, query audit, proposals, approvals,
135
+ receipts, replay, and events. Back it up like local operational state if you
136
+ depend on replay after restarts.
137
+
138
+ Recommended single-node practices:
139
+
140
+ - keep the ledger on persistent disk;
141
+ - back up `local.db`, `local.db-wal`, and `local.db-shm` together when the
142
+ server is stopped, or use your platform's filesystem snapshot mechanism;
143
+ - do not run multiple active MCP server modes against the same ledger unless
144
+ you intentionally pass `--allow-concurrent-store` for local debugging;
145
+ - use `store prune --dry-run` before retention cleanup;
146
+ - use `store vacuum` during a planned maintenance window.
147
+
148
+ Useful commands:
149
+
150
+ ```bash
151
+ synapsor-runner store stats --store ./.synapsor/local.db
152
+ synapsor-runner events tail --store ./.synapsor/local.db --follow
153
+ synapsor-runner store prune --store ./.synapsor/local.db --older-than 30d --dry-run
154
+ synapsor-runner store vacuum --store ./.synapsor/local.db
155
+ ```
156
+
157
+ Details: [Store Lifecycle](store-lifecycle.md).
158
+
159
+ ## Restart And Recovery
160
+
161
+ Runner stores proposal/evidence/replay state before writeback.
162
+
163
+ Expected restart behavior:
164
+
165
+ - after proposal creation: proposal, evidence, query audit, and replay remain
166
+ inspectable from the local ledger;
167
+ - after approval but before apply: rerun `apply`; the approved proposal remains
168
+ pending until a terminal receipt is recorded;
169
+ - after apply succeeds: retry returns an idempotent receipt, not a second write;
170
+ - after stale row or tenant mismatch: retry returns the recorded conflict path.
171
+
172
+ Inspection commands:
173
+
174
+ ```bash
175
+ synapsor-runner proposals show latest --store ./.synapsor/local.db
176
+ synapsor-runner receipts list --proposal wrp_... --store ./.synapsor/local.db
177
+ synapsor-runner replay show latest --store ./.synapsor/local.db
178
+ synapsor-runner activity search --proposal wrp_... --store ./.synapsor/local.db
179
+ ```
180
+
181
+ ## Deployment Recipes
182
+
183
+ ### Docker Compose Shape
184
+
185
+ Use Compose to run the MCP server next to your app and database network. Keep
186
+ secrets in environment variables or your platform secret manager.
187
+
188
+ ```yaml
189
+ services:
190
+ synapsor-runner:
191
+ image: node:22-bookworm
192
+ working_dir: /app
193
+ command: >
194
+ sh -lc "npm install -g @synapsor/runner &&
195
+ synapsor-runner up --review --config /config/synapsor.runner.json
196
+ --store /data/local.db --host 0.0.0.0 --port 8766"
197
+ environment:
198
+ SYNAPSOR_DATABASE_READ_URL: ${SYNAPSOR_DATABASE_READ_URL}
199
+ SYNAPSOR_DATABASE_WRITE_URL: ${SYNAPSOR_DATABASE_WRITE_URL}
200
+ SYNAPSOR_TENANT_ID: ${SYNAPSOR_TENANT_ID}
201
+ SYNAPSOR_PRINCIPAL: ${SYNAPSOR_PRINCIPAL}
202
+ volumes:
203
+ - ./synapsor.runner.json:/config/synapsor.runner.json:ro
204
+ - synapsor-runner-data:/data
205
+ ports:
206
+ - "8766:8766"
207
+
208
+ volumes:
209
+ synapsor-runner-data:
210
+ ```
211
+
212
+ ### systemd Shape
213
+
214
+ ```ini
215
+ [Unit]
216
+ Description=Synapsor Runner MCP server
217
+ After=network-online.target
218
+
219
+ [Service]
220
+ Type=simple
221
+ User=synapsor-runner
222
+ WorkingDirectory=/opt/synapsor-runner
223
+ EnvironmentFile=/etc/synapsor-runner.env
224
+ ExecStart=/usr/bin/synapsor-runner up --review --config /etc/synapsor.runner.json --store /var/lib/synapsor-runner/local.db --host 127.0.0.1 --port 8766
225
+ Restart=on-failure
226
+ RestartSec=5
227
+ NoNewPrivileges=true
228
+ PrivateTmp=true
229
+
230
+ [Install]
231
+ WantedBy=multi-user.target
232
+ ```
233
+
234
+ Put database credentials in `/etc/synapsor-runner.env` or your system secret
235
+ manager, not in `synapsor.runner.json`.
236
+
237
+ ## TLS And SSL
238
+
239
+ For staging or production-like databases:
240
+
241
+ - keep certificate verification enabled;
242
+ - use provider CA bundles when required;
243
+ - do not use `sslmode=disable` except disposable local fixtures;
244
+ - do not document or paste real DB URLs into logs, tickets, prompts, or MCP
245
+ client config.
246
+
247
+ For disposable local Docker fixtures, `sslmode=disable` is acceptable when the
248
+ database is bound to loopback and contains only test data.
249
+
250
+ ## Health And Doctor
251
+
252
+ Run these before exposing tools to an agent:
253
+
254
+ ```bash
255
+ synapsor-runner config validate --config synapsor.runner.json
256
+ synapsor-runner doctor --config synapsor.runner.json --report --redact --output synapsor-doctor.md
257
+ synapsor-runner doctor --config synapsor.runner.json --check-writeback
258
+ synapsor-runner tools preview --config synapsor.runner.json --store ./.synapsor/local.db
259
+ ```
260
+
261
+ Doctor reports should be redacted by default before sharing. They must not
262
+ include database passwords, bearer tokens, handler secrets, or raw driver
263
+ connection strings.
264
+
265
+ ## Logging And Redaction
266
+
267
+ Expected public outputs must avoid secrets in:
268
+
269
+ - demo output;
270
+ - doctor reports;
271
+ - evidence exports;
272
+ - query-audit output;
273
+ - replay exports;
274
+ - thrown errors and logs.
275
+
276
+ If you find a leak, treat it as a security bug. See [SECURITY.md](../SECURITY.md).
277
+
278
+ ## Release Gate
279
+
280
+ Before promoting a package or calling a build production-candidate:
281
+
282
+ ```bash
283
+ ./scripts/verify-release-gate.sh
284
+ ```
285
+
286
+ The release gate should cover typecheck, focused tests, packed-package install,
287
+ quick demo, own-db fixture, MCP stdio/HTTP checks, direct writeback,
288
+ app-owned executor paths, package dry-run, and docs/package consistency.
289
+
@@ -10,6 +10,38 @@ npx -y -p @synapsor/runner synapsor-runner demo --quick
10
10
  The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
11
11
  for the Synapsor Cloud CLI.
12
12
 
13
+ ## 0.1.2
14
+
15
+ ### Contract Compatibility
16
+
17
+ - Documents the canonical `synapsor.contract.json` path for contracts produced
18
+ by the DSL, Cloud, or the C++ exporter.
19
+ - Adds OSS-side conformance notes for C++/Cloud export snapshots that validate
20
+ with `@synapsor/spec` and load in Runner.
21
+ - Keeps `@synapsor/runner` publishable after `0.1.1` by reserving the next
22
+ stable patch version for this contract round-trip readiness pass.
23
+
24
+ ## 0.1.1
25
+
26
+ ### OSS Launch Readiness
27
+
28
+ - Reworked the README and packaged npm README so the first screen leads with
29
+ the `execute_sql` risk, the reviewed-business-action alternative, badges, and
30
+ the no-database quick demo.
31
+ - Added the self-contained `examples/support-billing-agent/` flagship demo with
32
+ schema, seed data, reviewed contract, app-boundary note, one-command
33
+ `make demo`, and the exact support/billing model-facing tool list.
34
+ - Added copy-paste example entry points for raw SQL vs Synapsor, Claude
35
+ Desktop, Cursor, OpenAI Agents SDK over Streamable HTTP and stdio, and MySQL
36
+ refund review.
37
+ - Added agent-native repo guidance files and verified that an agent can create
38
+ an inspect/propose capability with the non-interactive CLI without reading
39
+ generated `dist/` files.
40
+ - Restructured the docs index into a task-first path and added release-gate
41
+ repo hygiene assets.
42
+ - Hardened package building so generated `.synapsor` local ledgers are not
43
+ included in npm examples.
44
+
13
45
  ## 0.1.0
14
46
 
15
47
  ### Stable Channel
File without changes
@@ -0,0 +1,6 @@
1
+ .PHONY: config
2
+
3
+ config:
4
+ cd ../.. && corepack pnpm runner mcp config claude-desktop \
5
+ --config ./examples/mcp-postgres-billing/synapsor.runner.json \
6
+ --store ./.synapsor/local.db
@@ -0,0 +1,40 @@
1
+ # Claude Desktop + Postgres
2
+
3
+ This example prints a Claude Desktop MCP config for a reviewed Postgres-backed
4
+ Synapsor Runner capability set.
5
+
6
+ It uses the local `examples/mcp-postgres-billing/synapsor.runner.json` fixture.
7
+ The config contains command paths and environment variable names only; it does
8
+ not include database URLs or write credentials.
9
+
10
+ ## Run
11
+
12
+ ```bash
13
+ make config
14
+ ```
15
+
16
+ Expected output includes:
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "synapsor": {
22
+ "command": "...",
23
+ "args": ["...", "mcp", "serve", "..."]
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ Then paste the JSON into Claude Desktop's MCP settings and set these
30
+ environment variables in the client environment:
31
+
32
+ ```bash
33
+ export BILLING_POSTGRES_READ_URL="postgres://readonly:..."
34
+ export SYNAPSOR_TENANT_ID="acme"
35
+ export SYNAPSOR_PRINCIPAL="local_billing_agent"
36
+ ```
37
+
38
+ The model sees semantic tools such as `billing.inspect_invoice` and
39
+ `billing.propose_late_fee_waiver`; it does not see raw SQL or approval/commit
40
+ tools.
@@ -0,0 +1,6 @@
1
+ .PHONY: config
2
+
3
+ config:
4
+ cd ../.. && corepack pnpm runner mcp config cursor \
5
+ --config ./examples/mcp-postgres-billing/synapsor.runner.json \
6
+ --store ./.synapsor/local.db
@@ -0,0 +1,30 @@
1
+ # Cursor + Postgres
2
+
3
+ This example prints a Cursor MCP config for a reviewed Postgres-backed Synapsor
4
+ Runner capability set.
5
+
6
+ It uses the local `examples/mcp-postgres-billing/synapsor.runner.json` fixture.
7
+ The config contains command paths and environment variable names only; it does
8
+ not include database URLs or write credentials.
9
+
10
+ ## Run
11
+
12
+ ```bash
13
+ make config
14
+ ```
15
+
16
+ Expected output includes a Cursor-compatible `mcpServers.synapsor` entry that
17
+ launches:
18
+
19
+ ```text
20
+ synapsor-runner mcp serve --config ./examples/mcp-postgres-billing/synapsor.runner.json --store ./.synapsor/local.db
21
+ ```
22
+
23
+ Set the database and trusted-context variables in the environment that launches
24
+ Cursor:
25
+
26
+ ```bash
27
+ export BILLING_POSTGRES_READ_URL="postgres://readonly:..."
28
+ export SYNAPSOR_TENANT_ID="acme"
29
+ export SYNAPSOR_PRINCIPAL="local_billing_agent"
30
+ ```
@@ -0,0 +1,4 @@
1
+ .PHONY: demo
2
+
3
+ demo:
4
+ cd ../.. && corepack pnpm test:mcp-local
@@ -0,0 +1,36 @@
1
+ # MySQL Refund Agent
2
+
3
+ This example points at the MySQL order/refund fixture and proves Synapsor
4
+ Runner is not Postgres-only.
5
+
6
+ The reviewed tools are:
7
+
8
+ - `orders.inspect_order`
9
+ - `orders.propose_refund_review`
10
+ - `orders.propose_status_change`
11
+
12
+ The refund proposal updates only review fields on one existing order. It does
13
+ not issue money movement, call a payment provider, or expose a generic SQL
14
+ tool.
15
+
16
+ ## Run
17
+
18
+ ```bash
19
+ make demo
20
+ ```
21
+
22
+ Expected output includes the shared local MCP smoke passing for the MySQL orders
23
+ scenario:
24
+
25
+ ```text
26
+ MySQL orders
27
+ ACCEPT execute_sql approval and commit tools absent
28
+ ```
29
+
30
+ The source database remains unchanged until a proposal is approved outside MCP
31
+ and applied through guarded writeback.
32
+
33
+ ## Underlying Fixture
34
+
35
+ This folder wraps `../mcp-mysql-orders/`, which contains the Docker compose
36
+ file, seed SQL, and `synapsor.runner.json` contract.
@@ -0,0 +1,6 @@
1
+ .PHONY: smoke
2
+
3
+ smoke:
4
+ python3 -m py_compile agent.py
5
+ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http --help >/dev/null
6
+ @printf '%s\n' "OpenAI Agents Streamable HTTP example smoke passed."
@@ -20,6 +20,20 @@ metadata and maps calls back to the canonical Synapsor capability.
20
20
  The model still sees a semantic action. It does not receive raw SQL, database
21
21
  URLs, write credentials, approval tools, or commit tools.
22
22
 
23
+ ## Smoke Check
24
+
25
+ Run this without an OpenAI API key:
26
+
27
+ ```bash
28
+ make smoke
29
+ ```
30
+
31
+ Expected output:
32
+
33
+ ```text
34
+ OpenAI Agents Streamable HTTP example smoke passed.
35
+ ```
36
+
23
37
  ## Terminal 1: Start Synapsor Runner HTTP MCP
24
38
 
25
39
  ```bash
@@ -0,0 +1,6 @@
1
+ .PHONY: smoke
2
+
3
+ smoke:
4
+ python3 -m py_compile agent.py
5
+ npx -y -p @synapsor/runner synapsor-runner mcp serve --help >/dev/null
6
+ @printf '%s\n' "OpenAI Agents stdio example smoke passed."
@@ -11,6 +11,20 @@ it. The model
11
11
  does not receive raw SQL, database URLs, write credentials, approval tools, or
12
12
  commit tools.
13
13
 
14
+ ## Smoke Check
15
+
16
+ Run this without an OpenAI API key:
17
+
18
+ ```bash
19
+ make smoke
20
+ ```
21
+
22
+ Expected output:
23
+
24
+ ```text
25
+ OpenAI Agents stdio example smoke passed.
26
+ ```
27
+
14
28
  ## Prerequisites
15
29
 
16
30
  Generate `synapsor.runner.json` first:
@@ -0,0 +1,11 @@
1
+ .PHONY: demo
2
+
3
+ demo:
4
+ @printf '%s\n' "Unsafe shortcut:"
5
+ @printf '%s\n' ' agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")'
6
+ @printf '%s\n' ""
7
+ @printf '%s\n' "Synapsor quick proof:"
8
+ npx -y @synapsor/runner demo --quick --no-interactive
9
+ @printf '%s\n' ""
10
+ @printf '%s\n' "Risk audit example:"
11
+ npx -y @synapsor/runner audit --example dangerous-db-mcp --format markdown
@@ -0,0 +1,41 @@
1
+ # Raw SQL vs Synapsor
2
+
3
+ This minimal example shows the fear and the fix without requiring Docker, an
4
+ agent SDK, or a database.
5
+
6
+ ## Run
7
+
8
+ ```bash
9
+ make demo
10
+ ```
11
+
12
+ Expected output includes:
13
+
14
+ ```text
15
+ execute_sql
16
+ Synapsor quick demo complete.
17
+ proposal created
18
+ source DB changed: no
19
+ approval required outside MCP
20
+ ```
21
+
22
+ The raw-SQL shortcut is:
23
+
24
+ ```text
25
+ agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")
26
+ ```
27
+
28
+ The Synapsor path is:
29
+
30
+ ```text
31
+ agent -> billing.propose_late_fee_waiver(...)
32
+ human approves outside MCP
33
+ guarded writeback applies exactly one row
34
+ replay records what happened
35
+ ```
36
+
37
+ ## Why This Exists
38
+
39
+ Use this folder when you want to show the core idea quickly. It is not a full
40
+ database fixture; the full support/billing walkthrough lives in
41
+ `../support-billing-agent/`.
@@ -0,0 +1,19 @@
1
+ .PHONY: demo unsafe clean
2
+
3
+ demo:
4
+ cd ../.. && examples/support-billing-agent/scripts/run-demo.sh
5
+
6
+ unsafe:
7
+ @printf '%s\n' "Unsafe raw-SQL shortcut this demo avoids:"
8
+ @printf '%s\n' ""
9
+ @printf '%s\n' ' agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 WHERE status = '\''overdue'\''")'
10
+ @printf '%s\n' ""
11
+ @printf '%s\n' "Why it is risky:"
12
+ @printf '%s\n' " - the model controls SQL shape and scope"
13
+ @printf '%s\n' " - tenant filters can be omitted or hallucinated"
14
+ @printf '%s\n' " - there is no proposal, approval boundary, conflict receipt, or replay"
15
+ @printf '%s\n' ""
16
+ @printf '%s\n' "Run 'make demo' to see the Synapsor path: semantic tool -> proposal -> approval -> guarded writeback -> replay."
17
+
18
+ clean:
19
+ docker compose down -v --remove-orphans
@@ -0,0 +1,89 @@
1
+ # Support/Billing Agent Demo
2
+
3
+ This is the flagship Synapsor Runner demo.
4
+
5
+ It uses a disposable Postgres support/billing app and shows the full loop:
6
+
7
+ ```text
8
+ agent inspects scoped evidence
9
+ -> agent creates a proposal
10
+ -> source database is unchanged
11
+ -> human approves outside MCP
12
+ -> guarded writeback applies exactly one row
13
+ -> replay shows evidence, diff, approval, receipt, and conflict behavior
14
+ ```
15
+
16
+ ## Run It
17
+
18
+ From this folder:
19
+
20
+ ```bash
21
+ make demo
22
+ ```
23
+
24
+ Expected end state:
25
+
26
+ ```text
27
+ Reference support/billing app smoke passed.
28
+ ```
29
+
30
+ The model-facing tools are exactly:
31
+
32
+ - `support.inspect_ticket`
33
+ - `support.propose_plan_credit`
34
+ - `billing.inspect_invoice`
35
+ - `billing.propose_late_fee_waiver`
36
+
37
+ The demo proves:
38
+
39
+ - the model-facing tool list contains semantic capabilities such as
40
+ `billing.inspect_invoice` and `billing.propose_late_fee_waiver`;
41
+ - the model does not receive `execute_sql`, approval tools, commit/apply tools,
42
+ database URLs, write credentials, arbitrary table names, arbitrary column
43
+ names, or tenant authority;
44
+ - proposals do not mutate the source database;
45
+ - approved writeback uses tenant, primary-key, allowed-column,
46
+ idempotency, and `updated_at` conflict guards;
47
+ - replay contains the evidence and writeback receipt.
48
+
49
+ ## Compare The Unsafe Shortcut
50
+
51
+ To see why the boundary matters:
52
+
53
+ ```bash
54
+ make unsafe
55
+ ```
56
+
57
+ That target prints the raw-SQL shape this demo avoids. It does not mutate the
58
+ fixture; it shows the path an MCP client should not expose to the model:
59
+
60
+ ```text
61
+ execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")
62
+ ```
63
+
64
+ Use `make demo` for the real proposal, approval, writeback, idempotent retry,
65
+ stale-row conflict, and replay proof.
66
+
67
+ ## What This Wraps
68
+
69
+ This folder is self-contained for readers and agents looking for the canonical
70
+ support/billing demo. The smoke logic is shared with the reference fixture so
71
+ the product-facing walkthrough and package tests exercise the same safety
72
+ checks.
73
+
74
+ Relevant files:
75
+
76
+ - `db/schema.sql`
77
+ - `db/seed.sql`
78
+ - `synapsor.runner.json`
79
+ - `scripts/run-demo.sh`
80
+ - `app/README.md`
81
+
82
+ ## Stop And Clean Up
83
+
84
+ The demo script cleans up its disposable Docker database automatically. If you
85
+ interrupt it, run:
86
+
87
+ ```bash
88
+ make clean
89
+ ```