@noodleseed/agent-kit 0.91.0 → 0.92.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.
Files changed (100) hide show
  1. package/manifest.json +705 -273
  2. package/package.json +1 -1
  3. package/skills/claude-code/SKILL.md +1 -1
  4. package/skills/claude-code/authoring-mcp-servers/SKILL.md +4 -4
  5. package/skills/claude-code/authoring-mcp-servers/references/authoring-workflow.md +451 -0
  6. package/skills/claude-code/authoring-mcp-servers/references/build-an-mcp-server.md +56 -0
  7. package/skills/claude-code/authoring-mcp-servers/references/sdk-surface.md +258 -0
  8. package/skills/claude-code/building-mcp-apps/SKILL.md +4 -4
  9. package/skills/claude-code/building-mcp-apps/references/build-an-mcp-app.md +53 -0
  10. package/skills/claude-code/building-mcp-apps/references/experience-design.md +155 -0
  11. package/skills/claude-code/building-mcp-apps/references/widgets-and-apps.md +277 -0
  12. package/skills/claude-code/connecting-apis-to-mcp/SKILL.md +3 -3
  13. package/skills/claude-code/connecting-apis-to-mcp/references/authoring-workflow.md +451 -0
  14. package/skills/claude-code/connecting-apis-to-mcp/references/connect-an-api.md +245 -0
  15. package/skills/claude-code/creating-product-agent-guides/SKILL.md +2 -2
  16. package/skills/claude-code/creating-product-agent-guides/references/product-agent-guides.md +55 -0
  17. package/skills/claude-code/debugging-mcp-delivery/SKILL.md +4 -4
  18. package/skills/claude-code/debugging-mcp-delivery/references/inspect-hosted.md +26 -0
  19. package/skills/claude-code/debugging-mcp-delivery/references/troubleshooting.md +39 -0
  20. package/skills/claude-code/debugging-mcp-delivery/references/verify-and-recover.md +67 -0
  21. package/skills/claude-code/deploying-mcp-services/SKILL.md +3 -3
  22. package/skills/claude-code/deploying-mcp-services/references/cli-commands.md +106 -0
  23. package/skills/claude-code/deploying-mcp-services/references/deploy-and-ops.md +25 -0
  24. package/skills/claude-code/designing-mcp-products/SKILL.md +3 -3
  25. package/skills/claude-code/designing-mcp-products/references/authoring-workflow.md +451 -0
  26. package/skills/claude-code/designing-mcp-products/references/experience-design.md +155 -0
  27. package/skills/claude-code/embedding-mcp-assistants/SKILL.md +11 -10
  28. package/skills/claude-code/embedding-mcp-assistants/references/authoring-workflow.md +451 -0
  29. package/skills/claude-code/embedding-mcp-assistants/references/embedded-assistant.md +876 -0
  30. package/skills/claude-code/examples/customer-auth/README.md +200 -52
  31. package/skills/claude-code/examples/customer-auth/src/server.ts +3 -0
  32. package/skills/claude-code/examples/customer-auth/test/server.test.ts +6 -0
  33. package/skills/claude-code/examples/customer-auth/vitest.config.ts +6 -0
  34. package/skills/claude-code/examples/food-ordering/README.md +1 -1
  35. package/skills/claude-code/examples/food-ordering/src/server.ts +1 -0
  36. package/skills/claude-code/executing-noodle-plans/SKILL.md +1 -1
  37. package/skills/claude-code/publishing-mcp-integrations/SKILL.md +3 -3
  38. package/skills/claude-code/publishing-mcp-integrations/references/app-directory-compliance.md +59 -0
  39. package/skills/claude-code/publishing-mcp-integrations/references/publishing.md +63 -0
  40. package/skills/claude-code/references/authoring-workflow.md +8 -0
  41. package/skills/claude-code/references/embedded-assistant.md +258 -66
  42. package/skills/claude-code/references/sdk-surface.md +1 -1
  43. package/skills/claude-code/reporting-noodle-feedback/SKILL.md +2 -2
  44. package/skills/claude-code/reporting-noodle-feedback/references/feedback.md +80 -0
  45. package/skills/claude-code/verifying-mcp-delivery/SKILL.md +3 -3
  46. package/skills/claude-code/verifying-mcp-delivery/references/test-in-hosts.md +39 -0
  47. package/skills/claude-code/verifying-mcp-delivery/references/verify-and-recover.md +67 -0
  48. package/skills/claude-code/wrapping-existing-applications/SKILL.md +4 -4
  49. package/skills/claude-code/wrapping-existing-applications/references/authoring-workflow.md +451 -0
  50. package/skills/claude-code/wrapping-existing-applications/references/tool-design.md +107 -0
  51. package/skills/claude-code/wrapping-existing-applications/references/wrap-existing-app.md +65 -0
  52. package/skills/codex/SKILL.md +1 -1
  53. package/skills/codex/authoring-mcp-servers/SKILL.md +4 -4
  54. package/skills/codex/authoring-mcp-servers/references/authoring-workflow.md +451 -0
  55. package/skills/codex/authoring-mcp-servers/references/build-an-mcp-server.md +56 -0
  56. package/skills/codex/authoring-mcp-servers/references/sdk-surface.md +258 -0
  57. package/skills/codex/building-mcp-apps/SKILL.md +4 -4
  58. package/skills/codex/building-mcp-apps/references/build-an-mcp-app.md +53 -0
  59. package/skills/codex/building-mcp-apps/references/experience-design.md +155 -0
  60. package/skills/codex/building-mcp-apps/references/widgets-and-apps.md +277 -0
  61. package/skills/codex/connecting-apis-to-mcp/SKILL.md +3 -3
  62. package/skills/codex/connecting-apis-to-mcp/references/authoring-workflow.md +451 -0
  63. package/skills/codex/connecting-apis-to-mcp/references/connect-an-api.md +245 -0
  64. package/skills/codex/creating-product-agent-guides/SKILL.md +2 -2
  65. package/skills/codex/creating-product-agent-guides/references/product-agent-guides.md +55 -0
  66. package/skills/codex/debugging-mcp-delivery/SKILL.md +4 -4
  67. package/skills/codex/debugging-mcp-delivery/references/inspect-hosted.md +26 -0
  68. package/skills/codex/debugging-mcp-delivery/references/troubleshooting.md +39 -0
  69. package/skills/codex/debugging-mcp-delivery/references/verify-and-recover.md +67 -0
  70. package/skills/codex/deploying-mcp-services/SKILL.md +3 -3
  71. package/skills/codex/deploying-mcp-services/references/cli-commands.md +106 -0
  72. package/skills/codex/deploying-mcp-services/references/deploy-and-ops.md +25 -0
  73. package/skills/codex/designing-mcp-products/SKILL.md +3 -3
  74. package/skills/codex/designing-mcp-products/references/authoring-workflow.md +451 -0
  75. package/skills/codex/designing-mcp-products/references/experience-design.md +155 -0
  76. package/skills/codex/embedding-mcp-assistants/SKILL.md +11 -10
  77. package/skills/codex/embedding-mcp-assistants/references/authoring-workflow.md +451 -0
  78. package/skills/codex/embedding-mcp-assistants/references/embedded-assistant.md +876 -0
  79. package/skills/codex/examples/customer-auth/README.md +200 -52
  80. package/skills/codex/examples/customer-auth/src/server.ts +3 -0
  81. package/skills/codex/examples/customer-auth/test/server.test.ts +6 -0
  82. package/skills/codex/examples/customer-auth/vitest.config.ts +6 -0
  83. package/skills/codex/examples/food-ordering/README.md +1 -1
  84. package/skills/codex/examples/food-ordering/src/server.ts +1 -0
  85. package/skills/codex/executing-noodle-plans/SKILL.md +1 -1
  86. package/skills/codex/publishing-mcp-integrations/SKILL.md +3 -3
  87. package/skills/codex/publishing-mcp-integrations/references/app-directory-compliance.md +59 -0
  88. package/skills/codex/publishing-mcp-integrations/references/publishing.md +63 -0
  89. package/skills/codex/references/authoring-workflow.md +8 -0
  90. package/skills/codex/references/embedded-assistant.md +258 -66
  91. package/skills/codex/references/sdk-surface.md +1 -1
  92. package/skills/codex/reporting-noodle-feedback/SKILL.md +2 -2
  93. package/skills/codex/reporting-noodle-feedback/references/feedback.md +80 -0
  94. package/skills/codex/verifying-mcp-delivery/SKILL.md +3 -3
  95. package/skills/codex/verifying-mcp-delivery/references/test-in-hosts.md +39 -0
  96. package/skills/codex/verifying-mcp-delivery/references/verify-and-recover.md +67 -0
  97. package/skills/codex/wrapping-existing-applications/SKILL.md +4 -4
  98. package/skills/codex/wrapping-existing-applications/references/authoring-workflow.md +451 -0
  99. package/skills/codex/wrapping-existing-applications/references/tool-design.md +107 -0
  100. package/skills/codex/wrapping-existing-applications/references/wrap-existing-app.md +65 -0
