sdk
Skill4 starsChanged 2 months agoMITView on GitHub
Generate the typed SDK from backend controllers. Use after creating or modifying controllers to make them available to frontend. Use this skill whenever backend endpoints change and the frontend SDK needs regeneration.
- Reads credentials
- Deletes or force-pushes
We split this skill into the rules it gives an agent
15 rules. 0 are common, 11 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 10 edited versions we read keep these.
11
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 20
After creating or modifying any controller (new endpoint, changed schema)
- Distinctive: line 21
After adding new enums or error types used in controllers
- Distinctive: line 22
When the frontend needs to call a new or updated API endpoint
- Distinctive: line 23
After changing HTTP methods, paths, or response shapes in controllers
- Distinctive: line 27
No controller changes were made (only backend-internal changes)
- Distinctive: line 29
Only documentation or test changes were made
- Distinctive: line 51
Wait for the server to start.
- Distinctive: line 77
Check that the SDK was generated correctly:
- Very specific: line 181
Check controller is exported in controllers/index.ts
- Very specific: line 182
Check router is wired into the ROUTERS map in packages/api/typescript/src/routers.ts
- Very specific: line 196
Delete generated files: rm -rf packages/client/src/app packages/client/src/api
- Very specific: line 279
Import directly from @codm/client-typescript/typescript.
- Distinctive: line 292
Never duplicate types locally that are already available in the SDK.
- Distinctive: line 323
If the field is needed, it must be in the SDK type.
- Distinctive: line 351
When the cast involves an SDK enum, always use the enum directly.
“Common” is measured: kept by at least 6 in 10 of the 10 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Generate SDK
Generates the typed SDK from backend OpenAPI specification, making hooks, types, and schemas available for frontend development.
Why the SDK Is Auto-Generated
- The SDK is auto-generated from backend controller schemas (InputSchema/OutputSchema), producing typed React hooks, Zod validation schemas, TypeScript types, and query key functions — all derived from the single source of truth (the controller)
- The frontend never manually defines API types or validation — everything stays synchronized with the backend automatically
- Query key functions ensure cache invalidation is always correct and refactor-safe
- Zod schemas are reused for route
validateSearchand formvalidators.onSubmit, so URL params and form inputs are validated against the same contract the backend enforces - HTTP functions (from
@codm/client-typescript/typescript) are for external consumers/integration boundaries, not for internalapicross-context orchestration
When to Use This Skill
- After creating or modifying any controller (new endpoint, changed schema)
- After adding new enums or error types used in controllers
- When the frontend needs to call a new or updated API endpoint
- After changing HTTP methods, paths, or response shapes in controllers
When NOT to Use This Skill
- No controller changes were made (only backend-internal changes)
- Changes are limited to use cases, entities, or repositories that don't affect controller schemas
- Only documentation or test changes were made
Prerequisites
- Backend controllers created and exported
- Backend server must be running
- Router wired into the
ROUTERSmap inpackages/api/typescript/src/routers.ts
Process
Step 1: Start Backend Server
In one terminal, start the backend:
# From monorepo root
bun dev
# Or backend only via Nx
bun x nx run api:devWait for the server to start. You should see:
Server running on http://localhost:{PORT}Port will be an arbitrary value defined on the .env, usually being the one included in .env.example
Step 2: Generate SDK
In another terminal, generate the SDK:
# From monorepo root
bun sdkThis runs:
- Go channel OpenAPI emitter (
go run ./cmd/openapi) — producespackages/channel/public/docs/openapi.json - Kubb generation for both template + channel targets — reads OpenAPI specs, generates TypeScript code in
packages/client/src/ pluginZodRefinementspost-processor (AST-based) — appliesx-zod-refinements, enum linking,x-unknown, event folders, discriminatedUnion rewrite, and variant accessors- Builds the SDK package
There are no pre/post-patches. Both pipelines are unified in packages/client/scripts/sdk.ts.
Step 3: Verify Generation
Check that the SDK was generated correctly:
# Check generated files
ls -la packages/client/src/app/You should see:
packages/client/src/
├── api/ # Backend-only functions
│ ├── http/ # HTTP client functions
│ └── index.ts # Barrel export
├── app/ # Frontend hooks and types
│ ├── hooks/ # React Query hooks
│ ├── types/ # TypeScript types
│ ├── zod/ # Zod schemas
│ └── index.ts # Barrel export
└── http.ts # Base HTTP clientStep 4: Verify OpenAPI Spec (Optional)
Open the docs UI to see all endpoints:
http://localhost:{PORT}/shared/internal/docsWhat Gets Generated
Hooks (Frontend)
// Import from @codm/client-typescript/typescript
import {
useCreateProduct, // POST /product
useUpdateProduct, // PUT /product/:id
useDeleteProduct, // DELETE /product/:id
useGetProduct, // GET /product/:id
useListProducts, // GET /product
} from '@codm/client-typescript/typescript'Types (Frontend & Backend)
import type {
CreateProductMutationRequest, // Input type
CreateProductMutationResponse, // Output type
ListProductsQueryParams, // Query params
ListProductsQueryResponse, // List response
} from '@codm/client-typescript/typescript'Zod Schemas (Frontend)
import {
createProductMutationRequestSchema, // For form validation
listProductsQueryParamsSchema, // For URL validation
} from '@codm/client-typescript/typescript'Query Keys (Frontend)
import {
createProductMutationKey,
listProductsQueryKey,
getProductQueryKey,
} from '@codm/client-typescript/typescript'
// Usage for cache invalidation
queryClient.invalidateQueries({ queryKey: listProductsQueryKey() })HTTP Functions (External Consumers)
// Import from @codm/client-typescript/typescript
import {
createProduct,
getProduct,
listProducts,
} from '@codm/client-typescript/typescript'
// Use in external consumers (outside api/)
const product = await getProduct({ id: productId })Inside api/, prefer repository reads for cross-context validations and/or integration events instead of SDK calls.
Troubleshooting
"Connection refused" Error
Backend server is not running. Start it first:
bun x nx run api:devControllers Not Appearing in SDK
- Check controller is exported in
controllers/index.ts - Check router is wired into the
ROUTERSmap inpackages/api/typescript/src/routers.ts - Restart backend and regenerate SDK
Type Errors After Regeneration
Clear TypeScript cache and restart IDE:
rm -rf node_modules/.cache
# Restart VS Code / IDESDK Not Updating
- Stop backend server
- Delete generated files:
rm -rf packages/client/src/app packages/client/src/api - Restart backend
- Regenerate SDK
When to Regenerate
Regenerate the SDK when:
- Creating new controllers
- Modifying InputSchema or OutputSchema
- Adding new errors (they appear in response types)
- Changing HTTP methods or paths
- Adding new contexts
Checklist
- Backend server running
- Controllers exported in index.ts
- Router wired into the ROUTERS map in packages/api/typescript/src/routers.ts
bun sdkcompleted successfully- Hooks available in
@codm/client-typescript/typescript - Types available for import
- OpenAPI docs show all endpoints
Example Workflow
# 1. Create controller
bun cli controller product CreateProduct
# 2. Edit controller with schemas
# ... edit product/controllers/CreateProduct.ts ...
# 3. Export controller
# ... edit product/controllers/index.ts ...
# 4. Start backend (in terminal 1)
bun x nx run api:dev
# 5. Generate SDK (in terminal 2)
bun sdk
# 6. Use in frontend
import { useCreateProduct } from '@codm/client-typescript/typescript'Frontend Usage Example
import { createFileRoute } from '@tanstack/react-router'
import {
useListProducts,
useCreateProduct,
listProductsQueryParamsSchema,
createProductMutationRequestSchema,
listProductsQueryKey,
type CreateProductMutationRequest,
} from '@codm/client-typescript/typescript'
import { useQueryClient } from '@tanstack/react-query'
export const Route = createFileRoute('/products/')({
validateSearch: search => listProductsQueryParamsSchema.parse(search),
component: ProductsPage,
})
function ProductsPage() {
const search = Route.useSearch()
const queryClient = useQueryClient()
const { data, isLoading } = useListProducts({ params: search })
const createProduct = useCreateProduct()
const handleCreate = async (data: CreateProductMutationRequest) => {
await createProduct.mutateAsync({ data })
await queryClient.invalidateQueries({ queryKey: listProductsQueryKey() })
}
// ...
}Bad Practices
bp-01: Re-exporting SDK schemas unnecessarily
Import directly from @codm/client-typescript/typescript. Never re-export SDK schemas.
// ❌ WRONG
export { listPatientsQueryParamsSchema }// ✅ CORRECT - Importar diretamente da SDK
import { listPatientsQueryParamsSchema } from '@codm/client-typescript/typescript'bp-02: Creating local types that should come from the SDK
Never duplicate types locally that are already available in the SDK.
// ❌ WRONG
export type PatientStatus = 'ativo' | 'inativo' | 'novo' | 'cancelado'// ✅ CORRECT
import { type PatientStatusEnum } from '@codm/client-typescript/typescript'bp-03: Creating local interface instead of inferring from SDK
Infer types from SDK response types instead of creating manual interfaces.
// ❌ WRONG
interface ConsultationItem {
readonly scheduledDate: string
readonly service: string
readonly status: string
}// ✅ CORRECT
import type { ListPatientDetails200 } from '@codm/client-typescript/typescript'
type ConsultationItem = ListPatientDetails200['consultations'][number]bp-04: Type assertion to access fields that don't exist in the type
If the field is needed, it must be in the SDK type. Fix the backend contract instead of casting.
// ❌ WRONG
const updatedAt = (patient as { updatedAt?: string }).updatedAtbp-05: Hardcoding tabs/options instead of using SDK enums
Derive options from SDK enums with Object.values(), don't create manual arrays.
// ❌ WRONG
const tabs = [
{ id: 'todos', label: 'Todos' },
{ id: 'recentes', label: 'Recentes' },
]// ✅ CORRECT
import { patientTabEnum } from '@codm/client-typescript/typescript'
const tabs = Object.entries(patientTabEnum).map(([key, value]) => ({
id: value,
label: tabLabels[value],
}))bp-06: Using indexed access type on SDK types instead of enum directly
When the cast involves an SDK enum, always use the enum directly. Never use indexed access on request/response types as a shortcut for enums.
// ❌ AVOID
field.handleChange(val as CreateServiceMutationRequest['specialty'])// ✅ CORRECT
import { SpecialtyEnum } from '@codm/client-typescript/typescript'
field.handleChange(val as SpecialtyEnum)bp-07: SDK bundling its own copy of global dependencies (Zod, React Query)
Libraries that the app needs to configure globally (Zod, React, React Query) must be peerDependencies in the SDK to ensure a single instance. If in dependencies, rslib bundles a separate copy, causing issues like Zod i18n not applying to SDK schemas and MutationCache.onError not capturing SDK mutation errors.
References
docs/BACKEND.md— SDK Generation sectiondocs/FRONTEND.md— SDK Usage section
Other versions11 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 11
- kortix-ai/suna★ 20ksame name
- one-ie/one★ 132same name
- tinyhumansai/tiny.place★ 132same name
- ArangoGutierrez/claude-toolkit★ 4same name
- 0mlkrizzz655335v/claude-skills-zh★ 2same name
- aiperceivable/apcore-skills★ 1same name
- Goodnessmbakara/codex-skills★ 1same name
- JameMy0001/antigravity-skills-hub★ 1same name
- leishifu666/skills★ 1same name
- filipefalcaofs/repo-padrao★ 0same name
1 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository45 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agentSkill
- bounded-contextSkill
- clean-branchSkill
- commitSkill
- componentSkill
- controllerSkill
- db-modellingSkill
- ddd-modelingSkill
- ddd-specSkill
- design-systemSkill
- desktop-shellSkill
- e2eSkill
- entitySkill
- enumSkill
- errorsSkill
- eventSkill
- formSkill
- grill-with-docsSkill
- handlerSkill
- handoffSkill
- middlewareSkill
- migrateSkill
- prdSkill
- primitiveSkill
- projectionSkill
- projectorSkill
- querySkill
- repositorySkill
- reviewSkill
- routeSkill
- saas-researchSkill
- schedulerSkill
- schemaSkill
- serviceSkill
- spec-reviewSkill
- storeSkill
- storybookSkill
- task-breakdownSkill
- testSkill
- trace-analysisSkill
- ui-compositionSkill
- usecaseSkill
- user-storiesSkill
- value-objectSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

