@noodleseed/agent-kit 0.24.0 → 0.25.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,9 +1,9 @@
1
1
  {
2
- "packageVersion": "0.24.0",
2
+ "packageVersion": "0.25.0",
3
3
  "files": [
4
4
  {
5
5
  "path": "skills/codex/SKILL.md",
6
- "sha256": "0554c0c35261c583a8024b6762a2540ad6e6627f73d6d22867eae497db7b88d2",
6
+ "sha256": "16692acb9bc49afa05c81356a46dcf005bcae810089a596d32f59d241abc84f2",
7
7
  "agentTarget": "codex"
8
8
  },
9
9
  {
@@ -13,7 +13,7 @@
13
13
  },
14
14
  {
15
15
  "path": "skills/codex/references/cli-commands.md",
16
- "sha256": "abcd6d76e1c9e22e3104b04ca2eb436a0ee19ee114648689a7ba43e164007b34",
16
+ "sha256": "40985b107f9166ee7f199f97dd2c02c1b4232aa523a245a945fea9d345f8fca0",
17
17
  "agentTarget": "codex"
18
18
  },
19
19
  {
@@ -23,17 +23,17 @@
23
23
  },
24
24
  {
25
25
  "path": "skills/codex/references/compile-errors.md",
26
- "sha256": "1ed667250f8f14625012bd8e931812c5d80bac323fa2f39a79ec83dc119fc385",
26
+ "sha256": "d67bafe1aea7fb38c374a61cbebfa7af11eb5f3bdb8552ddb367918a2d415294",
27
27
  "agentTarget": "codex"
28
28
  },
29
29
  {
30
30
  "path": "skills/codex/references/authoring-workflow.md",
31
- "sha256": "3f4767bfe361090e172c7554f1121fe415e618f3a90304498535d177b0c633be",
31
+ "sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
32
32
  "agentTarget": "codex"
33
33
  },
34
34
  {
35
35
  "path": "skills/codex/references/embedded-assistant.md",
36
- "sha256": "9eebab3471ae21b3b3ed5755f8151b297ed39e1bc08d6bcd7cdc1d75afce2f11",
36
+ "sha256": "3909d5b6e2f556105a332ae8688225104627e6001d3bd05e8dd14d1585d32f0c",
37
37
  "agentTarget": "codex"
38
38
  },
39
39
  {
@@ -48,7 +48,7 @@
48
48
  },
49
49
  {
50
50
  "path": "skills/codex/references/widgets-and-apps.md",
51
- "sha256": "7e77eb1520883ad8bd0492fcefae97dfdb0e5bbe9351a7c554d19ee1f7c087cc",
51
+ "sha256": "3aee540c20e23f73d78b4ab1dc8b7dba9b71cf213c8570431190cf6ef48506e6",
52
52
  "agentTarget": "codex"
53
53
  },
54
54
  {
@@ -253,7 +253,7 @@
253
253
  },
254
254
  {
255
255
  "path": "skills/codex/examples/customer-auth/README.md",
256
- "sha256": "f0955609ac8a880d76e5f18fc4319d6de88e4e0d8623519a12afb111095fc057",
256
+ "sha256": "ce422b235866a21ab805e42fede54489b896db8171fa080d8465c31705c56eb0",
257
257
  "agentTarget": "codex"
258
258
  },
259
259
  {
@@ -268,7 +268,7 @@
268
268
  },
269
269
  {
270
270
  "path": "skills/codex/examples/customer-auth/src/server.ts",
271
- "sha256": "cdd95b74a3e219db2eb9bad9b0c128720d8b8e030d5acd8163e46dd65e79bdf6",
271
+ "sha256": "517e7e1b744e7aa7758c70c0f53e79588b9b92641af18acd487e0a9a1d6e5c4a",
272
272
  "agentTarget": "codex"
273
273
  },
274
274
  {
@@ -378,7 +378,7 @@
378
378
  },
379
379
  {
380
380
  "path": "skills/claude-code/SKILL.md",
381
- "sha256": "bc68fdca977ae01b9b0b02b075fbbe8fabf863d875fd539efd5f241390fc57d9",
381
+ "sha256": "728ddf5381fc4acce82d749565628f73b1164ece57319a6d50e287f3d99d1113",
382
382
  "agentTarget": "claude-code"
383
383
  },
384
384
  {
@@ -388,7 +388,7 @@
388
388
  },
389
389
  {
390
390
  "path": "skills/claude-code/references/cli-commands.md",
391
- "sha256": "abcd6d76e1c9e22e3104b04ca2eb436a0ee19ee114648689a7ba43e164007b34",
391
+ "sha256": "40985b107f9166ee7f199f97dd2c02c1b4232aa523a245a945fea9d345f8fca0",
392
392
  "agentTarget": "claude-code"
393
393
  },
394
394
  {
@@ -398,17 +398,17 @@
398
398
  },
399
399
  {
400
400
  "path": "skills/claude-code/references/compile-errors.md",
401
- "sha256": "1ed667250f8f14625012bd8e931812c5d80bac323fa2f39a79ec83dc119fc385",
401
+ "sha256": "d67bafe1aea7fb38c374a61cbebfa7af11eb5f3bdb8552ddb367918a2d415294",
402
402
  "agentTarget": "claude-code"
403
403
  },
404
404
  {
405
405
  "path": "skills/claude-code/references/authoring-workflow.md",
406
- "sha256": "3f4767bfe361090e172c7554f1121fe415e618f3a90304498535d177b0c633be",
406
+ "sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
407
407
  "agentTarget": "claude-code"
408
408
  },
409
409
  {
410
410
  "path": "skills/claude-code/references/embedded-assistant.md",
411
- "sha256": "9eebab3471ae21b3b3ed5755f8151b297ed39e1bc08d6bcd7cdc1d75afce2f11",
411
+ "sha256": "3909d5b6e2f556105a332ae8688225104627e6001d3bd05e8dd14d1585d32f0c",
412
412
  "agentTarget": "claude-code"
413
413
  },
414
414
  {
@@ -423,7 +423,7 @@
423
423
  },
424
424
  {
425
425
  "path": "skills/claude-code/references/widgets-and-apps.md",
426
- "sha256": "7e77eb1520883ad8bd0492fcefae97dfdb0e5bbe9351a7c554d19ee1f7c087cc",
426
+ "sha256": "3aee540c20e23f73d78b4ab1dc8b7dba9b71cf213c8570431190cf6ef48506e6",
427
427
  "agentTarget": "claude-code"
428
428
  },
429
429
  {
@@ -628,7 +628,7 @@
628
628
  },
629
629
  {
630
630
  "path": "skills/claude-code/examples/customer-auth/README.md",
631
- "sha256": "f0955609ac8a880d76e5f18fc4319d6de88e4e0d8623519a12afb111095fc057",
631
+ "sha256": "ce422b235866a21ab805e42fede54489b896db8171fa080d8465c31705c56eb0",
632
632
  "agentTarget": "claude-code"
633
633
  },
634
634
  {
@@ -643,7 +643,7 @@
643
643
  },
644
644
  {
645
645
  "path": "skills/claude-code/examples/customer-auth/src/server.ts",
646
- "sha256": "cdd95b74a3e219db2eb9bad9b0c128720d8b8e030d5acd8163e46dd65e79bdf6",
646
+ "sha256": "517e7e1b744e7aa7758c70c0f53e79588b9b92641af18acd487e0a9a1d6e5c4a",
647
647
  "agentTarget": "claude-code"
648
648
  },
649
649
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/agent-kit",
3
- "version": "0.24.0",
3
+ "version": "0.25.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.24.0
4
+ version: 0.25.0
5
5
  hash: b4fc528d406e2149
6
6
  ---
7
7
 
@@ -7,8 +7,7 @@ identity provider while still using the generic Noodle Seed authoring API.
7
7
  It also owns the embedded-assistant showcase: the same authenticated MCP surface can be dropped into the
8
8
  SaaS web application as a fully customer-branded assistant with independent light and dark themes. The
9
9
  assistant loads the active deployment's instructions and model-visible tools rather than installing a stale
10
- second skill bundle. Interactive MCP Apps widgets continue to render in supported external hosts; the
11
- initial embedded surface renders text and native tool confirmations.
10
+ second skill bundle. The standard embedded element also hosts linked MCP Apps behind its sandbox bridge.
12
11
 
13
12
  The public developer entrypoint is [`src/server.ts`](src/server.ts). It declares `customerAuth.firebase(...)` with
14
13
  the NoodleSeed.com Firebase project and Firebase Web App public config. It exposes a deliberately small MCP
@@ -87,8 +86,8 @@ API** with its own token issuance, use `delegatedTokenExchange` instead
87
86
  ([ADR 0152](../../docs/decisions/0152-delegated-token-exchange-connector-auth.md)): the platform signs a
88
87
  short-lived, JWKS-verifiable assertion of the signed-in user and exchanges it (RFC 8693) at a token
89
88
  endpoint you implement, which mints your own user-scoped token — so your API enforces its own per-user
90
- authorization on every call. It works for identities from `customerAuth.bridge(...)` and from embedded
91
- assistant sessions, with no per-user OAuth enrollment.
89
+ authorization on every call. It works for verified direct/federated OIDC, built-in provider identities, and
90
+ embedded assistant sessions, with no per-user OAuth enrollment.
92
91
 
93
92
  ```ts
94
93
  auth: {
@@ -115,6 +114,10 @@ noodle auth doctor examples/customer-auth/src/server.ts
115
114
  noodle validate examples/customer-auth/src/server.ts
116
115
  ```
117
116
 
117
+ Against a deployed customer-protected environment, set a short-lived real customer token only in
118
+ `NOODLE_CUSTOMER_TOKEN` and add `--live --org <org> --app <app> --env <env>`. The live doctor performs
119
+ credential exchanges without invoking either business tool.
120
+
118
121
  ## Run locally
119
122
 
120
123
  ```bash
@@ -138,6 +138,7 @@ export default server(
138
138
  }),
139
139
  tool('list_my_organizations', {
140
140
  description: 'List the NoodleSeed.com organizations the signed-in customer belongs to.',
141
+ contextProvider: true,
141
142
  input: z.object({}),
142
143
  output: z.object({
143
144
  organizations: z.array(z.unknown()),
@@ -104,7 +104,7 @@ More: `auth.kind` is `bearer` | `apiKey` (needs `header`) | `clientCredentials`
104
104
 
105
105
  Use delegated connector auth when the downstream API must enforce its own per-user authorization — a shared service credential plus a forwarded user id would bypass it. Three shapes exist; pick by who owns the downstream:
106
106
 
107
- - **`delegatedTokenExchange`** — your own API. The platform signs a short-lived, verifiable assertion of the signed-in user and exchanges it at a token endpoint you implement (RFC 8693). Works with `customerAuth.bridge(...)` identities and embedded-assistant sessions; no per-user OAuth enrollment.
107
+ - **`delegatedTokenExchange`** — your own API. The platform signs a short-lived, verifiable assertion of the signed-in user and exchanges it at a token endpoint you implement (RFC 8693). Works with verified customer OIDC identities, the built-in Firebase/Microsoft adapters, and embedded-assistant sessions; no per-user OAuth enrollment.
108
108
  - **`delegatedOAuth` with `provider: "firebase" | "microsoft"`** — Noodle-managed bridge providers using stored per-user refresh tokens. Requires the matching `customerAuth` bridge; any other provider string is the compile error `unsupported_delegated_provider`.
109
109
  - **`delegatedSessionCookie`** — Firebase-managed session-cookie apps only; not a generic mechanism.
110
110
 
@@ -167,7 +167,7 @@ export async function tokenEndpoint(req: Request): Promise<Response> {
167
167
  }
168
168
  ```
169
169
 
170
- Diagnose with `noodle auth doctor` (reports each delegated token exchange endpoint and whether managed delegated providers pair with the declared `customerAuth`). Common failures: `disallowed_token_origin` (add the tokenUrl origin to `allowedOrigins`), `unsupported_delegated_provider` (custom provider strings never reach a broker; use `delegatedTokenExchange`), and `delegated token exchange requires a verified customer caller` at runtime (the surface calling the tool has no verified customer identity check `customerAuth` and, for embeds, `createAssistantSession({ user })`).
170
+ Diagnose statically with `noodle auth doctor`; set a short-lived real customer token only in `NOODLE_CUSTOMER_TOKEN` and add `--live --org <org> --app <app> --env <env>` to perform one exchange per delegated binding without invoking a business tool. Common failures include structured `credential_unavailable` reasons such as `caller_identity_not_customer`. Direct/federated OIDC verification assigns the customer identity at the trusted verifier boundary; never ask an IdP to mint a Noodle-specific classification claim.
171
171
 
172
172
  ## Design tools for the model
173
173
 
@@ -233,7 +233,7 @@ The model never sees a task id from the user; `find_tasks` returns `{ id, title
233
233
 
234
234
  ## Invocation context
235
235
 
236
- Every executable invocation receives one immutable server-authoritative temporal snapshot. Canonical TypeScript `server()` authoring emits an empty context declaration even when you omit the option, so MCP clients get the reserved read-only `noodle_context` temporal tool with zero setup. Use `server(..., { context })` only to add locale/time-zone defaults and trusted ambient facts that every surface should resolve the same way. Tools, resources, prompts, and the embedded assistant consume the same snapshot; do not create a host-specific date tool.
236
+ Every executable invocation receives one immutable server-authoritative temporal snapshot. Canonical TypeScript authoring emits Core v2 and does not create a hidden context tool. Use `server(..., { context })` for locale/time-zone defaults and trusted ambient facts, and designate one normal zero-input tool with `contextProvider: true` when the model needs portable application context. The embedded host preloads it per turn; Claude, ChatGPT, and other MCP hosts call it normally.
237
237
 
238
238
  ```ts
239
239
  context: {
@@ -251,7 +251,7 @@ context: {
251
251
  },
252
252
  ```
253
253
 
254
- Ambient providers are recorded as fulfilment data at author time, may call read-only connector operations only, and have a declared output schema. Later fulfilments read `${context.temporal.localDate}`, `${context.temporal.timeZone}`, `${context.ambient.defaultTeamId}`, and `${context.ambientStatus}`. If ambient resolution fails, the status is `unavailable`; never invent the missing business facts. TypeScript-authored servers always reserve `noodle_context`; only a raw Core-v1 manifest that omits `server.context` retains that tool name. Ambient/model-visible context is capped at 16 KiB serialized JSON, depth 8, and 128 entries per container; credential-shaped keys are rejected.
254
+ Ambient providers are recorded as fulfilment data at author time, may call read-only connector operations only, and have a declared output schema. Later fulfilments read `${context.temporal.localDate}`, `${context.temporal.timeZone}`, `${context.ambient.defaultTeamId}`, and `${context.ambientStatus}`. If ambient resolution fails, the status is `unavailable`; never invent the missing business facts. Core-v1 `server.context` keeps the reserved `noodle_context` adapter; Core v2 never reserves it. Ambient/model-visible context is capped at 16 KiB serialized JSON, depth 8, and 128 entries per container; credential-shaped keys are rejected.
255
255
 
256
256
  ## Ask for structured missing input
257
257
 
@@ -22,7 +22,7 @@ Every `noodle` command, grouped by area. Local authoring commands (`validate`, `
22
22
  | `noodle setup` | Reconcile project config and local agent files (dry-run unless `--write`). |
23
23
  | `noodle doctor` | Check login, service, project, validation, and config. |
24
24
  | `noodle agents` | Manage AI agent skills and project context (`setup`/`context`/`doctor`). |
25
- | `noodle auth` | Diagnose `customerAuth` OIDC/bridge readiness. |
25
+ | `noodle auth` | Diagnose customer OIDC/provider declarations; `--live` probes delegated credentials without a business-tool call. |
26
26
  | `noodle docs` | Export docs in an LLM-readable format. |
27
27
  | `noodle connect` | Print connection setup for an agent host (Claude Code, Codex, Cursor, etc.). |
28
28
  | `noodle import` | Import an OpenAPI spec into a starter `server.ts`. |
@@ -100,6 +100,7 @@ Every `noodle` command, grouped by area. Local authoring commands (`validate`, `
100
100
  | `noodle help` | Print CLI usage and command help. |
101
101
  | `noodle version` | Print the installed CLI version. |
102
102
  | `noodle commands` | Print the machine-readable command catalog (`--json`) or a compact human list. Agents: `noodle commands --json` for every command, subcommand, flag, and exit code without reading source. |
103
+ | `noodle features` | Print the versioned Claude, ChatGPT, and Embedded compatibility registry (`--json` or `--markdown`). |
103
104
  | `noodle update` | Check for, install, or safely repair the CLI update. Agents: `noodle update --check --json`, then `noodle update --yes --json`; add `--repair` only when the check reports `repairSafe: true`. |
104
105
 
105
106
  ## Deprecated
@@ -13,11 +13,12 @@ Run `noodle validate` (add `--json` for the machine-readable envelope, `--fix-pr
13
13
 
14
14
  | Code | Fix |
15
15
  | :-- | :-- |
16
+ | `invalid_context_provider` | Designate at most one normal Core-v2 tool with `contextProvider: true`, and give it an empty object input schema. |
16
17
  | `yaml_parse_error` | Author in TypeScript; this means the compiled manifest was malformed — re-run from server.ts, do not hand-edit manifest data. |
17
18
  | `invalid_shape` | A field has the wrong type or structure; match the shape the compiler reports under `path` against the SDK builder you used. |
18
19
  | `invalid_name` | Rename the identifier to match the allowed pattern (lowercase, no spaces/reserved characters) cited at `path`. |
19
20
  | `duplicate_name` | Two tools/components share a name; give each a unique name at the cited `path`. |
20
- | `reserved_name` | Rename the tool at `path`; TypeScript `server()` always reserves `noodle_context`, while raw manifests reserve it when `server.context` is present. |
21
+ | `reserved_name` | For Core v1 with `server.context`, rename `noodle_context`; Core v2 does not reserve it and uses an explicit context-provider tool. |
21
22
  | `unsupported_manifest_version` | Update the SDK/CLI so the emitted manifest version is supported; do not pin an old manifest shape. |
22
23
  | `reserved_for_future_version` | The verb at `path` (currently `compute` as a flow step) is reserved for a future core version; express the step with `use` (a connector operation), `map` (a pure mapping), or the shipped `ctx.elicit` input primitive instead. |
23
24
  | `invalid_operation_ref` | Fix the connector operation reference to `alias.operation` for an operation that exists on that connector. |
@@ -102,8 +102,10 @@ Do not put these model values in the embedding SaaS environment. A production de
102
102
  Session exchange authenticates with the backend client credentials, so the embed works under any `--access` mode. Add `--access customers` only when verified end customers should also call the MCP endpoint directly. That mode requires `server.auth`; `noodle deploy` preflights the rule locally and fails with `server_auth_required` before contacting the service. Fix by adding auth to server options:
103
103
 
104
104
  ```ts
105
- auth: customerAuth.bridge({ verifyUrl: "https://app.example.com/api/auth/verify" }),
106
- // or a concrete adapter: customerAuth.firebase({ projectId, apiKey })
105
+ auth: customerAuth.federatedOidc({
106
+ issuers: [{ issuer: "https://id.example.com", audience: "https://api.example.com" }],
107
+ }),
108
+ // or a built-in adapter: customerAuth.firebase({ projectId, apiKey })
107
109
  ```
108
110
 
109
111
  ## Create the backend client
@@ -168,7 +170,7 @@ context: {
168
170
  },
169
171
  ```
170
172
 
171
- The callback records declarative fulfilment at author time; the shared runtime executes only read-only connector operations, validates the declared output, and freezes one snapshot for the whole invocation and any accepted interaction. Tools/resources/prompts read `context.temporal`, `context.ambient`, and `context.ambientStatus`. The embedded assistant receives the same snapshot in trusted platform context. Canonical TypeScript `server()` authoring emits an empty context declaration even when you omit the option, so MCP clients receive the reserved read-only `noodle_context` temporal tool with zero setup; add `server.context` only for custom defaults or ambient facts. Raw Core-v1 manifests activate the adapter only when that field is present. Never declare a TypeScript author tool named `noodle_context`. Keep ambient facts compact: the platform caps serialized JSON at 16 KiB, depth 8, and 128 entries per container, and rejects credential-shaped keys.
173
+ The callback records declarative fulfilment at author time; the shared runtime executes only read-only connector operations, validates the declared output, and freezes one snapshot for the whole invocation and any accepted interaction. Tools/resources/prompts read `context.temporal`, `context.ambient`, and `context.ambientStatus`. The embedded assistant receives the same snapshot in trusted platform context. For model-visible application context in every host, designate one normal zero-input tool with `contextProvider: true`; the embedded host preloads it per turn and external hosts call it normally. Core-v1 `server.context` retains the legacy reserved `noodle_context` adapter, while canonical Core-v2 TypeScript authoring does not create or reserve it. Keep ambient facts compact: the platform caps serialized JSON at 16 KiB, depth 8, and 128 entries per container, and rejects credential-shaped keys.
172
174
 
173
175
  ## Structured missing input
174
176
 
@@ -277,9 +279,9 @@ if (pendingId) {
277
279
  // The same pending id also accepts { action: 'decline' } or { action: 'cancel' }.
278
280
  ```
279
281
 
280
- `view_available` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, and bounded/redacted public result; it does not claim that anything rendered. A headless customer renderer maps that identity to an already-trusted component. Never fetch the `ui://` URI or inject its HTML. The standard element likewise does not render it; it dispatches `assistant-view-available` with the same detail.
282
+ `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.
281
283
 
282
- `clientContext` is recomputed for each turn. `updateContext(...)` changes separate untrusted page context for the next session exchange; call `resetSession()` when it must take effect immediately. `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. It is untrusted per-turn data, not conversation history or authorization input, and both 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.
284
+ `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.
283
285
 
284
286
  ## Toolchain requirements
285
287
 
@@ -304,7 +306,7 @@ if (pendingId) {
304
306
  | Widget renders but no reply arrives and model usage stays zero | Turns are not reaching the service: outdated `@noodleseed/assistant` package, or the session response was rebuilt/filtered by the backend route | Update the package to the latest version; forward the session response unchanged |
305
307
  | `assistant-error` with code `invalid_response` | The turn endpoint returned HTML or non-SSE content (auth redirect, proxy page) | Check the backend session route path and any middleware/rewrites on the embedding app |
306
308
  | Build error `Package path ./react is not exported` | Outdated package version with import-only export conditions | Update `@noodleseed/assistant`; do not add webpack aliases or type shims |
307
- | Deploy fails with `server_auth_required` | `--access customers` without `server.auth` | Add `customerAuth.bridge(...)` or an adapter to server options |
309
+ | Deploy fails with `server_auth_required` | `--access customers` without `server.auth` | Add direct/federated OIDC or a built-in Firebase/Microsoft adapter |
308
310
  | Validate rejects an origin | Non-loopback HTTP origin in `allowedOrigins` | Use the exact HTTPS production origin; HTTP is only for `localhost`/`127.0.0.1` |
309
311
  | Session exchange returns 404 | `serviceUrl` points at the deployment MCP endpoint | Use the control-plane service URL printed by `noodle assistant clients create` |
310
312
  | Session exchange returns 403 `origin is not allowed` | Request origin differs from `allowedOrigins` character-for-character | Align the exact scheme/host/port on both sides and redeploy |
@@ -317,5 +319,5 @@ if (pendingId) {
317
319
  | The model invents a team/holiday after context lookup fails | The ambient provider returned invalid data or its read-only connector failed (`ambientStatus: unavailable`) | Fix the provider/connector; treat unavailable ambient facts as missing, never prompt instructions |
318
320
  | Decline/cancel reports `unsupported_service` | The session came from a legacy service with no `endpoints.interactions` | Upgrade the service; legacy `toolConfirmations` supports accept only |
319
321
  | Behavior does not change after `noodle deploy` | Outdated platform: before the 2026-07 fix, clients were pinned to their creation-time deployment | Update the platform; sessions now follow the tenant's active deployment |
320
- | A delegated connector tool fails with `delegated token exchange requires a verified customer caller` | The calling surface has no verified customer identity (or an old session minted before the platform carried the resource audience) | Verify `customerAuth` is configured and the backend passes the verified `user` to `createAssistantSession`; re-mint the session |
322
+ | A delegated connector returns `credential_unavailable` / `caller_identity_not_customer` | The calling surface has no verified customer identity (or an old session minted before the platform carried the resource audience) | Verify `customerAuth` is configured, the backend passes the verified `user`, and run `noodle auth doctor --live` |
321
323
  | Deploy fails with `unsupported_delegated_provider` | `delegatedOAuth.provider` only supports the managed `firebase`/`microsoft` bridges | Use `auth.kind: "delegatedTokenExchange"` for your own token endpoint (see authoring-workflow.md) |
@@ -18,7 +18,7 @@ Use `tool(name, { description, input, output, fulfil, view })` for a model-visib
18
18
 
19
19
  Generated widgets, official examples, and agent-authored MCP Apps must start with `@noodleseed/one/react` primitives and semantic tokens. Custom React/CSS or third-party components remain valid when the kit lacks the required behavior or the developer explicitly requests them.
20
20
 
21
- `noodle init my-app` defaults to a comprehensive server—tools, resource, prompt, state contract, branding, handoff, widget, and embedded assistant—so begin by adapting that complete surface. Use `--template hello` only when the product explicitly needs the minimal server.
21
+ `noodle init my-app` defaults to the Core-v2 SaaS profile: federated OIDC placeholders, one explicit context-provider tool, MCP App UI, resource, prompt, state contract, branding, handoff, and embedded assistant. Begin by replacing the IdP/audience/domain placeholders. Use `--template widget`, `hello`, or `http-api` only when that narrower profile is intentional.
22
22
 
23
23
  The default composition rule is: build the smallest useful conversational surface. Inline has one purpose, one primary action, and at most two visible actions. Use progressive disclosure or a later conversational turn for secondary detail; request fullscreen only when the user asks or the task genuinely needs it. Never use nested scrolling. At 280px and wider, the widget must remain one-column, readable, touch-safe, and free of horizontal overflow. Remove secondary chrome before shrinking essential content.
24
24
 
@@ -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.24.0
4
+ version: 0.25.0
5
5
  hash: cd25535e1d6dbf4f
6
6
  ---
7
7
 
@@ -7,8 +7,7 @@ identity provider while still using the generic Noodle Seed authoring API.
7
7
  It also owns the embedded-assistant showcase: the same authenticated MCP surface can be dropped into the
8
8
  SaaS web application as a fully customer-branded assistant with independent light and dark themes. The
9
9
  assistant loads the active deployment's instructions and model-visible tools rather than installing a stale
10
- second skill bundle. Interactive MCP Apps widgets continue to render in supported external hosts; the
11
- initial embedded surface renders text and native tool confirmations.
10
+ second skill bundle. The standard embedded element also hosts linked MCP Apps behind its sandbox bridge.
12
11
 
13
12
  The public developer entrypoint is [`src/server.ts`](src/server.ts). It declares `customerAuth.firebase(...)` with
14
13
  the NoodleSeed.com Firebase project and Firebase Web App public config. It exposes a deliberately small MCP
@@ -87,8 +86,8 @@ API** with its own token issuance, use `delegatedTokenExchange` instead
87
86
  ([ADR 0152](../../docs/decisions/0152-delegated-token-exchange-connector-auth.md)): the platform signs a
88
87
  short-lived, JWKS-verifiable assertion of the signed-in user and exchanges it (RFC 8693) at a token
89
88
  endpoint you implement, which mints your own user-scoped token — so your API enforces its own per-user
90
- authorization on every call. It works for identities from `customerAuth.bridge(...)` and from embedded
91
- assistant sessions, with no per-user OAuth enrollment.
89
+ authorization on every call. It works for verified direct/federated OIDC, built-in provider identities, and
90
+ embedded assistant sessions, with no per-user OAuth enrollment.
92
91
 
93
92
  ```ts
94
93
  auth: {
@@ -115,6 +114,10 @@ noodle auth doctor examples/customer-auth/src/server.ts
115
114
  noodle validate examples/customer-auth/src/server.ts
116
115
  ```
117
116
 
117
+ Against a deployed customer-protected environment, set a short-lived real customer token only in
118
+ `NOODLE_CUSTOMER_TOKEN` and add `--live --org <org> --app <app> --env <env>`. The live doctor performs
119
+ credential exchanges without invoking either business tool.
120
+
118
121
  ## Run locally
119
122
 
120
123
  ```bash
@@ -138,6 +138,7 @@ export default server(
138
138
  }),
139
139
  tool('list_my_organizations', {
140
140
  description: 'List the NoodleSeed.com organizations the signed-in customer belongs to.',
141
+ contextProvider: true,
141
142
  input: z.object({}),
142
143
  output: z.object({
143
144
  organizations: z.array(z.unknown()),
@@ -104,7 +104,7 @@ More: `auth.kind` is `bearer` | `apiKey` (needs `header`) | `clientCredentials`
104
104
 
105
105
  Use delegated connector auth when the downstream API must enforce its own per-user authorization — a shared service credential plus a forwarded user id would bypass it. Three shapes exist; pick by who owns the downstream:
106
106
 
107
- - **`delegatedTokenExchange`** — your own API. The platform signs a short-lived, verifiable assertion of the signed-in user and exchanges it at a token endpoint you implement (RFC 8693). Works with `customerAuth.bridge(...)` identities and embedded-assistant sessions; no per-user OAuth enrollment.
107
+ - **`delegatedTokenExchange`** — your own API. The platform signs a short-lived, verifiable assertion of the signed-in user and exchanges it at a token endpoint you implement (RFC 8693). Works with verified customer OIDC identities, the built-in Firebase/Microsoft adapters, and embedded-assistant sessions; no per-user OAuth enrollment.
108
108
  - **`delegatedOAuth` with `provider: "firebase" | "microsoft"`** — Noodle-managed bridge providers using stored per-user refresh tokens. Requires the matching `customerAuth` bridge; any other provider string is the compile error `unsupported_delegated_provider`.
109
109
  - **`delegatedSessionCookie`** — Firebase-managed session-cookie apps only; not a generic mechanism.
110
110
 
@@ -167,7 +167,7 @@ export async function tokenEndpoint(req: Request): Promise<Response> {
167
167
  }
168
168
  ```
169
169
 
170
- Diagnose with `noodle auth doctor` (reports each delegated token exchange endpoint and whether managed delegated providers pair with the declared `customerAuth`). Common failures: `disallowed_token_origin` (add the tokenUrl origin to `allowedOrigins`), `unsupported_delegated_provider` (custom provider strings never reach a broker; use `delegatedTokenExchange`), and `delegated token exchange requires a verified customer caller` at runtime (the surface calling the tool has no verified customer identity check `customerAuth` and, for embeds, `createAssistantSession({ user })`).
170
+ Diagnose statically with `noodle auth doctor`; set a short-lived real customer token only in `NOODLE_CUSTOMER_TOKEN` and add `--live --org <org> --app <app> --env <env>` to perform one exchange per delegated binding without invoking a business tool. Common failures include structured `credential_unavailable` reasons such as `caller_identity_not_customer`. Direct/federated OIDC verification assigns the customer identity at the trusted verifier boundary; never ask an IdP to mint a Noodle-specific classification claim.
171
171
 
172
172
  ## Design tools for the model
173
173
 
@@ -233,7 +233,7 @@ The model never sees a task id from the user; `find_tasks` returns `{ id, title
233
233
 
234
234
  ## Invocation context
235
235
 
236
- Every executable invocation receives one immutable server-authoritative temporal snapshot. Canonical TypeScript `server()` authoring emits an empty context declaration even when you omit the option, so MCP clients get the reserved read-only `noodle_context` temporal tool with zero setup. Use `server(..., { context })` only to add locale/time-zone defaults and trusted ambient facts that every surface should resolve the same way. Tools, resources, prompts, and the embedded assistant consume the same snapshot; do not create a host-specific date tool.
236
+ Every executable invocation receives one immutable server-authoritative temporal snapshot. Canonical TypeScript authoring emits Core v2 and does not create a hidden context tool. Use `server(..., { context })` for locale/time-zone defaults and trusted ambient facts, and designate one normal zero-input tool with `contextProvider: true` when the model needs portable application context. The embedded host preloads it per turn; Claude, ChatGPT, and other MCP hosts call it normally.
237
237
 
238
238
  ```ts
239
239
  context: {
@@ -251,7 +251,7 @@ context: {
251
251
  },
252
252
  ```
253
253
 
254
- Ambient providers are recorded as fulfilment data at author time, may call read-only connector operations only, and have a declared output schema. Later fulfilments read `${context.temporal.localDate}`, `${context.temporal.timeZone}`, `${context.ambient.defaultTeamId}`, and `${context.ambientStatus}`. If ambient resolution fails, the status is `unavailable`; never invent the missing business facts. TypeScript-authored servers always reserve `noodle_context`; only a raw Core-v1 manifest that omits `server.context` retains that tool name. Ambient/model-visible context is capped at 16 KiB serialized JSON, depth 8, and 128 entries per container; credential-shaped keys are rejected.
254
+ Ambient providers are recorded as fulfilment data at author time, may call read-only connector operations only, and have a declared output schema. Later fulfilments read `${context.temporal.localDate}`, `${context.temporal.timeZone}`, `${context.ambient.defaultTeamId}`, and `${context.ambientStatus}`. If ambient resolution fails, the status is `unavailable`; never invent the missing business facts. Core-v1 `server.context` keeps the reserved `noodle_context` adapter; Core v2 never reserves it. Ambient/model-visible context is capped at 16 KiB serialized JSON, depth 8, and 128 entries per container; credential-shaped keys are rejected.
255
255
 
256
256
  ## Ask for structured missing input
257
257
 
@@ -22,7 +22,7 @@ Every `noodle` command, grouped by area. Local authoring commands (`validate`, `
22
22
  | `noodle setup` | Reconcile project config and local agent files (dry-run unless `--write`). |
23
23
  | `noodle doctor` | Check login, service, project, validation, and config. |
24
24
  | `noodle agents` | Manage AI agent skills and project context (`setup`/`context`/`doctor`). |
25
- | `noodle auth` | Diagnose `customerAuth` OIDC/bridge readiness. |
25
+ | `noodle auth` | Diagnose customer OIDC/provider declarations; `--live` probes delegated credentials without a business-tool call. |
26
26
  | `noodle docs` | Export docs in an LLM-readable format. |
27
27
  | `noodle connect` | Print connection setup for an agent host (Claude Code, Codex, Cursor, etc.). |
28
28
  | `noodle import` | Import an OpenAPI spec into a starter `server.ts`. |
@@ -100,6 +100,7 @@ Every `noodle` command, grouped by area. Local authoring commands (`validate`, `
100
100
  | `noodle help` | Print CLI usage and command help. |
101
101
  | `noodle version` | Print the installed CLI version. |
102
102
  | `noodle commands` | Print the machine-readable command catalog (`--json`) or a compact human list. Agents: `noodle commands --json` for every command, subcommand, flag, and exit code without reading source. |
103
+ | `noodle features` | Print the versioned Claude, ChatGPT, and Embedded compatibility registry (`--json` or `--markdown`). |
103
104
  | `noodle update` | Check for, install, or safely repair the CLI update. Agents: `noodle update --check --json`, then `noodle update --yes --json`; add `--repair` only when the check reports `repairSafe: true`. |
104
105
 
105
106
  ## Deprecated
@@ -13,11 +13,12 @@ Run `noodle validate` (add `--json` for the machine-readable envelope, `--fix-pr
13
13
 
14
14
  | Code | Fix |
15
15
  | :-- | :-- |
16
+ | `invalid_context_provider` | Designate at most one normal Core-v2 tool with `contextProvider: true`, and give it an empty object input schema. |
16
17
  | `yaml_parse_error` | Author in TypeScript; this means the compiled manifest was malformed — re-run from server.ts, do not hand-edit manifest data. |
17
18
  | `invalid_shape` | A field has the wrong type or structure; match the shape the compiler reports under `path` against the SDK builder you used. |
18
19
  | `invalid_name` | Rename the identifier to match the allowed pattern (lowercase, no spaces/reserved characters) cited at `path`. |
19
20
  | `duplicate_name` | Two tools/components share a name; give each a unique name at the cited `path`. |
20
- | `reserved_name` | Rename the tool at `path`; TypeScript `server()` always reserves `noodle_context`, while raw manifests reserve it when `server.context` is present. |
21
+ | `reserved_name` | For Core v1 with `server.context`, rename `noodle_context`; Core v2 does not reserve it and uses an explicit context-provider tool. |
21
22
  | `unsupported_manifest_version` | Update the SDK/CLI so the emitted manifest version is supported; do not pin an old manifest shape. |
22
23
  | `reserved_for_future_version` | The verb at `path` (currently `compute` as a flow step) is reserved for a future core version; express the step with `use` (a connector operation), `map` (a pure mapping), or the shipped `ctx.elicit` input primitive instead. |
23
24
  | `invalid_operation_ref` | Fix the connector operation reference to `alias.operation` for an operation that exists on that connector. |
@@ -102,8 +102,10 @@ Do not put these model values in the embedding SaaS environment. A production de
102
102
  Session exchange authenticates with the backend client credentials, so the embed works under any `--access` mode. Add `--access customers` only when verified end customers should also call the MCP endpoint directly. That mode requires `server.auth`; `noodle deploy` preflights the rule locally and fails with `server_auth_required` before contacting the service. Fix by adding auth to server options:
103
103
 
104
104
  ```ts
105
- auth: customerAuth.bridge({ verifyUrl: "https://app.example.com/api/auth/verify" }),
106
- // or a concrete adapter: customerAuth.firebase({ projectId, apiKey })
105
+ auth: customerAuth.federatedOidc({
106
+ issuers: [{ issuer: "https://id.example.com", audience: "https://api.example.com" }],
107
+ }),
108
+ // or a built-in adapter: customerAuth.firebase({ projectId, apiKey })
107
109
  ```
108
110
 
109
111
  ## Create the backend client
@@ -168,7 +170,7 @@ context: {
168
170
  },
169
171
  ```
170
172
 
171
- The callback records declarative fulfilment at author time; the shared runtime executes only read-only connector operations, validates the declared output, and freezes one snapshot for the whole invocation and any accepted interaction. Tools/resources/prompts read `context.temporal`, `context.ambient`, and `context.ambientStatus`. The embedded assistant receives the same snapshot in trusted platform context. Canonical TypeScript `server()` authoring emits an empty context declaration even when you omit the option, so MCP clients receive the reserved read-only `noodle_context` temporal tool with zero setup; add `server.context` only for custom defaults or ambient facts. Raw Core-v1 manifests activate the adapter only when that field is present. Never declare a TypeScript author tool named `noodle_context`. Keep ambient facts compact: the platform caps serialized JSON at 16 KiB, depth 8, and 128 entries per container, and rejects credential-shaped keys.
173
+ The callback records declarative fulfilment at author time; the shared runtime executes only read-only connector operations, validates the declared output, and freezes one snapshot for the whole invocation and any accepted interaction. Tools/resources/prompts read `context.temporal`, `context.ambient`, and `context.ambientStatus`. The embedded assistant receives the same snapshot in trusted platform context. For model-visible application context in every host, designate one normal zero-input tool with `contextProvider: true`; the embedded host preloads it per turn and external hosts call it normally. Core-v1 `server.context` retains the legacy reserved `noodle_context` adapter, while canonical Core-v2 TypeScript authoring does not create or reserve it. Keep ambient facts compact: the platform caps serialized JSON at 16 KiB, depth 8, and 128 entries per container, and rejects credential-shaped keys.
172
174
 
173
175
  ## Structured missing input
174
176
 
@@ -277,9 +279,9 @@ if (pendingId) {
277
279
  // The same pending id also accepts { action: 'decline' } or { action: 'cancel' }.
278
280
  ```
279
281
 
280
- `view_available` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, and bounded/redacted public result; it does not claim that anything rendered. A headless customer renderer maps that identity to an already-trusted component. Never fetch the `ui://` URI or inject its HTML. The standard element likewise does not render it; it dispatches `assistant-view-available` with the same detail.
282
+ `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.
281
283
 
282
- `clientContext` is recomputed for each turn. `updateContext(...)` changes separate untrusted page context for the next session exchange; call `resetSession()` when it must take effect immediately. `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. It is untrusted per-turn data, not conversation history or authorization input, and both 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.
284
+ `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.
283
285
 
284
286
  ## Toolchain requirements
285
287
 
@@ -304,7 +306,7 @@ if (pendingId) {
304
306
  | Widget renders but no reply arrives and model usage stays zero | Turns are not reaching the service: outdated `@noodleseed/assistant` package, or the session response was rebuilt/filtered by the backend route | Update the package to the latest version; forward the session response unchanged |
305
307
  | `assistant-error` with code `invalid_response` | The turn endpoint returned HTML or non-SSE content (auth redirect, proxy page) | Check the backend session route path and any middleware/rewrites on the embedding app |
306
308
  | Build error `Package path ./react is not exported` | Outdated package version with import-only export conditions | Update `@noodleseed/assistant`; do not add webpack aliases or type shims |
307
- | Deploy fails with `server_auth_required` | `--access customers` without `server.auth` | Add `customerAuth.bridge(...)` or an adapter to server options |
309
+ | Deploy fails with `server_auth_required` | `--access customers` without `server.auth` | Add direct/federated OIDC or a built-in Firebase/Microsoft adapter |
308
310
  | Validate rejects an origin | Non-loopback HTTP origin in `allowedOrigins` | Use the exact HTTPS production origin; HTTP is only for `localhost`/`127.0.0.1` |
309
311
  | Session exchange returns 404 | `serviceUrl` points at the deployment MCP endpoint | Use the control-plane service URL printed by `noodle assistant clients create` |
310
312
  | Session exchange returns 403 `origin is not allowed` | Request origin differs from `allowedOrigins` character-for-character | Align the exact scheme/host/port on both sides and redeploy |
@@ -317,5 +319,5 @@ if (pendingId) {
317
319
  | The model invents a team/holiday after context lookup fails | The ambient provider returned invalid data or its read-only connector failed (`ambientStatus: unavailable`) | Fix the provider/connector; treat unavailable ambient facts as missing, never prompt instructions |
318
320
  | Decline/cancel reports `unsupported_service` | The session came from a legacy service with no `endpoints.interactions` | Upgrade the service; legacy `toolConfirmations` supports accept only |
319
321
  | Behavior does not change after `noodle deploy` | Outdated platform: before the 2026-07 fix, clients were pinned to their creation-time deployment | Update the platform; sessions now follow the tenant's active deployment |
320
- | A delegated connector tool fails with `delegated token exchange requires a verified customer caller` | The calling surface has no verified customer identity (or an old session minted before the platform carried the resource audience) | Verify `customerAuth` is configured and the backend passes the verified `user` to `createAssistantSession`; re-mint the session |
322
+ | A delegated connector returns `credential_unavailable` / `caller_identity_not_customer` | The calling surface has no verified customer identity (or an old session minted before the platform carried the resource audience) | Verify `customerAuth` is configured, the backend passes the verified `user`, and run `noodle auth doctor --live` |
321
323
  | Deploy fails with `unsupported_delegated_provider` | `delegatedOAuth.provider` only supports the managed `firebase`/`microsoft` bridges | Use `auth.kind: "delegatedTokenExchange"` for your own token endpoint (see authoring-workflow.md) |
@@ -18,7 +18,7 @@ Use `tool(name, { description, input, output, fulfil, view })` for a model-visib
18
18
 
19
19
  Generated widgets, official examples, and agent-authored MCP Apps must start with `@noodleseed/one/react` primitives and semantic tokens. Custom React/CSS or third-party components remain valid when the kit lacks the required behavior or the developer explicitly requests them.
20
20
 
21
- `noodle init my-app` defaults to a comprehensive server—tools, resource, prompt, state contract, branding, handoff, widget, and embedded assistant—so begin by adapting that complete surface. Use `--template hello` only when the product explicitly needs the minimal server.
21
+ `noodle init my-app` defaults to the Core-v2 SaaS profile: federated OIDC placeholders, one explicit context-provider tool, MCP App UI, resource, prompt, state contract, branding, handoff, and embedded assistant. Begin by replacing the IdP/audience/domain placeholders. Use `--template widget`, `hello`, or `http-api` only when that narrower profile is intentional.
22
22
 
23
23
  The default composition rule is: build the smallest useful conversational surface. Inline has one purpose, one primary action, and at most two visible actions. Use progressive disclosure or a later conversational turn for secondary detail; request fullscreen only when the user asks or the task genuinely needs it. Never use nested scrolling. At 280px and wider, the widget must remain one-column, readable, touch-safe, and free of horizontal overflow. Remove secondary chrome before shrinking essential content.
24
24