@@ -367,6 +367,13 @@ and passes `routing: { endpoints: { customer_api: cluster.apiBaseUrl } }` to
367
367
  `createAssistantSession`. Noodle validates and privately stores that route; it is not returned to the
368
368
  browser. Do not copy the route into page context, session claims, tool input, or model instructions.
369
369
 
370
+ The authenticated assistant surface also declares `accountTier` as a model-visible session claim. Pass it
371
+ from the same backend-owned account record as `claims: { accountTier: account.tier }`; undeclared claims are
372
+ dropped. This is personalization context, not authorization: the verified roles/scopes beside each tool and
373
+ the server-owned customer route remain the enforcement boundaries. The public
374
+ [runtime guide](https://docs.noodleseed.dev/docs/guides/product-agent-guides#use-the-guide-at-runtime)
375
+ explains how verified session claims constrain the guide content available to the model.
376
+
370
377
  ```bash
371
378
  noodle variables set ASSISTANT_ORIGIN https://app.example.com --scope env
372
379
  noodle variables set ASSISTANT_MODEL_BASE_URL https://model.example.com/v1 --scope env
@@ -391,7 +398,7 @@ set the bounded surface to `glass` only when translucency is intentional.
391
398
  These TypeScript values remain the reusable developer defaults. After deployment, an environment operator
392
399
  can adjust theme, logo, launcher style, position, and the bounded color palette from the Console's
393
400
  **Assistant** tab or `noodle assistant appearance` without changing the customer's embed code. See the
394
- [embedded assistant guide](https://docs.noodleseed.dev/guides/embedded-assistant) for precedence and reset
401
+ [embedded assistant guide](https://docs.noodleseed.dev/docs/guides/embedded-assistant) for precedence and reset
395
402
  behavior.
396
403
 
397
404
  Create the backend credential after deployment. The CLI writes it to a mode-0600 file and never prints the
@@ -425,8 +432,12 @@ import { NoodleAssistant } from '@noodleseed/assistant/react';
425
432
  `resolvedTheme` is the application's current `'light' | 'dark'` value. Use `theme="auto"` only when the
426
433
  browser operating-system preference is intentionally authoritative.
427
434
 
428
- For an entirely application-owned React renderer, use the renderer-free hook. It creates no custom element
429
- and returns the AI SDK transcript plus the canonical client commands:
435
+ ### Minimal fail-closed custom renderer skeleton
436
+
437
+ Use the renderer-free hook only when the product has a concrete reason to own the conversation UI. This
438
+ minimal skeleton keeps the canonical client and App host, but intentionally refuses confirmation and input
439
+ acceptance until the application implements their complete schema-aware presentation. Start with the managed
440
+ renderer unless the application accepts every obligation below.
430
441
 
431
442
  ```tsx
432
443
  'use client';
@@ -438,12 +449,20 @@ import { useNoodleAssistant } from '@noodleseed/assistant/react/client';
438
449
  export function CustomerAssistant({
439
450
  principalKey,
440
451
  resolvedTheme,
452
+ onSignInRequested,
441
453
  }: {
442
454
  principalKey: string;
443
455
  resolvedTheme: 'light' | 'dark';
456
+ onSignInRequested: (request: {
457
+ signInTicket: string;
458
+ expiresAt: string;
459
+ }) => Promise<'started' | 'cancelled'>;
444
460
  }) {
445
461
  const [draft, setDraft] = useState('');
446
- const { client, messages, status, error } = useNoodleAssistant({
462
+ const [sessionNotice, setSessionNotice] = useState('');
463
+ const [turnNotice, setTurnNotice] = useState('');
464
+ const [pendingSignInTicket, setPendingSignInTicket] = useState<string>();
465
+ const { client, messages, suggestions, status, error } = useNoodleAssistant({
447
466
  sessionEndpoint: '/api/noodle-assistant/session',
448
467
  principalKey,
449
468
  });
@@ -453,6 +472,16 @@ export function CustomerAssistant({
453
472
  // The hook exposes this same structured failure through `error`.
454
473
  });
455
474
  };
475
+ useEffect(
476
+ () =>
477
+ client.subscribe((event) => {
478
+ if (event.event === 'session_expired') setSessionNotice('Session expired.');
479
+ if (event.event === 'session_started' || event.event === 'session_reset') {
480
+ setSessionNotice('');
481
+ }
482
+ }),
483
+ [client],
484
+ );
456
485
 
457
486
  return (
458
487
  <section aria-label="Assistant" aria-busy={busy}>
@@ -466,20 +495,18 @@ export function CustomerAssistant({
466
495
  <section key={review.id} aria-label="Review proposed action">
467
496
  <h3>{review.title ?? 'Review proposed action'}</h3>
468
497
  {review.description ? <p>{review.description}</p> : null}
469
- <pre aria-label="Proposed action arguments">
470
- {JSON.stringify(review.arguments ?? {}, null, 2)}
471
- </pre>
498
+ <p>This custom renderer has not implemented a complete schema-aware review.</p>
472
499
  <button
473
500
  disabled={busy || review.status !== 'pending'}
474
- onClick={() => settle(client.respond(review.id, { action: 'accept' }))}
501
+ onClick={() => settle(client.respond(review.id, { action: 'decline' }))}
475
502
  >
476
- Confirm
503
+ Don't proceed
477
504
  </button>
478
505
  <button
479
506
  disabled={busy || review.status !== 'pending'}
480
- onClick={() => settle(client.respond(review.id, { action: 'decline' }))}
507
+ onClick={() => settle(client.respond(review.id, { action: 'cancel' }))}
481
508
  >
482
- Don't proceed
509
+ Cancel
483
510
  </button>
484
511
  </section>
485
512
  );
@@ -489,21 +516,28 @@ export function CustomerAssistant({
489
516
  return (
490
517
  <section key={request.id} aria-label="Assistant needs input">
491
518
  <p>{request.message}</p>
492
- <p>This renderer has not implemented the requested form.</p>
519
+ {/* request.requestedSchema is the sole input-form contract. */}
520
+ <p>This custom renderer has not implemented the requested schema form.</p>
493
521
  <button
494
522
  disabled={busy || request.status !== 'pending'}
495
523
  onClick={() => settle(client.respond(request.id, { action: 'decline' }))}
496
524
  >
497
- Cancel request
525
+ Don't proceed
526
+ </button>
527
+ <button
528
+ disabled={busy || request.status !== 'pending'}
529
+ onClick={() => settle(client.respond(request.id, { action: 'cancel' }))}
530
+ >
531
+ Cancel
498
532
  </button>
499
533
  </section>
500
534
  );
501
535
  }
502
536
  if (part.type === 'data-tool-result') {
503
537
  return (
504
- <pre key={part.data.id} aria-label={`${part.data.tool} result`}>
505
- {JSON.stringify(part.data.result, null, 2)}
506
- </pre>
538
+ <p key={part.data.id} role="status">
539
+ A result is available, but this renderer has no trusted presentation for it.
540
+ </p>
507
541
  );
508
542
  }
509
543
  if (part.type === 'data-view') {
@@ -516,17 +550,67 @@ export function CustomerAssistant({
516
550
  />
517
551
  );
518
552
  }
553
+ if (part.type === 'data-sign-in') {
554
+ const request = part.data;
555
+ return (
556
+ <section key={request.id} aria-label="Sign in required">
557
+ <p>Continue with your account to use this capability.</p>
558
+ <button
559
+ disabled={busy || pendingSignInTicket !== undefined}
560
+ onClick={() => {
561
+ setPendingSignInTicket(request.signInTicket);
562
+ void Promise.resolve()
563
+ .then(() =>
564
+ onSignInRequested({
565
+ signInTicket: request.signInTicket,
566
+ expiresAt: request.expiresAt,
567
+ }),
568
+ )
569
+ .then(
570
+ (result) => {
571
+ if (result === 'cancelled') setPendingSignInTicket(undefined);
572
+ },
573
+ () => setPendingSignInTicket(undefined),
574
+ );
575
+ }}
576
+ >
577
+ Sign in
578
+ </button>
579
+ </section>
580
+ );
581
+ }
519
582
  return <p key={index}>Unsupported assistant content.</p>;
520
583
  })}
521
584
  </article>
522
585
  ))}
523
- {error ? <p role="alert">{error.message}</p> : null}
586
+ <p role="status" aria-live="polite">
587
+ {sessionNotice || turnNotice || (busy ? 'Assistant is working' : '')}
588
+ </p>
589
+ {suggestions?.prompts.length ? (
590
+ <nav aria-label="Suggested messages">
591
+ {suggestions.prompts.map((prompt) => (
592
+ <button
593
+ key={prompt}
594
+ type="button"
595
+ disabled={busy}
596
+ onClick={() => {
597
+ setTurnNotice('');
598
+ settle(client.sendMessage(prompt));
599
+ }}
600
+ >
601
+ {prompt}
602
+ </button>
603
+ ))}
604
+ </nav>
605
+ ) : null}
606
+ {error ? <p role="alert">The assistant could not complete that request.</p> : null}
524
607
  <form
525
608
  onSubmit={(event) => {
526
609
  event.preventDefault();
527
610
  const message = draft.trim();
528
611
  if (!message) return;
529
612
  setDraft('');
613
+ setTurnNotice('');
530
614
  settle(client.sendMessage(message));
531
615
  }}
532
616
  >
@@ -536,7 +620,13 @@ export function CustomerAssistant({
536
620
  onChange={(event) => setDraft(event.currentTarget.value)}
537
621
  />
538
622
  {busy ? (
539
- <button type="button" onClick={() => client.abort()}>
623
+ <button
624
+ type="button"
625
+ onClick={() => {
626
+ client.abort();
627
+ setTurnNotice('Response stopped. This does not undo a started action.');
628
+ }}
629
+ >
540
630
  Stop
541
631
  </button>
542
632
  ) : (
@@ -549,14 +639,26 @@ export function CustomerAssistant({
549
639
  ```
550
640
 
551
641
  `principalKey` stays in the browser. Change it whenever the authenticated user or tenant changes; the hook
552
- then aborts and clears the prior session and transcript. The sample fails closed on input requests until its
553
- fallback is replaced with a form generated from `requestedSchema`. A production renderer must show the
554
- complete confirmation review and both decisions. For `data-view`, map `resourceUri` or `tool` and the
555
- bounded/redacted result to a component already trusted by this application only when intentionally replacing
556
- the linked App with a native UI. Otherwise use `<noodle-app-view>` or its React `NoodleAppView` adapter;
557
- JSON result data is not the App UI. The element's semantic lifecycle identity is the client plus `view.id`
558
- plus `view.resourceUri`, so parent payload/callback rerenders keep the iframe and only a different view,
559
- disconnect, or App teardown request retires the bridge.
642
+ then aborts and clears the prior session and transcript. The sample does not render Confirm until the host
643
+ implements a complete schema-aware review, and it does not accept elicitation until a portable form covers
644
+ `requestedSchema`; use the managed renderer instead of shipping either unsupported branch. Suggestions are
645
+ hook-owned and submit ordinary messages through `client.sendMessage`.
646
+
647
+ `data-sign-in` has no status and is never passed to `client.respond`. Bind `signInTicket` to the host's
648
+ short-lived login transaction without putting it in URLs, logs, analytics, or durable browser storage. Resolve
649
+ the callback as `started` only after the host owns one active transaction; return `cancelled` or reject when no
650
+ transaction started so the renderer restores the sign-in affordance. A
651
+ mixed renderer uses separate public and authenticated clients: the public shell uses `embedId`, `serviceUrl`,
652
+ and a visitor principal key; after login, the destination mounts a new client against the same-origin session
653
+ endpoint under the user/tenant principal key. Never pass both source options or mutate the public client's
654
+ source in place. `session_expired` is observational: the client owns its single safe pre-execution re-exchange.
655
+ Never add a generic Retry button or replay an interaction decision automatically.
656
+
657
+ For `data-tool-result`, do not expose technical tool names or raw JSON. Prefer the linked `data-view`;
658
+ otherwise map a known bounded result to application-trusted UI or keep the explicit unsupported state. For
659
+ `data-view`, use `<noodle-app-view>` or its React `NoodleAppView` adapter. The element's semantic lifecycle
660
+ identity is the client plus `view.id` plus `view.resourceUri`, so payload/callback rerenders keep the iframe
661
+ and only a different view, disconnect, or App teardown request retires the bridge.
560
662
  App views remain inline by default: the host advertises only inline presentation and rejects a widget's
561
663
  fullscreen request. A customer-owned renderer may opt in explicitly with `allowFullscreen` on
562
664
  `NoodleAppView` or `allow-fullscreen` on `<noodle-app-view>` only when fullscreen is part of its intended
@@ -578,6 +680,13 @@ secret allowlist; regenerate existing framework-owned environment binding types
578
680
  Devtools/model exercises to synthetic data, and obtain approval before sending real connector data to an
579
681
  external model.
580
682
 
683
+ Read `evidence.levels` in order: static host, local contract, hosted session, production browser, then
684
+ operations. Stop at `evidence.firstUnproven`. A static result may be `passed`, `partial`, or `failed`; even
685
+ top-level `ready: true` means only that no static blocker was detected. It never proves the local session
686
+ contract or a production-browser flow. Value-free diagnostics call out an MCP endpoint used as the service
687
+ URL, an HTML redirect risk, an SSR mount risk, and a cross-origin session endpoint. The command has no live
688
+ or browser flag; its `postDeployProbes` are next actions, not executed evidence.
689
+
581
690
  After deployment, use the assistant doctor to verify the embed client, exact model transport, and static
582
691
  session boundary:
583
692
 
@@ -591,21 +700,10 @@ application-specific customer route. Prove routed assistant tools by
591
700
  having the authenticated embedding backend pass the user's server-verified endpoint during session
592
701
  exchange, then invoke one representative safe read.
593
702
 
594
- If the application deliberately sends a first turn on mount, do not combine a persistent "sent" ref with a
595
- mount effect. React Strict Mode can abort that provisional request and then suppress the stable remount.
596
- Schedule the send after the provisional cleanup and settle its promise:
597
-
598
- ```tsx
599
- useEffect(() => {
600
- let active = true;
601
- queueMicrotask(() => {
602
- if (active) settle(client.sendMessage(initialMessage));
603
- });
604
- return () => {
605
- active = false;
606
- };
607
- }, [client, initialMessage]);
608
- ```
703
+ Do not send a first turn on mount by default. React effect cleanup can suppress one provisional Strict Mode
704
+ effect, but it cannot make a remount, dependency change, or client replacement idempotent. Require an
705
+ explicit user action unless the host owns durable one-shot state and an application idempotency key that
706
+ makes repeated sends safe.
609
707
 
610
708
  For a chat-first custom host, raw `tool_started` supplies the direct call `id` and technical tool name. Map
611
709
  known tools to concise application copy and use a neutral fallback. Reserve a stable `role="status"` region
@@ -617,39 +715,81 @@ Use `${view.id}:${view.resourceUri}` as transport identity. Different call IDs a
617
715
  must not be deduplicated generically. If this application intentionally owns one current panel for a known
618
716
  resource, declare an application-owned slot for that resource and replace only that slot.
619
717
 
620
- Outside React, subscribe to the DOM-free client directly and use the isolated framework-neutral App host.
718
+ ### Framework-neutral DOM client
719
+
720
+ Subscribe to the DOM-free client directly without a component wrapper and use the isolated App host.
621
721
  It exposes the same conversation as headless AI SDK `UIMessage` state, including typed confirmation, input,
622
- tool-result, and linked-view parts, without installing React:
722
+ tool-result, and linked-view parts:
623
723
 
624
724
  ```html
625
- <noodle-app-view id="assistant-app-view"></noodle-app-view>
725
+ <div id="assistant-app-views"></div>
626
726
  ```
627
727
 
628
728
  ```ts
629
729
  import '@noodleseed/assistant/app-view';
730
+ import {
731
+ type AssistantViewAvailableDetail,
732
+ type NoodleAppViewElement,
733
+ } from '@noodleseed/assistant/app-view';
630
734
  import { createAssistantClient } from '@noodleseed/assistant/client';
631
735
 
632
736
  const assistant = createAssistantClient({
633
737
  sessionEndpoint: '/api/noodle-assistant/session',
634
738
  });
635
- const appView = document.querySelector('#assistant-app-view');
636
- if (!appView) throw new Error('Missing App view host');
637
- appView.client = assistant;
638
- appView.theme = resolvedTheme;
739
+ const appViews = document.querySelector('#assistant-app-views');
740
+ if (!appViews) throw new Error('Missing App views host');
741
+ const mountedViews = new Map<string, NoodleAppViewElement>();
742
+ const readResolvedTheme = (): 'light' | 'dark' =>
743
+ document.documentElement.classList.contains('dark') ? 'dark' : 'light';
744
+ let resolvedTheme: 'light' | 'dark' = readResolvedTheme();
745
+ const syncResolvedTheme = () => {
746
+ resolvedTheme = readResolvedTheme();
747
+ for (const mountedView of mountedViews.values()) mountedView.theme = resolvedTheme;
748
+ };
749
+ new MutationObserver(syncResolvedTheme).observe(document.documentElement, {
750
+ attributes: true,
751
+ attributeFilter: ['class'],
752
+ });
753
+ const appViewFor = (view: AssistantViewAvailableDetail) => {
754
+ const key = `${view.id}:${view.resourceUri}`;
755
+ let appView = mountedViews.get(key);
756
+ if (!appView) {
757
+ appView = document.createElement('noodle-app-view') as NoodleAppViewElement;
758
+ appView.client = assistant;
759
+ mountedViews.set(key, appView);
760
+ appViews.append(appView);
761
+ }
762
+ appView.theme = resolvedTheme;
763
+ return appView;
764
+ };
639
765
 
640
766
  assistant.subscribeChat((state) => {
641
- renderUIMessageState(state);
767
+ renderUIMessageState(state, {
768
+ respond: (id, response) => assistant.respond(id, response),
769
+ });
770
+ const activeViewKeys = new Set<string>();
642
771
  for (const message of state.messages) {
643
772
  for (const part of message.parts) {
644
- if (part.type === 'data-confirmation' && part.data.status === 'pending') {
645
- renderConfirmation(part.data, (response) => assistant.respond(part.data.id, response));
773
+ if (part.type === 'data-view') {
774
+ const key = `${part.data.id}:${part.data.resourceUri}`;
775
+ activeViewKeys.add(key);
776
+ appViewFor(part.data).view = part.data;
646
777
  }
647
- if (part.type === 'data-view') appView.view = part.data;
778
+ }
779
+ }
780
+ for (const [key, mountedView] of mountedViews) {
781
+ if (!activeViewKeys.has(key)) {
782
+ mountedView.remove();
783
+ mountedViews.delete(key);
648
784
  }
649
785
  }
650
786
  });
651
787
  ```
652
788
 
789
+ `renderUIMessageState` is application code. It must present a complete schema-aware confirmation or input
790
+ form and require an explicit user gesture before using `respond`; never call `respond` while scanning a
791
+ transcript snapshot.
792
+
653
793
  `theme="auto"` follows the operating-system preference, not a SaaS-owned toggle. Pass the resolved
654
794
  `light`/`dark` theme to `NoodleAssistant` and `<noodle-app-view>`/`NoodleAppView`; updates reach mounted MCP Apps without a
655
795
  remount. CSS custom properties inherit through the host, and documented `--ns-assistant-*` variables remain
@@ -666,6 +806,14 @@ deployment variables, and connector arguments do not select the tenant route.
666
806
  endpoint. They are not customer API bearer tokens. The exchange endpoint verifies the platform-signed
667
807
  subject assertion and mints a short-lived token scoped to the signed-in user and route binding.
668
808
 
809
+ ## Launch and qualified-usage proof
810
+
811
+ Use the [embedded assistant guide](https://docs.noodleseed.dev/docs/guides/embedded-assistant) for the complete
812
+ pre-launch, browser-proof, qualified-usage, recovery, measurement, and operator procedure; do not copy those
813
+ commands into this example. Keep deployed capability, production-browser proof, qualified usage, and measured
814
+ outcome separate; raw turn volume is utilization rather than outcome. Platform-owned completion events still
815
+ require a separate human-approved analytics and customer-data contract.
816
+
669
817
  ## Deploy customer-protected to Noodle Seed Cloud
670
818
 
671
819
  ```bash
@@ -173,6 +173,9 @@ export default server(
173
173
  // Production origins are exact HTTPS; http://localhost:<port> is allowed for local development.
174
174
  access: authenticatedWebsite({
175
175
  origins: [assistantOrigin, 'https://dev.noodleseed.com', 'http://localhost:3000'],
176
+ sessionClaims: {
177
+ accountTier: { exposeToModel: true },
178
+ },
176
179
  }),
177
180
  theme: 'auto',
178
181
  layout: { mode: 'floating', position: 'bottom-center', panelWidth: 970 },
@@ -19,6 +19,9 @@ describe('customer-auth example', () => {
19
19
  'https://dev.noodleseed.com',
20
20
  'http://localhost:3000',
21
21
  ]);
22
+ expect(manifest.server.assistant?.sessionClaims).toEqual({
23
+ accountTier: { exposeToModel: true },
24
+ });
22
25
  expect(manifest.server.branding).toMatchObject({
23
26
  name: 'Noodle Seed Assistant',
24
27
  colorScheme: 'auto',
@@ -100,5 +103,8 @@ describe('customer-auth example', () => {
100
103
  confirm: true,
101
104
  },
102
105
  });
106
+ expect(
107
+ manifest.tools.find((tool) => tool.name === 'list_org_apps')?.annotations?.readOnlyHint,
108
+ ).toBe(true);
103
109
  });
104
110
  });
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ // Keep the flagship's own contract test executable instead of inheriting the monorepo package-only glob.
4
+ export default defineConfig({
5
+ test: { include: ['test/**/*.test.ts'] },
6
+ });
@@ -17,7 +17,7 @@ private customer data.
17
17
  | Public entry tool | `open_ordering` returns structured fallback content and renders the React widget |
18
18
  | Product and distribution projections | `agentGuide` supplies grounded cross-capability guidance; `distribution` supplies listing, publisher, legal, image, and review facts separately from the runtime manifest |
19
19
  | App-only helper tools | `search_stores`, `load_menu`, `load_item`, `read_cart`, `sync_cart`, `prepare_checkout`; mutating widget-owned helpers use `confirm: false` (equivalent to omission) and execute directly because action hints alone never gate |
20
- | Durable cart state | `server(..., { state: { handles: { cart } }, use: { state } })` with caller scope and revision checks |
20
+ | Durable cart state | `server(..., { state: { handles: { cart } }, use: { state } })` with caller scope, revision checks, and explicit ticket-bound adoption when an anonymous visitor authenticates |
21
21
  | React app runtime kit | `@noodleseed/one/react` supplies app flow, shell/nav/view, async state, form, quantity, choice, and handoff primitives |
22
22
  | Multi-step widget flow | One React shell navigates stores, menu, item customization, cart, review, and handoff views through `useAppFlow` |
23
23
  | Invocation context | `server.context` sets locale/time-zone defaults, derives an ambient service area/date, and exposes optional host-supplied coordinates to tools and the reserved `noodle_context` MCP adapter; location is an untrusted convenience hint, never an authorization signal or a substitute for explicit input |
@@ -326,6 +326,7 @@ export default server(
326
326
  version: 'v1',
327
327
  scope: 'caller',
328
328
  ttlSeconds: 7200,
329
+ claimOnAuthentication: true,
329
330
  schema: cartStateSchema,
330
331
  },
331
332
  },
@@ -3,7 +3,7 @@ name: executing-noodle-plans
3
3
  description: "Use when the user asks to execute an approved, decision-complete implementation plan for a Noodle Seed project task by task with test-first changes, review, recovery, and final verification."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.91.0 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.92.0 hash:6a9f132ddb79352e -->
7
7
 
8
8
  # Execute a Noodle Seed implementation plan
9
9
 
@@ -3,7 +3,7 @@ name: publishing-mcp-integrations
3
3
  description: "Use when preparing, reviewing, or submitting a Noodle Seed MCP integration to a host or app directory."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.91.0 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.92.0 hash:0ccafb222038f553 -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -27,8 +27,8 @@ Produce complete submission evidence with host-review uncertainty stated explici
27
27
 
28
28
  ## Workflow
29
29
 
30
- Read and follow the canonical playbook `references/publishing.md` at `../noodle-seed/references/publishing.md`. It owns the workflow; do not recreate it here or load the command catalog speculatively.
31
- Load `references/app-directory-compliance.md` at `../noodle-seed/references/app-directory-compliance.md` only when the playbook or observed evidence names that concern.
30
+ Read and follow the canonical playbook at `references/publishing.md`. It owns the workflow; do not recreate it here or load the command catalog speculatively.
31
+ Load the supporting reference at `references/app-directory-compliance.md` only when the playbook or observed evidence names that concern.
32
32
 
33
33
  ## Verification evidence
34
34
 
@@ -0,0 +1,59 @@
1
+ # App directory compliance (pre-submission)
2
+
3
+ Use this shared checklist against the built integration before preparing a directory submission. It
4
+ covers evidence common to app and connector directories without assuming a particular host, review
5
+ portal, client framework, or vendor policy.
6
+
7
+ ## Contents
8
+
9
+ - Validation evidence
10
+ - Capability and interaction quality
11
+ - Safety, privacy, and data handling
12
+ - Reliability and accessibility
13
+ - Directory-specific delta
14
+
15
+ ## Validation evidence
16
+
17
+ A clean local validation result proves only the checks that actually ran. Record server validation,
18
+ behavior tests, protocol conformance, production reachability, and interactive rendering as separate
19
+ evidence levels. Never treat metadata readiness as proof of host rendering or directory acceptance.
20
+
21
+ ## Capability and interaction quality
22
+
23
+ 1. **User value** — each exposed capability solves a concrete user job and cites built behavior rather
24
+ than an aspiration.
25
+ 2. **Grounded capability** — knowledge, actions, and presentation come from authoritative application
26
+ data or bounded operations instead of invented state.
27
+ 3. **Atomic interfaces** — every action has a focused purpose, explicit input and output schemas, honest
28
+ effect annotations, and useful failure output.
29
+ 4. **Helpful UI only** — every interactive surface earns its place and preserves a useful text or
30
+ structured fallback when rendering is unavailable.
31
+ 5. **Meaningful completion** — the user can complete the promised task within the declared boundary,
32
+ with any external handoff clearly identified.
33
+
34
+ ## Safety, privacy, and data handling
35
+
36
+ - Minimize model-visible and UI-visible data; remove secrets, internal identifiers, unnecessary personal
37
+ data, and continuation credentials from results and logs.
38
+ - Document authentication, authorization scopes, retention, deletion, subprocessors, and external
39
+ handoffs accurately in the public privacy and support material.
40
+ - Make mutations explicit, bounded, and confirmation-aware. Never imply that a read or preparation
41
+ request authorizes a write.
42
+ - For regulated or consequential workflows, show source provenance, uncertainty, cautions, and the
43
+ boundary between information and a professional decision.
44
+
45
+ ## Reliability and accessibility
46
+
47
+ - Exercise representative positive, negative, empty, loading, error, and recovery cases against the
48
+ production-shaped endpoint.
49
+ - Preserve keyboard access, readable contrast, responsive layout, concise status feedback, and graceful
50
+ degradation when an interactive surface is unsupported.
51
+ - State latency, availability, rate-limit, and support expectations using observed evidence rather than
52
+ unverified claims.
53
+
54
+ ## Directory-specific delta
55
+
56
+ After the shared checklist passes, read the selected directory’s current official documentation and add
57
+ only its verified requirements. Keep directory-specific metadata, screenshots, test accounts, policy
58
+ statements, and review procedures in that submission evidence—not in this shared skill reference. Mark
59
+ unknown or untested requirements explicitly, and never reuse another directory’s checklist as a proxy.
@@ -0,0 +1,63 @@
1
+ # Publish to app directories
2
+
3
+ > Preparation is read-only unless the current user request explicitly authorizes the exact deploy, access change, host write, or submission target. A request to prepare must report missing readiness work and stop before mutation.
4
+
5
+ Directory requirements evolve. Identify the requested directory first and verify its current official requirements before preparing directory-specific evidence.
6
+
7
+ ## Contents
8
+
9
+ - Shared readiness gate
10
+ - Distribution metadata source
11
+ - Hosted immutable distribution
12
+ - Directory-specific evidence
13
+ - Submission boundary
14
+
15
+ ## Shared readiness gate
16
+
17
+ Before any submission:
18
+
19
+ Use `references/app-directory-compliance.md` as this route’s canonical shared compliance checklist.
20
+
21
+ Prepare evidence for a reachable production MCP endpoint, accurate capability descriptions and schemas, useful fallback behavior, realistic positive and negative tests, data minimization, privacy disclosures, support ownership, and any interactive surface the directory will review.
22
+
23
+ ## Distribution metadata source
24
+
25
+ When the user explicitly prepares host packaging, author the host-neutral `distribution` option in the same `server.ts`; do not add it during an ordinary build that has no distribution goal. It contains listing, publisher, support, legal, assets, and review facts that cannot be derived safely from MCP capability descriptions.
26
+
27
+ Reference real packaged images with `asset(...)`, write useful alt text, and include realistic positive and negative review scenarios. Name the exact expected MCP tools in each positive scenario’s `tools` array. A negative scenario is a non-invocation case: set `shouldInvoke: false` and do not define `tools`. For each MCP App screenshot, add the separate user `prompt` that produces that exact state. Capture only the rendered MCP App response—never the enclosing website, Devtools shell, host conversation, or an unrelated product photo—and meet the selected directory’s current format, dimension, and count limits. Keep reviewer credentials, tokens, secrets, personal data, and test-account passwords out of metadata and source control; supply any authorized reviewer credential out of band.
28
+
29
+ `distribution` is projected separately. It leaves the canonical App Package and Runtime Artifact unchanged, so editing listing copy cannot change deployment execution or product-skill identity. A product package still needs the separately judged `agentGuide`; do not duplicate capability schemas or workflow truth in listing metadata.
30
+
31
+ The shared framework can validate metadata and resolved image bytes, run an available target adapter, and create a reproducible archive. Target-specific availability and exact flags live in `references/cli-commands.md` and the live command catalog (`noodle commands --json`); never invent an unlisted target, bundle, filename, or acceptance claim.
32
+
33
+ When a directory has separate installable-plugin and remote-connector submission projections, generate each with its own exact live-catalog command. Never combine their archives or describe an operator dossier as directly portal-uploadable.
34
+
35
+ Local or repository testing and public-directory submission are distinct packaging states with distinct required inputs. An export command only compiles local source and writes the requested archive. It does not deploy, register, upload, submit, review, or publish the package.
36
+
37
+ When an export reports `uploadArtifacts`, treat its output archive as an outer review kit. Extract it, follow the generated instructions, and upload only the named inner artifacts to their matching fields. Never substitute the outer kit for a nested single-purpose upload.
38
+
39
+ ## Hosted immutable distribution
40
+
41
+ Publishing a deployment-bound archive is a hosted mutation. Run it only when the current request explicitly authorizes that exact deployment and target: `noodle distributions publish <deployment-id> [server.ts] --target <target>`. The command compiles local TypeScript and requires its package snapshot to exactly match the selected deployment before it uploads anything. It uses the endpoint and package identity returned by the service; never substitute a local URL or a different deployment.
42
+
43
+ Use `noodle distributions list <deployment-id>` to discover immutable versions, `noodle distributions inspect <distribution-id>` to inspect one, and `noodle distributions download <distribution-id> --output <archive.zip>` to retrieve its exact archive. Download verifies the service length and digest before an atomic local write; a failed verification must leave no output file.
44
+
45
+ Lifecycle and delivery are separate mutations. Run `readiness`, `review`, `release`, `rollback`, `deprecate`, `revoke`, or `grant` only when the request explicitly authorizes that exact distribution and action. Inspect first when the active state or version is not already known.
46
+
47
+ Set readiness from evidence you can verify. Record `review` only from a real human-observed host status; never infer submission, approval, or publication from a generated archive or a successful Noodle command, and never put reviewer credentials or secrets in feedback.
48
+
49
+ `release --visibility private` creates or advances a stable Noodle channel without anonymous discovery; `release --visibility public` enables Noodle public delivery only. Both still require the underlying MCP deployment to use exact public access. Neither action publishes to an external directory.
50
+
51
+ `grant` returns one short-lived, exact-version bearer URL. Treat the complete URL as a secret, disclose it only to the authorized reviewer, and do not paste it into source, logs, issues, or durable docs. `rollback` moves only the channel pointer to an older ready version; `deprecate` stops delivery and `revoke` is terminal.
52
+
53
+ A hosted archive is still a submission candidate. Creating, listing, inspecting, downloading, releasing, or granting it does not submit it to an external directory, satisfy review, or publish a host listing.
54
+
55
+ ## Directory-specific evidence
56
+
57
+ Read the selected directory’s current official submission documentation at review time. Record each additional requirement separately from the shared checklist, including listing fields, identity verification, test credentials, screenshots, policy declarations, review limits, and appeal or resubmission steps. Never project one directory’s requirements onto another.
58
+
59
+ When a requirement cannot be verified from the selected directory’s current documentation or direct review evidence, mark it unknown instead of borrowing a rule from another host.
60
+
61
+ ## Submission boundary
62
+
63
+ Preparation is read-only. Reverify current official requirements immediately before public submission. Deployment, access changes, directory registration, credential entry, final submission, and publication each remain separate human-operated mutations that require explicit authorization for the exact target. Report remaining evidence gaps and stop when that authority or required directory access is absent.
@@ -416,6 +416,14 @@ Author managed config as `secret("NAME")` / `variable("NAME")` and operate it wi
416
416
 
417
417
  To place the same server tools inside a SaaS web app, declare `assistant: embeddedAssistant(...)` alongside the one server-level brand kit. Read `embedded-assistant.md` before integrating: it owns the HTTPS-origin rule, managed model configuration, required deploy-before-client sequence, customer-backend exchange, browser mount, and verification checklist.
418
418
 
419
+ ## Managed capability reuse
420
+
421
+ Before authoring an HTTP connector for public-web search, page extraction, places/local search, routing, weather, translation, or media discovery, inspect the generated SDK surface reference. If the matching Noodle capability is actually exported, use its one documented declaration and generated tools directly—never wrap it, rename it, or build an assistant-only provider call. That single declaration is available to both the embedded assistant and external MCP agents under the same authorization and policy.
422
+
423
+ Use `provider: noodleManaged()` in reusable capability intent and let the app/environment operator bind a supported BYO provider through managed configuration. Keep provider names, endpoints, and credentials out of `server.ts`. Live fares, inventory, bookings, pricing, orders, accounts, and payments remain connectors to authoritative systems. Source order is not truth: preserve citations, freshness, and rights evidence returned by the capability.
424
+
425
+ A roadmap is not an SDK. If the capability is absent from the generated export list, do not invent an import or generic platform helper. With explicit developer agreement, a bounded application connector may prove the immediate use case; keep it application-specific and do not claim it as the canonical Noodle primitive.
426
+
419
427
  ## Knowledge components
420
428
 
421
429
  Ground an assistant in controlled documents and the customer's live public site with one declaration — never a handwritten `search`/`fetch` tool pair, a provider name, a sync job, or an index manifest. Declare `knowledge(...)` with `file(...)` documents (UTF-8 `.md`/`.txt`, project-root relative, ≤100 files, ≤1 MiB each, ≤25 MiB per component) and `site(...)` live scopes (exact HTTPS origin plus positive path globs), pass the declaration in the server's `knowledge` array, and include it in a public website surface's `capabilities` to project the generated `search_<name>` capability: