@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 +17 -17
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +1 -1
- package/skills/claude-code/examples/customer-auth/README.md +7 -4
- package/skills/claude-code/examples/customer-auth/src/server.ts +1 -0
- package/skills/claude-code/references/authoring-workflow.md +4 -4
- package/skills/claude-code/references/cli-commands.md +2 -1
- package/skills/claude-code/references/compile-errors.md +2 -1
- package/skills/claude-code/references/embedded-assistant.md +9 -7
- package/skills/claude-code/references/widgets-and-apps.md +1 -1
- package/skills/codex/SKILL.md +1 -1
- package/skills/codex/examples/customer-auth/README.md +7 -4
- package/skills/codex/examples/customer-auth/src/server.ts +1 -0
- package/skills/codex/references/authoring-workflow.md +4 -4
- package/skills/codex/references/cli-commands.md +2 -1
- package/skills/codex/references/compile-errors.md +2 -1
- package/skills/codex/references/embedded-assistant.md +9 -7
- package/skills/codex/references/widgets-and-apps.md +1 -1
package/manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"packageVersion": "0.
|
|
2
|
+
"packageVersion": "0.25.0",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": "skills/codex/SKILL.md",
|
|
6
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
26
|
+
"sha256": "d67bafe1aea7fb38c374a61cbebfa7af11eb5f3bdb8552ddb367918a2d415294",
|
|
27
27
|
"agentTarget": "codex"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "skills/codex/references/authoring-workflow.md",
|
|
31
|
-
"sha256": "
|
|
31
|
+
"sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
|
|
32
32
|
"agentTarget": "codex"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "skills/codex/references/embedded-assistant.md",
|
|
36
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
401
|
+
"sha256": "d67bafe1aea7fb38c374a61cbebfa7af11eb5f3bdb8552ddb367918a2d415294",
|
|
402
402
|
"agentTarget": "claude-code"
|
|
403
403
|
},
|
|
404
404
|
{
|
|
405
405
|
"path": "skills/claude-code/references/authoring-workflow.md",
|
|
406
|
-
"sha256": "
|
|
406
|
+
"sha256": "5eda7043237ca7d05e2fff4521ce6548f5666e320635df0d509cf52c3700b01c",
|
|
407
407
|
"agentTarget": "claude-code"
|
|
408
408
|
},
|
|
409
409
|
{
|
|
410
410
|
"path": "skills/claude-code/references/embedded-assistant.md",
|
|
411
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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.
|
|
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",
|
|
@@ -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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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` |
|
|
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.
|
|
106
|
-
|
|
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.
|
|
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,
|
|
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`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
package/skills/codex/SKILL.md
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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` |
|
|
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.
|
|
106
|
-
|
|
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.
|
|
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,
|
|
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`
|
|
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
|
|
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
|
|
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
|
|
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
|
|