@zackbart/connecta 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/skills.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Connector } from "./types.js";
2
- export declare const CONNECTA_INSTRUCTIONS = "Connecta exposes integrations behind seven meta-tools, and execute_code is the primary one: write an async arrow function and use connecta.search (empty query browses every catalog), connecta.describe, connecta.call, and connecta.batch inside it for discovery, two or more calls, dependent steps, loops, joins, and reducing large results before they reach you. For a single read at an unknown address, search_tools with 2\u20134 distinctive action/object terms and includeSchemas=\"compact\", then one call_tool \u2014 a lone cold call is cheaper direct than through a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: \"usage\" }).";
3
- export declare const USAGE_SKILL = "# Connecta usage\n\n## The surface\n\nSeven tools: `execute_code`, `search_tools`, `call_tool`, `call_destructive_tool`, `authorize_connector`, `get_result`, `skills`. Broad discovery and multi-call work live inside a program rather than in top-level tools.\n\n## Choose the smallest execution tool\n\nUse exact addresses returned by discovery; never invent one. Search with 2\u20134 distinctive action/object terms rather than the full request.\n\n- One read at an unknown address: `search_tools({ query, includeSchemas: \"compact\" })`, then `call_tool` once. A lone cold call is cheaper direct than through a program.\n- Anything wider \u2014 two or more calls, dependent steps, loops, joins, branching, browsing a whole catalog, or a result that must be reduced: one `execute_code` run.\n- Any unannotated, write-capable, or destructive call: `call_destructive_tool`, individually and only after reviewing its schema and consequences. Generated code cannot make one.\n- Truncated result: retry with `fields` when possible; otherwise page it with `get_result`.\n- `auth_required`: use `authorize_connector`, give its recovery handoff to the operator, then retry the original call.\n\n## Inside a program\n\nOne async arrow function. The only capabilities are one global per connector (`<connectorId>.<toolName>(args)`), the four `connecta` functions, and `console.log`.\n\n- What exists: `connecta.search({})` browses every catalog; add `safety: \"readOnly\"` for only calls the program can execute, and `connector: \"<id>\"` to browse one. This filters discovery results, not authority, and each match carries its `address` and annotations.\n- Exact schemas for known addresses: `connecta.describe({ address: \"connector.tool\" })` for one or `connecta.describe({ addresses: [...] })` for many; `format: \"json\"` only for exact constraints.\n- Two to ten independent calls: `connecta.batch([...])`. Each outcome is `{ address, ok: true, data }` or `{ address, ok: false, error, errorDetails: { code, retryable } }`, which is also how a program tells a policy refusal from a transient failure.\n- Search inside the run rather than searching first, and return only the reduction the answer needs \u2014 never raw payloads.\n- Only tools annotated `readOnlyHint: true` are reachable; the read-only gate, credentials, and admission are enforced below the sandbox, so nothing a program does widens what it can reach.\n";
2
+ export declare const CONNECTA_INSTRUCTIONS = "Connecta exposes seven meta-tools. execute_code is primary: use connecta.search, describe, call, and batch for discovery, multiple or dependent calls, loops, joins, and result reduction. connecta.ui(html) is a guest function inside execute_code, never a connector address or search_tools result; pass one HTML string for display-only, or bind named read-only refresh/drill-down calls in its optional reads argument, and return the same initial summary data the HTML renders. For one read at an unknown address, search_tools with 2\u20134 distinctive action/object terms and includeSchemas=\"compact\", then one call_tool \u2014 a lone cold call is cheaper direct than a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: \"usage\" }).";
3
+ export declare const USAGE_SKILL = "# Connecta usage\n\n## The surface\n\nSeven 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.\n\n## Choose the smallest execution tool\n\nUse exact addresses from discovery; never invent one. Search 2\u20134 distinctive action/object terms, not the whole request.\n\n- One read at an unknown address: `search_tools({ query, includeSchemas: \"compact\" })`, then `call_tool` once \u2014 one cold call is cheaper direct than a program.\n- Anything wider \u2014 two or more calls, dependent steps, loops, joins, branching, a whole-catalog browse, or a result to reduce: one `execute_code` run.\n- Any unannotated, write-capable, or destructive call: `call_destructive_tool`, one at a time, after reviewing its schema and consequences.\n- Truncated result: retry with `fields`, else page it with `get_result`.\n- `auth_required`: `authorize_connector`, hand its recovery text to the operator, retry the call.\n\n## Inside a program\n\nOne async arrow function. The only capabilities are one global per connector (`<connectorId>.<toolName>(args)`), the `connecta` functions, and `console.log`.\n\n- `connecta.search({})` browses every catalog; `safety: \"readOnly\"` narrows to calls a program can execute, `connector: \"<id>\"` to one. This filters results, not authority; matches carry `address` and annotations.\n- Exact schemas: `connecta.describe({ address: \"connector.tool\" })` for one, `{ addresses: [...] }` for many; `format: \"json\"` only for exact constraints.\n- Two to ten independent calls: `connecta.batch([...])`. Each outcome is `{ address, ok: true, data }` or `{ address, ok: false, error, errorDetails: { code, retryable } }` \u2014 how a program tells a policy refusal from a transient failure.\n- Search inside the run, not before it; return only the reduction the answer needs, never raw payloads.\n- Only tools annotated `readOnlyHint: true` are reachable; the gate, credentials, and admission are enforced below the sandbox \u2014 nothing a program does widens its reach.\n\n## Rendering a view\n\n`connecta.ui(html)` renders a display-only view on success for the client, never for the model. Fetch first, check the shape in code. On a surprise \u2014 empty array, missing key \u2014 return a trimmed first record instead of rendering: the wrong view becomes the sample you needed. Otherwise render from the variables you return; the model reads the return value, not the view.\n\n";
4
4
  /**
5
5
  * Appended to USAGE_SKILL only when the deployment actually has at least one
6
6
  * connector guide. A deployment with none — every deployment that has not
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,qBAAqB,+yBAC8vB,CAAC;AAEjyB,eAAO,MAAM,WAAW,u3EAyBvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,2eAIpC,CAAC;AAEF,mDAAmD;AACnD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAI5E;AA0BD,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAGvE;AAyDD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,YAAY,EAAE,CAc3E;AAED,MAAM,MAAM,WAAW,GACrB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,SAAS,EAAE,GAC/B,WAAW,CAwCb"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,qBAAqB,o5BACm2B,CAAC;AAEt4B,eAAO,MAAM,WAAW,mgFA8BvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,2eAIpC,CAAC;AAEF,mDAAmD;AACnD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAI5E;AA0BD,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAGvE;AAyDD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,YAAY,EAAE,CAc3E;AAED,MAAM,MAAM,WAAW,GACrB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,SAAS,EAAE,GAC/B,WAAW,CAwCb"}
package/dist/skills.js CHANGED
@@ -1,29 +1,34 @@
1
- export const CONNECTA_INSTRUCTIONS = 'Connecta exposes integrations behind seven meta-tools, and execute_code is the primary one: write an async arrow function and use connecta.search (empty query browses every catalog), connecta.describe, connecta.call, and connecta.batch inside it for discovery, two or more calls, dependent steps, loops, joins, and reducing large results before they reach you. For a single read at an unknown address, search_tools with 2–4 distinctive action/object terms and includeSchemas="compact", then one call_tool — a lone cold call is cheaper direct than through a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
1
+ export const CONNECTA_INSTRUCTIONS = 'Connecta exposes seven meta-tools. execute_code is primary: use connecta.search, describe, call, and batch for discovery, multiple or dependent calls, loops, joins, and result reduction. connecta.ui(html) is a guest function inside execute_code, never a connector address or search_tools result; pass one HTML string for display-only, or bind named read-only refresh/drill-down calls in its optional reads argument, and return the same initial summary data the HTML renders. For one read at an unknown address, search_tools with 2–4 distinctive action/object terms and includeSchemas="compact", then one call_tool — a lone cold call is cheaper direct than a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
2
2
  export const USAGE_SKILL = `# Connecta usage
3
3
 
4
4
  ## The surface
5
5
 
6
- Seven tools: \`execute_code\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Broad discovery and multi-call work live inside a program rather than in top-level tools.
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
  ## Choose the smallest execution tool
9
9
 
10
- Use exact addresses returned by discovery; never invent one. Search with 2–4 distinctive action/object terms rather than the full request.
10
+ Use exact addresses from discovery; never invent one. Search 2–4 distinctive action/object terms, not the whole request.
11
11
 
12
- - One read at an unknown address: \`search_tools({ query, includeSchemas: "compact" })\`, then \`call_tool\` once. A lone cold call is cheaper direct than through a program.
13
- - Anything wider — two or more calls, dependent steps, loops, joins, branching, browsing a whole catalog, or a result that must be reduced: one \`execute_code\` run.
14
- - Any unannotated, write-capable, or destructive call: \`call_destructive_tool\`, individually and only after reviewing its schema and consequences. Generated code cannot make one.
15
- - Truncated result: retry with \`fields\` when possible; otherwise page it with \`get_result\`.
16
- - \`auth_required\`: use \`authorize_connector\`, give its recovery handoff to the operator, then retry the original call.
12
+ - One read at an unknown address: \`search_tools({ query, includeSchemas: "compact" })\`, then \`call_tool\` once one cold call is cheaper direct than a program.
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.
17
17
 
18
18
  ## Inside a program
19
19
 
20
- One async arrow function. The only capabilities are one global per connector (\`<connectorId>.<toolName>(args)\`), the four \`connecta\` functions, and \`console.log\`.
20
+ One async arrow function. The only capabilities are one global per connector (\`<connectorId>.<toolName>(args)\`), the \`connecta\` functions, and \`console.log\`.
21
+
22
+ - \`connecta.search({})\` browses every catalog; \`safety: "readOnly"\` narrows to calls a program can execute, \`connector: "<id>"\` to one. This filters results, not authority; matches carry \`address\` and annotations.
23
+ - Exact schemas: \`connecta.describe({ address: "connector.tool" })\` for one, \`{ addresses: [...] }\` for many; \`format: "json"\` only for exact constraints.
24
+ - Two to ten independent calls: \`connecta.batch([...])\`. Each outcome is \`{ address, ok: true, data }\` or \`{ address, ok: false, error, errorDetails: { code, retryable } }\` — how a program tells a policy refusal from a transient failure.
25
+ - Search inside the run, not before it; 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.
27
+
28
+ ## Rendering a view
29
+
30
+ \`connecta.ui(html)\` renders a display-only view on success for the client, never for the model. Fetch first, check the shape in code. On a surprise — empty array, missing key — return a trimmed first record instead of rendering: the wrong view becomes the sample you needed. Otherwise render from the variables you return; the model reads the return value, not the view.
21
31
 
22
- - What exists: \`connecta.search({})\` browses every catalog; add \`safety: "readOnly"\` for only calls the program can execute, and \`connector: "<id>"\` to browse one. This filters discovery results, not authority, and each match carries its \`address\` and annotations.
23
- - Exact schemas for known addresses: \`connecta.describe({ address: "connector.tool" })\` for one or \`connecta.describe({ addresses: [...] })\` for many; \`format: "json"\` only for exact constraints.
24
- - Two to ten independent calls: \`connecta.batch([...])\`. Each outcome is \`{ address, ok: true, data }\` or \`{ address, ok: false, error, errorDetails: { code, retryable } }\`, which is also how a program tells a policy refusal from a transient failure.
25
- - Search inside the run rather than searching first, and return only the reduction the answer needs — never raw payloads.
26
- - Only tools annotated \`readOnlyHint: true\` are reachable; the read-only gate, credentials, and admission are enforced below the sandbox, so nothing a program does widens what it can reach.
27
32
  `;
28
33
  /**
29
34
  * Appended to USAGE_SKILL only when the deployment actually has at least one
@@ -1 +1 @@
1
- {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -4,5 +4,5 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export declare const CONNECTA_VERSION = "0.12.0";
7
+ export declare const CONNECTA_VERSION = "0.12.2";
8
8
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -4,5 +4,5 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.12.0";
7
+ export const CONNECTA_VERSION = "0.12.2";
8
8
  //# sourceMappingURL=version.js.map
@@ -326,7 +326,8 @@ classify, use `errorDetails`; to hand a failure to the model with its type
326
326
  intact, let it escape uncaught — connecta re-attaches the typed details on the
327
327
  way out. The model-facing version of this lives in `execute_code`'s description,
328
328
  not in the always-loaded usage skill, which `test/meta-tools.test.ts` caps at
329
- 1,800 bytes with three bytes spare.
329
+ 2,500 bytes a budget the guide already spends nearly all of, so new text there
330
+ displaces old rather than adding to what every request pays for.
330
331
 
331
332
  **E2.** The taxonomy. `retryable` is what connecta reports; `Y3` says what a
332
333
  program may do about it.
@@ -502,10 +503,9 @@ the security posture live in the [design record](./mcp-ui-design.md)
502
503
  [#277](https://github.com/zackbart/connecta/issues/277)); this section is the
503
504
  contract, and it wins where the two disagree.
504
505
 
505
- **U1.** `connecta.ui(html)` accepts exactly one argument: a non-empty string of
506
- HTML. A non-string, an empty string, an options bag, or an MCP block object
507
- throws catchably and nothing is accepted. There is no options parameter and no
508
- sugar form, for `M1`'s reason: sugar is how a one-shape contract grows hair.
506
+ **U1.** `connecta.ui(html, options?)` accepts one non-empty HTML string and at
507
+ most the bounded read manifest `V1` defines. The one-argument call stays
508
+ display-only; every other shape throws catchably and accepts nothing.
509
509
 
510
510
  **U2.** At most one payload per run. A second call throws catchably, naming the
511
511
  constraint; the first accepted payload stands. One tool result renders one view,
@@ -513,7 +513,7 @@ and last-wins would silently discard a payload the program deliberately
513
513
  supplied.
514
514
 
515
515
  **U3.** Delivered on success only, and out of model context: the tool result
516
- gains `_meta["connecta/ui"] = { html }` and the JSON envelope gains `ui: true`,
516
+ gains `_meta["connecta/ui"] = { html, reads? }` and the JSON envelope gains `ui: true`,
517
517
  so the model learns a view rendered without seeing its bytes. `structuredContent`
518
518
  stays the envelope alone. The single-label `connecta/ui` prefix is deliberate —
519
519
  connecta has no domain to reverse, and fabricating one to satisfy MCP's
@@ -526,27 +526,27 @@ with `emittedDiscarded: N` when one failure discards both.
526
526
 
527
527
  **U4.** The payload spends the aggregate emit byte budget
528
528
  (`ConnectaConfig.execute.maxEmittedBytes`), measured at the call as the
529
- serialized bytes of `{ html }` — `M5`'s measurement. Over budget throws
529
+ serialized bytes of `{ html, reads? }` — `M5`'s measurement. Over budget throws
530
530
  catchably, naming the budget and the room remaining, with nothing partially
531
531
  accepted. It spends no block count (`maxEmittedBlocks`: it is not a block) and no
532
532
  host-call budget (`L4`). One transport bound covers everything rich a program
533
533
  delivers.
534
534
 
535
535
  **U5.** One static shell: a connecta-authored HTML5 document at
536
- `ui://connecta/program-ui/v1`, mimeType `text/html;profile=mcp-app`, declared on
536
+ `ui://connecta/program-ui/v2`, mimeType `text/html;profile=mcp-app`, declared on
537
537
  `execute_code` via `_meta.ui.resourceUri` together with an explicit
538
- `_meta.ui.visibility: ["model"]` the default `["model","app"]` would tell hosts
539
- the view may call `execute_code`. A `resources/read` handler answers exactly that
538
+ `_meta.ui.visibility: ["model"]`. Only `call_tool` declares app visibility; all
539
+ other tools say model-only. A `resources/read` handler answers exactly that
540
540
  URI and fails on any other; `resources/list` is served and returns an empty list.
541
541
  The version segment bumps whenever the shell's bytes change, because hosts cache
542
542
  templates by URI.
543
543
 
544
- **U6.** The shell is display-only. It renders the payload in a nested iframe
544
+ **U6.** The shell renders the payload in a nested iframe
545
545
  (`srcdoc`, `sandbox="allow-scripts"`, no `allow-same-origin`) and declares no CSP
546
546
  domains, so the host applies its restrictive default and the `about:srcdoc` frame
547
- inherits `default-src 'none'; connect-src 'none'`. Program UI gets scripts and
548
- local interactivity and nothing else: no network, no tool calls, no conversation
549
- messages, no host-mediated links. The shell participates in the Apps lifecycle —
547
+ inherits `default-src 'none'; connect-src 'none'`. One argument stays display-only;
548
+ a `V1` manifest installs only named `connecta.read`, with no direct network, raw
549
+ tool calls, discovery, conversation, writes, or links. The shell participates in the Apps lifecycle —
550
550
  initialize, tool-result, size-changed, resource-teardown — and forwards no
551
551
  channel whatsoever from the inner frame to the host. That isolation makes
552
552
  program views fixed-height by construction: with no bridge there is no
@@ -580,6 +580,27 @@ host fetches the shell, and the whole design is inert. Reading the *client's*
580
580
  declaration in order to register tool metadata conditionally stays refused
581
581
  (`U10`), knowingly against a spec SHOULD.
582
582
 
583
+ **U12.** The return value, not the view, is what the model reads. `U3` puts the
584
+ view out of model context, so a program that renders one also returns the summary
585
+ the model should reason over, built from the same variables the initial view renders — a
586
+ view the return value does not mirror is a view nobody in the loop can check.
587
+ This binds program authors and nothing else: connecta never reads the HTML, diffs
588
+ it against the return, or enforces the correspondence. A heuristic there would be
589
+ the same mistake as automatic host-side projection, refused in `ethos.md`
590
+ ([#282](https://github.com/zackbart/connecta/issues/282)).
591
+
592
+ **U13.** The always-loaded MCP instructions locate `connecta.ui(html)` before an
593
+ agent chooses a route: it is a guest function inside `execute_code`, never a
594
+ connector address or catalog result, takes one HTML string, and carries `U12`'s
595
+ mirrored-return duty. The detailed tool description proved too late to stop cold
596
+ agents from searching downstream catalogs for UI; the location distinction
597
+ therefore rides `initialize`, under a 1,000-character ceiling for the complete
598
+ instructions string. This promotes existing contract, not capability: the
599
+ seven-tool surface, guest API, catalog, Apps delivery, and runtime do not change
600
+ ([#286](https://github.com/zackbart/connecta/issues/286)).
601
+
602
+ 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)).
603
+
583
604
  ## Retry semantics
584
605
 
585
606
  **Y1.** Connecta retries nothing beneath a program. `call_tool` accepts an
@@ -794,7 +815,7 @@ Two surfaces were added since, both additive by construction and each with its
794
815
  byte-for-byte no-call promise pinned by test:
795
816
  [emitted output](#emitted-output) (`M1`–`M10`,
796
817
  [#270](https://github.com/zackbart/connecta/issues/270)) and
797
- [rendered output](#rendered-output) (`U1`–`U11`,
818
+ [rendered output](#rendered-output) (`U1`–`U12`,
798
819
  [#277](https://github.com/zackbart/connecta/issues/277)).
799
820
 
800
821
  ## Verification
@@ -861,6 +882,8 @@ the upstream `Executor` shape assignable.
861
882
  | `U6` | `test/execute-ui.test.ts` (valid HTML5, `srcdoc` and sandbox attributes, no `allow-same-origin`, no path from the inner frame to the host) |
862
883
  | `U7`, `U8` | two arms passing one case table, `test/codemode-compat.test.ts` |
863
884
  | `U9` | `test/execute-ui.test.ts` (a `ui` byte aggregate distinct from `emitted`, absent when nothing was accepted) |
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 |
886
+ | `U13` | `test/code-first-surface.test.ts`, `test/server.test.ts` (served `initialize.instructions` locate UI inside `execute_code`, exclude it from catalog search, state the one-string call and mirrored return, and stay within the complete 1,000-character budget) |
864
887
  | `X3` | `test/quickjs-executor.test.ts` (cancels a running child) |
865
888
  | `X4` | `test/guest-api-contract.test.ts` (string logs only) |
866
889
  | `X6` | `test/quickjs-executor.test.ts` (never-settling await) |
@@ -319,14 +319,14 @@ official spec at all — it survives there as background prose, not as a deferre
319
319
  item with a queue position. Adopting a payload format the official spec never
320
320
  took, on the path the official spec superseded, is two bets on one square.
321
321
 
322
- **View-initiated tool calls from program UI.** Gated, not refused. The
323
- host-mediated `tools/call` path exists in the Apps spec and would go through
324
- the same admission, annotation, and consent path as any other call, so the
325
- safety story is not the blocker. What is missing is the argument: a
326
- program-authored UI that drives tools needs its own use case and its own
327
- consent story, and neither exists yet. Display-only until one arrives, and
328
- gated twice over: `U5` declares `_meta.ui.visibility: ["model"]` so no host is
329
- ever told the view may call, and `U6`'s shell has no bridge to call with.
322
+ **View-initiated tool calls from program UI.** This original gate was split by
323
+ [#287](https://github.com/zackbart/connecta/issues/287) on 2026-08-02. Bounded
324
+ refresh, pagination, and drill-down reads are accepted through named bindings
325
+ and the existing `call_tool`; mutations remain gated. The evidence, threat
326
+ trace, and boundary between live reads and Executor's artifact product live in
327
+ [`program-ui-read-calls.md`](./program-ui-read-calls.md). The normative contract
328
+ is `V1`–`V8` in [`code-mode.md`](./code-mode.md); it supersedes this record's
329
+ display-only clauses where they disagree.
330
330
 
331
331
  **Downstream MCP Apps template passthrough** (downstream connectors declaring
332
332
  their own `ui://` templates, proxied through connecta's `resources/read`).
@@ -0,0 +1,213 @@
1
+ # Bounded reads from program UI — evidence and decision
2
+
3
+ Decision note for [#287](https://github.com/zackbart/connecta/issues/287),
4
+ 2026-08-02. The implementation contract is [#289](https://github.com/zackbart/connecta/issues/289)
5
+ and the normative clauses are `V1`–`V8` in [code-mode.md](./code-mode.md).
6
+
7
+ ## Verdict
8
+
9
+ Accept explicitly bound, host-mediated **read-only** calls for refresh,
10
+ pagination, and drill-down. Keep mutations gated. Keep the one-string
11
+ `connecta.ui(html)` call display-only.
12
+
13
+ This is not an acceptance of interactive applications in general. It adds no
14
+ persistence, artifact catalog, sharing, component runtime, generated-code
15
+ library, deep link, direct network, conversation channel, or write path. One
16
+ successful program still delivers one request-local view and one ordinary text
17
+ result.
18
+
19
+ ## What display-only could not do
20
+
21
+ The current shell and the read-bound browser fixture were walked through with
22
+ the same three shapes. In the display-only arm, local JavaScript could sort,
23
+ filter, chart, expand already-delivered fields, and rerender indefinitely; every
24
+ attempt to obtain bytes not present in the original HTML stopped at the nested
25
+ frame. The read-bound arm exercised the same-origin-free nested frame, two
26
+ concurrent refreshes, fixed and view-supplied arguments, a refused fabricated
27
+ binding, a refused extra argument, and a host error.
28
+
29
+ | Workflow | Display-only attempt | Is a fresh program run adequate? | Decision |
30
+ | --- | --- | --- | --- |
31
+ | Refresh a current status or metrics view | A button can repaint only the original snapshot. Putting a timer around it changes no data. | No. It spends another model turn, reruns composition, and creates another view merely to repeat the same read. | Accept an exact named read with optional filter or cursor keys. |
32
+ | Page a cursor-backed list | The initial program can include the known next cursor, but the view cannot exchange it for the next page. Fetching every page up front defeats projection and can cross call/result budgets. | No. The model is an expensive pagination controller and has to reconstruct UI state it did not need. | Accept a binding whose declared `viewArgs` includes the cursor field. |
33
+ | Drill from a projected list into one record | Local expansion can show only fields prefetched for every row. Prefetching every detail multiplies calls and payload for records the human never opens. | Usually no. A new prompt can fetch the record, but loses the direct row selection and creates a second result instead of filling the existing view. | Accept a binding whose declared `viewArgs` includes the record identifier. |
34
+ | Sort, filter, chart, compare, or expand delivered data | Local HTML/JavaScript completes the interaction. | Yes; usually no new run is needed at all. | No call capability earned. |
35
+ | Change, delete, approve, send, or deploy | Display-only correctly cannot act. | Yes. The ordinary `call_destructive_tool` path keeps the proposed effect and host approval in the transcript. | Remain gated. A click is not approval, and this decision adds no mutation bridge. |
36
+
37
+ The accepted utility is therefore *live reads*, not “interactivity.” Local
38
+ interactivity already existed.
39
+
40
+ ## Executor comparison
41
+
42
+ Executor's inspected revision demonstrates a useful separation:
43
+
44
+ - its generated iframe disables direct `fetch`, XHR, WebSocket, EventSource,
45
+ workers, and related network primitives;
46
+ - declarative `tools.*` operations become one proxy-shaped call through a
47
+ trusted shell and an app-only action tool;
48
+ - integration roles resolve against server-owned saved bindings, and writes
49
+ can pause for shell-owned interaction handling.
50
+
51
+ That is evidence that a narrow bridge can keep untrusted markup away from raw
52
+ network and credentials. It is not evidence for Executor's React runtime,
53
+ saved artifacts, editing, previews, persistence, or deep-link fallback; those
54
+ features provide longevity and authoring ergonomics, not the refresh,
55
+ pagination, or drill-down read itself.
56
+
57
+ Connecta takes the smaller shape. The trusted shell maps names to the already
58
+ existing `call_tool`; bindings live in the completed result, not a database;
59
+ and the ordinary fail-closed read path remains the authority. No app-only tool
60
+ or eighth meta-tool is needed.
61
+
62
+ Inspected Executor sources:
63
+
64
+ - [artifact and app-only action registration](https://github.com/UsefulSoftwareCo/executor/blob/837e404acbebdf32924059d6b76f715565329307/packages/hosts/mcp/src/tool-server.ts#L1906-L2157)
65
+ - [single proxy-shaped action grammar](https://github.com/UsefulSoftwareCo/executor/blob/837e404acbebdf32924059d6b76f715565329307/packages/hosts/mcp-apps-shell/src/shell/proxy.ts#L38-L140)
66
+ - [disabled direct network primitives](https://github.com/UsefulSoftwareCo/executor/blob/837e404acbebdf32924059d6b76f715565329307/packages/hosts/mcp-apps-shell/src/shell/inner-renderer.tsx#L84-L131)
67
+
68
+ ## Contract in one pass
69
+
70
+ ```js
71
+ await connecta.ui(html, {
72
+ reads: {
73
+ refresh: {
74
+ address: "metrics.current",
75
+ fixedArgs: { service: "api" },
76
+ viewArgs: ["window", "cursor"],
77
+ },
78
+ detail: {
79
+ address: "incidents.get",
80
+ viewArgs: ["id"],
81
+ },
82
+ },
83
+ });
84
+ ```
85
+
86
+ Program markup calls `await connecta.read("detail", { id })`. It never receives
87
+ the address table. The outer shell checks the frame source, resolves `detail`,
88
+ rejects keys other than `id`, merges the arguments, and asks the host to call
89
+ the existing `call_tool` with `resultMode: "value"`.
90
+
91
+ The declaration-time catalog lookup proves the view was not born broken or
92
+ write-capable. The use-time `call_tool` lookup proves it is still read-only now.
93
+
94
+ ## Normative contract
95
+
96
+ **V1. Manifest.** The second argument is exactly
97
+ `{ reads: { name: { address, fixedArgs?, viewArgs? } } }`: 1–32 names matching
98
+ `[A-Za-z][A-Za-z0-9_-]{0,63}`, one non-empty address per name, optional fixed
99
+ arguments, and at most 32 distinct view-supplied keys. Extra fields, unsafe
100
+ control names (`__proto__`, `constructor`, `prototype`), a view key colliding
101
+ with a fixed key, and non-serializable content throw before acceptance.
102
+
103
+ **V2. Declaration admission.** Every address resolves through the request-local
104
+ catalog and passes the fail-closed `isExplicitlyReadOnly` classification before
105
+ the payload is accepted. The lookup dispatches nothing and spends no host-call
106
+ budget. `call_tool` repeats resolution and classification at use time.
107
+
108
+ **V3. Delivery.** Bindings ride beside `html` under `_meta["connecta/ui"]`,
109
+ share the existing emitted-byte aggregate, appear on success only, and never
110
+ enter `content` or `structuredContent`. The one-string payload stays exactly
111
+ `{ html }`.
112
+
113
+ **V4. Inner bridge.** A manifest alone installs `connecta.read(name, args?)`.
114
+ The outer shell accepts only its nested frame's exact `WindowProxy`, rejects an
115
+ unknown name, non-object arguments, undeclared keys, and more than eight
116
+ concurrent reads, then merges supplied keys into a null-prototype copy of fixed
117
+ arguments. The inner frame receives no address table or raw JSON-RPC.
118
+
119
+ **V5. Seven-tool boundary.** The shell calls only existing `call_tool` with
120
+ `resultMode: "value"`. That tool alone is app-visible; the other six are
121
+ explicitly model-only. No new MCP tool exists and the view cannot reach the
122
+ destructive boundary.
123
+
124
+ **V6. Ordinary admission.** A view read is a new MCP request crossing inbound
125
+ auth, request admission, current catalog and credentials, fail-closed safety,
126
+ connector admission, timeout, retry, result-size, and payload-free activity
127
+ exactly as ordinary `call_tool` does. No server-side grant or pending promise
128
+ survives the originating request.
129
+
130
+ **V7. Stale and replayed views.** A stale view retains no frozen authority:
131
+ removed tools, changed annotations, revoked credentials, lost inbound auth, and
132
+ new policy fail current admission. Replay repeats a read and may spend rate
133
+ limits, but cannot write. Cross-caller use is admitted as the current caller on
134
+ the host's originating connection; deployment remains the audience boundary.
135
+
136
+ **V8. Context, fallback, and parity.** Reads update only the human-visible view;
137
+ the return summarizes the initial snapshot and refreshed data must be labelled
138
+ as such. A host without app server tools keeps the ordinary result and initial
139
+ view while a read fails locally. The existing provider bridge carries the
140
+ manifest identically on both executors without changing `ExecuteResult`.
141
+
142
+ ## Threat and consent trace
143
+
144
+ 1. **Untrusted program declaration.** The guest supplies HTML and a strictly
145
+ shaped read manifest. The host rejects extra fields, unsafe control names,
146
+ fixed/view collisions, overlarge lists, unknown addresses, and anything not
147
+ explicitly read-only. This lookup executes nothing.
148
+ 2. **Result delivery.** On successful program completion only, HTML and
149
+ bindings ride result `_meta` under the existing aggregate byte budget. A
150
+ failed program delivers neither. The model sees only `ui: true` and the
151
+ program's initial summary.
152
+ 3. **Nested-frame request.** Only the exact payload `WindowProxy` may send the
153
+ `connecta/read` dialect to the trusted shell. A fabricated name fails before
154
+ a host call. Fabricated or prototype-shaped argument keys fail unless they
155
+ are explicitly declared; fixed keys cannot be overridden. Direct JSON-RPC
156
+ from the nested frame is ignored.
157
+ 4. **Host mediation.** The shell checks that the host advertised server-tool
158
+ calls, caps concurrent work, and emits one `tools/call` for `call_tool`.
159
+ `execute_code`, discovery, authorization, result paging, and the destructive
160
+ tool are model-only. The Apps host accepts calls only on the originating MCP
161
+ server connection.
162
+ 5. **Connecta admission.** The app call is a new authenticated request with a
163
+ fresh request scope. It crosses request admission, current catalog and
164
+ credential resolution, fail-closed read classification, connector call
165
+ admission, timeout, retry policy, result-size handling, and payload-free
166
+ activity recording. There is no UI bypass below the shell.
167
+ 6. **Result delivery.** The shell unwraps the ordinary value result and settles
168
+ only the matching inner-frame promise. Protocol errors and tool errors
169
+ reject it. It sends no result to model or conversation context.
170
+
171
+ ### Named failures
172
+
173
+ - **Fabricated address:** markup cannot submit an address; raw JSON-RPC is not
174
+ forwarded. A declaration-time invented address fails catalog resolution.
175
+ - **Fabricated binding name:** rejected by own-property lookup in the shell.
176
+ - **Fabricated argument:** an undeclared key or non-object argument is rejected;
177
+ a declared value still faces the downstream input schema and policy.
178
+ - **Stale view:** the later request reauthenticates and re-resolves the catalog.
179
+ A removed tool, newly unsafe annotation, revoked credential, or changed
180
+ admission policy fails current checks. No frozen grant exists server-side.
181
+ - **Replay:** it repeats a read and may consume rate limits, but cannot cross to
182
+ a write. The view should disable duplicate controls while its promise is
183
+ pending; the shell also bounds concurrency.
184
+ - **Cross-caller use:** the later request is admitted as the caller behind the
185
+ host's current originating connection. Connecta does not use identity to
186
+ scope tools inside one deployment; separate audiences remain separate
187
+ deployments. A copied manifest is no credential and grants nothing outside
188
+ ordinary inbound auth.
189
+ - **Destructive call:** the shell names only `call_tool`, and that handler
190
+ refuses missing, false, or contradictory read-only annotation. The
191
+ destructive meta-tool is not app-visible. No human gesture is interpreted as
192
+ write consent.
193
+
194
+ ## Invariants and parity
195
+
196
+ - **Seven tools:** unchanged; metadata makes one existing tool app-callable and
197
+ makes the other six explicitly model-only.
198
+ - **Stateless request scope:** binding state survives only in the client's
199
+ completed result and trusted shell. The server stores no grant or pending
200
+ promise.
201
+ - **Import-graph purity:** the shell remains a build-time string using browser
202
+ and Web APIs only.
203
+ - **Workers/Node parity:** the second argument crosses the existing provider
204
+ bridge, leaving `Executor` and `ExecuteResult` unchanged; the same contract
205
+ case runs on both executors and both Vitest projects.
206
+ - **Payload-free activity:** later reads use ordinary `call_tool` events, whose
207
+ schema has no arguments or results.
208
+ - **Fallback:** hosts without Apps keep the ordinary result; Apps hosts without
209
+ server-tool calls keep the initial view and fail a read locally.
210
+
211
+ The remaining gate is intentionally crisp: a mutation proposal needs real
212
+ workflow evidence plus a host-tested consent and replay story. Read utility is
213
+ not permission to smuggle that decision into this bridge.
package/ethos.md CHANGED
@@ -95,7 +95,9 @@ proposing one without a new argument is not.
95
95
  | Program-generated UI (`connecta.ui` + the Apps shell) | accepted | one MCP Apps view per successful run: the program supplies HTML only, delivered in result `_meta`, which hosts keep out of model context, and rendered by connecta's static shell inside the host's sandboxed frame ([design record](./documentation/mcp-ui-design.md), [#266](https://github.com/zackbart/connecta/issues/266)) |
96
96
  | Serving connecta's own UI template via `resources/read` | accepted | a narrow carve-out from the resources-aggregation refusal, not a reversal of it: one static build-time shell at one URI, an empty `resources/list`, nothing downstream ever listed or aggregated ([#266](https://github.com/zackbart/connecta/issues/266)) |
97
97
  | Downstream MCP Apps template passthrough | gated | proxying downstream `resources/read` earns its way in when a downstream connector actually ships an Apps template ([#266](https://github.com/zackbart/connecta/issues/266)) |
98
- | View-initiated tool calls from program UI | gated | the host-mediated path exists and would take the ordinary audit and consent route, but a program-authored UI driving tools needs its own argument; display-only until one arrives ([#266](https://github.com/zackbart/connecta/issues/266)) |
98
+ | View-initiated read calls from program UI | accepted | named bindings materially improve refresh, cursor pagination, and drill-down without persistence or a new tool; the trusted shell delegates only to the existing fail-closed `call_tool`, and the one-string UI remains display-only ([evidence](./documentation/program-ui-read-calls.md), [#287](https://github.com/zackbart/connecta/issues/287), [#289](https://github.com/zackbart/connecta/issues/289)) |
99
+ | View-initiated mutation calls from program UI | gated | live-read utility says nothing about write consent: a click is not approval, stale/replayed effects need a host-tested story, and the ordinary destructive path keeps the action in the transcript ([#287](https://github.com/zackbart/connecta/issues/287)) |
100
+ | Result sampling on the catalog surface (`sample` / `dryRun`) | refused | sampling is execution and cannot ride a catalog read; most tools carry required arguments no sampler can invent, and undeclared `outputSchema` (measured 0/30 and 3/30 on real deployments) is a real gap that is not a sampleable one — a program that checks the shape before rendering already hands back the first record inside the run it was going to make anyway, at zero new surface ([#282](https://github.com/zackbart/connecta/issues/282)) |
99
101
  | Legacy embedded `UIResource` delivery | refused | superseded upstream and rendered by none of the clients connecta faces; per-request minted URIs also fight the caching the Apps spec assumes ([#266](https://github.com/zackbart/connecta/issues/266)) |
100
102
 
101
103
  ## Invariants
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of seven meta-tools.",