From d546f76bc4cba22083982ba5d3849b4e49f604ff Mon Sep 17 00:00:00 2001 From: Carlos Date: Sat, 9 May 2026 13:01:49 +0200 Subject: [PATCH 1/5] chore(skills): update skill version to 1.11.0 and enhance documentation - Bump the skill version to 1.11.0, reflecting new capabilities and triggers. - Add new guidance for skill loading in AGENTS.md, including instructions for skill checks and loading preferences. - Update SKILL.md and registry.json to include additional triggers and capabilities related to schema metadata and AI tool integration. - Ensure consistency across documentation files to improve clarity and usability for developers. This update aims to enhance the skill's functionality and provide clearer instructions for users implementing the TanStack Fullstack Pattern. --- .../SKILL.md | 123 ++++++++++---- AGENTS.md | 10 ++ scripts/skills/buildSkills.test.ts | 4 +- ...stack-promptable-fullstack-app-template.md | 127 +++++++++++---- skills/registry.json | 26 ++- ...omptable-fullstack-app-template.skill.yaml | 154 ++++++++++++++---- 6 files changed, 353 insertions(+), 91 deletions(-) diff --git a/.agents/skills/tanstack-promptable-fullstack-app-template/SKILL.md b/.agents/skills/tanstack-promptable-fullstack-app-template/SKILL.md index 6cccc5d..94582af 100644 --- a/.agents/skills/tanstack-promptable-fullstack-app-template/SKILL.md +++ b/.agents/skills/tanstack-promptable-fullstack-app-template/SKILL.md @@ -8,7 +8,7 @@ description: 'Use when scaffolding a new TanStack Start project, adding domain instead of training data. Project: TanStack AI-Promptable Full-Stack Template. Triggers on "fullstack template", "TanStack Start project", "repository pattern", "interface-first", "new app scaffold", "nested routes", "layout - route", "beforeLoad", "tanstack cli".' + route", "beforeLoad", "tanstack cli", "tanstack intent", "package skills".' --- > This file is generated from `skills/src/*.skill.yaml`. Do not edit manually. @@ -16,7 +16,7 @@ description: 'Use when scaffolding a new TanStack Start project, adding domain An interface-first fullstack architecture built on TanStack Start. The pattern defines clear interface boundaries between layers -- interfaces are rigid, implementations are swappable. -> **Companion documentation:** In repositories built from this template, [AGENTS.md](https://github.com/carlosvin/tanstack-fullstack-ai-template/blob/main/AGENTS.md) holds the project handbook -- file structure, Mantine styling, auth snippets, Biome, testing/E2E commands, and the full validation checklist. This skill focuses on the architectural contract; refer to AGENTS.md for operational detail. +> **Companion documentation:** In repositories built from this template, [AGENTS.md](https://github.com/carlosvin/tanstack-fullstack-ai-template/blob/main/AGENTS.md) holds the project handbook -- file structure, chosen UI-library styling, auth snippets, Biome, testing/E2E commands, and the full validation checklist. This skill focuses on the architectural contract; refer to AGENTS.md for operational detail. ## Pattern Overview @@ -27,7 +27,7 @@ An interface-first fullstack architecture built on TanStack Start. The pattern d ## Rigid Rules (Must Follow) 1. Interface-first services: every external service (database, AI, observability) is accessed through an interface. -2. End-to-end type safety via schemas: every boundary uses a Zod/ArkType schema as the type source (`z.infer<>`). Never hand-write `type` for wire data. Service interfaces (`ReadRepository`, `AIAdapterService`, etc.) are hand-written contracts -- they define behaviour, not wire shapes. +2. End-to-end type safety via schemas: every boundary uses a Zod/ArkType schema as the type source (`z.infer<>`). Never hand-write `type` for wire data. Service interfaces (`ReadRepository`, `AIAdapterService`, etc.) are hand-written contracts -- they define behaviour, not wire shapes. Prefer schema metadata and introspection (`.describe()`, route `validateSearch`, tool schemas, router `staticData`, JSON Schema output) over hand-maintained AI metadata. 3. Three schema layers: repository (DB-shaped), server-function / AI-tool (API-shaped, shared), router search-param (URL-shaped). Mappers translate between layers. 4. Repository contracts use repository-layer schemas only. 5. Server functions and AI tools share the same tools-layer schemas (`.inputValidator(Schema)` / `toolDefinition({ inputSchema })`). Both parse with `Schema.parse(args)`. @@ -39,29 +39,33 @@ An interface-first fullstack architecture built on TanStack Start. The pattern d 11. Query pattern: GET server functions throw on failure for centralized error handling. When possible, use static server functions for performance improvements. 12. Maximize AI tool coverage: expose **every** repository method (reads and writes) via `createSafeServerTool()` so failures return `{ error, code }`. If a server function exists, it gets a tool. 13. Router capabilities as AI client tools: expose `router.navigate()` and `router.invalidate()` as client tools via `toolDefinition()`. -14. AI system prompt context: `buildSystemPrompt()` injects three context blocks into every AI chat request. (a) **Current User** — name, email, role from the auth middleware context (server-side; no client round-trip needed). (b) **Browser Context** — timezone, locale, and current date/time from `browserContext` sent by `ChatDrawer` (client-side). (c) **Current Location** — pathname, search params, and full URL from `browserContext`; route patterns (e.g. `/tasks/$taskId`) are matched to resolve dynamic segments. The navigation manifest mirrors `routeTree.gen.ts` and lists each route's search params. When adding routes, update `navigationManifest.ts` and add pattern-matching in `buildSystemPrompt()` for new dynamic segments. +14. AI system prompt context: `buildSystemPrompt()` injects context into every AI chat request from the single request context and the client ticket sent by the chat UI. Keep the request context flat (for example `{ ticket, client }` inside TanStack's `ctx.context`) and destructure it early in handlers; do not introduce nested custom context wrappers. Include current user, browser context, and current location. Derive route patterns and search params from live router/schema metadata where possible instead of maintaining static route tables. 15. JSDoc on exports: every exported function, interface, type, and constant gets a JSDoc comment stating *what* and *why*. -16. AI chat drawer: render the AI chat in a Mantine `Drawer` (`position="right"`, `size="lg"`) mounted at the root layout level so messages persist across navigation. `useDisclosure` controls open/close. See AGENTS.md section 8 for rendering details. -17. AI renders rich markdown: use `react-markdown` + `remark-gfm` for assistant messages. Tables/code styled via `.markdown` CSS Module with Mantine CSS variables. Internal links render as TanStack Router `Link` with `preload="intent"` (client-side navigation without losing chat). External links open in a new tab. The AI uses markdown links in replies (e.g. `[Pending tasks](/tasks?status=pending)`). +16. AI chat drawer: render the AI chat in the chosen UI library's right-side drawer/panel component mounted at the root layout level so messages persist across navigation. The template's default is a Mantine `Drawer` (`position="right"`, `size="lg"`), but generated apps may swap the component library when the user chooses a different stack. +17. AI renders rich markdown: use `react-markdown` + `remark-gfm` for assistant messages. Tables/code are styled through the chat markdown container using the chosen design system's theme tokens or CSS variables. Internal links render as TanStack Router `Link` with `preload="intent"` (client-side navigation without losing chat). External links open in a new tab. The AI uses markdown links in replies (e.g. `[Pending tasks](/tasks?status=pending)`). 18. Thin routes: route files contain only route config (`createFileRoute`, `validateSearch`, `loaderDeps`, `loader`, `component`). Page UI lives in `src/components/PageName/PageName.tsx`. 19. Promptable by default: check AI availability at the root loader level via `getAIAvailability()`. Only render the chat trigger and drawer when AI is configured — no disabled-state fallback. 20. Icon library: use `lucide-react` as the default icon library. Keep one icon library per project for visual consistency. 21. Structured logging: use `pino` for all server-side logging instead of `console.*`. Configure `@sentry/pino-transport` so error-level logs are automatically forwarded to Sentry when `VITE_SENTRY_DSN` is set. The logger singleton lives in `src/services/logger.ts`. 22. Build-time app version: extract the semver version from `package.json` at build time via Vite `define` and expose it as `__APP_VERSION__`. Inject it into Sentry (`release`), the pino logger (`version` field), and any other observability tool. -23. Latest dependencies: install and keep dependencies at latest compatible versions. Never pin exact versions unless a known incompatibility exists. Use `pnpm add ` (no version suffix); run `pnpm outdated` and `pnpm update` to align the lockfile. +23. Dependency discipline: avoid installing unnecessary packages. Prefer existing project dependencies and platform APIs. When a package is truly required by the chosen stack, requested capability, or validation contract, use the latest stable compatible version via the package manager (`pnpm add ` with no guessed version suffix unless a known incompatibility requires a pin); run `pnpm outdated` and `pnpm update` to align the lockfile. 24. Ask for LLM provider: when scaffolding a new project or when the user's LLM preference is unclear, ask which provider they want before writing the adapter. Install only the chosen `@tanstack/ai-*` adapter package and configure matching env vars. Default is `@tanstack/ai-openai`; do not assume OpenAI without asking. See AGENTS.md section 8 for the full provider table. 25. Generate the system prompt: when scaffolding a new app, ask the user about their domain — entities, capabilities, and permissions — then generate a tailored `BASE_SYSTEM_PROMPT` in `src/routes/api/chat.ts` with six sections (Capabilities, Data Model, Links and navigation, Mutations and data refresh, Permissions and errors, Guidelines). Do not reuse the template's task-management prompt. `buildSystemPrompt()` composes this base with dynamic context (rule 14) and the navigation manifest. `chat()` from `@tanstack/ai` receives it via `systemPrompts: string[]`. See AGENTS.md section 8 "System Prompt Generation" for the full template. -26. Repository-resolved authorization: `authMiddleware` extracts JWT claims **and** calls a repository method (e.g. `getReadRepository().getUserAccess(email)`) to enrich `AuthContext` with application-defined access data — roles, group memberships, owned scopes, superuser flags. Downstream guards (`requireAuth`, `requireGroup`, any app-specific `requireOwnerOf`) and AI tools read this enriched context so UI and AI see the same permission signals. Authorization checks live **inside** server-function handlers (not only in UI components), so permissions are enforced regardless of whether the caller is the UI, the AI, or a direct HTTP client. -27. Write attribution via traceability context: `WritableRepository` methods accept an optional `TraceabilityContext` (`createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate`) built from the authenticated identity. Mutation server-function handlers construct it from `ctx.context.user.email` (available after `requireAuthMiddleware`) and pass it to the repository. Seed and production implementations apply it consistently. This gives UI and AI callers the same audit trail without duplicating logic at each call site. -29. Explicit agent loop depth: configure `agentLoopStrategy: maxIterations(N)` explicitly on the `chat()` call (default N=10). This caps the number of consecutive tool-calling iterations the AI can run before returning a final answer, which bounds latency, cost, and infinite-loop risk. Tune N only after measuring; do not rely on the framework default. -30. Public runtime config bridge: expose non-secret runtime config (Sentry DSN, environment name, feature flags) via a GET server function `getPublicEnv()` and inline the result as `window.__ENV__` in the root `RootDocument` using a small `