brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
nuqs-scaffolderScaffolds URL-state filters for a Next.js page — typed `searchParams.ts` parser map and a `<Filters />` client component backed by `useQueryStates`. From a single JSON spec, generates four files in lockstep — client parser map, server loader/cache/serializer, client component, and Vitest test — all sharing the same parser definitions per the nuqs Standard S…
Independent GitHub snapshot · Automated classification · Original documentation governs
searchParams.ts parser map and a <Filters /> client component backed by useQueryStates. From a single JSON spec, generates four files in lockstep — client parser map, server loader/cache/serializer, client component, and Vitest test — all sharing the same parser definitions per the nuqs Standard Schema pattern. Trigger even when the user only says "add filters to /search" or "I need a typed query string for this page" — both are exactly this skill's job.Generate a coherent set of nuqs files from one spec. The skill is template-driven — you read the spec, copy the templates, and substitute placeholders. No build step, no codegen runtime; the templates ARE the artifact.
Use this skill when:
useState filters onto nuqssearchParams.server.ts already exports the schemaIf the codebase has legacy nuqs patterns instead, run the nuqs-codemod-runner skill first.
assets/templates/spec.template.json and fill in name, module, and params. See "Spec Format" below.config.json (overridable per-call).The agent does the rendering — Claude is the templating engine. Each template is annotated with markers (/*= ... =*/) that name the placeholder slot and document the substitution rule.
{
"name": "Search", // PascalCase — drives the exported symbol names
"module": "search", // kebab-case — drives file paths and the "module" folder
"params": {
"q": { "type": "string", "default": "" },
"page": { "type": "integer", "default": 1 },
"limit": { "type": "integer", "default": 10 },
"categories": { "type": "array-of-string-native", "default": [] },
"sort": { "type": "string-literal", "values": ["asc","desc"], "default": "asc" },
"minPrice": { "type": "float", "default": null },
"lastSeen": { "type": "iso-date", "default": null }
}
}
type valuestype | Parser used | Notes |
|---|---|---|
string | parseAsString | |
integer | parseAsInteger | |
float | parseAsFloat | |
boolean | parseAsBoolean | |
iso-date | parseAsIsoDate | Date-only |
iso-date-time | parseAsIsoDateTime | Date + time |
timestamp | parseAsTimestamp | ms since epoch |
hex | parseAsHex | Numeric value, hex URL form |
index | parseAsIndex | 0-based in code, 1-based in URL |
array-of-string | parseAsArrayOf(parseAsString) | ?tags=a,b,c |
array-of-string-native | parseAsNativeArrayOf(parseAsString) | ?tag=a&tag=b — requires nuqs ≥ 2.7 |
string-literal | parseAsStringLiteral(values) | Requires values: string[] |
number-literal | parseAsNumberLiteral(values) | Requires values: number[] |
json | parseAsJson(SchemaName.parse) | Generates a Zod schema stub; mark default separately |
If default is null, the param is nullable; otherwise the template uses .withDefault(...).
| Template | Renders to (default) | Loaded when |
|---|---|---|
searchParams.ts.template | lib/{module}-search-params.ts | Always |
searchParams.server.ts.template | lib/{module}-search-params.server.ts | Always |
filters.tsx.template | components/{module}/{name}-filters.tsx | Always |
filters.test.tsx.template | components/{module}/{name}-filters.test.tsx | If config.generate_tests is true |
spec.json.template | Anywhere — starter for the user | First-run prompt |
Template files end in .template so editors don't apply syntax highlighting to placeholder markers — the original extension is preserved as the suffix-before-.template so you can still tell at a glance what the rendered file will be.
Paths are configurable in config.json — override globs, file naming style (kebab vs PascalCase), and whether tests are emitted.
All templates use the same placeholder syntax. The agent substitutes them in one pass:
| Placeholder | Source | Example |
|---|---|---|
__NAME__ | spec.name | Search |
__name__ | camelCase form of spec.name | search |
__module__ | spec.module | search |
/*= PARSERS =*/ | Iterate spec.params → key: parseAsXxx.withDefault(...) lines | see template |
/*= COMPONENT_FIELDS =*/ | Iterate spec.params → one input/select per type | see template |
/*= TEST_CASES =*/ | Iterate spec.params → one assertion per default | see template |
/*= NULLABLE_IMPORTS =*/ | Add Nullable helper import if any param is nullable | conditional |
/*= ZOD_SCHEMAS =*/ | For json type params, emit a Zod schema stub | conditional |
/*= ... =*/ markers are instructions to the agent, not literal substitutions. Replace the entire marker (including the /*= =*/ delimiters) with the expanded content.
Read references/conventions.md for:
app/config.json is pre-populated with sensible Next.js App Router defaults. Override only if your repo uses different conventions:
{
"lib_dir": "lib",
"components_dir": "components",
"generate_tests": true,
"test_runner": "vitest"
}
On first use, the agent should ask the user for the spec via AskUserQuestion if no spec file is provided.
nuqs — Best-practice reference these templates encode. Read it to understand WHY the templates are shaped this way.nuqs-codemod-runner — Run BEFORE this skill if migrating an existing page from pre-v2.5 nuqs.See gotchas.md for edge cases discovered during use.