@synapsor/runner 1.5.3 → 1.6.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.
- package/CHANGELOG.md +82 -2
- package/README.md +131 -130
- package/dist/authoring.mjs +405 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +2 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +19532 -14246
- package/dist/runtime.mjs +10856 -8495
- package/dist/shadow.mjs +101 -1
- package/docs/README.md +14 -6
- package/docs/aggregate-reads.md +22 -0
- package/docs/auto-boundary-and-scoped-explore.md +338 -0
- package/docs/capability-authoring.md +36 -1
- package/docs/cloud-mode.md +18 -0
- package/docs/conformance.md +16 -0
- package/docs/current-scope.md +55 -28
- package/docs/cursor-plugin.md +20 -3
- package/docs/database-enforced-scope.md +8 -0
- package/docs/dsl-reference.md +123 -4
- package/docs/getting-started-own-database.md +42 -35
- package/docs/guarded-crud-writeback.md +10 -1
- package/docs/http-mcp.md +222 -207
- package/docs/limitations.md +33 -9
- package/docs/local-mode.md +5 -2
- package/docs/mcp-client-setup.md +24 -11
- package/docs/mcp-clients.md +10 -4
- package/docs/openai-agents-sdk.md +16 -2
- package/docs/production.md +72 -7
- package/docs/release-notes.md +77 -3
- package/docs/runner-bundles.md +7 -2
- package/docs/runner-config-reference.md +96 -6
- package/docs/running-a-runner-fleet.md +42 -13
- package/docs/schema-api-candidates.md +28 -1
- package/docs/security-boundary.md +38 -3
- package/docs/store-lifecycle.md +93 -5
- package/docs/troubleshooting-first-run.md +98 -0
- package/examples/auto-boundary-churn/README.md +23 -0
- package/examples/auto-boundary-churn/app/page.tsx +8 -0
- package/examples/auto-boundary-churn/docker-compose.yml +16 -0
- package/examples/auto-boundary-churn/package.json +18 -0
- package/examples/auto-boundary-churn/prisma/schema.prisma +36 -0
- package/examples/auto-boundary-churn/seed/postgres.sql +126 -0
- package/examples/openai-agents-http/README.md +10 -4
- package/examples/openai-agents-http/agent.py +2 -2
- package/examples/runner-fleet/Dockerfile +7 -2
- package/examples/runner-fleet/README.md +11 -7
- package/examples/runner-fleet/docker-compose.yml +4 -4
- package/examples/runner-fleet/mint-dev-token.mjs +1 -1
- package/examples/runner-fleet/start-tls-runner.sh +21 -0
- package/examples/runner-fleet/synapsor.runner.json +27 -1
- package/examples/support-plan-credit/README.md +6 -1
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +4 -0
- package/examples/support-plan-credit/synapsor.contract.json +0 -3
- package/fixtures/compatibility/published-1.5.4/manifest.json +76 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/llms.txt +37 -0
- package/package.json +7 -4
- package/schemas/synapsor.runner.schema.json +98 -1
package/docs/mcp-client-setup.md
CHANGED
|
@@ -49,10 +49,13 @@ developer path. Streamable HTTP implements MCP initialize/session behavior over
|
|
|
49
49
|
an authenticated `/mcp` endpoint. The JSON-RPC bridge is intentionally smaller
|
|
50
50
|
and does not implement MCP initialize/session behavior.
|
|
51
51
|
|
|
52
|
-
HTTP requires
|
|
52
|
+
HTTP requires Bearer authentication by default. `Bearer` is the HTTP
|
|
53
|
+
presentation scheme; for this loopback example it carries one opaque random
|
|
54
|
+
endpoint token, not a user identity or JWT. The operator generates it and
|
|
55
|
+
provisions the same environment value to Runner and the authorized client:
|
|
53
56
|
|
|
54
57
|
```bash
|
|
55
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="
|
|
58
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
56
59
|
|
|
57
60
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
58
61
|
--config ./synapsor.runner.json \
|
|
@@ -88,8 +91,10 @@ npx -y -p @synapsor/runner synapsor-runner tools preview \
|
|
|
88
91
|
--alias-mode openai
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
Do not distribute one opaque token to unrelated users or tenants. A
|
|
95
|
+
non-loopback service also needs direct TLS or an explicitly trusted TLS proxy;
|
|
96
|
+
a shared service uses short-lived signed JWTs issued by your identity provider,
|
|
97
|
+
with tenant/principal bound from verified claims. Details: [HTTP MCP](http-mcp.md).
|
|
93
98
|
|
|
94
99
|
## Generate A Client Snippet
|
|
95
100
|
|
|
@@ -142,8 +147,10 @@ npx -y -p @synapsor/runner synapsor-runner mcp configure \
|
|
|
142
147
|
When the destination already exists, Synapsor Runner creates a timestamped
|
|
143
148
|
backup before writing. Noninteractive scripts must add `--yes`.
|
|
144
149
|
|
|
145
|
-
The command writes only
|
|
146
|
-
|
|
150
|
+
The command writes only command arguments and, for HTTP clients, credential
|
|
151
|
+
environment references plus external authorization metadata. It never writes
|
|
152
|
+
database URLs, passwords, token values, client secrets, or refresh tokens into
|
|
153
|
+
the generated client config.
|
|
147
154
|
|
|
148
155
|
No separate Apps flag is required. A compatible host discovers
|
|
149
156
|
`ui://synapsor/proposal-review.html` from proposal-tool metadata. The app can
|
|
@@ -165,8 +172,6 @@ the current `latest` release.
|
|
|
165
172
|
For standard app/server HTTP MCP mode:
|
|
166
173
|
|
|
167
174
|
```bash
|
|
168
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="dev-local-token"
|
|
169
|
-
|
|
170
175
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
171
176
|
--config ./examples/mcp-postgres-billing/synapsor.runner.json \
|
|
172
177
|
--store ./.synapsor/local.db \
|
|
@@ -174,6 +179,8 @@ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
|
174
179
|
```
|
|
175
180
|
|
|
176
181
|
For the smaller JSON-RPC bridge, use `synapsor-runner mcp serve-http` instead.
|
|
182
|
+
The bridge is not standard Streamable HTTP and cannot provide claim-bound MCP
|
|
183
|
+
sessions, so do not use it for a shared identity deployment.
|
|
177
184
|
|
|
178
185
|
## Generic stdio Client
|
|
179
186
|
|
|
@@ -195,9 +202,9 @@ For the smaller JSON-RPC bridge, use `synapsor-runner mcp serve-http` instead.
|
|
|
195
202
|
"./.synapsor/local.db"
|
|
196
203
|
],
|
|
197
204
|
"env": {
|
|
198
|
-
"BILLING_POSTGRES_READ_URL": "
|
|
199
|
-
"SYNAPSOR_TENANT_ID": "
|
|
200
|
-
"SYNAPSOR_PRINCIPAL": "
|
|
205
|
+
"BILLING_POSTGRES_READ_URL": "${BILLING_POSTGRES_READ_URL}",
|
|
206
|
+
"SYNAPSOR_TENANT_ID": "${SYNAPSOR_TENANT_ID}",
|
|
207
|
+
"SYNAPSOR_PRINCIPAL": "${SYNAPSOR_PRINCIPAL}"
|
|
201
208
|
}
|
|
202
209
|
}
|
|
203
210
|
}
|
|
@@ -265,6 +272,12 @@ examples/mcp-client-configs/vscode.json
|
|
|
265
272
|
|
|
266
273
|
Each example uses the same stdio command/args/env structure. Replace the placeholder environment variables in your client settings or shell environment.
|
|
267
274
|
|
|
275
|
+
These checked-in desktop examples use stdio, which is the recommended local
|
|
276
|
+
path for Claude Desktop, Cursor, and VS Code. The OpenAI Agents SDK recipe is
|
|
277
|
+
syntax-checked, and the HTTP endpoint is interoperability-tested with the
|
|
278
|
+
official MCP TypeScript client; repository CI does not claim to exercise an
|
|
279
|
+
identity-provider login inside every third-party host.
|
|
280
|
+
|
|
268
281
|
Do not add a write database URL to the MCP server environment unless you are intentionally running a local review/writeback demo. For normal read/proposal tool calls, use the read URL and trusted context values only.
|
|
269
282
|
|
|
270
283
|
Before documenting a client UI as officially tested, verify:
|
package/docs/mcp-clients.md
CHANGED
|
@@ -115,19 +115,25 @@ metadata preserves the canonical dotted Synapsor capability name.
|
|
|
115
115
|
## Streamable HTTP
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
119
|
+
|
|
118
120
|
synapsor-runner mcp serve \
|
|
119
121
|
--transport streamable-http \
|
|
120
122
|
--alias-mode openai \
|
|
121
123
|
--host 127.0.0.1 \
|
|
122
124
|
--port 8766 \
|
|
123
125
|
--config ./synapsor.runner.json \
|
|
124
|
-
--store ./.synapsor/local.db
|
|
126
|
+
--store ./.synapsor/local.db \
|
|
127
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
125
128
|
```
|
|
126
129
|
|
|
127
130
|
Connect a standard Streamable HTTP MCP client to
|
|
128
|
-
`http://127.0.0.1:8766/mcp
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
`http://127.0.0.1:8766/mcp` with `Authorization: Bearer` loaded from the same
|
|
132
|
+
protected environment value. Keep it on loopback for local development. A
|
|
133
|
+
non-loopback listener refuses to bind without direct TLS, an explicitly trusted
|
|
134
|
+
TLS proxy, or authenticated emergency break glass. Shared deployments require
|
|
135
|
+
identity-provider-issued signed claims. Follow [HTTP MCP](http-mcp.md) and the
|
|
136
|
+
[production guide](production.md).
|
|
131
137
|
|
|
132
138
|
Use `--alias-mode openai` for the OpenAI Agents SDK. Omit it for clients that
|
|
133
139
|
accept canonical dotted names, or use `--alias-mode both` only during a planned
|
|
@@ -8,7 +8,7 @@ surface.
|
|
|
8
8
|
## Start Runner
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="
|
|
11
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
12
12
|
|
|
13
13
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
14
14
|
--config ./synapsor.runner.json \
|
|
@@ -17,6 +17,11 @@ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
|
17
17
|
--alias-mode openai
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
For this loopback/single-service example, the operator provisions that same
|
|
21
|
+
opaque value to the Runner process and the Python client through protected
|
|
22
|
+
environment injection. HTTP `Bearer` describes how the credential is sent; it
|
|
23
|
+
does not make the opaque value a JWT, and Runner does not issue it.
|
|
24
|
+
|
|
20
25
|
`--alias-mode openai` is important because OpenAI function/tool names cannot
|
|
21
26
|
contain dots. Runner exposes names such as `billing__inspect_invoice` to the
|
|
22
27
|
model and maps calls back to canonical Synapsor capability names such as
|
|
@@ -28,7 +33,8 @@ model and maps calls back to canonical Synapsor capability names such as
|
|
|
28
33
|
npx -y -p @synapsor/runner synapsor-runner mcp client-config \
|
|
29
34
|
--client openai-agents \
|
|
30
35
|
--config ./synapsor.runner.json \
|
|
31
|
-
--store ./.synapsor/local.db
|
|
36
|
+
--store ./.synapsor/local.db \
|
|
37
|
+
--client-access-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
32
38
|
```
|
|
33
39
|
|
|
34
40
|
The generated output includes:
|
|
@@ -41,6 +47,14 @@ The generated output includes:
|
|
|
41
47
|
It does not include database URLs, passwords, write credentials, API keys, or
|
|
42
48
|
bearer token values.
|
|
43
49
|
|
|
50
|
+
For a shared deployment, configure `http_claims`, asymmetric `session_auth`, and
|
|
51
|
+
`http_security.oauth_resource`, then use a separate env name such as
|
|
52
|
+
`SYNAPSOR_MCP_ACCESS_TOKEN`. Your configured identity provider issues that
|
|
53
|
+
short-lived token for the protected-resource audience; Runner validates it on
|
|
54
|
+
every request but never stores end-user passwords or issues/refreshes tokens.
|
|
55
|
+
The generated client URL is the configured HTTPS protected resource. See
|
|
56
|
+
[HTTP MCP](http-mcp.md) for the complete profile and TLS/proxy requirements.
|
|
57
|
+
|
|
44
58
|
## Sanity Check
|
|
45
59
|
|
|
46
60
|
Before giving the agent a real task, ask it to inspect one known object and
|
package/docs/production.md
CHANGED
|
@@ -421,6 +421,36 @@ synapsor-runner activity search --proposal wrp_... --store ./.synapsor/local.db
|
|
|
421
421
|
|
|
422
422
|
## Deployment Recipes
|
|
423
423
|
|
|
424
|
+
### Networked MCP boundary
|
|
425
|
+
|
|
426
|
+
Prefer stdio when one local client can launch Runner. For Streamable HTTP,
|
|
427
|
+
choose the deployment profile before binding:
|
|
428
|
+
|
|
429
|
+
- loopback: authenticated opaque endpoint token by default;
|
|
430
|
+
- remote single-tenant: direct TLS or an explicitly trusted TLS proxy, plus one
|
|
431
|
+
high-entropy rotated service token;
|
|
432
|
+
- shared multi-user/tenant: direct TLS or trusted proxy, asymmetric signed JWT
|
|
433
|
+
sessions, exact issuer/audience/resource, verified tenant/principal claims,
|
|
434
|
+
and RFC 9728 protected-resource metadata.
|
|
435
|
+
|
|
436
|
+
An opaque token is generated by the operator and provisioned to server and
|
|
437
|
+
authorized client through environment/secret-manager injection. Runner does not
|
|
438
|
+
issue it. In a shared deployment, the configured external identity provider
|
|
439
|
+
issues short-lived access tokens; Runner verifies them but does not store user
|
|
440
|
+
passwords or issue refresh tokens. See [HTTP MCP](http-mcp.md) before exposing a
|
|
441
|
+
listener outside loopback.
|
|
442
|
+
|
|
443
|
+
Run the transport-specific doctor check before serving:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
synapsor-runner doctor \
|
|
447
|
+
--config ./synapsor.runner.json \
|
|
448
|
+
--transport streamable-http \
|
|
449
|
+
--host 0.0.0.0 \
|
|
450
|
+
--trusted-tls-proxy \
|
|
451
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
452
|
+
```
|
|
453
|
+
|
|
424
454
|
### Docker Compose Shape
|
|
425
455
|
|
|
426
456
|
Use Compose to run the MCP server next to your app and database network. Keep
|
|
@@ -436,14 +466,20 @@ export SYNAPSOR_SECRET_MAP='{
|
|
|
436
466
|
}'
|
|
437
467
|
|
|
438
468
|
synapsor-runner mcp serve-streamable-http \
|
|
469
|
+
--host 0.0.0.0 \
|
|
439
470
|
--config ./synapsor.runner.json \
|
|
440
471
|
--store ./.synapsor/local.db \
|
|
472
|
+
--trusted-tls-proxy \
|
|
473
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
|
|
441
474
|
--secrets-provider aws-secretsmanager-cli \
|
|
442
475
|
--secret-map-env SYNAPSOR_SECRET_MAP
|
|
443
476
|
```
|
|
444
477
|
|
|
445
478
|
The AWS provider shells out to `aws secretsmanager get-secret-value`; the runner
|
|
446
|
-
logs only how many target env vars were loaded or skipped.
|
|
479
|
+
logs only how many target env vars were loaded or skipped. This command assumes
|
|
480
|
+
`http_security.deployment: single_tenant`, an exact `allowed_hosts` list, and a
|
|
481
|
+
TLS proxy on a private hop. Use asymmetric claim-bound identity instead for a
|
|
482
|
+
shared user/tenant service.
|
|
447
483
|
|
|
448
484
|
```yaml
|
|
449
485
|
services:
|
|
@@ -453,22 +489,30 @@ services:
|
|
|
453
489
|
command: >
|
|
454
490
|
sh -lc "npm install -g @synapsor/runner &&
|
|
455
491
|
synapsor-runner up --review --config /config/synapsor.runner.json
|
|
456
|
-
--store /data/local.db --host 0.0.0.0 --port 8766
|
|
492
|
+
--store /data/local.db --host 0.0.0.0 --port 8766
|
|
493
|
+
--trusted-tls-proxy --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN"
|
|
457
494
|
environment:
|
|
458
495
|
SYNAPSOR_DATABASE_READ_URL: ${SYNAPSOR_DATABASE_READ_URL}
|
|
459
496
|
SYNAPSOR_DATABASE_WRITE_URL: ${SYNAPSOR_DATABASE_WRITE_URL}
|
|
460
497
|
SYNAPSOR_TENANT_ID: ${SYNAPSOR_TENANT_ID}
|
|
461
498
|
SYNAPSOR_PRINCIPAL: ${SYNAPSOR_PRINCIPAL}
|
|
499
|
+
SYNAPSOR_RUNNER_HTTP_TOKEN: ${SYNAPSOR_RUNNER_HTTP_TOKEN}
|
|
462
500
|
volumes:
|
|
463
501
|
- ./synapsor.runner.json:/config/synapsor.runner.json:ro
|
|
464
502
|
- synapsor-runner-data:/data
|
|
465
|
-
|
|
466
|
-
- "8766
|
|
503
|
+
expose:
|
|
504
|
+
- "8766"
|
|
467
505
|
|
|
468
506
|
volumes:
|
|
469
507
|
synapsor-runner-data:
|
|
470
508
|
```
|
|
471
509
|
|
|
510
|
+
This shape deliberately does not publish the Runner port to the host. Put a
|
|
511
|
+
TLS-terminating proxy on the same private container network, publish only that
|
|
512
|
+
proxy, preserve the reviewed external Host, and prevent direct client access to
|
|
513
|
+
Runner. If Runner itself owns TLS, replace `--trusted-tls-proxy` with protected
|
|
514
|
+
`--tls-cert-env`/`--tls-key-env` PEM references.
|
|
515
|
+
|
|
472
516
|
### systemd Shape
|
|
473
517
|
|
|
474
518
|
```ini
|
|
@@ -491,10 +535,20 @@ PrivateTmp=true
|
|
|
491
535
|
WantedBy=multi-user.target
|
|
492
536
|
```
|
|
493
537
|
|
|
494
|
-
Put database credentials
|
|
495
|
-
manager, not in
|
|
538
|
+
Put database credentials and the random loopback endpoint token in
|
|
539
|
+
`/etc/synapsor-runner.env` or your system secret manager, not in
|
|
540
|
+
`synapsor.runner.json`. The systemd command binds loopback, so a local trusted
|
|
541
|
+
proxy may connect to it without exposing cleartext Bearer traffic on the
|
|
542
|
+
network.
|
|
496
543
|
|
|
497
|
-
## TLS And SSL
|
|
544
|
+
## TLS, mTLS, And Database SSL
|
|
545
|
+
|
|
546
|
+
For MCP HTTP, Runner-owned TLS reads certificate/key PEM only from named
|
|
547
|
+
environment variables. Optional mTLS verifies client certificates against an
|
|
548
|
+
explicit CA and supplements Bearer authentication; it does not replace
|
|
549
|
+
per-session tenant/principal identity in a shared service. A trusted proxy must
|
|
550
|
+
be protected from direct bypass and must not inject forwarded tenant/principal
|
|
551
|
+
headers as authority.
|
|
498
552
|
|
|
499
553
|
For staging or production-like databases:
|
|
500
554
|
|
|
@@ -507,6 +561,17 @@ For staging or production-like databases:
|
|
|
507
561
|
For disposable local Docker fixtures, `sslmode=disable` is acceptable when the
|
|
508
562
|
database is bound to loopback and contains only test data.
|
|
509
563
|
|
|
564
|
+
Rotate credentials independently:
|
|
565
|
+
|
|
566
|
+
- opaque endpoint token: active plus at most one previous env during rollout;
|
|
567
|
+
- HS256 session key: active plus one previous key, only for controlled use;
|
|
568
|
+
- asymmetric JWT key: publish a new `kid`, honor bounded JWKS cache/cooldown,
|
|
569
|
+
then retire the old public key after clients rotate;
|
|
570
|
+
- TLS certificate and mTLS client CA: roll protected PEM material and restart
|
|
571
|
+
instances without changing tenant identity;
|
|
572
|
+
- database and handler credentials: rotate their separate env/secret-manager
|
|
573
|
+
entries without reusing an MCP or Cloud credential.
|
|
574
|
+
|
|
510
575
|
## Health And Doctor
|
|
511
576
|
|
|
512
577
|
Run these before exposing tools to an agent:
|
package/docs/release-notes.md
CHANGED
|
@@ -10,7 +10,81 @@ 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
|
-
## 1.
|
|
13
|
+
## 1.6.0 (prepared, not published)
|
|
14
|
+
|
|
15
|
+
### Connect, Explore, Protect
|
|
16
|
+
|
|
17
|
+
- A fresh interactive `start --from-env DATABASE_URL` can inspect the whole
|
|
18
|
+
staging schema and structured Prisma/Drizzle/OpenAPI/Synapsor artifacts,
|
|
19
|
+
then emit a disabled candidate boundary without executing adopter code,
|
|
20
|
+
reading source rows, or using an LLM.
|
|
21
|
+
- The local Workbench requires explicit review of scope, fields, aggregate
|
|
22
|
+
measures/dimensions/time buckets, one-hop relationships, privacy budgets,
|
|
23
|
+
role/grant/RLS posture, profile, generation lock, and exact digest.
|
|
24
|
+
- The temporary Cursor authoring entry exposes only `app.describe_data` and
|
|
25
|
+
`app.explore_data`. Typed row and PM-style aggregate plans are bounded by the
|
|
26
|
+
activated authority, run read-only, and cannot introduce SQL, identifiers,
|
|
27
|
+
tenant/principal identity, or wider limits.
|
|
28
|
+
- Aggregate Explore supports reviewed count/distinct/sum/avg, categorical and
|
|
29
|
+
time grouping, bounded comparisons/top-N, cohort suppression, and durable
|
|
30
|
+
anti-differencing/extraction/rate limits. It is descriptive analysis, not a
|
|
31
|
+
causation claim.
|
|
32
|
+
- Protect This Query writes public DSL, canonical JSON, tests, and a disabled
|
|
33
|
+
named capability. Exact-digest activation disables broad Explore; production
|
|
34
|
+
serves only the named protected tool.
|
|
35
|
+
- Scoped Explore is absent from production, unknown-profile, shared HTTP,
|
|
36
|
+
remote, and non-loopback `tools/list`. Write-capable, owner, superuser,
|
|
37
|
+
`BYPASSRLS`, or unverifiable credentials cannot enable source-row Explore.
|
|
38
|
+
- Existing 1.x projects do not need Workbench, generation locks, rescans, or
|
|
39
|
+
new fields. Published legacy contracts preserve exact normalization/digests,
|
|
40
|
+
and established CLI/headless/CI routes keep their behavior.
|
|
41
|
+
|
|
42
|
+
Prepared package versions: `@synapsor/runner@1.6.0`,
|
|
43
|
+
`@synapsor/dsl@1.5.0`, and `@synapsor/spec@1.5.0`. Nothing has been published
|
|
44
|
+
by this repository change.
|
|
45
|
+
|
|
46
|
+
## 1.5.4 (published 2026-07-22)
|
|
47
|
+
|
|
48
|
+
### Networked MCP authentication hardening
|
|
49
|
+
|
|
50
|
+
- Local stdio still opens no network listener and needs no HTTP credential.
|
|
51
|
+
Loopback HTTP remains authenticated by default with an operator-provisioned
|
|
52
|
+
opaque token.
|
|
53
|
+
- Remote HTTP now refuses to bind over an undeclared cleartext channel. Operators
|
|
54
|
+
must use Runner-owned TLS, explicitly declare a trusted TLS proxy, or select an
|
|
55
|
+
authenticated and prominently diagnosed break-glass posture.
|
|
56
|
+
- Opaque endpoint tokens are constrained to local or explicit single-tenant use.
|
|
57
|
+
Remote use requires adequate entropy; one active and one previous env-provided
|
|
58
|
+
value support bounded rotation without logging either value.
|
|
59
|
+
- Shared deployments require signed per-session identity and `http_claims`
|
|
60
|
+
trusted context. Runner revalidates issuer, audience/resource, time, scope,
|
|
61
|
+
tenant, principal, signature, and algorithm on every request and rejects token
|
|
62
|
+
or identity swaps inside an MCP session.
|
|
63
|
+
- RFC 9728 protected-resource metadata and Bearer challenges let compatible MCP
|
|
64
|
+
clients discover the configured external authorization server. Runner verifies
|
|
65
|
+
access tokens but does not implement user login or token issuance.
|
|
66
|
+
- TLS/mTLS preflight, public-only bounded JWKS handling, exact Origin/Host checks,
|
|
67
|
+
request/session bounds, doctor diagnostics, client recipes, and fleet examples
|
|
68
|
+
now share one documented deployment ladder.
|
|
69
|
+
- `lifecycle`, `lifecycle show`, and `lifecycle show latest` now inspect the
|
|
70
|
+
newest complete proposal lifecycle without an id. Filters and known
|
|
71
|
+
proposal/evidence/replay/job/intent/receipt/audit handles resolve a stable,
|
|
72
|
+
read-only `synapsor.lifecycle-view.v1` domain document across local SQLite
|
|
73
|
+
and shared PostgreSQL runtime stores.
|
|
74
|
+
- DSL UPDATE authoring now requires an exact `CONFLICT GUARD <column>` instead
|
|
75
|
+
of silently choosing projection hashing. A reviewer-visible weak compatibility
|
|
76
|
+
clause remains only for ordinary single-row source-DB UPDATE and is rejected
|
|
77
|
+
for the stronger operation modes.
|
|
78
|
+
- Runner rejects canonical `FROM SESSION` with
|
|
79
|
+
`SESSION_BINDING_UNSUPPORTED` rather than treating its key as a process
|
|
80
|
+
environment variable. Explicit ENVIRONMENT, verified HTTP_CLAIM, verified
|
|
81
|
+
CLOUD_SESSION, and STATIC_DEV behavior remains distinct.
|
|
82
|
+
|
|
83
|
+
Published package versions: `@synapsor/runner@1.5.4` and
|
|
84
|
+
`@synapsor/dsl@1.4.4`. `@synapsor/spec@1.4.2` and the Cloud CLI were
|
|
85
|
+
unchanged.
|
|
86
|
+
|
|
87
|
+
## 1.5.3 (published 2026-07-21)
|
|
14
88
|
|
|
15
89
|
### Intent to Safe Action
|
|
16
90
|
|
|
@@ -37,8 +111,8 @@ for the Synapsor Cloud CLI.
|
|
|
37
111
|
- The first two README screens, public website, article, discovery routes, and
|
|
38
112
|
36-second evidence-backed demo now lead with the own-project Data PR path.
|
|
39
113
|
|
|
40
|
-
|
|
41
|
-
packages
|
|
114
|
+
Published package version: `@synapsor/runner@1.5.3`. Spec, DSL, and Cloud CLI
|
|
115
|
+
packages were unchanged.
|
|
42
116
|
|
|
43
117
|
## 1.5.2 (prepared, not published)
|
|
44
118
|
|
package/docs/runner-bundles.md
CHANGED
|
@@ -67,8 +67,13 @@ npx -y -p @synapsor/runner synapsor-runner cloud sync latest \
|
|
|
67
67
|
|
|
68
68
|
For the OpenAI Agents SDK, use the included TypeScript examples. Their stdio
|
|
69
69
|
command enables `--alias-mode openai`; the Streamable HTTP example includes the
|
|
70
|
-
matching server command
|
|
71
|
-
|
|
70
|
+
matching server command and reads its Bearer credential from
|
|
71
|
+
`SYNAPSOR_RUNNER_HTTP_TOKEN`. The generic HTTP template uses the same environment
|
|
72
|
+
reference. Neither file embeds a credential value. An operator generates and
|
|
73
|
+
provisions the opaque token to the Runner process and authorized client; use a
|
|
74
|
+
signed identity-provider token instead for shared multi-user deployments. See
|
|
75
|
+
[HTTP MCP](http-mcp.md). Claude, Cursor, and generic stdio templates use
|
|
76
|
+
canonical dotted capability names and need no HTTP credential.
|
|
72
77
|
|
|
73
78
|
Approval and writeback remain outside the model-facing MCP tool surface. Use
|
|
74
79
|
`proposals`, `apply`, `receipts`, and `replay` from a trusted operator shell.
|
|
@@ -36,6 +36,7 @@ Unknown keys fail when `strict` is true (the default).
|
|
|
36
36
|
| `approvals` | No | Local approval overrides. |
|
|
37
37
|
| `operator_identity` | No | Verified operator identity and apply-role wiring for approve/reject/apply. |
|
|
38
38
|
| `session_auth` | HTTP claims | HS256 development or asymmetric RS256/ES256 session-token verification. |
|
|
39
|
+
| `http_security` | Networked HTTP | Deployment profile, protected channel, endpoint-token env names, OAuth protected-resource metadata, exact Origin/Host policy, and request/session bounds. |
|
|
39
40
|
| `rate_limits` | No | Operational fixed-window limits; fleet-wide only with shared `runtime_store`. |
|
|
40
41
|
| `metrics` | No | Separately authorized scrapeable HTTP metrics. Disabled by default. |
|
|
41
42
|
| `graduated_trust` | No | Off-by-default, operator-only policy recommendation criteria and kill switch. |
|
|
@@ -212,8 +213,16 @@ Providers are `environment`, `static_dev`, `http_claims`, and `cloud_session`.
|
|
|
212
213
|
Capabilities may reference a context by name. The model never receives tenant
|
|
213
214
|
or principal as an overridable argument.
|
|
214
215
|
|
|
215
|
-
|
|
216
|
-
session
|
|
216
|
+
The language-neutral canonical contract can preserve a `session` binding for
|
|
217
|
+
implementations such as C++/Cloud that own a typed session boundary. Runner has
|
|
218
|
+
no generic web-session provider and rejects it with
|
|
219
|
+
`SESSION_BINDING_UNSUPPORTED`; it never treats the key as an environment
|
|
220
|
+
variable. Use `environment` for local stdio, verified `http_claims` for shared
|
|
221
|
+
Streamable HTTP, or verified `cloud_session` for Cloud embedding.
|
|
222
|
+
|
|
223
|
+
For controlled loopback development, `http_claims` can use an HS256 session
|
|
224
|
+
token. Runner holds the symmetric signing/verification secret in this mode, so
|
|
225
|
+
it is not the recommended shared production profile:
|
|
217
226
|
|
|
218
227
|
```json
|
|
219
228
|
{
|
|
@@ -229,7 +238,7 @@ session auth:
|
|
|
229
238
|
"secret_env": "SYNAPSOR_SESSION_JWT_SECRET",
|
|
230
239
|
"previous_secret_env": "SYNAPSOR_PREVIOUS_SESSION_JWT_SECRET",
|
|
231
240
|
"issuer": "https://identity.example",
|
|
232
|
-
"audience": "
|
|
241
|
+
"audience": "https://runner.example/mcp"
|
|
233
242
|
}
|
|
234
243
|
}
|
|
235
244
|
```
|
|
@@ -239,16 +248,24 @@ the active secret first, then the previous secret. Existing MCP sessions remain
|
|
|
239
248
|
bound to the exact token fingerprint, so clients cannot swap tenant/principal
|
|
240
249
|
identity inside an initialized session.
|
|
241
250
|
|
|
242
|
-
For networked
|
|
251
|
+
For a shared networked deployment, use asymmetric public-key verification and
|
|
252
|
+
declare the protected resource and channel explicitly:
|
|
243
253
|
|
|
244
254
|
```json
|
|
245
255
|
{
|
|
256
|
+
"trusted_context": {
|
|
257
|
+
"provider": "http_claims",
|
|
258
|
+
"values": {
|
|
259
|
+
"tenant_id_key": "tenant_id",
|
|
260
|
+
"principal_key": "sub"
|
|
261
|
+
}
|
|
262
|
+
},
|
|
246
263
|
"session_auth": {
|
|
247
264
|
"provider": "jwt_asymmetric",
|
|
248
|
-
"algorithms": ["RS256"],
|
|
265
|
+
"algorithms": ["RS256", "ES256"],
|
|
249
266
|
"jwks_url_env": "SYNAPSOR_SESSION_JWKS_URL",
|
|
250
267
|
"issuer": "https://identity.example",
|
|
251
|
-
"audience": "
|
|
268
|
+
"audience": "https://runner.example/mcp",
|
|
252
269
|
"tenant_claim": "tenant_id",
|
|
253
270
|
"principal_claim": "sub",
|
|
254
271
|
"clock_skew_seconds": 30,
|
|
@@ -256,6 +273,19 @@ For networked deployments prefer asymmetric public-key verification:
|
|
|
256
273
|
"jwks_cooldown_seconds": 30,
|
|
257
274
|
"fetch_timeout_ms": 3000,
|
|
258
275
|
"max_response_bytes": 1048576
|
|
276
|
+
},
|
|
277
|
+
"http_security": {
|
|
278
|
+
"deployment": "shared",
|
|
279
|
+
"channel": "trusted_tls_proxy",
|
|
280
|
+
"oauth_resource": {
|
|
281
|
+
"resource": "https://runner.example/mcp",
|
|
282
|
+
"authorization_servers": ["https://identity.example"],
|
|
283
|
+
"scopes_supported": ["synapsor:mcp"],
|
|
284
|
+
"required_scopes": ["synapsor:mcp"],
|
|
285
|
+
"resource_name": "Synapsor Runner"
|
|
286
|
+
},
|
|
287
|
+
"allowed_origins": ["https://agent-console.example"],
|
|
288
|
+
"allowed_hosts": ["runner.example"]
|
|
259
289
|
}
|
|
260
290
|
}
|
|
261
291
|
```
|
|
@@ -268,6 +298,66 @@ rejected. Every effective named context in an `http_claims` server must bind
|
|
|
268
298
|
tenant and principal from claims; environment/static contradictions fail with
|
|
269
299
|
`TRUSTED_CONTEXT_PROVIDER_CONFLICT` before serving.
|
|
270
300
|
|
|
301
|
+
`session_auth` verifies identity; it does not issue access tokens. The external
|
|
302
|
+
identity provider identified by `issuer` issues a short-lived token whose
|
|
303
|
+
audience is the exact protected-resource URL. Runner fetches only public JWKS
|
|
304
|
+
material and validates the configured claims on every request. Required OAuth
|
|
305
|
+
scopes are declared under `http_security.oauth_resource`.
|
|
306
|
+
|
|
307
|
+
## HTTP security
|
|
308
|
+
|
|
309
|
+
`http_security` is Runner deployment wiring, not part of a portable contract:
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"http_security": {
|
|
314
|
+
"deployment": "single_tenant",
|
|
315
|
+
"channel": "trusted_tls_proxy",
|
|
316
|
+
"static_token": {
|
|
317
|
+
"active_env": "SYNAPSOR_RUNNER_HTTP_TOKEN",
|
|
318
|
+
"previous_env": "SYNAPSOR_RUNNER_HTTP_TOKEN_PREVIOUS"
|
|
319
|
+
},
|
|
320
|
+
"allowed_origins": ["https://agent-console.example"],
|
|
321
|
+
"allowed_hosts": ["runner.internal.example"],
|
|
322
|
+
"limits": {
|
|
323
|
+
"max_request_bytes": 65536,
|
|
324
|
+
"max_header_bytes": 8192,
|
|
325
|
+
"max_sessions": 500,
|
|
326
|
+
"session_idle_timeout_seconds": 300,
|
|
327
|
+
"request_timeout_ms": 15000,
|
|
328
|
+
"headers_timeout_ms": 5000,
|
|
329
|
+
"keep_alive_timeout_ms": 5000,
|
|
330
|
+
"max_connections": 1000
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
- `deployment` is `loopback`, `single_tenant`, or `shared`. Shared requires
|
|
337
|
+
verified signed `http_claims`, exact issuer/audience, and RFC 9728
|
|
338
|
+
`oauth_resource` metadata.
|
|
339
|
+
- `channel` is `direct_tls`, `trusted_tls_proxy`, or the explicitly unsafe
|
|
340
|
+
`insecure_http_break_glass`. A non-loopback listener without one refuses to
|
|
341
|
+
bind. Break glass remains authenticated.
|
|
342
|
+
- `static_token` names one active and optionally one previous environment
|
|
343
|
+
variable. It is opaque service access for loopback/single-tenant use, not
|
|
344
|
+
tenant identity. Values never belong in config.
|
|
345
|
+
- `oauth_resource.resource` is the exact HTTPS MCP endpoint and must equal
|
|
346
|
+
`session_auth.audience`. `authorization_servers` names external issuers;
|
|
347
|
+
Runner does not implement login or token refresh.
|
|
348
|
+
- `allowed_origins` contains exact browser origins; an omitted browser Origin
|
|
349
|
+
remains valid for native clients. Wildcards are forbidden.
|
|
350
|
+
- `allowed_hosts` contains exact direct/public Host authorities. Forwarded Host
|
|
351
|
+
and forwarded identity headers are not trusted automatically.
|
|
352
|
+
- `limits` bounds bodies, headers, concurrent sessions/connections, idle
|
|
353
|
+
sessions, and HTTP timing. Defaults are documented in [HTTP MCP](http-mcp.md).
|
|
354
|
+
|
|
355
|
+
Runner-owned TLS certificate, key, and optional client-CA PEM values are passed
|
|
356
|
+
by environment references on the serve command (`--tls-cert-env`,
|
|
357
|
+
`--tls-key-env`, `--tls-ca-env`, `--require-client-cert`). Private TLS material
|
|
358
|
+
does not go in this JSON file. A trusted-proxy channel assumes firewall/private
|
|
359
|
+
network controls prevent clients from bypassing that proxy.
|
|
360
|
+
|
|
271
361
|
## Contracts and embedded capabilities
|
|
272
362
|
|
|
273
363
|
```json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Running A Small Runner Fleet
|
|
2
2
|
|
|
3
|
-
Synapsor Runner
|
|
3
|
+
Synapsor Runner supports a bounded small-fleet deployment. It does not
|
|
4
4
|
turn the OSS package into Synapsor Cloud and it does not promise an unbounded,
|
|
5
5
|
multi-region, or SLA-backed control plane.
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ model-facing approval/apply tools as blockers. Audit is a static review, not a
|
|
|
32
32
|
security proof; follow it with `tools preview`, `doctor`, and the live fleet
|
|
33
33
|
verification.
|
|
34
34
|
|
|
35
|
-
## What
|
|
35
|
+
## What The Bounded Fleet Guarantees
|
|
36
36
|
|
|
37
37
|
With `storage.shared_postgres.mode = "runtime_store"`:
|
|
38
38
|
|
|
@@ -116,7 +116,7 @@ Use asymmetric verification for a networked fleet:
|
|
|
116
116
|
"algorithms": ["RS256"],
|
|
117
117
|
"jwks_url_env": "SYNAPSOR_SESSION_JWKS_URL",
|
|
118
118
|
"issuer": "https://identity.example",
|
|
119
|
-
"audience": "
|
|
119
|
+
"audience": "https://runner.example/mcp",
|
|
120
120
|
"tenant_claim": "tenant_id",
|
|
121
121
|
"principal_claim": "sub",
|
|
122
122
|
"clock_skew_seconds": 30,
|
|
@@ -124,10 +124,28 @@ Use asymmetric verification for a networked fleet:
|
|
|
124
124
|
"jwks_cooldown_seconds": 30,
|
|
125
125
|
"fetch_timeout_ms": 3000,
|
|
126
126
|
"max_response_bytes": 1048576
|
|
127
|
+
},
|
|
128
|
+
"http_security": {
|
|
129
|
+
"deployment": "shared",
|
|
130
|
+
"channel": "trusted_tls_proxy",
|
|
131
|
+
"oauth_resource": {
|
|
132
|
+
"resource": "https://runner.example/mcp",
|
|
133
|
+
"authorization_servers": ["https://identity.example"],
|
|
134
|
+
"scopes_supported": ["synapsor:mcp"],
|
|
135
|
+
"required_scopes": ["synapsor:mcp"]
|
|
136
|
+
},
|
|
137
|
+
"allowed_hosts": ["runner.example"],
|
|
138
|
+
"allowed_origins": ["https://agent-console.example"]
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
```
|
|
130
142
|
|
|
143
|
+
The external identity provider issues the short-lived client JWT for resource
|
|
144
|
+
`https://runner.example/mcp`; Runner only verifies it. The load balancer must
|
|
145
|
+
terminate TLS and prevent direct access to the private Runner listeners. If
|
|
146
|
+
Runner owns TLS instead, use protected certificate/key env references and set
|
|
147
|
+
`channel` to `direct_tls`.
|
|
148
|
+
|
|
131
149
|
Every served capability context must bind tenant and principal from
|
|
132
150
|
`HTTP_CLAIM`. Runner rejects an environment-bound contract mixed into this
|
|
133
151
|
server with `TRUSTED_CONTEXT_PROVIDER_CONFLICT` before tools are served.
|
|
@@ -147,6 +165,12 @@ material. Unknown `kid` triggers at most one controlled refresh. For offline
|
|
|
147
165
|
deployments, configure one public PEM through `public_key_env` or
|
|
148
166
|
`public_key_path`; never place a private key in Runner config.
|
|
149
167
|
|
|
168
|
+
Runner publishes RFC 9728 protected-resource metadata at the path derived from
|
|
169
|
+
the public resource and returns scope-aware Bearer challenges. The identity
|
|
170
|
+
provider, not Runner, owns user login, client registration, token issuance, and
|
|
171
|
+
refresh. An MCP session ID is only protocol state; every request is
|
|
172
|
+
reauthenticated and remains pinned to the initialized credential identity.
|
|
173
|
+
|
|
150
174
|
## Ledger And Source Pools
|
|
151
175
|
|
|
152
176
|
```json
|
|
@@ -329,12 +353,13 @@ configured handler timeout. A hard kill is recoverable through leases and
|
|
|
329
353
|
source-side idempotency receipts, but should remain an incident signal.
|
|
330
354
|
|
|
331
355
|
Rotate JWKS keys by publishing the new `kid`, waiting at least the configured
|
|
332
|
-
cache lifetime
|
|
333
|
-
|
|
334
|
-
|
|
356
|
+
cache lifetime while issuers sign with the new key, then retiring the old key.
|
|
357
|
+
Do not casually change the issuer or protected-resource audience during a key
|
|
358
|
+
rotation. Rotate TLS/mTLS, metrics, handler, database, and ledger credentials
|
|
359
|
+
independently through their named environment variables.
|
|
335
360
|
|
|
336
|
-
Only homogeneous Runner
|
|
337
|
-
|
|
361
|
+
Only homogeneous Runner instances at the release under test are verified by
|
|
362
|
+
`test:fleet`. Mixed-version operation is not claimed. For rolling upgrades:
|
|
338
363
|
|
|
339
364
|
1. back up and verify the ledger;
|
|
340
365
|
2. run schema/config validation with the target version;
|
|
@@ -351,8 +376,12 @@ roll back the full fleet. Never mix versions merely because both are `1.x`.
|
|
|
351
376
|
|
|
352
377
|
## TLS Boundary
|
|
353
378
|
|
|
354
|
-
Terminate public TLS or mTLS at a trusted load balancer
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
379
|
+
Terminate public TLS or mTLS at a trusted load balancer and declare
|
|
380
|
+
`channel: trusted_tls_proxy`, or configure Runner's tested TLS/mTLS options
|
|
381
|
+
directly. A proxy declaration is a security assertion: firewall the private
|
|
382
|
+
listener so clients cannot bypass the proxy, protect the private hop, and
|
|
383
|
+
preserve an allowed Host. Keep Runner-to-database TLS verification on, use
|
|
384
|
+
private networking where possible, and restrict `/metrics` separately. The
|
|
385
|
+
verified Bearer JWT itself, not a proxy-added tenant/principal header, is the
|
|
386
|
+
session authority. See [HTTP MCP](http-mcp.md) for channel flags, limits, and
|
|
387
|
+
doctor checks.
|