@agent-native/core 0.101.12 → 0.101.14
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +15 -0
- package/corpus/core/package.json +4 -2
- package/corpus/core/src/cli/create.ts +76 -17
- package/corpus/core/src/client/AgentPanel.tsx +61 -48
- package/corpus/core/src/client/assistant-ui-recovery.tsx +9 -3
- package/corpus/core/src/client/chat/message-components.tsx +26 -2
- package/corpus/core/src/client/chat/tool-call-display.tsx +18 -11
- package/corpus/core/src/mcp/server.ts +10 -1
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +0 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +2 -58
- package/corpus/core/src/server/prompts/framework-core-compact.ts +0 -1
- package/corpus/core/src/server/prompts/framework-core.ts +0 -30
- package/corpus/core/src/server/prompts/index.ts +1 -4
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +0 -14
- package/corpus/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/changelog/2026-07-15-public-clip-links-are-labeled-share-with-humans-for-clarity.md +6 -0
- package/corpus/templates/forms/actions/delete-form.ts +4 -0
- package/corpus/templates/forms/actions/patch-form-fields.ts +3 -0
- package/corpus/templates/forms/actions/restore-form.ts +3 -0
- package/corpus/templates/forms/actions/update-form.ts +3 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +2 -2
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +2 -2
- package/corpus/templates/forms/changelog/2026-07-15-published-forms-now-reflect-field-updates-immediately-at-the.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-15-response-rows-now-keep-every-column-aligned-to-the-top-for-c.md +6 -0
- package/corpus/templates/forms/server/handlers/forms.ts +1 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +47 -4
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +189 -82
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +1 -1
- package/dist/cli/create.d.ts +5 -2
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +52 -17
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +2 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +24 -13
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/assistant-ui-recovery.d.ts +2 -0
- package/dist/client/assistant-ui-recovery.d.ts.map +1 -1
- package/dist/client/assistant-ui-recovery.js +5 -2
- package/dist/client/assistant-ui-recovery.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +6 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +15 -2
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +4 -2
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +11 -13
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +10 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +0 -3
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +0 -22
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +2 -51
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/prompts/framework-core-compact.d.ts +0 -1
- package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
- package/dist/server/prompts/framework-core-compact.js +0 -1
- package/dist/server/prompts/framework-core-compact.js.map +1 -1
- package/dist/server/prompts/framework-core.d.ts +0 -9
- package/dist/server/prompts/framework-core.d.ts.map +1 -1
- package/dist/server/prompts/framework-core.js +0 -29
- package/dist/server/prompts/framework-core.js.map +1 -1
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.d.ts.map +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/index.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +492 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +189 -0
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +76 -0
- package/dist/templates/chat/.agents/skills/capture-learnings/SKILL.md +89 -0
- package/dist/templates/chat/.agents/skills/create-skill/SKILL.md +221 -0
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +263 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +112 -0
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +232 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +280 -0
- package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +106 -0
- package/dist/templates/chat/.agents/skills/shadcn-ui/SKILL.md +95 -0
- package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/dist/templates/chat/.env.example +5 -0
- package/dist/templates/chat/.ignore +0 -0
- package/dist/templates/chat/.oxfmtrc.json +8 -0
- package/dist/templates/chat/.react-router/types/+server-build.d.ts +18 -0
- package/dist/templates/chat/.react-router/types/app/+types/root.ts +68 -0
- package/dist/templates/chat/AGENTS.md +62 -0
- package/dist/templates/chat/CHANGELOG.md +10 -0
- package/dist/templates/chat/DEVELOPING.md +185 -0
- package/dist/templates/chat/README.md +32 -0
- package/dist/templates/chat/_gitignore +43 -0
- package/dist/templates/chat/actions/hello.ts +13 -0
- package/dist/templates/chat/actions/navigate.ts +41 -0
- package/dist/templates/chat/actions/run.ts +2 -0
- package/dist/templates/chat/actions/view-screen.ts +31 -0
- package/dist/templates/chat/app/components/layout/Header.tsx +59 -0
- package/dist/templates/chat/app/components/layout/Layout.tsx +184 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +580 -0
- package/dist/templates/chat/app/components/ui/button.tsx +1 -0
- package/dist/templates/chat/app/components/ui/card.tsx +1 -0
- package/dist/templates/chat/app/components/ui/dropdown-menu.tsx +1 -0
- package/dist/templates/chat/app/components/ui/input.tsx +1 -0
- package/dist/templates/chat/app/components/ui/label.tsx +1 -0
- package/dist/templates/chat/app/components/ui/sheet.tsx +1 -0
- package/dist/templates/chat/app/components/ui/toolkit-provider.tsx +12 -0
- package/dist/templates/chat/app/components/ui/tooltip.tsx +1 -0
- package/dist/templates/chat/app/entry.client.tsx +19 -0
- package/dist/templates/chat/app/entry.server.tsx +10 -0
- package/dist/templates/chat/app/global.css +93 -0
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +111 -0
- package/dist/templates/chat/app/i18n/ar-SA.ts +68 -0
- package/dist/templates/chat/app/i18n/de-DE.ts +71 -0
- package/dist/templates/chat/app/i18n/en-US.ts +70 -0
- package/dist/templates/chat/app/i18n/es-ES.ts +71 -0
- package/dist/templates/chat/app/i18n/fr-FR.ts +71 -0
- package/dist/templates/chat/app/i18n/hi-IN.ts +69 -0
- package/dist/templates/chat/app/i18n/index.ts +34 -0
- package/dist/templates/chat/app/i18n/ja-JP.ts +70 -0
- package/dist/templates/chat/app/i18n/ko-KR.ts +70 -0
- package/dist/templates/chat/app/i18n/pt-BR.ts +71 -0
- package/dist/templates/chat/app/i18n/zh-CN.ts +67 -0
- package/dist/templates/chat/app/i18n/zh-TW.ts +67 -0
- package/dist/templates/chat/app/i18n-data.ts +556 -0
- package/dist/templates/chat/app/lib/agent-page.tsx +40 -0
- package/dist/templates/chat/app/lib/app-config.ts +11 -0
- package/dist/templates/chat/app/lib/tab-id.ts +1 -0
- package/dist/templates/chat/app/lib/utils.ts +1 -0
- package/dist/templates/chat/app/root.tsx +172 -0
- package/dist/templates/chat/app/routes/_index.tsx +91 -0
- package/dist/templates/chat/app/routes/agent.tsx +17 -0
- package/dist/templates/chat/app/routes/chat.$threadId.tsx +1 -0
- package/dist/templates/chat/app/routes/database.tsx +17 -0
- package/dist/templates/chat/app/routes/extensions.$id.$slug.tsx +2 -0
- package/dist/templates/chat/app/routes/extensions.$id.tsx +11 -0
- package/dist/templates/chat/app/routes/extensions._index.tsx +11 -0
- package/dist/templates/chat/app/routes/extensions.tsx +5 -0
- package/dist/templates/chat/app/routes/observability.tsx +18 -0
- package/dist/templates/chat/app/routes/settings.tsx +88 -0
- package/dist/templates/chat/app/routes/team.tsx +11 -0
- package/dist/templates/chat/app/routes.ts +4 -0
- package/dist/templates/chat/app/vite-env.d.ts +6 -0
- package/dist/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
- package/dist/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
- package/dist/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/dist/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/dist/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/dist/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/dist/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/dist/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
- package/dist/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
- package/dist/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
- package/dist/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/dist/templates/chat/components.json +20 -0
- package/dist/templates/chat/data/.gitkeep +0 -0
- package/dist/templates/chat/data/sync-config.json +1 -0
- package/dist/templates/chat/learnings.defaults.md +5 -0
- package/dist/templates/chat/netlify.toml +10 -0
- package/dist/templates/chat/package.json +92 -0
- package/dist/templates/chat/public/agent-native-icon-dark.svg +10 -0
- package/dist/templates/chat/public/agent-native-icon-light.svg +10 -0
- package/dist/templates/chat/public/agent-native-logo-dark.svg +21 -0
- package/dist/templates/chat/public/agent-native-logo-light.svg +21 -0
- package/dist/templates/chat/public/favicon.svg +1 -0
- package/dist/templates/chat/public/icon-180.svg +1 -0
- package/dist/templates/chat/public/icon-192.svg +1 -0
- package/dist/templates/chat/public/icon-512.svg +1 -0
- package/dist/templates/chat/public/manifest.json +21 -0
- package/dist/templates/chat/react-router.config.ts +7 -0
- package/dist/templates/chat/server/middleware/auth.ts +15 -0
- package/dist/templates/chat/server/plugins/agent-chat.ts +21 -0
- package/dist/templates/chat/server/plugins/auth.ts +17 -0
- package/dist/templates/chat/server/routes/[...page].get.ts +5 -0
- package/dist/templates/chat/ssr-entry.ts +15 -0
- package/dist/templates/chat/tsconfig.json +21 -0
- package/dist/templates/chat/vite.config.ts +19 -0
- package/package.json +2 -1
- package/src/templates/chat/.agents/skills/actions/SKILL.md +492 -0
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +189 -0
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +76 -0
- package/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +89 -0
- package/src/templates/chat/.agents/skills/create-skill/SKILL.md +221 -0
- package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +263 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +112 -0
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +232 -0
- package/src/templates/chat/.agents/skills/security/SKILL.md +280 -0
- package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +106 -0
- package/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +95 -0
- package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/src/templates/chat/.env.example +5 -0
- package/src/templates/chat/.ignore +0 -0
- package/src/templates/chat/.oxfmtrc.json +8 -0
- package/src/templates/chat/.react-router/types/+server-build.d.ts +18 -0
- package/src/templates/chat/.react-router/types/app/+types/root.ts +68 -0
- package/src/templates/chat/AGENTS.md +62 -0
- package/src/templates/chat/CHANGELOG.md +10 -0
- package/src/templates/chat/DEVELOPING.md +185 -0
- package/src/templates/chat/README.md +32 -0
- package/src/templates/chat/_gitignore +43 -0
- package/src/templates/chat/actions/hello.spec.ts +23 -0
- package/src/templates/chat/actions/hello.ts +13 -0
- package/src/templates/chat/actions/navigate.spec.ts +68 -0
- package/src/templates/chat/actions/navigate.ts +41 -0
- package/src/templates/chat/actions/run.ts +2 -0
- package/src/templates/chat/actions/view-screen.spec.ts +40 -0
- package/src/templates/chat/actions/view-screen.ts +31 -0
- package/src/templates/chat/app/components/layout/Header.tsx +59 -0
- package/src/templates/chat/app/components/layout/Layout.tsx +184 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +580 -0
- package/src/templates/chat/app/components/ui/button.tsx +1 -0
- package/src/templates/chat/app/components/ui/card.tsx +1 -0
- package/src/templates/chat/app/components/ui/dropdown-menu.tsx +1 -0
- package/src/templates/chat/app/components/ui/input.tsx +1 -0
- package/src/templates/chat/app/components/ui/label.tsx +1 -0
- package/src/templates/chat/app/components/ui/sheet.tsx +1 -0
- package/src/templates/chat/app/components/ui/toolkit-provider.tsx +12 -0
- package/src/templates/chat/app/components/ui/tooltip.tsx +1 -0
- package/src/templates/chat/app/entry.client.tsx +19 -0
- package/src/templates/chat/app/entry.server.tsx +10 -0
- package/src/templates/chat/app/global.css +93 -0
- package/src/templates/chat/app/hooks/use-navigation-state.ts +111 -0
- package/src/templates/chat/app/i18n/ar-SA.ts +68 -0
- package/src/templates/chat/app/i18n/de-DE.ts +71 -0
- package/src/templates/chat/app/i18n/en-US.ts +70 -0
- package/src/templates/chat/app/i18n/es-ES.ts +71 -0
- package/src/templates/chat/app/i18n/fr-FR.ts +71 -0
- package/src/templates/chat/app/i18n/hi-IN.ts +69 -0
- package/src/templates/chat/app/i18n/index.ts +34 -0
- package/src/templates/chat/app/i18n/ja-JP.ts +70 -0
- package/src/templates/chat/app/i18n/ko-KR.ts +70 -0
- package/src/templates/chat/app/i18n/pt-BR.ts +71 -0
- package/src/templates/chat/app/i18n/zh-CN.ts +67 -0
- package/src/templates/chat/app/i18n/zh-TW.ts +67 -0
- package/src/templates/chat/app/i18n-data.ts +556 -0
- package/src/templates/chat/app/lib/agent-page.spec.tsx +52 -0
- package/src/templates/chat/app/lib/agent-page.tsx +40 -0
- package/src/templates/chat/app/lib/app-config.ts +11 -0
- package/src/templates/chat/app/lib/tab-id.ts +1 -0
- package/src/templates/chat/app/lib/utils.ts +1 -0
- package/src/templates/chat/app/root.tsx +172 -0
- package/src/templates/chat/app/routes/_index.tsx +91 -0
- package/src/templates/chat/app/routes/agent.tsx +17 -0
- package/src/templates/chat/app/routes/chat.$threadId.tsx +1 -0
- package/src/templates/chat/app/routes/database.tsx +17 -0
- package/src/templates/chat/app/routes/extensions.$id.$slug.tsx +2 -0
- package/src/templates/chat/app/routes/extensions.$id.tsx +11 -0
- package/src/templates/chat/app/routes/extensions._index.tsx +11 -0
- package/src/templates/chat/app/routes/extensions.tsx +5 -0
- package/src/templates/chat/app/routes/observability.tsx +18 -0
- package/src/templates/chat/app/routes/settings.tsx +88 -0
- package/src/templates/chat/app/routes/team.tsx +11 -0
- package/src/templates/chat/app/routes.ts +4 -0
- package/src/templates/chat/app/vite-env.d.ts +6 -0
- package/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
- package/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
- package/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
- package/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
- package/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
- package/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/src/templates/chat/components.json +20 -0
- package/src/templates/chat/data/.gitkeep +0 -0
- package/src/templates/chat/data/sync-config.json +1 -0
- package/src/templates/chat/learnings.defaults.md +5 -0
- package/src/templates/chat/netlify.toml +10 -0
- package/src/templates/chat/package.json +92 -0
- package/src/templates/chat/public/agent-native-icon-dark.svg +10 -0
- package/src/templates/chat/public/agent-native-icon-light.svg +10 -0
- package/src/templates/chat/public/agent-native-logo-dark.svg +21 -0
- package/src/templates/chat/public/agent-native-logo-light.svg +21 -0
- package/src/templates/chat/public/favicon.svg +1 -0
- package/src/templates/chat/public/icon-180.svg +1 -0
- package/src/templates/chat/public/icon-192.svg +1 -0
- package/src/templates/chat/public/icon-512.svg +1 -0
- package/src/templates/chat/public/manifest.json +21 -0
- package/src/templates/chat/react-router.config.ts +7 -0
- package/src/templates/chat/server/middleware/auth.ts +15 -0
- package/src/templates/chat/server/plugins/agent-chat.ts +21 -0
- package/src/templates/chat/server/plugins/auth.ts +17 -0
- package/src/templates/chat/server/routes/[...page].get.ts +5 -0
- package/src/templates/chat/ssr-entry.ts +15 -0
- package/src/templates/chat/tsconfig.json +21 -0
- package/src/templates/chat/vite.config.ts +19 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: delegate-to-agent
|
|
3
|
+
description: >-
|
|
4
|
+
How to delegate all AI work to the agent chat. Use when delegating AI work
|
|
5
|
+
from UI or scripts to the agent, when a user asks for agent behavior or
|
|
6
|
+
LLM-powered features, when tempted to add inline LLM calls, or when sending
|
|
7
|
+
messages to the agent from application code.
|
|
8
|
+
scope: dev
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Delegate All AI to the Agent
|
|
14
|
+
|
|
15
|
+
## Rule
|
|
16
|
+
|
|
17
|
+
The UI never calls an LLM directly. Product workflows are delegated to the
|
|
18
|
+
agent through the chat bridge so users can see, steer, and audit the work.
|
|
19
|
+
Server-side one-shot model calls are an explicit escape hatch for narrow text
|
|
20
|
+
transforms only; use `completeText()` from `@agent-native/core/server` when the
|
|
21
|
+
work intentionally does not need tools, chat history, or run state.
|
|
22
|
+
|
|
23
|
+
## Why
|
|
24
|
+
|
|
25
|
+
The agent is the single AI interface. It has context about the full project, can read/write any file, and can run scripts. Inline LLM calls bypass this — they create a shadow AI that doesn't know what the agent knows and can't coordinate with it.
|
|
26
|
+
|
|
27
|
+
## How
|
|
28
|
+
|
|
29
|
+
**From the UI (client):**
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { sendToAgentChat } from "@agent-native/core/client";
|
|
33
|
+
|
|
34
|
+
sendToAgentChat({
|
|
35
|
+
message: "Generate a summary of this document",
|
|
36
|
+
context: documentContent, // optional hidden context (not shown in chat UI)
|
|
37
|
+
submit: true, // auto-submit to the agent
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**From the UI, in the background:**
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { sendToAgentChat } from "@agent-native/core/client";
|
|
45
|
+
|
|
46
|
+
sendToAgentChat({
|
|
47
|
+
message: "Analyze this import and create any missing records",
|
|
48
|
+
context: `Import batch id: ${batchId}`,
|
|
49
|
+
submit: true,
|
|
50
|
+
newTab: true,
|
|
51
|
+
background: true,
|
|
52
|
+
openSidebar: false,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This is still a full agent run: tools, actions, thread state, and run tracking
|
|
57
|
+
all remain active. It simply does not focus or open the sidebar.
|
|
58
|
+
|
|
59
|
+
**From scripts (Node):**
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { agentChat } from "@agent-native/core";
|
|
63
|
+
|
|
64
|
+
agentChat.submit("Process the uploaded images and create thumbnails");
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**For narrow server-side text transforms:**
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { completeText } from "@agent-native/core/server";
|
|
71
|
+
|
|
72
|
+
const result = await completeText({
|
|
73
|
+
systemPrompt: "Return exactly one sentiment label.",
|
|
74
|
+
input: messageBody,
|
|
75
|
+
maxOutputTokens: 12,
|
|
76
|
+
temperature: 0,
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Wrap user-facing uses in actions so the UI and agent share the same operation.
|
|
81
|
+
Do not call provider SDKs directly.
|
|
82
|
+
|
|
83
|
+
**From the UI, detecting when agent is done:**
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { useAgentChatGenerating } from "@agent-native/core/client";
|
|
87
|
+
|
|
88
|
+
function MyComponent() {
|
|
89
|
+
const isGenerating = useAgentChatGenerating();
|
|
90
|
+
// Show loading state while agent is working
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## `submit` vs Prefill
|
|
95
|
+
|
|
96
|
+
The `submit` option controls whether the message is sent automatically or placed in the chat input for user review:
|
|
97
|
+
|
|
98
|
+
| `submit` value | Behavior | Use when |
|
|
99
|
+
| -------------- | --------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
100
|
+
| `true` | Auto-submits to the agent immediately | Routine operations the user has already approved |
|
|
101
|
+
| `false` | Prefills the chat input for user review | High-stakes operations (deleting data, modifying code, API calls with side effects) |
|
|
102
|
+
| omitted | Uses the project's default setting | General-purpose delegation |
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// Auto-submit: routine operation
|
|
106
|
+
sendToAgentChat({ message: "Update the project summary", submit: true });
|
|
107
|
+
|
|
108
|
+
// Prefill: let user review before sending
|
|
109
|
+
sendToAgentChat({
|
|
110
|
+
message: "Delete all projects older than 30 days",
|
|
111
|
+
submit: false,
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Capture user input first when generating from a prompt
|
|
116
|
+
|
|
117
|
+
Buttons that produce new content ("New Design", "Create Dashboard", "Make Deck", "Generate Form") need the user's prompt as input. **Never hardcode a generic message** — the result will be a generic generation the user didn't actually ask for.
|
|
118
|
+
|
|
119
|
+
**Bad** — auto-submits a placeholder message; the user never said what they wanted:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<Button
|
|
123
|
+
onClick={() =>
|
|
124
|
+
sendToAgentChat({ message: "make a design", submit: true })
|
|
125
|
+
}
|
|
126
|
+
>
|
|
127
|
+
New Design
|
|
128
|
+
</Button>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Good** — Popover anchored to the button captures the prompt, then submits it:
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
135
|
+
<PopoverTrigger asChild>
|
|
136
|
+
<Button>New Design</Button>
|
|
137
|
+
</PopoverTrigger>
|
|
138
|
+
<PopoverContent className="w-96">
|
|
139
|
+
<Textarea
|
|
140
|
+
autoFocus
|
|
141
|
+
value={prompt}
|
|
142
|
+
onChange={(e) => setPrompt(e.target.value)}
|
|
143
|
+
placeholder="What do you want to design?"
|
|
144
|
+
/>
|
|
145
|
+
<Button
|
|
146
|
+
onClick={() => {
|
|
147
|
+
sendToAgentChat({ message: prompt, submit: true });
|
|
148
|
+
setOpen(false);
|
|
149
|
+
setPrompt("");
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
Create
|
|
153
|
+
</Button>
|
|
154
|
+
</PopoverContent>
|
|
155
|
+
</Popover>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Always ask for input first when** the output depends on a prompt the user must provide — "design what?", "deck about what?", "dashboard for which metric?", "form for which use case?".
|
|
159
|
+
|
|
160
|
+
**Auto-submit without input is fine when intent is unambiguous:**
|
|
161
|
+
|
|
162
|
+
- "Try to fix" on a tool error — submits the error details with a clear fix instruction
|
|
163
|
+
- "Retry the last operation" after a transient failure
|
|
164
|
+
- Single-purpose buttons where there is nothing meaningful for the user to add
|
|
165
|
+
|
|
166
|
+
If you find yourself writing `submit: true` with a hardcoded creative verb (`"design a..."`, `"write a..."`, `"build a..."`), stop and add a Popover.
|
|
167
|
+
|
|
168
|
+
## Delegating to a Sub-Agent (Agent Teams)
|
|
169
|
+
|
|
170
|
+
`sendToAgentChat()` delegates from app code _to_ the agent. The other axis of
|
|
171
|
+
delegation is the agent handing work _to a sub-agent_ through the Agent Teams
|
|
172
|
+
run-manager. The main chat stays the orchestrator: it spawns sub-agents, then
|
|
173
|
+
reads and integrates their results.
|
|
174
|
+
|
|
175
|
+
### When to spawn a sub-agent vs do it yourself
|
|
176
|
+
|
|
177
|
+
- **Do it yourself** when the work is small, on the critical path, or tightly
|
|
178
|
+
coupled to what you're already doing. Sub-agent overhead and coordination risk
|
|
179
|
+
outweigh the benefit.
|
|
180
|
+
- **Spawn a sub-agent** for a self-contained unit of work that can run
|
|
181
|
+
independently — a disjoint investigation, an isolated implementation slice, a
|
|
182
|
+
long-running search — especially when it frees the main thread to keep
|
|
183
|
+
orchestrating.
|
|
184
|
+
|
|
185
|
+
### Briefing contract
|
|
186
|
+
|
|
187
|
+
Every sub-agent brief must specify four things, or the sub-agent will guess:
|
|
188
|
+
|
|
189
|
+
- **Objective** — the one concrete outcome it owns, in a sentence.
|
|
190
|
+
- **Context** — the facts it needs (paths, prior findings, constraints) so it
|
|
191
|
+
doesn't re-derive them.
|
|
192
|
+
- **Output** — the exact shape you want back (a summary, a file edited, a list
|
|
193
|
+
of paths, a yes/no with rationale).
|
|
194
|
+
- **Boundaries** — what it must NOT touch (files, branches, side effects) and
|
|
195
|
+
when to stop and report rather than push forward.
|
|
196
|
+
|
|
197
|
+
### Fan-out discipline
|
|
198
|
+
|
|
199
|
+
- **Default to a single sub-agent.** Most delegation is one focused task.
|
|
200
|
+
- **Spawn multiple only for genuinely independent units** that don't share state
|
|
201
|
+
or files. Never parallelize coupled work — if B needs A's output, run them in
|
|
202
|
+
sequence.
|
|
203
|
+
- **Cap parallel fan-out at ~3.** More sub-agents means more synthesis cost and
|
|
204
|
+
more chance of conflicting edits to the same area.
|
|
205
|
+
|
|
206
|
+
### Synthesis discipline
|
|
207
|
+
|
|
208
|
+
- **Read every result** before concluding — don't act on the first one back.
|
|
209
|
+
- **Reconcile conflicts** between sub-agent findings explicitly; decide which is
|
|
210
|
+
right rather than averaging or ignoring.
|
|
211
|
+
- **Integrate into one answer.** The main thread produces the single coherent
|
|
212
|
+
result; it never just forwards raw sub-agent transcripts to the user.
|
|
213
|
+
|
|
214
|
+
Background sub-agents must use the core run-manager / Agent Teams infrastructure
|
|
215
|
+
rather than ad-hoc LLM calls.
|
|
216
|
+
|
|
217
|
+
## Don't
|
|
218
|
+
|
|
219
|
+
- Don't `import Anthropic from "@anthropic-ai/sdk"` in client or server code
|
|
220
|
+
- Don't `import OpenAI from "openai"` in client or server code
|
|
221
|
+
- Don't make direct API calls to any LLM provider
|
|
222
|
+
- Don't use AI SDK functions like `generateText()`, `streamText()`, etc.
|
|
223
|
+
- Don't build "AI features" that bypass the agent chat
|
|
224
|
+
- Don't auto-submit a hardcoded prompt for generative actions — capture user input first (see above)
|
|
225
|
+
- Don't use `completeText()` for workflows that need tools, database writes,
|
|
226
|
+
auditability, user steering, or multi-step reasoning. Use the agent chat
|
|
227
|
+
instead, optionally with `background: true`.
|
|
228
|
+
|
|
229
|
+
## Exception
|
|
230
|
+
|
|
231
|
+
Scripts may call external APIs (image generation, search, etc.) — but the AI
|
|
232
|
+
reasoning and orchestration still goes through the agent. A script is a tool
|
|
233
|
+
the agent uses, not a replacement for the agent.
|
|
234
|
+
|
|
235
|
+
`completeText()` is allowed for small server-side transforms such as
|
|
236
|
+
classification, extraction, rewriting a short string, or normalizing messy
|
|
237
|
+
provider text. It deliberately runs with `tools: []` and does not create chat
|
|
238
|
+
thread state.
|
|
239
|
+
|
|
240
|
+
## When to Use A2A Instead
|
|
241
|
+
|
|
242
|
+
`sendToAgentChat()` delegates work to the **local** agent — the one running alongside your app. When the work should go to a **different** agent entirely (e.g., asking an analytics agent for data, or a calendar agent for availability), use the A2A (agent-to-agent) protocol instead.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import { callAgent } from "@agent-native/core/a2a";
|
|
246
|
+
|
|
247
|
+
// Call a different agent — not the local agent chat
|
|
248
|
+
const stats = await callAgent(
|
|
249
|
+
"https://analytics.example.com",
|
|
250
|
+
"What were last week's signups?",
|
|
251
|
+
{ apiKey: process.env.ANALYTICS_A2A_KEY },
|
|
252
|
+
);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
See the **a2a-protocol** skill for the full pattern.
|
|
256
|
+
|
|
257
|
+
## Related Skills
|
|
258
|
+
|
|
259
|
+
- **a2a-protocol** — When the work goes to a different agent, not the local one
|
|
260
|
+
- **actions** — The agent invokes actions via `pnpm action <name>` to perform complex operations
|
|
261
|
+
- **self-modifying-code** — The agent operates through the chat bridge to make code changes
|
|
262
|
+
- **storing-data** — The agent writes results to the database after processing requests
|
|
263
|
+
- **real-time-sync** — The UI updates automatically when the agent writes data
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: >-
|
|
4
|
+
Create distinctive, production-grade frontend interfaces with high design
|
|
5
|
+
quality. Use when building web components, pages, artifacts, posters, or
|
|
6
|
+
applications (websites, landing pages, dashboards, React components,
|
|
7
|
+
HTML/CSS layouts, or when styling/beautifying any web UI). Generates
|
|
8
|
+
creative, polished UI that avoids generic AI aesthetics.
|
|
9
|
+
scope: dev
|
|
10
|
+
license: Complete terms in LICENSE.txt
|
|
11
|
+
source: https://github.com/anthropics/skills/blob/main/skills/frontend-design/SKILL.md
|
|
12
|
+
metadata:
|
|
13
|
+
internal: true
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Frontend Design
|
|
17
|
+
|
|
18
|
+
This skill guides creation of distinctive, production-grade frontend interfaces. Implement real working code with strong product judgment, excellent accessibility, and a clear visual point of view.
|
|
19
|
+
|
|
20
|
+
The user may ask for a component, page, full app, dashboard, marketing surface, or restyle. Before coding, understand the audience and pick a direction that fits the product instead of defaulting to generic SaaS polish.
|
|
21
|
+
|
|
22
|
+
## Design Thinking
|
|
23
|
+
|
|
24
|
+
Before coding, decide:
|
|
25
|
+
|
|
26
|
+
- **Purpose**: What workflow does this surface make easier? What is the primary action?
|
|
27
|
+
- **Audience**: Who will use it repeatedly, and what should feel fast, calm, playful, premium, editorial, technical, or utilitarian?
|
|
28
|
+
- **Tone**: Choose a concrete aesthetic direction: refined minimal, dense operations console, editorial, playful, industrial, warm handmade, high-contrast data tool, etc.
|
|
29
|
+
- **Information hierarchy**: What must be visible in the first five seconds, and what should be progressively disclosed?
|
|
30
|
+
- **Differentiation**: What makes this feel designed for this exact domain?
|
|
31
|
+
|
|
32
|
+
Then implement working code that is cohesive, accessible, responsive, and polished in small details: typography, spacing, copy, motion, empty states, loading states, focus states, and error states.
|
|
33
|
+
|
|
34
|
+
## Minimalism And Progressive Disclosure
|
|
35
|
+
|
|
36
|
+
Default to Apple/Linear-level restraint: make the primary workflow obvious, then remove everything that does not help that workflow right now. A polished UI often has fewer visible controls, fewer borders, fewer labels, and fewer explanatory surfaces than the first reasonable implementation.
|
|
37
|
+
|
|
38
|
+
- **Start by subtracting**: Before adding a visible control, banner, toolbar row, card, or explanatory block, ask what can be removed, merged, renamed, or moved into an existing affordance.
|
|
39
|
+
- **One primary action**: Each surface should have one dominant next action. Secondary actions belong in menus, popovers, command palettes, disclosure rows, or contextual hover/focus states unless they are used constantly.
|
|
40
|
+
- **Progressively disclose rare work**: Advanced options, diagnostics, metadata, settings, import/export, destructive actions, and inspection tools should stay tucked away until requested. Prefer small icon triggers with tooltips, popovers, drawers, or detail panels over permanent chrome.
|
|
41
|
+
- **Keep chrome quiet**: Avoid new always-visible bars, badges, callouts, helper text, and counters unless they prevent mistakes or are central to repeated use. Status can often be a dot, ring, muted count, or tooltip.
|
|
42
|
+
- **Favor content over containers**: Do not wrap every section in a card. Use whitespace, alignment, typography, dividers, and full-width bands before adding boxes.
|
|
43
|
+
- **Design for repeated use**: Production app UI should feel calm after the hundredth use. If a control shouts, animates, explains itself, or occupies a full row for an occasional action, hide or compress it.
|
|
44
|
+
- **Make absence intentional**: Empty states should be sparse and action-oriented. Do not fill blank space with marketing copy, decorative art, or lists of features just because the screen feels empty.
|
|
45
|
+
- **Use familiar primitives**: Icon buttons need clear tooltips. Menus, popovers, tabs, switches, and segmented controls should carry complexity instead of exposing every option at once.
|
|
46
|
+
|
|
47
|
+
## Aesthetic Guidelines
|
|
48
|
+
|
|
49
|
+
- **Typography**: Use the product's existing type system first. For net-new public pages, choose characterful but readable type and keep sizing appropriate to the surface.
|
|
50
|
+
- **Color and theme**: Use semantic tokens and CSS variables. Avoid one-note palettes and default purple/blue gradients unless the brand demands them.
|
|
51
|
+
- **Motion**: Prefer purposeful transitions and small state changes. Use CSS transitions/keyframes unless the app already uses a motion library. Never `transition-all` — list the properties that actually change (e.g. `transition-[opacity,transform]`). Use the shared easing tokens defined in `packages/core/src/styles/agent-native.css` instead of hand-typing curves: `var(--ease-drawer)` (260ms, drawers/app chrome), `var(--ease-collapse)` (200ms, expand/collapse), `var(--ease-out-strong)` (snappy entrances) — in Tailwind, `ease-[var(--ease-collapse)]`. Enter/exit with ease-out, never `ease-in`. Overlays that zoom in must set the Radix origin var (e.g. `origin-[--radix-popover-content-transform-origin]`). Animate `transform`/`opacity`, not width/height/padding/box-shadow. Gate looping or large-movement animations with `motion-reduce:`. Command palettes and keyboard-triggered actions get no animation.
|
|
52
|
+
- **Composition**: Match the workflow. Operational apps should be dense and scannable; marketing or portfolio pages can be more immersive.
|
|
53
|
+
- **Visual assets**: Websites, games, and object-focused pages need real or generated media when images help users understand the subject.
|
|
54
|
+
- **Responsive fit**: Text must not overflow buttons, cards, tabs, sidebars, or fixed-format tools. Use stable dimensions for boards, grids, toolbars, and counters.
|
|
55
|
+
|
|
56
|
+
**Beat convergence, not just defaults.** You sample toward the "on-distribution" center, so naming what to avoid is not enough: every "don't" needs a "do", or you converge on the next safe option (ban Inter and you reach for Roboto; ban purple gradients and you reach for Space Grotesk + a teal accent on every screen). Commit to one named direction, pair any reference with the reason it fits ("Linear: the quiet confidence of its spacing" — a bare "Linear" collapses back to the average), and match implementation effort to the vision: maximalist wants elaborate motion and effects, minimal wants restraint and precise spacing. When building on an existing app, inspect its tokens/type/components first and treat any drift back to a default as a missing token to pin, not something to re-prompt.
|
|
57
|
+
|
|
58
|
+
## Agent-Native UI Rules
|
|
59
|
+
|
|
60
|
+
- Agent-native apps use React, Vite, Tailwind CSS, shadcn/ui, and `@tabler/icons-react`.
|
|
61
|
+
- **Use shadcn/ui primitives for standard UI**: `DropdownMenu`, `Popover`, `Dialog`, `AlertDialog`, `Sheet`, `Tabs`, `Tooltip`, `Select`, `Command`, `Sidebar`, `Table`, `Card`, `Badge`, `Skeleton`, and related primitives.
|
|
62
|
+
- **When touching shadcn/ui components, also read `shadcn-ui` if it exists.** That skill covers `components.json`, CLI docs, component composition, theming, and registry workflows.
|
|
63
|
+
- Check `app/components/ui/` before importing a shadcn component. If a primitive is missing, add it from the app root with `pnpm dlx shadcn@latest add <component>`, then review the generated file.
|
|
64
|
+
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
65
|
+
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
66
|
+
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
67
|
+
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
68
|
+
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
69
|
+
- Custom styles belong in Tailwind classes, component CSS, or the existing global CSS theme file; avoid inline styles.
|
|
70
|
+
|
|
71
|
+
## shadcn/ui Design Rules
|
|
72
|
+
|
|
73
|
+
- Use built-in component variants first (`variant`, `size`) before overriding classes.
|
|
74
|
+
- Use semantic tokens (`bg-background`, `text-muted-foreground`, `border-border`, `bg-primary`) instead of raw Tailwind colors for app chrome and reusable components.
|
|
75
|
+
- Use `gap-*` in flex/grid layouts instead of `space-x-*` or `space-y-*`.
|
|
76
|
+
- Use `size-*` when width and height are equal, and `truncate` instead of spelling out overflow/ellipsis/nowrap.
|
|
77
|
+
- Use `cn()` from the local utils alias for conditional classes.
|
|
78
|
+
- Dialog, Sheet, Drawer, and AlertDialog content must have an accessible title. Use `sr-only` only when the visible design already communicates the title.
|
|
79
|
+
- Put menu/list items inside their group primitives: `SelectGroup`, `DropdownMenuGroup`, `CommandGroup`, and equivalents.
|
|
80
|
+
- Use full `Card` composition when the content has a title, description, content, or actions. Do not dump complex cards into a single `CardContent`.
|
|
81
|
+
- Use `ToggleGroup` for small option sets, `Switch` for binary settings, `Checkbox` for multi-select, `RadioGroup` for one-of-many, and `Slider`/inputs for numeric values.
|
|
82
|
+
- For forms, prefer the app's existing shadcn form pattern. If newer `Field`, `FieldGroup`, or `InputGroup` primitives are installed or appropriate to add, use them instead of raw layout divs.
|
|
83
|
+
- Loading states use `Skeleton`, `Progress`, `Spinner`, or the app's existing loading primitives. Empty states should have one clear next action.
|
|
84
|
+
|
|
85
|
+
## Anti-Patterns
|
|
86
|
+
|
|
87
|
+
Avoid:
|
|
88
|
+
|
|
89
|
+
- Generic AI aesthetics: purple gradients, glassy cards everywhere, vague sparkle language, decorative blobs, and context-free hero sections.
|
|
90
|
+
- Custom reimplementations of shadcn primitives.
|
|
91
|
+
- Raw color overrides on shared components when semantic tokens or variants would work.
|
|
92
|
+
- New always-visible controls for rare actions. Prefer menus, popovers, sheets, tabs, collapsibles, or advanced sections.
|
|
93
|
+
- Full-width banners, persistent helper rows, decorative cards, or explanatory chrome for status that could be a compact affordance.
|
|
94
|
+
- Treating progressive disclosure as optional. If a control is not part of the main daily workflow, hide it until context, hover, focus, or explicit user intent makes it relevant.
|
|
95
|
+
- UI cards nested inside other cards.
|
|
96
|
+
- Text or icons that resize or shift fixed-format UI on hover/loading.
|
|
97
|
+
|
|
98
|
+
## Verification
|
|
99
|
+
|
|
100
|
+
For substantial frontend work:
|
|
101
|
+
|
|
102
|
+
1. Run the relevant formatter/checks.
|
|
103
|
+
2. Start the dev server when the app needs one.
|
|
104
|
+
3. Verify with browser screenshots at desktop and mobile widths.
|
|
105
|
+
4. Check interactive states: hover, focus, loading, empty, error, and destructive confirmations.
|
|
106
|
+
|
|
107
|
+
## Related Skills
|
|
108
|
+
|
|
109
|
+
- **shadcn-ui** — shadcn CLI, component docs, composition rules, theming, and registries
|
|
110
|
+
- **self-modifying-code** — The agent can edit source code to apply design changes
|
|
111
|
+
- **storing-data** — All data lives in SQL; use actions for data access
|
|
112
|
+
- **actions** — `useActionQuery`/`useActionMutation` hooks for frontend data fetching
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: real-time-sync
|
|
3
|
+
description: >-
|
|
4
|
+
How to keep the UI in sync with agent changes via SSE plus polling fallback.
|
|
5
|
+
Use when wiring query invalidation for new data models, debugging UI not
|
|
6
|
+
updating, or understanding jitter prevention.
|
|
7
|
+
scope: dev
|
|
8
|
+
metadata:
|
|
9
|
+
internal: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Real-Time Sync
|
|
13
|
+
|
|
14
|
+
## Rule
|
|
15
|
+
|
|
16
|
+
The UI stays in sync with agent/script changes through `useDbSync()`. In-process writes stream over `/_agent-native/events` first; `/_agent-native/poll` remains the cross-process/serverless fallback. When the agent writes to the database, the UI detects the change and updates automatically — no manual refresh needed.
|
|
17
|
+
|
|
18
|
+
## Why
|
|
19
|
+
|
|
20
|
+
The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same-process writes immediately; polling bridges anything SSE cannot see, such as another serverless invocation, cron job, or external script. Every visible write increments a version counter, `useDbSync()` receives the change, and React Query invalidates the relevant caches. This is what makes database writes feel real-time without relying on aggressive polling.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
1. **Server** increments a version counter on every database write. In-process events stream through the authenticated `/_agent-native/events` endpoint.
|
|
25
|
+
|
|
26
|
+
2. **Client** listens for sync events and updates per-source change counters:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { useDbSync } from "@agent-native/core/client";
|
|
30
|
+
useDbSync({ queryClient });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries — that caused request storms in production. A successful mutating action refreshes active `useActionQuery` observers under the `["action"]` prefix. Browser actions carry a tab id so their originating tab ignores the sync echo while other tabs refresh. Legacy apps can opt into broader compatibility with `actionInvalidatePredicate`, but first-party apps should use action-backed or source-versioned query keys. Idle fallback polling runs once per minute; active agent work temporarily uses the faster cadence.
|
|
34
|
+
|
|
35
|
+
3. **Templates fold per-source counters into their query keys.** This is the pattern that makes "agent writes show up without a manual refresh" reliable:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { useChangeVersion } from "@agent-native/core/client";
|
|
39
|
+
import { useQuery } from "@tanstack/react-query";
|
|
40
|
+
|
|
41
|
+
const v = useChangeVersion("dashboards");
|
|
42
|
+
const dashboard = useQuery({
|
|
43
|
+
queryKey: ["dashboard", id, v],
|
|
44
|
+
queryFn: () => fetchDashboard(id),
|
|
45
|
+
placeholderData: (prev) => prev, // no flicker on refetch
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
When the agent writes (`update-dashboard` action → server emits `source: "dashboards"`), the counter advances, the queryKey changes, and React Query refetches that one query. The old data stays on screen during the refetch thanks to `placeholderData`.
|
|
50
|
+
|
|
51
|
+
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
|
+
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It runs every 2 seconds until SSE is connected, then relaxes to 15 seconds (`SSE_FALLBACK_INTERVAL_MS`). If SSE is disabled or unavailable (e.g., edge/serverless deployments), polling continues at the 2 s cadence. Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
|
+
|
|
55
|
+
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
|
+
|
|
57
|
+
## Don't
|
|
58
|
+
|
|
59
|
+
- Don't create manual polling loops — `useDbSync()` handles SSE plus fallback polling
|
|
60
|
+
- Don't create your own fetch-based polling alongside `useDbSync` — use the `onEvent` callback for custom handling
|
|
61
|
+
- Don't open your own `EventSource` to `/_agent-native/events`. A tab must hold exactly ONE SSE connection no matter how many features listen — extra streams eat the browser's per-origin connection budget and can starve ordinary data fetches (worst on HTTP/1.1 dev servers). Subscribe to the shared transport instead:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { subscribeSyncEvents } from "@agent-native/core/client";
|
|
65
|
+
|
|
66
|
+
const unsubscribe = subscribeSyncEvents({
|
|
67
|
+
onEvents: (events) => {
|
|
68
|
+
// filter by event.source and handle push-style updates
|
|
69
|
+
},
|
|
70
|
+
// Optional: relax your own fallback cadence while push is healthy.
|
|
71
|
+
onSseStateChange: (connected) => {},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events.
|
|
76
|
+
|
|
77
|
+
## Which sources to depend on
|
|
78
|
+
|
|
79
|
+
Common sources you'll fold into query keys:
|
|
80
|
+
|
|
81
|
+
| Source | Bumped by |
|
|
82
|
+
| ----------------- | --------------------------------------------------------------------------- |
|
|
83
|
+
| `action` | The agent runner after every successful mutating action tool call |
|
|
84
|
+
| `app-state` | Writes to `application_state` (navigation, selections, ephemeral UI state) |
|
|
85
|
+
| `settings` | Writes to the `settings` table |
|
|
86
|
+
| `dashboards` | Dashboard CRUD via `upsertDashboard` / `archiveDashboard` etc. |
|
|
87
|
+
| `analyses` | Analysis CRUD |
|
|
88
|
+
| `extensions` | Extension CRUD |
|
|
89
|
+
| `collab` | Yjs collaborative-doc updates |
|
|
90
|
+
| `screen-refresh` | Explicit `refresh-screen` agent tool call |
|
|
91
|
+
|
|
92
|
+
If a query reads data the agent can mutate via more than one path, depend on multiple sources with `useChangeVersions`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const v = useChangeVersions(["dashboards", "action"]);
|
|
96
|
+
useQuery({ queryKey: ["dashboard", id, v], ... });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`useChangeVersions` returns a single integer that advances whenever any of the listed sources advance.
|
|
100
|
+
|
|
101
|
+
## Tuning refetch behavior
|
|
102
|
+
|
|
103
|
+
To prevent cache thrashing during rapid agent writes, set `staleTime` on your queries:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
useQuery({
|
|
107
|
+
queryKey: ["items"],
|
|
108
|
+
queryFn: fetchItems,
|
|
109
|
+
staleTime: 2000, // don't refetch within 2 seconds
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Troubleshooting
|
|
114
|
+
|
|
115
|
+
| Symptom | Check |
|
|
116
|
+
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| UI not updating after agent writes | Is `useDbSync` called with the correct `queryClient`? Does the affected query have an active observer? |
|
|
118
|
+
| Poll endpoint not responding | Is `/_agent-native/poll` accessible? Is the server running? |
|
|
119
|
+
| SSE not connecting | Is `/_agent-native/events` accessible and authenticated? Polling should still keep the UI fresh as fallback. |
|
|
120
|
+
| High CPU / event storms | Use targeted source keys, settle bursty list counters, and avoid broad action invalidation. |
|
|
121
|
+
|
|
122
|
+
## Jitter Prevention
|
|
123
|
+
|
|
124
|
+
When the agent writes to application-state via script helpers (`writeAppState`, `deleteAppState`), the write is automatically tagged with `requestSource: "agent"`. This prevents the UI from overwriting active user edits when it receives the change event.
|
|
125
|
+
|
|
126
|
+
### How it works
|
|
127
|
+
|
|
128
|
+
1. **Agent writes** are tagged: the script helpers in `@agent-native/core/application-state` pass `{ requestSource: "agent" }` to the store.
|
|
129
|
+
2. **UI writes** are tagged: templates send a per-tab ID via the `X-Request-Source` header on PUT/DELETE requests to application-state endpoints.
|
|
130
|
+
3. **Sync filters**: `useDbSync()` accepts an `ignoreSource` option. The UI passes its own tab ID so it ignores events from its own writes — but still picks up events from agents, other tabs, and scripts.
|
|
131
|
+
|
|
132
|
+
### Template setup
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// app/lib/tab-id.ts
|
|
136
|
+
export const TAB_ID = `tab-${Math.random().toString(36).slice(2, 8)}`;
|
|
137
|
+
|
|
138
|
+
// app/root.tsx
|
|
139
|
+
import { TAB_ID } from "@/lib/tab-id";
|
|
140
|
+
|
|
141
|
+
useDbSync({
|
|
142
|
+
queryClient,
|
|
143
|
+
ignoreSource: TAB_ID,
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The `use-navigation-state.ts` hook sends the same `TAB_ID` in the `X-Request-Source` header when writing navigation state, so the tab that wrote the state does not refetch it.
|
|
148
|
+
|
|
149
|
+
### Why this matters
|
|
150
|
+
|
|
151
|
+
Without jitter prevention, a cycle occurs: the UI writes state, sync detects the change, the UI refetches and re-renders, potentially overwriting what the user is actively editing. With `ignoreSource`, the UI only reacts to changes from other sources (agent scripts, other browser tabs, other users).
|
|
152
|
+
|
|
153
|
+
## Action Routes and Live Sync
|
|
154
|
+
|
|
155
|
+
Actions work with the same sync system. When a mutating action writes to the database, the version counter increments and `useDbSync` picks up the change. Frontend mutations via `useActionMutation` automatically invalidate `["action"]` query keys on success, triggering refetches of `useActionQuery` hooks. Client components should call actions through those hooks, not with raw action-route fetches.
|
|
156
|
+
|
|
157
|
+
For custom apps, the best out-of-the-box path is:
|
|
158
|
+
|
|
159
|
+
1. Put read actions in `actions/` with `defineAction({ http: { method: "GET" } })`.
|
|
160
|
+
2. Put write actions in `actions/` with the default POST/PUT/DELETE behavior.
|
|
161
|
+
3. Call reads from React with `useActionQuery` and writes with `useActionMutation`.
|
|
162
|
+
|
|
163
|
+
This avoids duplicate `/api/*` JSON CRUD routes and makes agent-created records show up automatically. Raw `useQuery` can still work, but it should include `useChangeVersions(["action", "<domain-source>"])` in the query key for targeted refreshes.
|
|
164
|
+
|
|
165
|
+
### Auto-emit on mutating actions
|
|
166
|
+
|
|
167
|
+
The framework emits a change event with `source: "action"` whenever any non-read-only action runs to completion — whether called via HTTP (`/_agent-native/actions/:name`) or as an agent tool call. Read-only actions (`http: { method: "GET" }` or explicit `readOnly: true`) are skipped.
|
|
168
|
+
|
|
169
|
+
This means UIs don't need the agent to remember to call `refresh-screen` after every mutation. A listener like this (used in the `macros` template) will refresh after any mutating agent call:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
useDbSync({
|
|
173
|
+
queryClient,
|
|
174
|
+
ignoreSource: TAB_ID,
|
|
175
|
+
onEvent: (data) => {
|
|
176
|
+
if (data.requestSource === TAB_ID) return;
|
|
177
|
+
// Invalidate all useActionQuery caches so list-*, get-*, etc. refetch
|
|
178
|
+
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`refresh-screen` remains available for unusual cases — e.g. the agent mutated data via a path the framework can't see (external system the app mirrors), or the agent wants to pass a `scope` hint for narrower invalidation.
|
|
184
|
+
|
|
185
|
+
## Keeping Stateful Components In Sync
|
|
186
|
+
|
|
187
|
+
The `useChangeVersion` / `useActionQuery` pattern above keeps the **query layer** fresh. But components that copy a server value into local React state still go stale on agent edits — refetching the query updates the prop, yet the local copy never re-adopts it. This is a recurring bug.
|
|
188
|
+
|
|
189
|
+
**Never do this** for a value the agent can mutate:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
// BUG: `title` is captured once and never re-reads the prop.
|
|
193
|
+
const [title, setTitle] = useState(props.title);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
When the agent renames the record, the query refetches, `props.title` updates, but the input still shows the stale value until the component remounts.
|
|
197
|
+
|
|
198
|
+
**Derived-state surfaces (form fields, inline editors, popovers): use `useReconciledState`.** It re-adopts the authoritative external value when it changes, except while the user is actively editing that field — so agent mutations show up live without clobbering in-progress typing:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { useReconciledState } from "@agent-native/core/client";
|
|
202
|
+
|
|
203
|
+
// `active` = true while the user is editing this field (focused / dirty).
|
|
204
|
+
const [title, setTitle] = useReconciledState(props.title, { active: isEditing });
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Collaborative rich-text editors are different** — they don't copy a value into `useState`. They reconcile authoritative SQL content into a shared Y.Doc under an `updatedAt` gate with lead-client election. See `real-time-collab` → "Agent edits as a real-time peer editor". Don't reach for `useReconciledState` for a Yjs-backed editor.
|
|
208
|
+
|
|
209
|
+
| Surface | Keep it fresh with |
|
|
210
|
+
| ------- | ------------------ |
|
|
211
|
+
| React Query reads | `useChangeVersion` / `useActionQuery` (above) |
|
|
212
|
+
| Local edit state copied from a server value (inputs, popovers, inline editors) | `useReconciledState(externalValue, { active })` |
|
|
213
|
+
| Collaborative rich-text editor (Yjs) | `updatedAt`-gated reconcile + `isReconcileLeadClient` — see `real-time-collab` |
|
|
214
|
+
|
|
215
|
+
## Granular server-side merge for non-body fields
|
|
216
|
+
|
|
217
|
+
For structured documents (slide decks, form builders, design files) where the
|
|
218
|
+
Yjs body collab would cause LWW conflicts at the container level, pair the
|
|
219
|
+
change-sync `updatedAt` bump with a **granular server-side merge action** that
|
|
220
|
+
accepts targeted per-item operations (add/patch/delete/reorder). Concurrent
|
|
221
|
+
edits to different items both survive at the action level; the `collab` source
|
|
222
|
+
version bump then propagates the merged state to all open clients. See
|
|
223
|
+
`real-time-collab` for the pattern and examples.
|
|
224
|
+
|
|
225
|
+
## Related Skills
|
|
226
|
+
|
|
227
|
+
- **storing-data** — Application-state and settings are data stores that sync through change events
|
|
228
|
+
- **context-awareness** — Navigation state writes use jitter prevention to avoid overwriting active edits
|
|
229
|
+
- **actions** — Mutating actions trigger change events
|
|
230
|
+
- **client-methods** — Route details belong in helpers/hooks, not components
|
|
231
|
+
- **self-modifying-code** — Agent code edits trigger change events; rapid edits can cause event storms
|
|
232
|
+
- **real-time-collab** — Collaborative editors reconcile agent edits into a shared Y.Doc, driven by the same change-sync `updatedAt` bump; also the granular server-side merge pattern for structured data
|