@zackbart/connecta 0.17.0 → 0.18.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 +78 -0
- package/README.md +4 -0
- package/dist/catalog-service.d.ts +6 -0
- package/dist/catalog-service.js +69 -4
- package/dist/execute.d.ts +2 -0
- package/dist/execute.js +43 -17
- package/dist/meta-tools.js +9 -9
- package/dist/providers/stripe.d.ts +23 -22
- package/dist/providers/stripe.js +58 -31
- package/dist/routes/ui.js +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +53 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +1 -1
- package/documentation/code-mode.md +23 -15
- package/documentation/connector-guides.md +7 -10
- package/documentation/meta-tools.md +27 -2
- package/documentation/notion.md +17 -0
- package/documentation/operations.md +10 -10
- package/documentation/provider-audit.md +13 -5
- package/documentation/stripe.md +43 -67
- package/documentation/upgrading.md +22 -4
- package/ethos.md +4 -4
- package/package.json +2 -2
- package/templates/node/README.md +7 -0
- package/templates/node/package.json +5 -2
package/dist/skills.js
CHANGED
|
@@ -1,33 +1,70 @@
|
|
|
1
|
-
export const CONNECTA_INSTRUCTIONS = '
|
|
1
|
+
export const CONNECTA_INSTRUCTIONS = 'Choose a route before discovery. For one read at an unknown address, use search_tools then call_tool; a known address needs only call_tool. For read-only reduction, multiple or dependent calls, loops, joins, or branches, use one execute_code program that discovers, calls, and returns the reduced answer. Only readOnlyHint: true tools run there. Keep unannotated, write-capable, or destructive work top level: search_tools then call_destructive_tool. After auth_required use authorize_connector. After a truncated direct result use fields or get_result. connecta.ui(html) exists only inside execute_code, not in connector search; return the same summary data the HTML renders. Fetch skills({ name: "usage" }) once for program syntax, selection, repair, examples, and runtime details.';
|
|
2
2
|
const USAGE_SKILL_BASE = `# Connecta usage
|
|
3
3
|
|
|
4
4
|
## The surface
|
|
5
5
|
|
|
6
6
|
Seven tools: \`execute_code\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Broad discovery and multi-call work live in a program, not in top-level tools.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The always-loaded MCP instructions are authoritative for choosing the top-level route. Read this skill at most once per task for the program workflow and recovery details below.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Inside a program
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
- Anything wider — two or more calls, dependent steps, loops, joins, branching, a whole-catalog browse, or a result to reduce: one \`execute_code\` run.
|
|
14
|
-
- Any unannotated, write-capable, or destructive call: \`call_destructive_tool\`, one at a time, after reviewing its schema and consequences.
|
|
15
|
-
- Truncated result: retry with \`fields\`, else page it with \`get_result\`.
|
|
16
|
-
- \`auth_required\`: \`authorize_connector\`, hand its recovery text to the operator, retry the call.
|
|
12
|
+
Write one plain-JavaScript async arrow function. TypeScript syntax and portable imports do not work. Return JSON-shaped data and reduce large results before returning.
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
The minimum guest API is:
|
|
15
|
+
|
|
16
|
+
- \`<connectorId>.<toolName>(args)\` calls a sanitized shortcut. Non-identifier characters become \`_\`; leading digits gain \`_\`; reserved words gain a trailing \`_\`.
|
|
17
|
+
- \`connecta.call("connector.tool", args)\` uses the canonical address and returns the unwrapped value.
|
|
18
|
+
- \`connecta.search(args)\` returns \`{ tools, total, offset, limit, hasMore }\`; \`connecta.describe(args)\` returns \`{ tools }\`.
|
|
19
|
+
- \`connecta.batch(calls)\` runs 2–10 independent calls. Each outcome is \`{ address, ok: true, data }\` or \`{ address, ok: false, error, errorDetails }\`.
|
|
20
|
+
- \`console.log(...)\` is captured. \`connecta.emit(block)\` and \`connecta.ui(html, options?)\` produce rich output.
|
|
21
|
+
|
|
22
|
+
## Discover and select
|
|
23
|
+
|
|
24
|
+
Search inside the run and finish the task there. A discovery-only program wastes a round trip. Use 2–4 distinctive action/object terms, not the full request. Use separate short searches for distinct operations.
|
|
25
|
+
|
|
26
|
+
For top-level \`search_tools\`, omit \`limit\` initially (the default is 10), then page with a limit up to 50 if needed. Empty or whitespace-only queries browse all tools. A non-empty query with no ASCII terms returns no matches; mixed input searches with its ASCII terms. \`includeSchemas: "compact"\` adds bounded input and declared output shapes. Plain objects expose \`inputKeys\`, \`requiredInputKeys\`, and \`outputKeys\`; truncation flags mark incomplete shapes; matches also carry declared annotations.
|
|
27
|
+
|
|
28
|
+
- \`connecta.search({})\` loads all catalogs. Pass \`connector: "<id>"\` when the integration is obvious. Use \`safety: "readOnly"\` for program calls. These inputs filter discovery; they grant no authority.
|
|
29
|
+
- Request \`includeSchemas: "compact"\`. Check address, purpose, annotations, required inputs, truncation, safety, and declared outputs. Never select only because a result ranks first or has fewer required inputs.
|
|
30
|
+
- Supply every \`requiredInputKey\` from the task or a prior result. For dependencies, match the earlier \`outputKey\` to the later required key. An empty required-key list does not permit invented arguments. Missing \`outputKeys\` means inspect \`outputSchema\`.
|
|
31
|
+
- Use \`connecta.describe({ address })\` or \`{ addresses }\` when a compact schema is truncated or insufficient. Use \`format: "json"\` only for exact constraints. Write the property names the schema displays; never guess positions or aliases.
|
|
32
|
+
- Reduce through declared output keys. Do not guess collection roots such as \`items\` or \`results\`. If a match or result key is missing, inspect, re-search, or describe inside the same run instead of returning discovery for another call.
|
|
33
|
+
|
|
34
|
+
Only tools explicitly annotated \`readOnlyHint: true\` are reachable. The catalog, credential, admission, and read-only gates run below the sandbox; code cannot widen its authority.
|
|
35
|
+
|
|
36
|
+
## Errors and repair
|
|
37
|
+
|
|
38
|
+
Caught Connecta errors expose \`message\`, \`code\`, \`retryable\`, and \`details\`. Batch failures expose the same classification in \`errorDetails\`. Branch on fields, never prose. Do not retry \`retryable: false\`, and do not retry \`rate_limited\` immediately because portable code has no timer.
|
|
39
|
+
|
|
40
|
+
- \`destructive_tool_requires_approval\`: stop the program and use the returned canonical address with top-level \`call_destructive_tool\`.
|
|
41
|
+
- \`auth_required\`: let the failure reach the model, then use top-level \`authorize_connector\`, give its handoff to the operator, and retry after recovery.
|
|
42
|
+
- A truncated direct-call result: retry \`call_tool\` with \`fields\`, or follow its \`get_result\` action. A truncated program result has no page handle; filter, map, or slice inside a new program.
|
|
43
|
+
- Unknown addresses and tools carry scoped search recovery. Use it inside the current run. Do not invent an address.
|
|
44
|
+
|
|
45
|
+
For a direct call, \`fields\` selects JSON dot-paths and \`[]\` traverses arrays, for example \`results[].id\`. Projection misses return \`data\` plus \`$connecta\` feedback. \`resultMode: "value"\` unwraps the result. \`timeoutMs\` sets its deadline. \`maxRetries\` is honored only for safely annotated tools. \`diagnostics: true\` adds timing.
|
|
46
|
+
|
|
47
|
+
\`get_result({ id, offset?, maxBytes? })\` returns \`{ text, offset, nextOffset?, totalBytes }\` for a direct-call result. Both sizes are byte counts: \`maxBytes\` must be a whole number at least 1 and defaults to the deployment cap; \`offset\` must be a whole number at least 0 and defaults to 0. An offset inside a multi-byte character moves back to its first byte, and the response reports the served offset. Follow \`nextOffset\` to reassemble pages. An unknown or expired id is an error.
|
|
48
|
+
|
|
49
|
+
Limits: 20 host calls per run, 10 calls per batch, and a 15-second deadline per host call.
|
|
50
|
+
|
|
51
|
+
## Runtime portability
|
|
52
|
+
|
|
53
|
+
Portable code uses only connector globals, \`connecta\`, and \`console.*\`. QuickJS blocks imports and lacks fetch, process, timers, crypto, and WebSocket. Dynamic Workers must use only \`{ loader }\`; bindings, modules, or globalOutbound grant ambient authority. With loader only, environment maps are empty; node:fs/http/https are absent; outbound fetch, WebSocket, node:net, and node:tls are denied; DNS is unresolved. Runtime builtins remain through \`import()\` and \`process.getBuiltinModule()\`, including node:path and cloudflare:workers; this set can drift. Timers, process, crypto, WebSocket, and data: fetch remain. Avoid every runtime-only capability because QuickJS fails.
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
One read-only call at a known address:
|
|
58
|
+
|
|
59
|
+
\`async () => await connecta.call("crm.get_account", { id: "acct_42" })\`
|
|
19
60
|
|
|
20
|
-
|
|
61
|
+
Dependent calls, only when the second needs a value from the first:
|
|
21
62
|
|
|
22
|
-
|
|
23
|
-
- Exact schemas: \`connecta.describe({ address: "connector.tool" })\` for one, \`{ addresses: [...] }\` for many; \`format: "json"\` only for exact constraints.
|
|
24
|
-
- Caught Connecta errors have \`message\`, \`code\`, \`retryable\`, and \`details\`; branch on fields. For 2–10 independent calls, \`connecta.batch([...])\` returns success data or an \`errorDetails\` whose code and retryable flag match the throw.
|
|
25
|
-
- Search inside the run; return only the reduction the answer needs, never raw payloads.
|
|
26
|
-
- Only tools annotated \`readOnlyHint: true\` are reachable; the gate, credentials, and admission are enforced below the sandbox — nothing a program does widens its reach.
|
|
63
|
+
\`async () => { const { tools } = await connecta.search({ query: "pipeline run job logs", safety: "readOnly", includeSchemas: "compact" }); const address = (suffix) => { const tool = tools.find((entry) => entry.address.endsWith(suffix)); if (!tool) throw new Error("missing " + suffix); return tool.address; }; const run = await connecta.call(address(".get_run"), { runId: 42 }); const logs = await connecta.call(address(".get_job_logs"), { jobId: run.failedJobId }); return logs.map(({ timestamp, message }) => ({ timestamp, message })); }\`
|
|
27
64
|
|
|
28
65
|
## Rendering a view
|
|
29
66
|
|
|
30
|
-
\`connecta.ui(html)\` renders one success-only display view,
|
|
67
|
+
\`connecta.emit\` accepts text, image, or audio blocks and delivers them only on success. \`connecta.ui(html)\` renders one success-only display view outside model context. One argument is display-only. Bind read-only refresh or drill-down calls with \`{ reads: { name: { address, fixedArgs?, viewArgs? } } }\`; page markup calls \`connecta.read(name, args)\`. Admission and one shared budget apply to the UI and emitted content, not separate budgets. Fetch and check the data shape first. On empty or missing data, return a trimmed first record instead of rendering. Otherwise render returned variables and return the same initial summary because the model reads the return value, not the view. A second, invalid, or over-budget UI call throws catchably.
|
|
31
68
|
|
|
32
69
|
`;
|
|
33
70
|
/** Deployment-scoped guide routing appended to the shared usage guide. */
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -185,7 +185,7 @@ src/
|
|
|
185
185
|
| The core imports no `node:` builtin and reaches no Node-only module | `test/purity.test.ts` |
|
|
186
186
|
| The published surface matches the same boundary | `test/package-surface.test.ts`, `scripts/check-package.mjs` |
|
|
187
187
|
| Route order, per-route auth, and byte-exact refusals | `test/server-route-contracts.test.ts` |
|
|
188
|
-
| `/mcp` end to end, the open routes, exactly seven tools | `test/server.test.ts`, `test/code-first-surface.test.ts` |
|
|
188
|
+
| `/mcp` end to end, the open routes, exactly seven tools, bounded connector orientation | `test/server.test.ts`, `test/code-first-surface.test.ts` |
|
|
189
189
|
| Construction-time refusals and the grouped config boundary | `test/config.test.ts`, `test/registry.test.ts` |
|
|
190
190
|
| Program and top-level calls take the same enforced path | `test/execute.test.ts` |
|
|
191
191
|
| Both deployment shapes still compile and configure the real thing | `test/deployment-shapes.test.ts`, `npm run check:examples` |
|
|
@@ -173,7 +173,10 @@ global whose properties are its tools, so `<connectorId>.<toolName>(args)` works
|
|
|
173
173
|
with both parts sanitized into JavaScript identifiers — characters outside
|
|
174
174
|
`[A-Za-z0-9_$]` become `_`, a leading digit gets `_` prefixed, and a reserved
|
|
175
175
|
word gets `_` appended (`my-service.get.thing` → `my_service.get_thing`). The
|
|
176
|
-
globals are lazy: no catalog is fetched until a program touches one.
|
|
176
|
+
globals are lazy: no catalog is fetched until a program touches one. The
|
|
177
|
+
bounded deployment inventory in the `execute_code` description shows each
|
|
178
|
+
canonical connector id and labels the shortcut only when it differs; the
|
|
179
|
+
[discovery guide](./meta-tools.md#discovery-context) defines that bound.
|
|
177
180
|
|
|
178
181
|
**A3.** A shortcut that resolves to more than one tool fails closed with
|
|
179
182
|
`ambiguous_tool_alias`, naming the colliding tool names and pointing at
|
|
@@ -256,10 +259,13 @@ const { tools } = await connecta.describe({
|
|
|
256
259
|
});
|
|
257
260
|
```
|
|
258
261
|
|
|
259
|
-
**S4.** Returns `{ tools }` in
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
**S4.** Returns `{ tools }` in order, one entry per address. An unknown address
|
|
263
|
+
or failed catalog returns `error` plus typed `errorDetails`: `code`, `message`, and `retryable`. Misses
|
|
264
|
+
carry a route-aware `nextAction`; a close miss may add three canonical `suggestions`.
|
|
265
|
+
Catalog failures add only `retryAfterMs` when known. One bad address never fails the whole call. Each failed entry clamps its
|
|
266
|
+
caller-authored `address` to 512 UTF-8 bytes with an `…` marker. Entry order
|
|
267
|
+
correlates a clipped address with its request; successes keep canonical addresses. More than 100
|
|
268
|
+
addresses is `invalid_args`; the same 256,000-byte ceiling applies.
|
|
263
269
|
|
|
264
270
|
### connecta.call
|
|
265
271
|
|
|
@@ -377,7 +383,7 @@ exactly first, by containment second — so a program that *wraps* a failure's
|
|
|
377
383
|
message in its own text still reports the underlying typed failure. Keeping the
|
|
378
384
|
type beats keeping the prose.
|
|
379
385
|
|
|
380
|
-
**E7.** `retryable` for `unknown_address`, `unknown_tool`, `ambiguous_tool_alias`, and `destructive_tool_requires_approval` is pinned false, never inferred from an address containing `503`, `429`, or `temporar`. The first two carry `nextAction: { function: "connecta.search", arguments: { query, connector?, includeSchemas: "compact" } }` — the same scoped discovery the top-level record names, keyed to the surface the caller actually has. A program cannot call `search_tools`, so it is never told to.
|
|
386
|
+
**E7.** `retryable` for `unknown_address`, `unknown_tool`, `ambiguous_tool_alias`, and `destructive_tool_requires_approval` is pinned false, never inferred from an address containing `503`, `429`, or `temporar`. The first two carry `nextAction: { function: "connecta.search", arguments: { query, connector?, includeSchemas: "compact" } }` — the same scoped discovery the top-level record names, keyed to the surface the caller actually has. A program cannot call `search_tools`, so it is never told to. The message, the derived `query`, and a failed describe entry's `address` clamp caller-authored text to 512 UTF-8 bytes with an `…` marker. Those values land in the text content and `structuredContent`, so an invented 50 KB address would otherwise produce a refusal orders of magnitude past the deployment's result cap. A clipped address still identifies the mistake by its position; a short one — the common case — is exact and untagged.
|
|
381
387
|
|
|
382
388
|
**E8.** A remote MCP tool whose advertised schema rejects the call fails before provider dispatch with `invalid_args`, carrying bounded, value-free `{ path, code, expected }` findings and scoped search recovery keyed `function: "connecta.search"` like every other in-program miss. A declared property reports the schema keyword that failed, never the validator's duplicate `additionalProperties` branch; a truly undeclared property still reports `additionalProperties`. Unsupported schemas pass through; unrecognized provider prose remains `connector_call_failed`.
|
|
383
389
|
|
|
@@ -585,14 +591,14 @@ the same mistake as automatic host-side projection, refused in `ethos.md`
|
|
|
585
591
|
([#282](https://github.com/zackbart/connecta/issues/282)).
|
|
586
592
|
|
|
587
593
|
**U13.** The always-loaded MCP instructions locate `connecta.ui(html)` before an
|
|
588
|
-
agent chooses a route: it
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
therefore rides `initialize`, under a 1,000-character ceiling for the complete
|
|
594
|
+
agent chooses a route: it exists only inside `execute_code`, never in connector
|
|
595
|
+
search, and carries `U12`'s mirrored-return duty. The detailed call, binding,
|
|
596
|
+
budget, and repair rules live in the on-demand `usage` skill. The location
|
|
597
|
+
distinction rides `initialize`, under a 1,000-character ceiling for the complete
|
|
593
598
|
instructions string. This promotes existing contract, not capability: the
|
|
594
599
|
seven-tool surface, guest API, catalog, Apps delivery, and runtime do not change
|
|
595
|
-
([#286](https://github.com/zackbart/connecta/issues/286)
|
|
600
|
+
([#286](https://github.com/zackbart/connecta/issues/286),
|
|
601
|
+
[#418](https://github.com/zackbart/connecta/issues/418)).
|
|
596
602
|
|
|
597
603
|
Bounded view reads follow normative [`V1`–`V8`](./program-ui-read-calls.md) ([#287](https://github.com/zackbart/connecta/issues/287), [#289](https://github.com/zackbart/connecta/issues/289)).
|
|
598
604
|
|
|
@@ -645,6 +651,8 @@ because connecta enforces them above the sandbox:
|
|
|
645
651
|
| Deadline per host call | 15 s |
|
|
646
652
|
| Discovery page | ≤ 100 tools, ≤ 256,000 serialized bytes |
|
|
647
653
|
| `describe` addresses | ≤ 100 |
|
|
654
|
+
| `describe` nearby suggestions | ≤ 3 canonical addresses per failed entry |
|
|
655
|
+
| Caller text echoed by `describe` recovery | ≤ 512 UTF-8 bytes per field, plus `…` |
|
|
648
656
|
| Result | 24,000 serialized characters |
|
|
649
657
|
| Logs presented to the model | 4,000 characters |
|
|
650
658
|
|
|
@@ -828,13 +836,13 @@ the upstream `Executor` shape assignable.
|
|
|
828
836
|
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.test.ts` (exact absent globals and blocked imports), `test/deployment-shapes.test.ts` (loader-only Worker construction) |
|
|
829
837
|
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
830
838
|
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
831
|
-
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (sanitizing) |
|
|
839
|
+
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (sanitizing), `test/server.test.ts` (bounded live connector inventory) |
|
|
832
840
|
| `A3` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (colliding alias) |
|
|
833
841
|
| `A4` | `test/execute.test.ts` (namespace collisions, reserved namespace) |
|
|
834
842
|
| `A5` | verdict; `A1`–`A3` are its enforcement |
|
|
835
843
|
| `S1`, `S2` | `test/guest-api-contract.test.ts` (flat page, connector guides, schema keys, and the unfiltered browse that replaces `list_connectors`), `test/execute.test.ts` (guide pagination/partial/no-match behavior and `$ref`/`allOf`), `test/meta-tools.test.ts` (mixed complete/partial ranking and stable pagination) |
|
|
836
844
|
| `S3` | `test/guest-api-contract.test.ts` (typed uncaught bound), `test/execute.test.ts` (count limits, fan-out bound) |
|
|
837
|
-
| `S4` | `test/
|
|
845
|
+
| `S4` | both guest-contract executors (ordered mixed describe results with unknown-address, unknown-tool suggestion, and catalog-failure details), `test/meta-tools.test.ts` (top-level routing, no-suggestion, catalog-failure, and hostile-input bounds) |
|
|
838
846
|
| `S5` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`) |
|
|
839
847
|
| `S6` | `test/execute.test.ts` (fail-closed annotations, activity parity) |
|
|
840
848
|
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (batch cap) |
|
|
@@ -875,7 +883,7 @@ the upstream `Executor` shape assignable.
|
|
|
875
883
|
| `U7`, `U8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
876
884
|
| `U9` | `test/execute-ui.test.ts` (a `ui` byte aggregate distinct from `emitted`, absent when nothing was accepted) |
|
|
877
885
|
| `U12` | `test/server.test.ts` (the `connecta.ui` bullet carries the return-value clause); a duty on program authors, so the description is the only place it can be enforced |
|
|
878
|
-
| `U13` | `test/code-first-surface.test.ts`, `test/server.test.ts` (served `initialize.instructions` locate UI inside `execute_code`, exclude it from
|
|
886
|
+
| `U13` | `test/code-first-surface.test.ts`, `test/server.test.ts` (served `initialize.instructions` locate UI inside `execute_code`, exclude it from connector search, state the mirrored-return duty, and stay within the complete 1,000-character budget; the usage skill carries detailed call rules) |
|
|
879
887
|
| `X3` | `test/quickjs-executor.test.ts` (cancels a running child) |
|
|
880
888
|
| `X4` | `test/guest-api-contract.test.ts` (string logs only) |
|
|
881
889
|
| `X6` | `test/quickjs-executor.test.ts` (never-settling await) |
|
|
@@ -60,15 +60,12 @@ unknown name, unknown connector, connector with no guide — is an explicit
|
|
|
60
60
|
error. Nothing silently falls back to the generic guide, because a generic
|
|
61
61
|
answer to a specific question is worse than no answer.
|
|
62
62
|
|
|
63
|
-
Discovery text is conditional on the deployment actually having a guide.
|
|
64
|
-
|
|
63
|
+
Discovery text is conditional on the deployment actually having a guide. Short
|
|
64
|
+
pointers in the `skills`, `search_tools`, `call_destructive_tool`, and
|
|
65
65
|
`execute_code` descriptions appear only when at least one visible connector
|
|
66
|
-
declares one
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
exception: it stays byte-identical across every deployment, including its
|
|
70
|
-
per-connector-guides section, so an agent that has read it once in a task never
|
|
71
|
-
needs a deployment-local copy of it.
|
|
66
|
+
declares one. The detailed selection rules live only in the built-in `usage`
|
|
67
|
+
skill. That skill stays byte-identical across deployments, including its
|
|
68
|
+
per-connector-guides section, so an agent reads it at most once per task.
|
|
72
69
|
|
|
73
70
|
## What belongs in a guide
|
|
74
71
|
|
|
@@ -175,5 +172,5 @@ each branch, the `guide` pointer in search output, and `guideRequired`
|
|
|
175
172
|
appearing for connector-required conventions, approval-bound tools, and
|
|
176
173
|
truncated schemas — and being absent from a search that asked for no schemas.
|
|
177
174
|
`test/server.test.ts` owns the conditional half: it compares a guide-free
|
|
178
|
-
deployment's four
|
|
179
|
-
`usage` skill is byte-identical between them.
|
|
175
|
+
deployment's four short pointers against a guided one's, and asserts the
|
|
176
|
+
complete `usage` skill is byte-identical between them.
|
|
@@ -60,6 +60,14 @@ their smallest successful one-tool shapes:
|
|
|
60
60
|
|
|
61
61
|
## Discovery context
|
|
62
62
|
|
|
63
|
+
The deployment-derived `execute_code` description includes a live connector
|
|
64
|
+
inventory before any catalog search. It preserves registry order and uses each
|
|
65
|
+
canonical id, adding `shortcut <name>` only when the program namespace differs.
|
|
66
|
+
The complete inventory line is capped at 256 UTF-8 bytes. Entries stay whole,
|
|
67
|
+
and a truncated line ends with the exact `+N more` count. This reads only the
|
|
68
|
+
configured registry: it loads no catalog, probes no credential, grants no
|
|
69
|
+
capability, and does not replace canonical discovery or addressing.
|
|
70
|
+
|
|
63
71
|
Start an unknown-address lookup with two to four distinctive action/object
|
|
64
72
|
terms, not the full request, and omit `limit` so the default eight-result page
|
|
65
73
|
stays small. When the integration is obvious, set `connector` to its id: a
|
|
@@ -146,8 +154,12 @@ the zero-tool page.
|
|
|
146
154
|
The built-in `usage` skill is byte-identical across deployments and says to
|
|
147
155
|
read it at most once per task. Connector guides remain scoped to the deployment
|
|
148
156
|
that listed them, even when two deployments happen to use identical content.
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
The always-loaded instructions and seven tool definitions own route selection,
|
|
158
|
+
the fail-closed boundary, and the minimum guest syntax. The usage skill owns
|
|
159
|
+
program selection detail, examples, runtime differences, and repair guidance.
|
|
160
|
+
This split avoids two normative copies while preserving a valid first program
|
|
161
|
+
for clients that never fetch the skill. Deployments without connector guides
|
|
162
|
+
receive none of the short conditional guide pointers in their definitions.
|
|
151
163
|
|
|
152
164
|
## Result representation
|
|
153
165
|
|
|
@@ -316,6 +328,16 @@ a tool. A read path that reaches an unannotated, write-capable, or destructive
|
|
|
316
328
|
tool returns `nextAction` for `call_destructive_tool` with the canonical
|
|
317
329
|
address. Nothing is executed by these records.
|
|
318
330
|
|
|
331
|
+
`connecta.describe` keeps failures inline so one miss cannot discard the other
|
|
332
|
+
schemas. Each failed entry keeps its human `error` and adds `errorDetails` with
|
|
333
|
+
the equivalent invocation `code` and `retryable`. Address and tool misses use
|
|
334
|
+
the same route-aware discovery action above. A close tool-name miss on a known
|
|
335
|
+
connector may also carry `suggestions`: at most three deterministically ranked
|
|
336
|
+
canonical addresses, with no scores or descriptions. An unknown connector
|
|
337
|
+
stays unscoped and has no suggestions. A catalog-load failure carries only
|
|
338
|
+
`code`, bounded `message`, `retryable`, and any `retryAfterMs`; discovery does
|
|
339
|
+
not inherit later additions to the call-failure envelope.
|
|
340
|
+
|
|
319
341
|
That route echoes the caller's own arguments back only while they fit a
|
|
320
342
|
512-byte budget, and then whole — never clipped. An error envelope is not
|
|
321
343
|
size-guarded the way a result is, so an unbounded echo would let a large
|
|
@@ -393,3 +415,6 @@ duplicate `additionalProperties` branches never reach the caller. A schema the l
|
|
|
393
415
|
validator cannot evaluate passes through to the provider. Provider error prose
|
|
394
416
|
is not parsed or guessed, so an unknown format remains
|
|
395
417
|
`connector_call_failed`.
|
|
418
|
+
|
|
419
|
+
Describe's nearby-address list uses the same three-item recovery bound. It
|
|
420
|
+
contains addresses only; it never serializes ranking scores or result prose.
|
package/documentation/notion.md
CHANGED
|
@@ -237,6 +237,23 @@ and all deliberately absent: this is a deliberate tool surface, not a mirror of
|
|
|
237
237
|
the API. Anything missing is reachable through a custom `api()` connector
|
|
238
238
|
beside this one, which remains a first-class path.
|
|
239
239
|
|
|
240
|
+
The 2026-03-11 contract also offers more fields on create and update. They were
|
|
241
|
+
reviewed after the 0.17.0 drift check and remain deliberately absent:
|
|
242
|
+
|
|
243
|
+
- `create_page` does not create workspace-private pages, apply templates,
|
|
244
|
+
choose page placement, or accept expanded icon and cover forms. Those change
|
|
245
|
+
ownership, start asynchronous content work, control ordering, or depend on
|
|
246
|
+
file surfaces. They are not extensions of the maintained page/row authoring
|
|
247
|
+
contract (#408).
|
|
248
|
+
- `update_page_properties` does not lock pages, apply templates, or erase page
|
|
249
|
+
content. Locking is coordination state, templates finish asynchronously, and
|
|
250
|
+
`erase_content` permanently deletes every child block through the API. None
|
|
251
|
+
belongs under an approval named for property replacement (#409).
|
|
252
|
+
|
|
253
|
+
`trash_page` stays separate and reversible. The current `create_page`,
|
|
254
|
+
`update_page_properties`, and `trash_page` request subsets remain valid against
|
|
255
|
+
the expanded published contract.
|
|
256
|
+
|
|
240
257
|
There is also **no guarded raw-REST escape hatch** — no `notion_api_get`, no
|
|
241
258
|
`notion_api_mutate`. The convention that permits one
|
|
242
259
|
([H14](./provider-conventions.md#h14--a-named-tool-must-beat-the-escape-hatch-and-the-escape-hatch-splits-by-safety))
|
|
@@ -183,7 +183,7 @@ Two more runners are deliberately outside `check`:
|
|
|
183
183
|
|
|
184
184
|
- `npm run test:browser` — Playwright against a real headless Chromium
|
|
185
185
|
(`npm run test:browser:install` once). It covers the embedded bundle without
|
|
186
|
-
adding a browser download to
|
|
186
|
+
adding a browser download to the CI release check.
|
|
187
187
|
- `npm run drift:check` — the maintainer-run provider drift check, with local
|
|
188
188
|
provider credentials exported. No credential goes near CI and nothing files
|
|
189
189
|
itself; findings are read by a human and become issues
|
|
@@ -225,23 +225,23 @@ in.
|
|
|
225
225
|
| `clerk.test.ts` | protected-resource metadata, the browser sign-in config, OAuth and session tokens, cached best-effort activity labels with their caps, the hand-applied `azp` rejection, and the `allowedDomains` allowlist including every lookalike that must not be repaired into a match |
|
|
226
226
|
| `cloudflare-provider.test.ts` | `cloudflare()` construction, tool surface, request building, projections, typed failures, and credential test |
|
|
227
227
|
| `cloudflare-registry.test.ts` | the same provider inside a real deployment: discovery including compact page bounds, addressing, and admission through the registry |
|
|
228
|
-
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required
|
|
228
|
+
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required, every removed option and top-level tool refused, compact always-loaded routing pinned below 1,000 characters, complete on-demand usage served, and `connecta.ui` findable before connector search |
|
|
229
229
|
| `codemode-compat.test.ts` | the `Executor` seam staying structurally compatible with `@cloudflare/codemode`'s `DynamicWorkerExecutor`, enforced by `tsc` |
|
|
230
230
|
| `config.test.ts` | the grouped `ConnectaConfig` boundary — each group forwarding to its internals, malformed admission bounds failing construction, and one complete migration error for legacy own-properties |
|
|
231
231
|
| `credentials.test.ts` | the pure stored-shape classifier (containment, not equality) and the AES-GCM vault: round-trip, ciphertext bound to its connector id, named field sets, masked metadata, wrong-key rejection, deletion, coexistence with OAuth keys |
|
|
232
232
|
| `d1-activity-example.test.ts` | the Worker example's deployment-owned D1 activity store: actor namespace round-trip, payload-free friction reconstructed from the persisted code, and agreement with the package's friction table |
|
|
233
233
|
| `downstream-oauth.test.ts` | `KvOAuthProvider` round-trips and races, `auth_required` versus `error`, `startAuth`/`finishAuth`, callback refusal equality, bounded diagnostics, and HTML escaping |
|
|
234
234
|
| `errors.test.ts` | `ConnectorCallError` codes, retryable defaults and overrides, `retryAfterMs` round-trip, typed-over-heuristic classification, `AbortError` as a retryable timeout, and framing errors |
|
|
235
|
-
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools,
|
|
235
|
+
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools, MCP/code-mode invocation parity, and payload-free describe diagnostics |
|
|
236
236
|
| `execute-emit.test.ts` | `connecta.emit` (M1–M10) — block validation, budgets, the provider, delivery after the result envelope on success only, and the defaults |
|
|
237
237
|
| `execute-ui.test.ts` | `connecta.ui` (U1–U9) — validation, multiplicity and budget, the provider, `_meta` delivery, and the Apps shell |
|
|
238
238
|
| `executor-admission.test.ts` | the portable bounded FIFO both pools use: active and queue ceilings, stable retryable overload, queue timeout, cancellation removal, idempotent release, shutdown |
|
|
239
239
|
| `guarded-fetch.test.ts` | the guarded transport — construction, request building, destination confinement, and response handling |
|
|
240
|
-
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, discovery, utility, batch, and budget failure codes; plus the real authority boundary — local `data:` fetch, denied egress, unresolved DNS, empty environment paths, unavailable filesystem/HTTP builtins, and present runtime globals |
|
|
240
|
+
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, typed inline describe recovery, discovery, utility, batch, and budget failure codes; plus the real authority boundary — local `data:` fetch, denied egress, unresolved DNS, empty environment paths, unavailable filesystem/HTTP builtins, and present runtime globals |
|
|
241
241
|
| `linear-provider.test.ts` / `linear-registry.test.ts` | the Linear proxy's construction, classification, and guide; then the same connector inside a real deployment |
|
|
242
|
-
| `meta-tools.test.ts` | the registry-backed meta-tools: bounded discovery with page and address maxima,
|
|
242
|
+
| `meta-tools.test.ts` | the registry-backed meta-tools: bounded discovery with page and address maxima, compact descriptions and the complete on-demand usage skill, compact and JSON schemas with constraints, typed describe recovery and suggestions, structured errors, connector-guide selection and summary bounds, stored-credential drift, catalog health, field projection, truncation and `get_result`, per-connector result bounds, probe timeouts, and unavailable or unknown browse recovery |
|
|
243
243
|
| `mixpanel-provider.test.ts` / `mixpanel-registry.test.ts` | the Mixpanel proxy, its conditional-input guide and complete reviewed schema-digest manifest, then the same connector inside a real deployment |
|
|
244
|
-
| `notion-provider.test.ts` / `notion-registry.test.ts` | Notion's tool surface, request construction, lean projections, both pagination conventions, error mapping, and writes; then the connector in a real deployment |
|
|
244
|
+
| `notion-provider.test.ts` / `notion-registry.test.ts` | Notion's deliberate tool surface, including declined expanded page inputs, request construction, lean projections, both pagination conventions, error mapping, and writes; then the connector in a real deployment |
|
|
245
245
|
| `operator-boundary.test.ts` | the operator row of the decisions table, after every mutation route: authentication material managed without moving a declared structure, and the one honest exception — a credential write making a remote catalog appear, which is discovery arriving, not an operator editing the deployment |
|
|
246
246
|
| `operator-store.test.ts` | `src/operator-ui/app/store.ts` against a fake browser: the Clerk listener, `gate()`, the generation fence, and the request path |
|
|
247
247
|
| `provider-conventions.test.ts` | the conventions a test can hold: hand-written providers refusing schemas they cannot enforce (H5), their compact discovery schemas staying complete (H7), Cloudflare stating its second pagination convention in the schema (H10), and Notion saying it has no escape hatch (H14) |
|
|
@@ -249,10 +249,10 @@ in.
|
|
|
249
249
|
| `remote-mcp.test.ts` | `remoteMcp()` against an in-process server through the `_transportFactory` seam: passthrough, downstream `isError`, Workers-safe output-schema validation, request-scoped client reuse and at-most-once scope close; plus the real transport's manual redirect policy, destination guard, credential containment, and downstream session termination |
|
|
250
250
|
| `remote-mcp-pagination.test.ts` | the `tools/list` cursor chain in both directions — exact cursor handoff, first-wins dedup, a failed later page rejecting rather than returning its prefix, the runaway backstops, the tool-metadata re-prime across pages, and paginated catalogs reaching the discovery path |
|
|
251
251
|
| `request-admission.test.ts` | `/mcp` bounded before auth, the stable 503 and `Retry-After`, health and operator responsiveness under saturation, payload-free counters, queued cancellation, shutdown rejection while active work drains, and the separate fallback code pool |
|
|
252
|
-
| `server.test.ts` | end-to-end `/mcp` (401 → initialize instructions → seven
|
|
252
|
+
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory → complete usage skill → `call_tool`), conditional guide pointers, open routes, Clerk `.well-known` metadata without network, code mode, and deferred catalog reads through both discovery surfaces |
|
|
253
253
|
| `server-route-contracts.test.ts` | the route contracts `server.ts` must keep byte-identical: every built-in answered ahead of connector routes inside the security wrapper, open data-free shells with framing denied, per-route auth and same-origin requirements with exact 401/403/405 bodies, and OAuth `verifyState`-before-`finishAuth` ordering |
|
|
254
254
|
| `startup-warnings.test.ts` | every construction-time `logger.warn` and, as importantly, the conditions that must *not* trigger one: open mode with a credential or OAuth connector, `publicUrl` unset beside OAuth, dropped branding and `uiAuth` URLs, a missing `verifyState`, a credential test-hook mismatch, and an unusable `calls.maxResultBytes` |
|
|
255
|
-
| `stripe-provider.test.ts` / `stripe-registry.test.ts` | the Stripe proxy's
|
|
255
|
+
| `stripe-provider.test.ts` / `stripe-registry.test.ts` | the Stripe proxy's mixed-mode OAuth and fixed-mode header contracts, admission, exact account selectors, and no-guess rule; then fixed credentials in a real deployment |
|
|
256
256
|
| `ui.test.ts` | the server shell and `/ui/*` routes and the app's pure state rules from `view.ts` — filtering, page routing and capability states, credential management, gated `/ui/data` with broken-connector isolation and registry-owned catalog-observation containment, and the URL safety gates |
|
|
257
257
|
| `validate.test.ts` | `validateToolInput()` — a returned (not thrown) `invalid_args` naming the path, `additionalProperties: false` enforcement, per-schema validator caching, and an unusable schema passed through with one warning |
|
|
258
258
|
|
|
@@ -263,12 +263,12 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
263
263
|
|
|
264
264
|
| Suite | Covers | Why Node |
|
|
265
265
|
| --- | --- | --- |
|
|
266
|
-
| `deployment-shapes.test.ts` | the Worker as the only example with a loader-only sandbox, one Node template that is also its own container, the same source running locally and in the container, the full operator surface in both, a template that cannot start on its own `.env.example`, a Worker README naming every optional peer its entrypoint imports, and the initializer's `.gitignore` staying in step | walks the template and example trees with Node filesystem APIs |
|
|
266
|
+
| `deployment-shapes.test.ts` | the Worker as the only example with a loader-only sandbox, one Node template that is also its own container, the same source running locally and in the container, the Node template's pinned esbuild install-script approval, the full operator surface in both, a template that cannot start on its own `.env.example`, a Worker README naming every optional peer its entrypoint imports, and the initializer's `.gitignore` staying in step | walks the template and example trees with Node filesystem APIs |
|
|
267
267
|
| `doc-links.test.ts` | the documentation checker itself — local file and fragment resolution, repository URLs resolved back to the checkout, duplicate heading slugs, fenced-code exclusion, and useful failures | spawns the Node checker against filesystem fixtures |
|
|
268
268
|
| `doctor-cli.test.ts` | `connecta doctor`'s executor line end to end — the sandbox the deployment reports is the one named, an unidentifiable executor gets an executor-neutral line, and a hostile name is bounded and stripped before it reaches a terminal | spawns the CLI against a Node HTTP deployment over real sockets |
|
|
269
269
|
| `drift-check.test.ts` | the maintainer drift checker — hosted-provider credential framing, recorded touched endpoints, a quiet revision bump, clear failures for an unavailable spec/manifest/credential, `$ref` traversal, and one well-formed row per endpoint | spawns the Node checker against filesystem fixtures |
|
|
270
270
|
| `file-storage.test.ts` | `fileStorage()` across instances, logical TTL plus physical pruning without clobbering a newer value, and corrupt-file quarantine | exercises the Node filesystem storage adapter |
|
|
271
|
-
| `guest-api-contract-quickjs.test.ts` | the shared guest-contract cases on the real QuickJS executor, including identical caught failure codes, its exact absent globals, and blocked runtime imports | runs the contract cases on the Node QuickJS executor |
|
|
271
|
+
| `guest-api-contract-quickjs.test.ts` | the shared guest-contract cases on the real QuickJS executor, including identical caught failure codes and inline describe recovery, its exact absent globals, and blocked runtime imports | runs the contract cases on the Node QuickJS executor |
|
|
272
272
|
| `node.test.ts` | the `listen()` adapter propagating an HTTP client disconnect through the Web `Request` and the MCP handler into a program's connector call, releasing both admission permits | exercises the Node HTTP adapter over real TCP sockets |
|
|
273
273
|
| `packed-links.test.ts` | the packed-link gate itself — shipped targets and repository URLs accepted, relative links into unshipped paths and directories rejected with the citation to write instead, reference definitions seen, fenced examples ignored, the changelog exempt | spawns the Node packed-link gate against filesystem fixtures |
|
|
274
274
|
| `package-surface.test.ts` | the published boundary — built output shipped, the `exports` map carrying exactly the documented subpaths plus `./package.json`, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, every provider independently importable, and the Cloudflare provider free of bare specifiers | walks the package tree with Node filesystem APIs |
|
|
@@ -81,6 +81,14 @@ deliberate surface.
|
|
|
81
81
|
| H13 guide | meets | structured, declared summary, `required: true` with a stated reason — the database→data-source lookup is a sequence no complete schema can express |
|
|
82
82
|
| H14 hatch | **missed → fixed** | Notion has no guarded raw-REST tool, which H14 explicitly permits for a finite surface — provided it says so. It did not. The guide now names the absence, so an agent does not spend a search proving there is no `notion_api_get` |
|
|
83
83
|
|
|
84
|
+
The 0.17.0 drift review also considered Notion's expanded create and update
|
|
85
|
+
contracts. Workspace-private creation, templates, placement, richer media,
|
|
86
|
+
locking, and irreversible content erasure stay outside the maintained surface.
|
|
87
|
+
They are separate ownership, ordering, asynchronous, coordination, file, or
|
|
88
|
+
deletion workflows rather than missing fields on the five existing writes
|
|
89
|
+
([#408](https://github.com/zackbart/connecta/issues/408),
|
|
90
|
+
[#409](https://github.com/zackbart/connecta/issues/409)).
|
|
91
|
+
|
|
84
92
|
## Linear — hosted-MCP proxy
|
|
85
93
|
|
|
86
94
|
| Convention | Verdict | Notes |
|
|
@@ -105,16 +113,16 @@ deliberate surface.
|
|
|
105
113
|
| --- | --- | --- |
|
|
106
114
|
| P1 add, never rewrite | meets | annotations only |
|
|
107
115
|
| P2 identity | meets | required `purpose`, `instructions` appended, classification untouchable from there; purpose states deployment routing intent and the guide says it is not proof of authenticated account identity |
|
|
108
|
-
| P3 routing fact | meets |
|
|
109
|
-
| P4 endpoint default | meets |
|
|
116
|
+
| P3 routing fact | meets | OAuth metadata states mixed account scope and the guide resolves mode from `livemode`; fixed header credentials retain their mode in every routing surface |
|
|
117
|
+
| P4 endpoint default | meets | OAuth has no connector-wide mode to default; static headers require one, and construction throws when a recognizable key prefix contradicts it |
|
|
110
118
|
| P5 classification | meets | including the two verdicts that needed an argument — `stripe_api_read` is a read because the tool is the boundary, `create_refund` is destructive despite its name |
|
|
111
119
|
| P6 catalog varies | **missed → fixed** | the doc already knew this (`get_balance_summary` is Treasury and gated; a `create_customer` example survives in Stripe's prose but not its tool table), but the *guide* did not say it, and the guide is what reaches the agent. Added |
|
|
112
|
-
| P7 reduction advice | **missed → fixed** |
|
|
113
|
-
| P8 identity resolution | **missed → fixed** |
|
|
120
|
+
| P7 reduction advice | **missed → fixed** | OAuth has a mixed-scope summary; fixed credentials keep mode-shaped summaries. `required` stays unset because the four generic tools remain the routing decision |
|
|
121
|
+
| P8 identity resolution | **missed → fixed** | The guide names typed object ids and their read sources. For OAuth it requires `list_available_accounts_or_orgs`, then carries the returned `stripe_context` and `livemode` unchanged; ambiguity stops ([#404](https://github.com/zackbart/connecta/issues/404), [#414](https://github.com/zackbart/connecta/issues/414)) |
|
|
114
122
|
| P9 authentication | meets | OAuth default, `requireHttps`, restricted key documented as a secret and paired with the narrowest scope. The guide distinguishes organization accounts within an OAuth session from Connect connected accounts, whose calls reject OAuth and use a deployment-configured restricted key plus `Stripe-Account`. The `auth_required` → `authorize_connector` route was added alongside P8, since a proxy's only recovery instruction lives there |
|
|
115
123
|
| P10 no credential test | meets | no credential slot; the mode/key contradiction throws at construction instead, which is where P10 says the H12 guarantee gets paid |
|
|
116
124
|
| P11 transport vs tool error | meets | inherited from `remoteMcp()`; the guide now also says that a rejected argument or plan restriction arrives in Stripe's own words and is not an authorization problem |
|
|
117
|
-
| P12 admission budget | meets |
|
|
125
|
+
| P12 admission budget | meets | fixed credentials use their documented mode rate; mixed OAuth uses the stricter 25/s sandbox rate and concurrency bound |
|
|
118
126
|
| P13 drift visible | meets | both lists are module-level constants in one file, and are the manifest the refresh-time drift check compares against ([#343](https://github.com/zackbart/connecta/issues/343)) |
|
|
119
127
|
|
|
120
128
|
## Mixpanel — hosted-MCP proxy
|