ai-sdk-model-manager
Manages AI SDK model configurations - updates packages, identifies missing models, adds new models with research, and updates documentation
Guides CRUD operations for API resources with cascading dependencies, descriptive validation, and orphan prevention. Use when adding delete/remove operations, creating validation logic, building resources that depend on other resources, or when the user mentions "cascade
$ npx -y skills add tambo-ai/tambo --skill api-resource-lifecycle --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/api-resource-lifecycleContext preview
The summary Claude sees to decide when to auto-load this skill.
Guides CRUD operations for API resources with cascading dependencies, descriptive validation, and orphan prevention. Use when adding delete/remove operations, creating validation logic, building resources that depend on other resources, or when the user mentions "cascade
name: api-resource-lifecycle description: Guides CRUD operations for API resources with cascading dependencies, descriptive validation, and orphan prevention. Use when adding delete/remove operations, creating validation logic, building resources that depend on other resources, or when the user mentions "cascade delete", "orphan records", "duplicate detection", "validation errors", "resource cleanup", or "rollback on failure". metadata: internal: true
Patterns for building reliable CRUD operations in Tambo Cloud.
Default to `onDelete: "cascade"` in the schema. Only use manual transaction cascades when deletion requires external API calls, metadata cleanup, or cross-reference logic.
// packages/db/src/schema.ts
export const skills = pgTable("skills", {
id: text("id").primaryKey(),
projectId: text("project_id")
.notNull()
.references(() => projects.id, { onDelete: "cascade" }),
// ...
});When deletion requires cleanup beyond FK cascades (external APIs, metadata, cross-references), wrap in a transaction:
// packages/db/src/operations/project.ts
export async function deleteProject(db: HydraDb, id: string): Promise<boolean> {
return await db.transaction(async (tx) => {
await tx
.delete(schema.providerKeys)
.where(eq(schema.providerKeys.projectId, id));
await tx.delete(schema.apiKeys).where(eq(schema.apiKeys.projectId, id));
await tx
.delete(schema.projectMembers)
.where(eq(schema.projectMembers.projectId, id));
const deleted = await tx
.delete(schema.projects)
.where(eq(schema.projects.id, id))
.returning();
return deleted.length > 0;
});
}**Reference:** `packages/db/src/operations/project.ts` lines 255-278
When a resource is replaced (not deleted), clear dependent metadata so dependents re-sync under the new resource:
// apps/web/server/api/routers/project.ts - addProviderKey
// When replacing a provider key, clear skill metadata for that provider
const skills = await operations.listSkillsForProject(ctx.db, projectId);
await Promise.all(
skills
.filter((s) => s.externalSkillMetadata?.[providerName])
.map(async (s) => {
const { [providerName]: _, ...remaining } = s.externalSkillMetadata ?? {};
return operations.updateSkill(ctx.db, {
projectId,
skillId: s.id,
externalSkillMetadata: remaining,
});
}),
);**Reference:** `apps/web/server/api/routers/project.ts` lines 863-880
Every error must say what went wrong and what to do instead. Include the specific value that failed and an example of what's valid.
// Zod: include format example
name: z.string().min(1, "Name is required").max(64)
.regex(SKILL_NAME_PATTERN, "Name must be kebab-case (e.g. scheduling-assistant)"),
// tRPC: include the conflicting value
throw new TRPCError({
code: "CONFLICT",
message: `Server key "${serverKey}" is already in use by another MCP server in this project`,
});| Situation | tRPC Code | When to use | | ----------------------- | ----------------------- | ------------------------------------- | | Resource not found | `NOT_FOUND` | ID lookup returned null | | Input validation failed | `BAD_REQUEST` | Zod schema or business rule violation | | Duplicate resource | `CONFLICT` | Name/key already exists | | Unexpected failure | `INTERNAL_SERVER_ERROR` | Catch-all for unhandled errors |
Default to database unique constraints with custom exception mapping. Only use pre-creation queries when no DB constraint exists.
// packages/db/src/operations/skills.ts
const PG_UNIQUE_VIOLATION = "23505";
const SKILLS_NAME_UNIQUE_CONSTRAINT = "skills_project_id_name_idx";
export class SkillNameConflictError extends Error {
constructor(name: string) {
super(`A skill named "${name}" already exists in this project`);
this.name = "SkillNameConflictError";
}
}
export async function createSkill(
db: HydraDb,
data: NewSkill,
): Promise<DBSkill> {
try {
const [skill] = await db.insert(schema.skills).values(data).returning();
return skill;
} catch (error) {
if (isSkillNameConflict(error)) {
throw new SkillNameConflictError(data.name);
}
throw error;
}
}When no unique DB constraint exists, query before inserting:
const existingKeys = await getExistingServerKeys(ctx.db, projectId)
Repo: tambo-ai/tambo
Manages AI SDK model configurations - updates packages, identifies missing models, adds new models with research, and updates documentation
Use this skill when adding or modifying settings UI in Tambo Cloud. Covers where a new settings section belongs (Agent tab vs Settings tab), and the component…
Creates unstyled compound components that separate business logic from styles. Use when building headless UI primitives, creating component libraries,…
Creates styled wrapper components that compose headless/base compound components. Use when refactoring styled components to use base primitives, implementing…
Use this skill when creating, modifying, or reviewing any .tsx component in apps/web, even if the user doesn't mention "accessibility." Covers semantic HTML,…
Integrates Tambo into existing React apps — detects tech stack, installs @tambo-ai/react, wires TamboProvider, registers components with Zod schemas, and sets…