@noodleseed/agent-kit 0.28.0 → 0.29.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/manifest.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
- "packageVersion": "0.28.0",
2
+ "packageVersion": "0.29.0",
3
3
  "files": [
4
4
  {
5
5
  "path": "skills/codex/SKILL.md",
6
- "sha256": "46a6304e7263dc8d466e8a63cbfa8e236e81c12d32ac248d75114ea07696baae",
6
+ "sha256": "748275d8f350af4390d07fccb571bedf0ea6dc9c7c074f28fe3a493f41bcbef1",
7
7
  "agentTarget": "codex"
8
8
  },
9
9
  {
10
10
  "path": "skills/codex/references/sdk-surface.md",
11
- "sha256": "23b901198b1d6a2cb5c140810b2fc4d58b7008c2afb2fdd57a8e2993333a7600",
11
+ "sha256": "769ac9217397298ec8b25236a008d11a84406a7fab6584ae929e5eacc2054cdc",
12
12
  "agentTarget": "codex"
13
13
  },
14
14
  {
@@ -28,12 +28,12 @@
28
28
  },
29
29
  {
30
30
  "path": "skills/codex/references/authoring-workflow.md",
31
- "sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
31
+ "sha256": "d553234ffd7c4d8d22624123b6c91f359f8643ae305584742b241763c8868eeb",
32
32
  "agentTarget": "codex"
33
33
  },
34
34
  {
35
35
  "path": "skills/codex/references/embedded-assistant.md",
36
- "sha256": "16ef1df5ad641f6b36fa9530f920c3588f77f929c4d609fe4aeffd0dc11abc94",
36
+ "sha256": "7b9de2f1033291312b2b4cc58bffa3e1cb0c8eeed6a77505daab5dc492bb00db",
37
37
  "agentTarget": "codex"
38
38
  },
39
39
  {
@@ -198,7 +198,7 @@
198
198
  },
199
199
  {
200
200
  "path": "skills/codex/examples/acme-tasks/README.md",
201
- "sha256": "e1d654d1a98b721ef7ce4f5d5d3d868611079ed4dbf2126b766018adb95d4194",
201
+ "sha256": "3fbc0821badfea43af4aab131d09f7c953095e0d241de7ea5cfcc3491b70fce5",
202
202
  "agentTarget": "codex"
203
203
  },
204
204
  {
@@ -228,7 +228,7 @@
228
228
  },
229
229
  {
230
230
  "path": "skills/codex/examples/acme-tasks/src/server.ts",
231
- "sha256": "514cca681ffd5f686364cb2d3b8ab27c9145b1aa1e2bf22d665fa1935ac55ce6",
231
+ "sha256": "0abd695218d0fd73abde31b2ea16742a028721044ef3c565bdc88cdbb10f19aa",
232
232
  "agentTarget": "codex"
233
233
  },
234
234
  {
@@ -378,12 +378,12 @@
378
378
  },
379
379
  {
380
380
  "path": "skills/claude-code/SKILL.md",
381
- "sha256": "0c0dd5641e72b641a87e4814eb6d0b8e46e3c9bb23abfe213763a2a36777f6d5",
381
+ "sha256": "4b22a1c1b1f113567d61aa9ccddb1b47c61f07c899dc195577dde61535508dfd",
382
382
  "agentTarget": "claude-code"
383
383
  },
384
384
  {
385
385
  "path": "skills/claude-code/references/sdk-surface.md",
386
- "sha256": "23b901198b1d6a2cb5c140810b2fc4d58b7008c2afb2fdd57a8e2993333a7600",
386
+ "sha256": "769ac9217397298ec8b25236a008d11a84406a7fab6584ae929e5eacc2054cdc",
387
387
  "agentTarget": "claude-code"
388
388
  },
389
389
  {
@@ -403,12 +403,12 @@
403
403
  },
404
404
  {
405
405
  "path": "skills/claude-code/references/authoring-workflow.md",
406
- "sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
406
+ "sha256": "d553234ffd7c4d8d22624123b6c91f359f8643ae305584742b241763c8868eeb",
407
407
  "agentTarget": "claude-code"
408
408
  },
409
409
  {
410
410
  "path": "skills/claude-code/references/embedded-assistant.md",
411
- "sha256": "16ef1df5ad641f6b36fa9530f920c3588f77f929c4d609fe4aeffd0dc11abc94",
411
+ "sha256": "7b9de2f1033291312b2b4cc58bffa3e1cb0c8eeed6a77505daab5dc492bb00db",
412
412
  "agentTarget": "claude-code"
413
413
  },
414
414
  {
@@ -573,7 +573,7 @@
573
573
  },
574
574
  {
575
575
  "path": "skills/claude-code/examples/acme-tasks/README.md",
576
- "sha256": "e1d654d1a98b721ef7ce4f5d5d3d868611079ed4dbf2126b766018adb95d4194",
576
+ "sha256": "3fbc0821badfea43af4aab131d09f7c953095e0d241de7ea5cfcc3491b70fce5",
577
577
  "agentTarget": "claude-code"
578
578
  },
579
579
  {
@@ -603,7 +603,7 @@
603
603
  },
604
604
  {
605
605
  "path": "skills/claude-code/examples/acme-tasks/src/server.ts",
606
- "sha256": "514cca681ffd5f686364cb2d3b8ab27c9145b1aa1e2bf22d665fa1935ac55ce6",
606
+ "sha256": "0abd695218d0fd73abde31b2ea16742a028721044ef3c565bdc88cdbb10f19aa",
607
607
  "agentTarget": "claude-code"
608
608
  },
609
609
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/agent-kit",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "private": false,
5
5
  "description": "Self-checking, self-updating agent skills for the Noodle Seed CLI. Authored in this repo by @noodle-borg/agent-kit; this is the published, independently-versioned canonical skills artifact the CLI fetches and verifies.",
6
6
  "license": "Apache-2.0",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: noodle-seed
3
3
  description: Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI.
4
- version: 0.28.0
4
+ version: 0.29.0
5
5
  hash: b4fc528d406e2149
6
6
  ---
7
7
 
@@ -30,6 +30,10 @@ on the flows.
30
30
  invents a task.
31
31
  - **Two users** — tools are atomic and model-fillable ("high priority" → `priority: "high"`), and each
32
32
  returns a spoken-ready status so the model can confirm in one turn.
33
+ - **Cross-host confirmation** — `complete_task` keeps `confirm: true`. The server's explicit
34
+ `interactions.confirmationFallback: 'host'` uses Noodle confirmation in capable/embedded hosts and trusts
35
+ ChatGPT's native write approval only when the stateless transport cannot present that form. Backend
36
+ authorization remains independent.
33
37
 
34
38
  ## Wireframe (one screen: the three flows in place)
35
39
 
@@ -43,6 +43,9 @@ export default server(
43
43
  {
44
44
  title: 'Acme Tasks',
45
45
  version: '1.0.0',
46
+ // ChatGPT's stateless MCP lane cannot carry Noodle's standard confirmation form. Keep
47
+ // confirm:true for capable/embedded hosts, but explicitly trust native host approval there.
48
+ interactions: { confirmationFallback: 'host' },
46
49
  branding: {
47
50
  name: 'Acme Tasks',
48
51
  accent: '#7C3AED',
@@ -273,7 +273,7 @@ tool('prepare_time_off', {
273
273
  });
274
274
  ```
275
275
 
276
- Use a stable lowercase/number/underscore id and a flat form of string/number/integer/boolean, string choices or multi-select, with optional `email`, `uri`, `date`, or `date-time` formats. Nested objects and credential-shaped fields fail with `invalid_elicitation_schema`. Every interactive flow must place all `ctx.elicit` calls before its first connector operation or compilation fails with `invalid_elicitation_flow`. Embedded/headless clients receive `input_requested`; bidirectional MCP transports map the primitive to standard form `elicitation/create`. An adapter that cannot carry the request fails before executing the tool. Accept validates and resumes without rerunning completed steps; invalid assistant content returns `arg_invalid` with the same interaction still pending for correction; decline/cancel stop. Elicitation gathers missing input and does not replace confirmation for a subsequent write. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews original tool input, elicited values, and the sole exact connector version/operation/resolved arguments. Accept is bound to that action and only then may execution start. A confirmable flow may contain at most one connector operation or compilation fails with `invalid_confirmation_flow`. MCP uses a final standard form-elicitation confirmation on capable bidirectional transports and fails closed otherwise. At the manifest/runtime boundary and in TypeScript action helpers, omitted or `false` executes directly; action, destructive, and open-world hints alone never gate execution. `annotations.action({ confirm: false })` is equivalent to omission, while `annotations.action({ confirm: true })` explicitly enables confirmation.
276
+ Use a stable lowercase/number/underscore id and a flat form of string/number/integer/boolean, string choices or multi-select, with optional `email`, `uri`, `date`, or `date-time` formats. Nested objects and credential-shaped fields fail with `invalid_elicitation_schema`. Every interactive flow must place all `ctx.elicit` calls before its first connector operation or compilation fails with `invalid_elicitation_flow`. Embedded/headless clients receive `input_requested`; bidirectional MCP transports map the primitive to standard form `elicitation/create`. An adapter that cannot carry the request returns a structured non-executing `interaction_unavailable` result. Accept validates and resumes without rerunning completed steps; invalid content returns `arg_invalid` and leaves the same interaction pending; decline/cancel stop. Elicitation gathers missing input and does not replace confirmation. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews the original input, elicited values, and sole exact connector action. Accept is bound to that action and only then may execution start. A confirmable flow may contain at most one connector operation; additional operations fail with `invalid_confirmation_flow`. MCP uses final standard form confirmation on capable bidirectional transports and fails closed otherwise. Setting `interactions: { confirmationFallback: "host" }` in the server options explicitly trusts native host approval only when confirmation transport is unavailable and no elicited input is needed; it is never inferred from client name and does not replace authorization. Omitted or `false` annotations execute directly; hints alone never gate. `annotations.action({ confirm: true })` explicitly enables confirmation; `annotations.action({ confirm: false })` explicitly preserves direct execution.
277
277
 
278
278
  ## Compute connector example
279
279
 
@@ -176,7 +176,7 @@ The callback records declarative fulfilment at author time; the shared runtime e
176
176
 
177
177
  ## Structured missing input
178
178
 
179
- A tool authored with `ctx.elicit({ id, message, input })` produces `input_requested` when it reaches the missing value. The built-in and headless renderers consume the same advertised endpoints and interaction-event protocol: either renderer presents that event and, after the current turn stream completes, calls `respond(id, { action: "accept", content })`; decline/cancel stop the flow. Accepted content is schema-validated and completed steps are not rerun; invalid content returns `arg_invalid` and leaves the same request pending for correction. A chained request receives a fresh id and `tool_completed` appears only after the final answer. Every interactive flow must collect all elicited input before its first connector operation. Elicitation gathers an input; it does not approve a later write, which remains separately confirmation-gated. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews the original tool input, elicited values, and sole exact connector version/operation/resolved arguments. Accept is bound to that action and only then may execution start. Confirmable flows may contain at most one connector operation. Bidirectional MCP transports map missing input to standard form `elicitation/create`; an adapter that cannot carry that request fails before executing the tool. The same negotiated form capability carries a final affirmative confirmation and fails closed when unavailable. At the manifest/runtime boundary and in TypeScript action helpers, omitted or `false` preserves direct execution; action hints alone never gate. `annotations.action({ confirm: false })`, like omission, runs directly, while `annotations.action({ confirm: true })` explicitly enables confirmation.
179
+ A tool authored with `ctx.elicit({ id, message, input })` produces `input_requested` when it reaches missing input. Built-in and headless renderers present it and call `respond(id, { action: "accept", content })`; decline/cancel stop. Accepted content is schema-validated and completed steps are not rerun; invalid content returns `arg_invalid` and keeps the interaction pending. Elicitation gathers an input and does not approve a later write. Every interactive flow collects elicited input before its first connector operation; every eligible `input_requested` precedes `tool_proposed`. In a `confirm: true` flow, the final proposal reviews original input, elicited values, and the sole exact connector action; a confirmable flow has at most one connector operation. Accept is bound to that action. Bidirectional MCP and the embedded assistant use the same advertised endpoints and interaction-event protocol: missing input maps to standard `elicitation/create`, and an adapter that cannot carry that request fails safely with a structured non-executing result. The same negotiated channel carries the final affirmative confirmation. Setting `interactions: { confirmationFallback: "host" }` in server options explicitly trusts native host approval only when confirmation transport is unavailable and no elicited input is required; embedded/headless confirmation remains Noodle-owned. Omitted or false annotations execute directly; hints never gate.
180
180
 
181
181
  ## Verified session context (identity and claims)
182
182
 
@@ -283,7 +283,7 @@ if (pendingId) {
283
283
 
284
284
  `view_available` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, bounded/redacted public result, and—on current services—the self-contained bridged document. The standard element is an MCP Apps host and mounts that document behind a double iframe. It supports lifecycle, app tool/resource calls, ui/message, ui/update-model-context, links, resize, and inline/fullscreen; sampling, tasks, downloads, and remote DOM are not advertised. It also dispatches `assistant-view-available` for a customer-owned renderer.
285
285
 
286
- `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version, operation, and resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
286
+ `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version/operation/resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
287
287
 
288
288
  ## Toolchain requirements
289
289
 
@@ -127,7 +127,7 @@ prompt('summarize_ticket', {
127
127
 
128
128
  ### Non-trivial tool: ctx connectors, annotations, visibility, async
129
129
 
130
- `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
130
+ `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
131
131
 
132
132
  ```ts
133
133
  import { annotations, connector, server, tool, z } from '@noodleseed/one';
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: noodle-seed
3
3
  description: Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI.
4
- version: 0.28.0
4
+ version: 0.29.0
5
5
  hash: cd25535e1d6dbf4f
6
6
  ---
7
7
 
@@ -30,6 +30,10 @@ on the flows.
30
30
  invents a task.
31
31
  - **Two users** — tools are atomic and model-fillable ("high priority" → `priority: "high"`), and each
32
32
  returns a spoken-ready status so the model can confirm in one turn.
33
+ - **Cross-host confirmation** — `complete_task` keeps `confirm: true`. The server's explicit
34
+ `interactions.confirmationFallback: 'host'` uses Noodle confirmation in capable/embedded hosts and trusts
35
+ ChatGPT's native write approval only when the stateless transport cannot present that form. Backend
36
+ authorization remains independent.
33
37
 
34
38
  ## Wireframe (one screen: the three flows in place)
35
39
 
@@ -43,6 +43,9 @@ export default server(
43
43
  {
44
44
  title: 'Acme Tasks',
45
45
  version: '1.0.0',
46
+ // ChatGPT's stateless MCP lane cannot carry Noodle's standard confirmation form. Keep
47
+ // confirm:true for capable/embedded hosts, but explicitly trust native host approval there.
48
+ interactions: { confirmationFallback: 'host' },
46
49
  branding: {
47
50
  name: 'Acme Tasks',
48
51
  accent: '#7C3AED',
@@ -273,7 +273,7 @@ tool('prepare_time_off', {
273
273
  });
274
274
  ```
275
275
 
276
- Use a stable lowercase/number/underscore id and a flat form of string/number/integer/boolean, string choices or multi-select, with optional `email`, `uri`, `date`, or `date-time` formats. Nested objects and credential-shaped fields fail with `invalid_elicitation_schema`. Every interactive flow must place all `ctx.elicit` calls before its first connector operation or compilation fails with `invalid_elicitation_flow`. Embedded/headless clients receive `input_requested`; bidirectional MCP transports map the primitive to standard form `elicitation/create`. An adapter that cannot carry the request fails before executing the tool. Accept validates and resumes without rerunning completed steps; invalid assistant content returns `arg_invalid` with the same interaction still pending for correction; decline/cancel stop. Elicitation gathers missing input and does not replace confirmation for a subsequent write. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews original tool input, elicited values, and the sole exact connector version/operation/resolved arguments. Accept is bound to that action and only then may execution start. A confirmable flow may contain at most one connector operation or compilation fails with `invalid_confirmation_flow`. MCP uses a final standard form-elicitation confirmation on capable bidirectional transports and fails closed otherwise. At the manifest/runtime boundary and in TypeScript action helpers, omitted or `false` executes directly; action, destructive, and open-world hints alone never gate execution. `annotations.action({ confirm: false })` is equivalent to omission, while `annotations.action({ confirm: true })` explicitly enables confirmation.
276
+ Use a stable lowercase/number/underscore id and a flat form of string/number/integer/boolean, string choices or multi-select, with optional `email`, `uri`, `date`, or `date-time` formats. Nested objects and credential-shaped fields fail with `invalid_elicitation_schema`. Every interactive flow must place all `ctx.elicit` calls before its first connector operation or compilation fails with `invalid_elicitation_flow`. Embedded/headless clients receive `input_requested`; bidirectional MCP transports map the primitive to standard form `elicitation/create`. An adapter that cannot carry the request returns a structured non-executing `interaction_unavailable` result. Accept validates and resumes without rerunning completed steps; invalid content returns `arg_invalid` and leaves the same interaction pending; decline/cancel stop. Elicitation gathers missing input and does not replace confirmation. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews the original input, elicited values, and sole exact connector action. Accept is bound to that action and only then may execution start. A confirmable flow may contain at most one connector operation; additional operations fail with `invalid_confirmation_flow`. MCP uses final standard form confirmation on capable bidirectional transports and fails closed otherwise. Setting `interactions: { confirmationFallback: "host" }` in the server options explicitly trusts native host approval only when confirmation transport is unavailable and no elicited input is needed; it is never inferred from client name and does not replace authorization. Omitted or `false` annotations execute directly; hints alone never gate. `annotations.action({ confirm: true })` explicitly enables confirmation; `annotations.action({ confirm: false })` explicitly preserves direct execution.
277
277
 
278
278
  ## Compute connector example
279
279
 
@@ -176,7 +176,7 @@ The callback records declarative fulfilment at author time; the shared runtime e
176
176
 
177
177
  ## Structured missing input
178
178
 
179
- A tool authored with `ctx.elicit({ id, message, input })` produces `input_requested` when it reaches the missing value. The built-in and headless renderers consume the same advertised endpoints and interaction-event protocol: either renderer presents that event and, after the current turn stream completes, calls `respond(id, { action: "accept", content })`; decline/cancel stop the flow. Accepted content is schema-validated and completed steps are not rerun; invalid content returns `arg_invalid` and leaves the same request pending for correction. A chained request receives a fresh id and `tool_completed` appears only after the final answer. Every interactive flow must collect all elicited input before its first connector operation. Elicitation gathers an input; it does not approve a later write, which remains separately confirmation-gated. In a flow marked `confirm: true`, every eligible `input_requested` precedes `tool_proposed`; the final proposal reviews the original tool input, elicited values, and sole exact connector version/operation/resolved arguments. Accept is bound to that action and only then may execution start. Confirmable flows may contain at most one connector operation. Bidirectional MCP transports map missing input to standard form `elicitation/create`; an adapter that cannot carry that request fails before executing the tool. The same negotiated form capability carries a final affirmative confirmation and fails closed when unavailable. At the manifest/runtime boundary and in TypeScript action helpers, omitted or `false` preserves direct execution; action hints alone never gate. `annotations.action({ confirm: false })`, like omission, runs directly, while `annotations.action({ confirm: true })` explicitly enables confirmation.
179
+ A tool authored with `ctx.elicit({ id, message, input })` produces `input_requested` when it reaches missing input. Built-in and headless renderers present it and call `respond(id, { action: "accept", content })`; decline/cancel stop. Accepted content is schema-validated and completed steps are not rerun; invalid content returns `arg_invalid` and keeps the interaction pending. Elicitation gathers an input and does not approve a later write. Every interactive flow collects elicited input before its first connector operation; every eligible `input_requested` precedes `tool_proposed`. In a `confirm: true` flow, the final proposal reviews original input, elicited values, and the sole exact connector action; a confirmable flow has at most one connector operation. Accept is bound to that action. Bidirectional MCP and the embedded assistant use the same advertised endpoints and interaction-event protocol: missing input maps to standard `elicitation/create`, and an adapter that cannot carry that request fails safely with a structured non-executing result. The same negotiated channel carries the final affirmative confirmation. Setting `interactions: { confirmationFallback: "host" }` in server options explicitly trusts native host approval only when confirmation transport is unavailable and no elicited input is required; embedded/headless confirmation remains Noodle-owned. Omitted or false annotations execute directly; hints never gate.
180
180
 
181
181
  ## Verified session context (identity and claims)
182
182
 
@@ -283,7 +283,7 @@ if (pendingId) {
283
283
 
284
284
  `view_available` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, bounded/redacted public result, and—on current services—the self-contained bridged document. The standard element is an MCP Apps host and mounts that document behind a double iframe. It supports lifecycle, app tool/resource calls, ui/message, ui/update-model-context, links, resize, and inline/fullscreen; sampling, tasks, downloads, and remote DOM are not advertised. It also dispatches `assistant-view-available` for a customer-owned renderer.
285
285
 
286
- `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version, operation, and resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
286
+ `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version/operation/resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
287
287
 
288
288
  ## Toolchain requirements
289
289
 
@@ -127,7 +127,7 @@ prompt('summarize_ticket', {
127
127
 
128
128
  ### Non-trivial tool: ctx connectors, annotations, visibility, async
129
129
 
130
- `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
130
+ `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
131
131
 
132
132
  ```ts
133
133
  import { annotations, connector, server, tool, z } from '@noodleseed/one';