@synapsor/runner 0.1.9 → 0.1.11
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 +32 -0
- package/README.md +60 -29
- package/dist/cli.d.ts.map +1 -1
- package/dist/runner.mjs +719 -47
- package/docs/README.md +6 -0
- package/docs/cloud-mode.md +18 -0
- package/docs/cloud-push.md +54 -0
- package/docs/current-scope.md +1 -1
- package/docs/local-mode.md +4 -3
- package/docs/mcp-clients.md +123 -0
- package/docs/release-notes.md +30 -0
- package/docs/runner-bundles.md +59 -0
- package/examples/support-plan-credit/.env.example +10 -0
- package/examples/support-plan-credit/README.md +273 -0
- package/examples/support-plan-credit/contract.synapsor +59 -0
- package/examples/support-plan-credit/docker-compose.yml +12 -0
- package/examples/support-plan-credit/expected-output/cloud-push-response.json +9 -0
- package/examples/support-plan-credit/expected-output/proposal-created.json +23 -0
- package/examples/support-plan-credit/expected-output/receipt.json +13 -0
- package/examples/support-plan-credit/expected-output/replay-summary.json +13 -0
- package/examples/support-plan-credit/expected-output/tools-preview.txt +15 -0
- package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +20 -0
- package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +20 -0
- package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +20 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +17 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +5 -0
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +19 -0
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +20 -0
- package/examples/support-plan-credit/seed/001_seed.sql +92 -0
- package/examples/support-plan-credit/synapsor.contract.json +198 -0
- package/examples/support-plan-credit/synapsor.runner.json +18 -0
- package/package.json +2 -1
package/docs/README.md
CHANGED
|
@@ -49,6 +49,8 @@ then read the concepts once the safety boundary is visible.
|
|
|
49
49
|
|
|
50
50
|
- [MCP Client Setup](mcp-client-setup.md): connect Claude, Cursor, VS Code, or
|
|
51
51
|
another stdio MCP client.
|
|
52
|
+
- [MCP Client Configs](mcp-clients.md): complete Claude, Cursor, OpenAI Agents,
|
|
53
|
+
generic stdio, and Streamable HTTP templates.
|
|
52
54
|
- `examples/claude-desktop-postgres/`: copy-paste Claude Desktop config for the
|
|
53
55
|
Postgres billing fixture.
|
|
54
56
|
- `examples/cursor-postgres/`: copy-paste Cursor config for the Postgres
|
|
@@ -96,6 +98,10 @@ then read the concepts once the safety boundary is visible.
|
|
|
96
98
|
scope, database roles, receipt grants, local ledger backup, restart behavior,
|
|
97
99
|
Docker/systemd shapes, TLS, and release-gate expectations.
|
|
98
100
|
- [Cloud Mode](cloud-mode.md): what stays local and what Cloud-linked mode adds.
|
|
101
|
+
- [Cloud Push](cloud-push.md): register a validated local contract in the
|
|
102
|
+
versioned Cloud registry.
|
|
103
|
+
- [Runner Bundles](runner-bundles.md): download the same immutable contract and
|
|
104
|
+
its local MCP wiring from Cloud.
|
|
99
105
|
- [Release Notes](release-notes.md): release history and behavior changes.
|
|
100
106
|
- [Release Policy](release-policy.md): stable gates and publish verification.
|
|
101
107
|
- [Licensing](licensing.md): Apache-2.0 scope, trademark boundary, and what is
|
package/docs/cloud-mode.md
CHANGED
|
@@ -6,6 +6,8 @@ guarded writeback, or replay.
|
|
|
6
6
|
|
|
7
7
|
Cloud-linked mode is for teams that need a shared control plane:
|
|
8
8
|
|
|
9
|
+
- versioned canonical contract registry and server-computed digests;
|
|
10
|
+
- Cloud-to-local runner bundle downloads;
|
|
9
11
|
- team approvals and RBAC;
|
|
10
12
|
- hosted evidence/replay search;
|
|
11
13
|
- runner registration and heartbeat;
|
|
@@ -17,6 +19,22 @@ The local runner still keeps database credentials in your environment. MCP
|
|
|
17
19
|
client config snippets should contain command paths and runner arguments, not
|
|
18
20
|
database URLs or write credentials.
|
|
19
21
|
|
|
22
|
+
Push and retrieve the portable contract without moving database credentials
|
|
23
|
+
into Cloud:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
synapsor-runner cloud push ./synapsor.contract.json --dry-run
|
|
27
|
+
synapsor-runner cloud push ./synapsor.contract.json \
|
|
28
|
+
--workspace "$SYNAPSOR_WORKSPACE_ID" \
|
|
29
|
+
--name support-plan-credit
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
See [Cloud Push](cloud-push.md) and [Runner Bundles](runner-bundles.md).
|
|
33
|
+
|
|
34
|
+
Cloud registry storage preserves approval policies but does not, by itself,
|
|
35
|
+
mean hosted policy enforcement is enabled. Local Runner enforcement and hosted
|
|
36
|
+
Cloud approval enforcement are separate runtime boundaries.
|
|
37
|
+
|
|
20
38
|
Run the local smoke for this mode with:
|
|
21
39
|
|
|
22
40
|
```bash
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Push A Contract To Synapsor Cloud
|
|
2
|
+
|
|
3
|
+
Cloud push registers the same canonical contract that you validate and run
|
|
4
|
+
locally. Cloud stores a normalized immutable version, computes its digest,
|
|
5
|
+
records the actor, and makes the safety boundary visible in the workspace
|
|
6
|
+
registry.
|
|
7
|
+
|
|
8
|
+
## Preview Without A Network Call
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
synapsor-runner cloud push ./synapsor.contract.json --dry-run
|
|
12
|
+
synapsor-runner cloud push ./synapsor.contract.json --dry-run --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Dry-run validates and normalizes locally. It performs no network request.
|
|
16
|
+
|
|
17
|
+
## Push
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
export SYNAPSOR_CLOUD_BASE_URL="https://api.synapsor.ai"
|
|
21
|
+
export SYNAPSOR_CLOUD_TOKEN="<workspace-scoped-token>"
|
|
22
|
+
export SYNAPSOR_WORKSPACE_ID="<workspace-id>"
|
|
23
|
+
|
|
24
|
+
synapsor-runner cloud push ./synapsor.contract.json \
|
|
25
|
+
--name support-plan-credit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The response includes the contract id, immutable version id, server-computed
|
|
29
|
+
digest, summary counts, status, and registry path. Identical normalized content
|
|
30
|
+
is idempotent; changed content creates the next version.
|
|
31
|
+
|
|
32
|
+
Tokens are sent in the authorization header and are never part of the contract.
|
|
33
|
+
Database URLs, passwords, private keys, and model-controlled tenant bindings
|
|
34
|
+
are rejected by server-side validation.
|
|
35
|
+
|
|
36
|
+
`SYNAPSOR_CLOUD_WORKSPACE` is accepted as an alias for
|
|
37
|
+
`SYNAPSOR_WORKSPACE_ID`. Explicit `--workspace` wins over environment values.
|
|
38
|
+
|
|
39
|
+
Cloud push fails before upload when local validation fails. HTTP failures are
|
|
40
|
+
reported distinctly for invalid/expired tokens (`401`), insufficient workspace
|
|
41
|
+
permission (`403`), missing workspace/API paths (`404`), registry conflicts
|
|
42
|
+
(`409`), server validation (`422`), and Cloud/network failures. Error output
|
|
43
|
+
does not echo the bearer token.
|
|
44
|
+
|
|
45
|
+
## Cloud To Local
|
|
46
|
+
|
|
47
|
+
Open **Contract registry** in the workspace, choose a version, and download its
|
|
48
|
+
runner bundle. The ZIP contains the normalized contract, local runner wiring,
|
|
49
|
+
placeholder environment file, README, and MCP client examples. It contains no
|
|
50
|
+
live credentials or table rows.
|
|
51
|
+
|
|
52
|
+
Cloud currently preserves approval policy definitions in the contract and
|
|
53
|
+
bundle. Hosted approval-policy enforcement remains a separate Cloud feature;
|
|
54
|
+
do not infer it from registry storage alone.
|
package/docs/current-scope.md
CHANGED
package/docs/local-mode.md
CHANGED
|
@@ -345,7 +345,7 @@ For CI or direct verification, use:
|
|
|
345
345
|
corepack pnpm test:mcp-local
|
|
346
346
|
```
|
|
347
347
|
|
|
348
|
-
It launches the official MCP stdio client transport against `synapsor-runner mcp serve`, exercises the Postgres billing, Postgres support,
|
|
348
|
+
It launches the official MCP stdio client transport against `synapsor-runner mcp serve`, exercises the Postgres billing, Postgres support, MySQL orders, and support plan-credit examples, checks that source rows are unchanged before approval, approves locally, generates versioned writeback jobs, applies them, retries idempotently, and then proves stale-row conflict:
|
|
349
349
|
|
|
350
350
|
```text
|
|
351
351
|
The business state changed after the agent saw it, so Synapsor refused to commit.
|
|
@@ -360,14 +360,15 @@ corepack pnpm test:live-apply
|
|
|
360
360
|
Prerequisites:
|
|
361
361
|
|
|
362
362
|
- Docker daemon running;
|
|
363
|
-
- local ports `55433`, `55434`, and `53307` available;
|
|
363
|
+
- local ports `55433`, `55434`, `55438`, and `53307` available;
|
|
364
364
|
- no Synapsor Cloud account, API key, hosted workspace, or production database.
|
|
365
365
|
|
|
366
366
|
Expected output:
|
|
367
367
|
|
|
368
|
-
- disposable Postgres billing, Postgres support, and MySQL orders containers start;
|
|
368
|
+
- disposable Postgres billing, Postgres support, support plan-credit, and MySQL orders containers start;
|
|
369
369
|
- MCP `tools/list` exposes reviewed semantic tools, not raw SQL;
|
|
370
370
|
- proposal calls create exact before/after diffs while source rows remain unchanged;
|
|
371
|
+
- the support plan-credit scenario proves `$25` policy auto-approval, `$100` human approval, and `$1000` bound rejection;
|
|
371
372
|
- local approval happens outside MCP;
|
|
372
373
|
- guarded writeback applies approved jobs and records receipts/replay;
|
|
373
374
|
- idempotent retry returns the existing receipt;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# MCP Client Configs
|
|
2
|
+
|
|
3
|
+
Synapsor Runner exposes reviewed semantic tools over standard MCP. The model
|
|
4
|
+
receives inspect/propose capabilities; it does not receive raw SQL, database
|
|
5
|
+
credentials, approval commands, or apply commands.
|
|
6
|
+
|
|
7
|
+
The complete copy-paste templates live in:
|
|
8
|
+
|
|
9
|
+
- [`examples/support-plan-credit/mcp-client-examples/`](../examples/support-plan-credit/mcp-client-examples/)
|
|
10
|
+
- every local `synapsor-runner contract bundle` output;
|
|
11
|
+
- every downloadable Synapsor Cloud runner bundle.
|
|
12
|
+
|
|
13
|
+
Before connecting a client, validate the local boundary:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
synapsor-runner config validate --config ./synapsor.runner.json
|
|
17
|
+
synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Set database and trusted-context values in the environment that launches the
|
|
21
|
+
MCP process. Keep real URLs and tokens in your shell or secret manager, not in
|
|
22
|
+
the checked-in client JSON.
|
|
23
|
+
|
|
24
|
+
## Stdio
|
|
25
|
+
|
|
26
|
+
Use stdio for Claude Desktop, Cursor, and other local MCP clients:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": [
|
|
32
|
+
"-y", "-p", "@synapsor/runner", "synapsor-runner",
|
|
33
|
+
"mcp", "serve", "--config", "./synapsor.runner.json",
|
|
34
|
+
"--store", "./.synapsor/local.db"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Relative paths are resolved from the MCP client's working directory. Use the
|
|
40
|
+
project template when the client starts in your repository; replace the marked
|
|
41
|
+
bundle path in the global template when it does not.
|
|
42
|
+
|
|
43
|
+
### Claude Desktop
|
|
44
|
+
|
|
45
|
+
1. Open Claude Desktop settings and choose the developer option to edit its MCP
|
|
46
|
+
configuration.
|
|
47
|
+
2. Merge `claude-desktop.json` into the existing `mcpServers` object.
|
|
48
|
+
3. Replace the marked working directory or use absolute paths when Claude does
|
|
49
|
+
not start in the bundle directory.
|
|
50
|
+
4. Restart Claude Desktop completely, then confirm the two semantic tools are
|
|
51
|
+
listed.
|
|
52
|
+
|
|
53
|
+
Claude Desktop launched from a graphical session may not inherit your terminal
|
|
54
|
+
environment. Supply the required env values through the OS process environment
|
|
55
|
+
or a local secret-manager wrapper; do not paste production credentials into a
|
|
56
|
+
repository file.
|
|
57
|
+
|
|
58
|
+
### Cursor
|
|
59
|
+
|
|
60
|
+
For one repository, place the project template at `.cursor/mcp.json`. For a
|
|
61
|
+
global setup, merge `cursor-global.mcp.json` through Cursor's MCP settings and
|
|
62
|
+
replace every `<absolute-path-to-bundle>` marker. Restart the MCP server from
|
|
63
|
+
Cursor settings after editing.
|
|
64
|
+
|
|
65
|
+
The model-facing list should contain only the contract's inspect/propose tools.
|
|
66
|
+
If Cursor reports a missing config or store, use absolute paths and rerun
|
|
67
|
+
`tools preview` from the same working directory.
|
|
68
|
+
|
|
69
|
+
### OpenAI Agents SDK
|
|
70
|
+
|
|
71
|
+
Install the SDK in your agent project and run either TypeScript template:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm install @openai/agents
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
OpenAI function names cannot contain dots. The stdio template therefore starts
|
|
78
|
+
Runner with `--alias-mode openai`; model-visible names use `__`, while result
|
|
79
|
+
metadata preserves the canonical dotted Synapsor capability name.
|
|
80
|
+
|
|
81
|
+
## Streamable HTTP
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
synapsor-runner mcp serve \
|
|
85
|
+
--transport streamable-http \
|
|
86
|
+
--alias-mode openai \
|
|
87
|
+
--host 127.0.0.1 \
|
|
88
|
+
--port 8766 \
|
|
89
|
+
--config ./synapsor.runner.json \
|
|
90
|
+
--store ./.synapsor/local.db
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Connect a standard Streamable HTTP MCP client to
|
|
94
|
+
`http://127.0.0.1:8766/mcp`. Keep it on loopback for local development. For a
|
|
95
|
+
network deployment, terminate TLS, require authentication, restrict network
|
|
96
|
+
access, and follow the [production guide](production.md).
|
|
97
|
+
|
|
98
|
+
Use `--alias-mode openai` for the OpenAI Agents SDK. Omit it for clients that
|
|
99
|
+
accept canonical dotted names, or use `--alias-mode both` only during a planned
|
|
100
|
+
migration where duplicate canonical/alias tools are acceptable.
|
|
101
|
+
|
|
102
|
+
## Verify The Boundary
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
106
|
+
synapsor-runner smoke call --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The preview must list semantic capabilities and must not list `execute_sql`,
|
|
110
|
+
approval/apply tools, database URLs, write credentials, or model-controlled
|
|
111
|
+
tenant authority.
|
|
112
|
+
|
|
113
|
+
## Troubleshooting
|
|
114
|
+
|
|
115
|
+
- `ENOENT` or missing config: use absolute config/store paths.
|
|
116
|
+
- empty tool list: run `contract validate`, then `tools preview` against the
|
|
117
|
+
exact config used by the client.
|
|
118
|
+
- database connection failure: verify the client process received the read URL
|
|
119
|
+
and trusted tenant/principal env values.
|
|
120
|
+
- OpenAI rejects a dotted name: start Runner with `--alias-mode openai`.
|
|
121
|
+
- HTTP `initialize` failure: use `mcp serve --transport streamable-http`, not
|
|
122
|
+
the legacy `serve-http` JSON-RPC bridge.
|
|
123
|
+
- no ready message: inspect client stderr; Runner keeps stdout protocol-clean.
|
package/docs/release-notes.md
CHANGED
|
@@ -12,6 +12,36 @@ for the Synapsor Cloud CLI.
|
|
|
12
12
|
|
|
13
13
|
## Unreleased
|
|
14
14
|
|
|
15
|
+
Prepared package versions: `@synapsor/spec@0.1.4`,
|
|
16
|
+
`@synapsor/dsl@0.1.4`, and `@synapsor/runner@0.1.11`. Nothing in this section
|
|
17
|
+
is published until the manual release commands are run.
|
|
18
|
+
|
|
19
|
+
### Cloud Adoption Loop
|
|
20
|
+
|
|
21
|
+
- Adds complete Claude, Cursor, OpenAI Agents SDK, and generic MCP templates to
|
|
22
|
+
local and Cloud-generated Runner bundles.
|
|
23
|
+
- Adds a flagship adoption verifier and a real local Cloud registry/version/ZIP
|
|
24
|
+
bundle round trip.
|
|
25
|
+
- Expands the `support-plan-credit` walkthrough from no-database validation to
|
|
26
|
+
Docker-backed policy tiers, MCP setup, Cloud push, bundle download, replay,
|
|
27
|
+
cleanup, and troubleshooting.
|
|
28
|
+
- Supports `SYNAPSOR_CLOUD_WORKSPACE` and verifies distinct 401/403/404/409/422,
|
|
29
|
+
server, and network errors without exposing tokens.
|
|
30
|
+
- Clarifies that Cloud registry/versioning is beta-ready while managed runners,
|
|
31
|
+
SAML/SCIM, hosted policy enforcement, legal hold, and enterprise SLA are not
|
|
32
|
+
part of this release.
|
|
33
|
+
- Corrects `cloud push --help` to describe the real authenticated registry
|
|
34
|
+
upload and network-free dry-run behavior.
|
|
35
|
+
|
|
36
|
+
## 0.1.10
|
|
37
|
+
|
|
38
|
+
### Policy Auto-Approval
|
|
39
|
+
|
|
40
|
+
- Adds portable approval-policy references and threshold rules.
|
|
41
|
+
- Adds DSL `AUTO APPROVE WHEN field <= integer` and the three-tier
|
|
42
|
+
`support-plan-credit` example: policy approval, operator review, and bound
|
|
43
|
+
rejection.
|
|
44
|
+
|
|
15
45
|
## 0.1.9
|
|
16
46
|
|
|
17
47
|
### CLI Hygiene
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Runner Bundles
|
|
2
|
+
|
|
3
|
+
A runner bundle is the portable Cloud-to-local side of the canonical loop:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
local DSL/spec -> cloud push -> immutable registry version -> runner bundle -> local Runner
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Every bundle contains:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
synapsor.contract.json
|
|
13
|
+
synapsor.runner.json
|
|
14
|
+
.env.example
|
|
15
|
+
README.md
|
|
16
|
+
mcp-client-examples/
|
|
17
|
+
claude-desktop.json
|
|
18
|
+
cursor-project.mcp.json
|
|
19
|
+
cursor-global.mcp.json
|
|
20
|
+
openai-agents-stdio.ts
|
|
21
|
+
openai-agents-streamable-http.ts
|
|
22
|
+
generic-stdio.json
|
|
23
|
+
generic-streamable-http.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
It never contains database passwords, write credentials, live API tokens,
|
|
27
|
+
private keys, customer rows, or machine-specific local paths.
|
|
28
|
+
|
|
29
|
+
## Create Locally
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
synapsor-runner contract bundle ./synapsor.contract.json \
|
|
33
|
+
--out ./synapsor-runner-bundle
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Run A Downloaded Bundle
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd ./synapsor-runner-bundle
|
|
40
|
+
cp .env.example .env
|
|
41
|
+
set -a && . ./.env && set +a
|
|
42
|
+
|
|
43
|
+
npx -y -p @synapsor/runner synapsor-runner contract validate ./synapsor.contract.json
|
|
44
|
+
npx -y -p @synapsor/runner synapsor-runner config validate --config ./synapsor.runner.json
|
|
45
|
+
npx -y -p @synapsor/runner synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
46
|
+
npx -y -p @synapsor/runner synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For the OpenAI Agents SDK, use the included TypeScript examples. Their stdio
|
|
50
|
+
command enables `--alias-mode openai`; the Streamable HTTP example includes the
|
|
51
|
+
matching server command. Claude, Cursor, and generic templates use canonical
|
|
52
|
+
dotted capability names.
|
|
53
|
+
|
|
54
|
+
Approval and writeback remain outside the model-facing MCP tool surface. Use
|
|
55
|
+
`proposals`, `apply`, `receipts`, and `replay` from a trusted operator shell.
|
|
56
|
+
|
|
57
|
+
The bundle's `.env.example` contains names and placeholders only. Fill it for a
|
|
58
|
+
local or staging source, source it into the shell or process that launches your
|
|
59
|
+
MCP client, and keep the resulting `.env` out of source control.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Disposable Docker example credentials only. Do not reuse in staging or production.
|
|
2
|
+
PLAN_CREDIT_POSTGRES_READ_URL=postgresql://synapsor_reader:synapsor_reader_password@127.0.0.1:55438/synapsor_runner_plan_credit
|
|
3
|
+
PLAN_CREDIT_POSTGRES_WRITE_URL=postgresql://synapsor_writer:synapsor_writer_password@127.0.0.1:55438/synapsor_runner_plan_credit
|
|
4
|
+
SYNAPSOR_TENANT_ID=acme
|
|
5
|
+
SYNAPSOR_PRINCIPAL=local_support_agent
|
|
6
|
+
|
|
7
|
+
# Optional Cloud registry upload. Keep real values outside git.
|
|
8
|
+
SYNAPSOR_CLOUD_BASE_URL=
|
|
9
|
+
SYNAPSOR_CLOUD_TOKEN=
|
|
10
|
+
SYNAPSOR_WORKSPACE_ID=
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Support Plan Credit Example
|
|
2
|
+
|
|
3
|
+
This example shows three enforcement tiers on one support action:
|
|
4
|
+
|
|
5
|
+
- `$25` (`2500` cents): policy-approved, then applied locally through guarded writeback.
|
|
6
|
+
- `$100` (`10000` cents): saved as `pending_review` until a local operator approves.
|
|
7
|
+
- `$1000` (`100000` cents): rejected before proposal creation by the contract bound.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Docker
|
|
12
|
+
- Node 22.5+
|
|
13
|
+
- Port `55438` available
|
|
14
|
+
|
|
15
|
+
Install the stable CLI once for the commands below:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install --global @synapsor/runner
|
|
19
|
+
synapsor-runner --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
When working from this source checkout, use `corepack pnpm runner` in place of
|
|
23
|
+
`synapsor-runner`.
|
|
24
|
+
|
|
25
|
+
## No-Database Check
|
|
26
|
+
|
|
27
|
+
Validate the authored boundary before starting Docker:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
synapsor-runner dsl compile examples/support-plan-credit/contract.synapsor \
|
|
31
|
+
--out /tmp/support-plan-credit.contract.json \
|
|
32
|
+
--strict
|
|
33
|
+
synapsor-runner contract validate /tmp/support-plan-credit.contract.json
|
|
34
|
+
synapsor-runner config validate \
|
|
35
|
+
--config examples/support-plan-credit/synapsor.runner.json
|
|
36
|
+
synapsor-runner cloud push /tmp/support-plan-credit.contract.json \
|
|
37
|
+
--dry-run \
|
|
38
|
+
--workspace local-preview \
|
|
39
|
+
--name support-plan-credit
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This compiles, validates, and previews the Cloud payload without opening a
|
|
43
|
+
network connection or connecting to a database. From a source checkout,
|
|
44
|
+
`corepack pnpm verify:adoption` runs this boundary check plus the no-database
|
|
45
|
+
quick demo and MCP config validation.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
docker compose -f examples/support-plan-credit/docker-compose.yml up -d
|
|
51
|
+
|
|
52
|
+
set -a
|
|
53
|
+
. examples/support-plan-credit/.env.example
|
|
54
|
+
set +a
|
|
55
|
+
|
|
56
|
+
synapsor-runner tools preview \
|
|
57
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
58
|
+
--store ./tmp/support-plan-credit/local.db
|
|
59
|
+
|
|
60
|
+
# Run this in a second terminal if you want to attach an MCP client.
|
|
61
|
+
synapsor-runner mcp serve \
|
|
62
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
63
|
+
--store ./tmp/support-plan-credit/local.db
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The checked-in `.env.example` contains disposable localhost Docker credentials
|
|
67
|
+
only. Never reuse them for staging or production.
|
|
68
|
+
|
|
69
|
+
## Walkthrough
|
|
70
|
+
|
|
71
|
+
Inspect the customer first:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
synapsor-runner smoke call support.inspect_customer \
|
|
75
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
76
|
+
--store ./tmp/support-plan-credit/local.db \
|
|
77
|
+
--json '{"customer_id":"CUS-3001"}'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Propose a `$25` credit:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
synapsor-runner propose support.propose_plan_credit \
|
|
84
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
85
|
+
--store ./tmp/support-plan-credit/local.db \
|
|
86
|
+
--json '{"customer_id":"CUS-3001","credit_cents":2500,"reason":"SLA outage ticket SUP-481"}'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`proposals show` displays `policy:support_propose_plan_credit_auto_approval`.
|
|
90
|
+
The proposal is approved, but it is not applied until the local writeback step:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
synapsor-runner proposals show latest --store ./tmp/support-plan-credit/local.db
|
|
94
|
+
synapsor-runner apply latest \
|
|
95
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
96
|
+
--store ./tmp/support-plan-credit/local.db
|
|
97
|
+
synapsor-runner receipts list --proposal <proposal_id> --store ./tmp/support-plan-credit/local.db
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Propose a `$100` credit:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
synapsor-runner propose support.propose_plan_credit \
|
|
104
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
105
|
+
--store ./tmp/support-plan-credit/local.db \
|
|
106
|
+
--json '{"customer_id":"CUS-3001","credit_cents":10000,"reason":"larger support credit"}'
|
|
107
|
+
|
|
108
|
+
synapsor-runner proposals approve latest --yes --store ./tmp/support-plan-credit/local.db
|
|
109
|
+
synapsor-runner apply latest \
|
|
110
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
111
|
+
--store ./tmp/support-plan-credit/local.db
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Propose a `$1000` credit:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
synapsor-runner propose support.propose_plan_credit \
|
|
118
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
119
|
+
--store ./tmp/support-plan-credit/local.db \
|
|
120
|
+
--json '{"customer_id":"CUS-3001","credit_cents":100000,"reason":"too large"}'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The contract bound rejects it before a proposal row exists.
|
|
124
|
+
|
|
125
|
+
Replay and stale-row checks:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
synapsor-runner replay export --proposal latest --store ./tmp/support-plan-credit/local.db --output ./tmp/support-plan-credit/replay.json
|
|
129
|
+
synapsor-runner apply latest --config examples/support-plan-credit/synapsor.runner.json --store ./tmp/support-plan-credit/local.db
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The live smoke test mutates `updated_at` before apply and proves stale proposals
|
|
133
|
+
return `VERSION_CONFLICT` without changing the source row.
|
|
134
|
+
|
|
135
|
+
Run the complete Docker-backed scenario, including all three policy tiers and
|
|
136
|
+
the stale-row conflict:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
corepack pnpm test:live-apply
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## What The Agent Never Sees
|
|
143
|
+
|
|
144
|
+
The contract keeps these fields out:
|
|
145
|
+
|
|
146
|
+
- `card_token`
|
|
147
|
+
- `raw_payment_method`
|
|
148
|
+
- `internal_risk_score`
|
|
149
|
+
- `private_notes`
|
|
150
|
+
|
|
151
|
+
`tools preview` should show only:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
support.inspect_customer
|
|
155
|
+
support.propose_plan_credit
|
|
156
|
+
auto-approval: enabled
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
No raw SQL, approval tools, commit tools, write credentials, or model-controlled
|
|
160
|
+
tenant authority are exposed to MCP.
|
|
161
|
+
|
|
162
|
+
Representative outputs are checked in under [`expected-output/`](expected-output/)
|
|
163
|
+
so you can compare the tool boundary, proposal, receipt, replay, and Cloud push
|
|
164
|
+
shape without guessing which state should change.
|
|
165
|
+
|
|
166
|
+
## Connect An MCP Client
|
|
167
|
+
|
|
168
|
+
Copy the matching template from [`mcp-client-examples/`](mcp-client-examples/):
|
|
169
|
+
|
|
170
|
+
- Claude Desktop: `claude-desktop.json`
|
|
171
|
+
- Cursor project/global: `cursor-project.mcp.json`, `cursor-global.mcp.json`
|
|
172
|
+
- OpenAI Agents SDK: stdio and Streamable HTTP TypeScript examples
|
|
173
|
+
- generic MCP: stdio and Streamable HTTP JSON examples
|
|
174
|
+
|
|
175
|
+
For Streamable HTTP, run:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
synapsor-runner mcp serve \
|
|
179
|
+
--transport streamable-http \
|
|
180
|
+
--alias-mode openai \
|
|
181
|
+
--host 127.0.0.1 \
|
|
182
|
+
--port 8766 \
|
|
183
|
+
--config examples/support-plan-credit/synapsor.runner.json \
|
|
184
|
+
--store ./tmp/support-plan-credit/local.db
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The OpenAI client receives `support__inspect_customer` and
|
|
188
|
+
`support__propose_plan_credit`; Runner preserves the dotted canonical names in
|
|
189
|
+
tool metadata and results. For Claude, Cursor, or generic MCP clients, omit
|
|
190
|
+
`--alias-mode openai` to expose `support.inspect_customer` and
|
|
191
|
+
`support.propose_plan_credit`. Approval and apply remain outside MCP.
|
|
192
|
+
|
|
193
|
+
## How The Policy Is Governed
|
|
194
|
+
|
|
195
|
+
The auto-approval policy lives in `contract.synapsor`:
|
|
196
|
+
|
|
197
|
+
```sql
|
|
198
|
+
AUTO APPROVE WHEN plan_credit_cents <= 2500
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
That compiles into `synapsor.contract.json` as a reviewed approval policy. It is
|
|
202
|
+
stored in git, validated by `@synapsor/spec`, and included in Cloud push payloads.
|
|
203
|
+
|
|
204
|
+
To disable local policy approval without changing the contract:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"approvals": {
|
|
209
|
+
"disable_auto_approval": true
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Auto-approval never applies the write. It only records an approval row and audit
|
|
215
|
+
event with actor `policy:<policy_name>`.
|
|
216
|
+
|
|
217
|
+
## Cloud
|
|
218
|
+
|
|
219
|
+
Dry-run the Cloud payload:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
synapsor-runner cloud push examples/support-plan-credit/synapsor.contract.json --dry-run
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Real push uses your Cloud env vars:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
export SYNAPSOR_CLOUD_BASE_URL="https://api.synapsor.ai"
|
|
229
|
+
export SYNAPSOR_CLOUD_TOKEN="<workspace-scoped-token>"
|
|
230
|
+
export SYNAPSOR_WORKSPACE_ID="<workspace_id>"
|
|
231
|
+
|
|
232
|
+
synapsor-runner cloud push examples/support-plan-credit/synapsor.contract.json \
|
|
233
|
+
--name support-plan-credit
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
After push, Cloud can return the registered version and a runner bundle with
|
|
237
|
+
placeholder env names:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
curl -H "Authorization: Bearer $SYNAPSOR_CLOUD_TOKEN" \
|
|
241
|
+
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_WORKSPACE_ID/agent-contracts/<contract_id>/versions/<version_id>"
|
|
242
|
+
|
|
243
|
+
curl -H "Authorization: Bearer $SYNAPSOR_CLOUD_TOKEN" \
|
|
244
|
+
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_WORKSPACE_ID/agent-contracts/<contract_id>/versions/<version_id>/runner-bundle?download=1" \
|
|
245
|
+
-o support-plan-credit-runner-bundle.zip
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The push response supplies `<contract_id>` and `<version_id>`. The Cloud
|
|
249
|
+
workspace also exposes the same download from **Contract registry**.
|
|
250
|
+
|
|
251
|
+
No Cloud account is needed to run this local example.
|
|
252
|
+
|
|
253
|
+
## Clean Up
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
docker compose -f examples/support-plan-credit/docker-compose.yml down -v
|
|
257
|
+
rm -rf ./tmp/support-plan-credit
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Troubleshooting
|
|
261
|
+
|
|
262
|
+
- `synapsor-runner: command not found`: install `@synapsor/runner` globally or
|
|
263
|
+
use `corepack pnpm runner` from this repository.
|
|
264
|
+
- port `55438` is busy: stop the previous example container or change the
|
|
265
|
+
published port and both URLs in `.env.example` together.
|
|
266
|
+
- missing table/connection: wait for the Docker health check, then rerun the
|
|
267
|
+
command from the repository root with the `.env.example` values exported.
|
|
268
|
+
- OpenAI rejects dotted tool names: start the MCP server with
|
|
269
|
+
`--alias-mode openai` and use the OpenAI template.
|
|
270
|
+
- proposal stays pending: `$100` intentionally requires
|
|
271
|
+
`proposals approve`; only the `$25` tier is policy-approved.
|
|
272
|
+
- apply reports a conflict: the row changed after the proposal read. Inspect
|
|
273
|
+
the new row, create a fresh proposal, and do not bypass the version guard.
|