Generative-UI sandbox kit
Write the sandbox-kit docs for @dudousxd/nestjs-agent alongside the generated client.
@dudousxd/nestjs-agent can render
generative UI in a sandbox in your design system, whatever its stack: your styles (Tailwind,
Bootstrap, Sass, plain CSS), your React components (shadcn components/ui by default, MUI, your
own) and your providers. The model is told which components exist and what props they take, and
what your styles offer (Tailwind tokens, or the CSS classes they define), from a
descriptor, .genui/sandbox-kit.json, that the Nest server reads relative to the app root.
The genuiSandboxKit() extension, built into @dudousxd/nestjs-codegen, writes that
descriptor on every codegen pass: one-off nestjs-codegen codegen, --watch, and the Nest
module's watcher. It takes the same options as the agent's Vite plugin
(genuiSandboxKit() from @dudousxd/nestjs-agent/vite). The component names and props are read
from their TypeScript types, and the styles are compiled and read, by
writeSandboxKitDocs from @dudousxd/nestjs-agent-core/genui/kit, an optional peer
dependency:
pnpm add -D @dudousxd/nestjs-agent-core@">=0.53.0"import { defineConfig, genuiSandboxKit } from '@dudousxd/nestjs-codegen';
export default defineConfig({
contracts: { glob: 'src/**/*.controller.ts' },
codegen: { outDir: 'src/generated' },
extensions: [
genuiSandboxKit({
components: 'web/components/ui', // default: the first shadcn `components/ui` dir found
styles: 'web/styles/globals.css', // Tailwind tokens or CSS classes, and the theme's variables
}),
],
});Options
| Option | Default | What it does |
|---|---|---|
components | the first of inertia/, resources/js/, src/, app/, or the root components/ui that exists | Modules whose exports are the kit's React components: files, globs, directories or packages. |
styles | — | The app's style entry files (plain CSS, Sass, a Tailwind stylesheet…). With Tailwind, the model is told your theme tokens and utilities; otherwise the classes the CSS defines. Either way it gets the root custom properties as the theme. |
wrapper | — | A module whose default export wraps the model's App (theme providers). It is recorded in the docs; the agent's Vite plugin bundles it. |
stylesDocs | — | Guidance on the styles for the model: a markdown file, or the text itself. |
tsconfig | the project's | The tsconfig the component prop types are read through. |
output | .genui/sandbox-kit.json | Where the descriptor is written, relative to the app cwd (or absolute). |
generate | writeSandboxKitDocs | Replace the docs writer (tests, or another generator). It receives { root, output, components?, styles?, wrapper?, stylesDocs?, tsconfig? } and is expected to write output itself. |
Migration from 0.28
include and entry are now components, and css is now styles. Passing the old options throws a CodegenError that names the replacement. It needs @dudousxd/nestjs-agent-core >= 0.53.
A project with no kit (no components match, no components/ui, no styles) writes
nothing; the extension is a no-op there. Without generate and without
@dudousxd/nestjs-agent-core installed, codegen fails with an error naming the package to
install.
Freshness and watch mode
The descriptor lives outside outDir, so the extension writes it directly rather than
through emitFiles, and nothing it does collides with the core's output files. It declares
the kit files, their directories, the stylesheets (and the files they @import) and the descriptor itself through
ctx.trackInput, so:
- editing a component, adding one to the kit directory, or editing a stylesheet regenerates the descriptor, in both watch mode and the next one-off run;
- a deleted descriptor (e.g.
.genui/is gitignored and the checkout is fresh) is rewritten even when everything else is up to date.
The writer leaves an unchanged descriptor untouched, so a regenerate that changes nothing does not trigger a reload in the server.