[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6X752P049RCFWVRP4QA02D6":3,"skill-same:01M6X752P049RCFWVRP4QA02D6":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":54,"repositoryHtmlUrl":55,"repositoryHomepageUrl":6,"ownerHtmlUrl":56,"ownerBlogUrl":57,"ownerDescription":58,"updatedAt":59,"install":60,"resources":72},"01M6X752P049RCFWVRP4QA02D6","convex-best-practices",null,"Guidelines for building production-ready Convex apps covering function organization, query patterns, validation, TypeScript usage, error handling, and the Zen of Convex design philosophy","Cheggin\u002Frequest-for-startups","Cheggin","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F79483996?v=4","01M6X6MGT5512GJHE8DY5B1ZQJ","Reagan Hsu","01M6X6MGY03X7ZJNVRFM3R1040",1,"GPL-3.0","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fconvex-best-practices\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"convex","best practices","convex best practices","philosophy","zen","production-ready","usage","error","apps","authoring","full","organization","query","design","patterns","ready","design philosophy","component","typescript","convex design","2026-11-10 10:12:30",false,"---\nname: convex-best-practices\ndescription: Guidelines for building production-ready Convex apps covering function organization, query patterns, validation, TypeScript usage, error handling, and the Zen of Convex design philosophy\nuser-invocable: true\ngroup: build\nprerequisites: [convex]\nnext: [convex-component-authoring]\nworkflows: [full-startup]\n---\n\n# Convex Best Practices\n\nBuild production-ready Convex applications by following established patterns for function organization, query optimization, validation, TypeScript usage, and error handling.\n\n## Code Quality\n\nAll patterns in this skill comply with `@convex-dev\u002Feslint-plugin`. Install it for build-time validation:\n\n```bash\nnpm i @convex-dev\u002Feslint-plugin --save-dev\n```\n\n```js\n\u002F\u002F eslint.config.js\nimport { defineConfig } from \"eslint\u002Fconfig\";\nimport convexPlugin from \"@convex-dev\u002Feslint-plugin\";\n\nexport default defineConfig([\n  ...convexPlugin.configs.recommended,\n]);\n```\n\nThe plugin enforces four rules:\n\n| Rule                                | What it enforces                  |\n| ----------------------------------- | --------------------------------- |\n| `no-old-registered-function-syntax` | Object syntax with `handler`      |\n| `require-argument-validators`       | `args: {}` on all functions       |\n| `explicit-table-ids`                | Table name in db operations       |\n| `import-wrong-runtime`              | No Node imports in Convex runtime |\n\nDocs: https:\u002F\u002Fdocs.convex.dev\u002Feslint\n\n## Documentation Sources\n\nBefore implementing, do not assume; fetch the latest documentation:\n\n- Primary: https:\u002F\u002Fdocs.convex.dev\u002Funderstanding\u002Fbest-practices\u002F\n- Error Handling: https:\u002F\u002Fdocs.convex.dev\u002Ffunctions\u002Ferror-handling\n- Write Conflicts: https:\u002F\u002Fdocs.convex.dev\u002Ferror#1\n- For broader context: https:\u002F\u002Fdocs.convex.dev\u002Fllms.txt\n\n## Instructions\n\n### The Zen of Convex\n\n1. **Convex manages the hard parts** - Let Convex handle caching, real-time sync, and consistency\n2. **Functions are the API** - Design your functions as your application's interface\n3. **Schema is truth** - Define your data model explicitly in schema.ts\n4. **TypeScript everywhere** - Leverage end-to-end type safety\n5. **Queries are reactive** - Think in terms of subscriptions, not requests\n\n### Function Organization\n\nOrganize your Convex functions by domain:\n\n```typescript\n\u002F\u002F convex\u002Fusers.ts - User-related functions\nimport { query, mutation } from \".\u002F_generated\u002Fserver\";\nimport { v } from \"convex\u002Fvalues\";\n\nexport const get = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.union(\n    v.object({\n      _id: v.id(\"users\"),\n      _creationTime: v.number(),\n      name: v.string(),\n      email: v.string(),\n    }),\n    v.null(),\n  ),\n  handler: async (ctx, args) => {\n    return await ctx.db.get(\"users\", args.userId);\n  },\n});\n```\n\n### Argument and Return Validation\n\nAlways define validators for arguments AND return types:\n\n```typescript\nexport const createTask = mutation({\n  args: {\n    title: v.string(),\n    description: v.optional(v.string()),\n    priority: v.union(v.literal(\"low\"), v.literal(\"medium\"), v.literal(\"high\")),\n  },\n  returns: v.id(\"tasks\"),\n  handler: async (ctx, args) => {\n    return await ctx.db.insert(\"tasks\", {\n      title: args.title,\n      description: args.description,\n      priority: args.priority,\n      completed: false,\n      createdAt: Date.now(),\n    });\n  },\n});\n```\n\n### Query Patterns\n\nUse indexes instead of filters for efficient queries:\n\n```typescript\n\u002F\u002F Schema with index\nexport default defineSchema({\n  tasks: defineTable({\n    userId: v.id(\"users\"),\n    status: v.string(),\n    createdAt: v.number(),\n  })\n    .index(\"by_user\", [\"userId\"])\n    .index(\"by_user_and_status\", [\"userId\", \"status\"]),\n});\n\n\u002F\u002F Query using index\nexport const getTasksByUser = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.array(\n    v.object({\n      _id: v.id(\"tasks\"),\n      _creationTime: v.number(),\n      userId: v.id(\"users\"),\n      status: v.string(),\n      createdAt: v.number(),\n    }),\n  ),\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"tasks\")\n      .withIndex(\"by_user\", (q) => q.eq(\"userId\", args.userId))\n      .order(\"desc\")\n      .collect();\n  },\n});\n```\n\n### Error Handling\n\nUse ConvexError for user-facing errors:\n\n```typescript\nimport { ConvexError } from \"convex\u002Fvalues\";\n\nexport const updateTask = mutation({\n  args: {\n    taskId: v.id(\"tasks\"),\n    title: v.string(),\n  },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const task = await ctx.db.get(\"tasks\", args.taskId);\n\n    if (!task) {\n      throw new ConvexError({\n        code: \"NOT_FOUND\",\n        message: \"Task not found\",\n      });\n    }\n\n    await ctx.db.patch(\"tasks\", args.taskId, { title: args.title });\n    return null;\n  },\n});\n```\n\n### Avoiding Write Conflicts (Optimistic Concurrency Control)\n\nConvex uses OCC. Follow these patterns to minimize conflicts:\n\n```typescript\n\u002F\u002F GOOD: Make mutations idempotent\nexport const completeTask = mutation({\n  args: { taskId: v.id(\"tasks\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const task = await ctx.db.get(\"tasks\", args.taskId);\n\n    \u002F\u002F Early return if already complete (idempotent)\n    if (!task || task.status === \"completed\") {\n      return null;\n    }\n\n    await ctx.db.patch(\"tasks\", args.taskId, {\n      status: \"completed\",\n      completedAt: Date.now(),\n    });\n    return null;\n  },\n});\n\n\u002F\u002F GOOD: Patch directly without reading first when possible\nexport const updateNote = mutation({\n  args: { id: v.id(\"notes\"), content: v.string() },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    \u002F\u002F Patch directly - ctx.db.patch throws if document doesn't exist\n    await ctx.db.patch(\"notes\", args.id, { content: args.content });\n    return null;\n  },\n});\n\n\u002F\u002F GOOD: Use Promise.all for parallel independent updates\nexport const reorderItems = mutation({\n  args: { itemIds: v.array(v.id(\"items\")) },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const updates = args.itemIds.map((id, index) =>\n      ctx.db.patch(\"items\", id, { order: index }),\n    );\n    await Promise.all(updates);\n    return null;\n  },\n});\n```\n\n### TypeScript Best Practices\n\n```typescript\nimport { Id, Doc } from \".\u002F_generated\u002FdataModel\";\n\n\u002F\u002F Use Id type for document references\ntype UserId = Id\u003C\"users\">;\n\n\u002F\u002F Use Doc type for full documents\ntype User = Doc\u003C\"users\">;\n\n\u002F\u002F Define Record types properly\nconst userScores: Record\u003CId\u003C\"users\">, number> = {};\n```\n\n### Internal vs Public Functions\n\n```typescript\n\u002F\u002F Public function - exposed to clients\nexport const getUser = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.union(\n    v.null(),\n    v.object({\n      \u002F* ... *\u002F\n    }),\n  ),\n  handler: async (ctx, args) => {\n    \u002F\u002F ...\n  },\n});\n\n\u002F\u002F Internal function - only callable from other Convex functions\nexport const _updateUserStats = internalMutation({\n  args: { userId: v.id(\"users\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    \u002F\u002F ...\n  },\n});\n```\n\n## Examples\n\n### Complete CRUD Pattern\n\n```typescript\n\u002F\u002F convex\u002Ftasks.ts\nimport { query, mutation } from \".\u002F_generated\u002Fserver\";\nimport { v } from \"convex\u002Fvalues\";\nimport { ConvexError } from \"convex\u002Fvalues\";\n\nconst taskValidator = v.object({\n  _id: v.id(\"tasks\"),\n  _creationTime: v.number(),\n  title: v.string(),\n  completed: v.boolean(),\n  userId: v.id(\"users\"),\n});\n\nexport const list = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.array(taskValidator),\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"tasks\")\n      .withIndex(\"by_user\", (q) => q.eq(\"userId\", args.userId))\n      .collect();\n  },\n});\n\nexport const create = mutation({\n  args: {\n    title: v.string(),\n    userId: v.id(\"users\"),\n  },\n  returns: v.id(\"tasks\"),\n  handler: async (ctx, args) => {\n    return await ctx.db.insert(\"tasks\", {\n      title: args.title,\n      completed: false,\n      userId: args.userId,\n    });\n  },\n});\n\nexport const update = mutation({\n  args: {\n    taskId: v.id(\"tasks\"),\n    title: v.optional(v.string()),\n    completed: v.optional(v.boolean()),\n  },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const { taskId, ...updates } = args;\n\n    \u002F\u002F Remove undefined values\n    const cleanUpdates = Object.fromEntries(\n      Object.entries(updates).filter(([_, v]) => v !== undefined),\n    );\n\n    if (Object.keys(cleanUpdates).length > 0) {\n      await ctx.db.patch(\"tasks\", taskId, cleanUpdates);\n    }\n    return null;\n  },\n});\n\nexport const remove = mutation({\n  args: { taskId: v.id(\"tasks\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    await ctx.db.delete(\"tasks\", args.taskId);\n    return null;\n  },\n});\n```\n\n## Best Practices\n\n- Never run `npx convex deploy` unless explicitly instructed\n- Never run any git commands unless explicitly instructed\n- Always define return validators for functions\n- Use indexes for all queries that filter data\n- Make mutations idempotent to handle retries gracefully\n- Use ConvexError for user-facing error messages\n- Organize functions by domain (users.ts, tasks.ts, etc.)\n- Use internal functions for sensitive operations\n- Leverage TypeScript's Id and Doc types\n\n## Common Pitfalls\n\n1. **Using filter instead of withIndex** - Always define indexes and use withIndex\n2. **Missing return validators** - Always specify the returns field\n3. **Non-idempotent mutations** - Check current state before updating\n4. **Reading before patching unnecessarily** - Patch directly when possible\n5. **Not handling null returns** - Document IDs might not exist\n\n## References\n\n- Convex Documentation: https:\u002F\u002Fdocs.convex.dev\u002F\n- Convex LLMs.txt: https:\u002F\u002Fdocs.convex.dev\u002Fllms.txt\n- Best Practices: https:\u002F\u002Fdocs.convex.dev\u002Funderstanding\u002Fbest-practices\u002F\n- Error Handling: https:\u002F\u002Fdocs.convex.dev\u002Ffunctions\u002Ferror-handling\n- Write Conflicts: https:\u002F\u002Fdocs.convex.dev\u002Ferror#1\n","# Convex Best Practices\n\nBuild production-ready Convex applications by following established patterns for function organization, query optimization, validation, TypeScript usage, and error handling.\n\n## Code Quality\n\nAll patterns in this skill comply with `@convex-dev\u002Feslint-plugin`. Install it for build-time validation:\n\n```bash\nnpm i @convex-dev\u002Feslint-plugin --save-dev\n```\n\n```js\n\u002F\u002F eslint.config.js\nimport { defineConfig } from \"eslint\u002Fconfig\";\nimport convexPlugin from \"@convex-dev\u002Feslint-plugin\";\n\nexport default defineConfig([\n  ...convexPlugin.configs.recommended,\n]);\n```\n\nThe plugin enforces four rules:\n\n| Rule                                | What it enforces                  |\n| ----------------------------------- | --------------------------------- |\n| `no-old-registered-function-syntax` | Object syntax with `handler`      |\n| `require-argument-validators`       | `args: {}` on all functions       |\n| `explicit-table-ids`                | Table name in db operations       |\n| `import-wrong-runtime`              | No Node imports in Convex runtime |\n\nDocs: https:\u002F\u002Fdocs.convex.dev\u002Feslint\n\n## Documentation Sources\n\nBefore implementing, do not assume; fetch the latest documentation:\n\n- Primary: https:\u002F\u002Fdocs.convex.dev\u002Funderstanding\u002Fbest-practices\u002F\n- Error Handling: https:\u002F\u002Fdocs.convex.dev\u002Ffunctions\u002Ferror-handling\n- Write Conflicts: https:\u002F\u002Fdocs.convex.dev\u002Ferror#1\n- For broader context: https:\u002F\u002Fdocs.convex.dev\u002Fllms.txt\n\n## Instructions\n\n### The Zen of Convex\n\n1. **Convex manages the hard parts** - Let Convex handle caching, real-time sync, and consistency\n2. **Functions are the API** - Design your functions as your application's interface\n3. **Schema is truth** - Define your data model explicitly in schema.ts\n4. **TypeScript everywhere** - Leverage end-to-end type safety\n5. **Queries are reactive** - Think in terms of subscriptions, not requests\n\n### Function Organization\n\nOrganize your Convex functions by domain:\n\n```typescript\n\u002F\u002F convex\u002Fusers.ts - User-related functions\nimport { query, mutation } from \".\u002F_generated\u002Fserver\";\nimport { v } from \"convex\u002Fvalues\";\n\nexport const get = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.union(\n    v.object({\n      _id: v.id(\"users\"),\n      _creationTime: v.number(),\n      name: v.string(),\n      email: v.string(),\n    }),\n    v.null(),\n  ),\n  handler: async (ctx, args) => {\n    return await ctx.db.get(\"users\", args.userId);\n  },\n});\n```\n\n### Argument and Return Validation\n\nAlways define validators for arguments AND return types:\n\n```typescript\nexport const createTask = mutation({\n  args: {\n    title: v.string(),\n    description: v.optional(v.string()),\n    priority: v.union(v.literal(\"low\"), v.literal(\"medium\"), v.literal(\"high\")),\n  },\n  returns: v.id(\"tasks\"),\n  handler: async (ctx, args) => {\n    return await ctx.db.insert(\"tasks\", {\n      title: args.title,\n      description: args.description,\n      priority: args.priority,\n      completed: false,\n      createdAt: Date.now(),\n    });\n  },\n});\n```\n\n### Query Patterns\n\nUse indexes instead of filters for efficient queries:\n\n```typescript\n\u002F\u002F Schema with index\nexport default defineSchema({\n  tasks: defineTable({\n    userId: v.id(\"users\"),\n    status: v.string(),\n    createdAt: v.number(),\n  })\n    .index(\"by_user\", [\"userId\"])\n    .index(\"by_user_and_status\", [\"userId\", \"status\"]),\n});\n\n\u002F\u002F Query using index\nexport const getTasksByUser = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.array(\n    v.object({\n      _id: v.id(\"tasks\"),\n      _creationTime: v.number(),\n      userId: v.id(\"users\"),\n      status: v.string(),\n      createdAt: v.number(),\n    }),\n  ),\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"tasks\")\n      .withIndex(\"by_user\", (q) => q.eq(\"userId\", args.userId))\n      .order(\"desc\")\n      .collect();\n  },\n});\n```\n\n### Error Handling\n\nUse ConvexError for user-facing errors:\n\n```typescript\nimport { ConvexError } from \"convex\u002Fvalues\";\n\nexport const updateTask = mutation({\n  args: {\n    taskId: v.id(\"tasks\"),\n    title: v.string(),\n  },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const task = await ctx.db.get(\"tasks\", args.taskId);\n\n    if (!task) {\n      throw new ConvexError({\n        code: \"NOT_FOUND\",\n        message: \"Task not found\",\n      });\n    }\n\n    await ctx.db.patch(\"tasks\", args.taskId, { title: args.title });\n    return null;\n  },\n});\n```\n\n### Avoiding Write Conflicts (Optimistic Concurrency Control)\n\nConvex uses OCC. Follow these patterns to minimize conflicts:\n\n```typescript\n\u002F\u002F GOOD: Make mutations idempotent\nexport const completeTask = mutation({\n  args: { taskId: v.id(\"tasks\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const task = await ctx.db.get(\"tasks\", args.taskId);\n\n    \u002F\u002F Early return if already complete (idempotent)\n    if (!task || task.status === \"completed\") {\n      return null;\n    }\n\n    await ctx.db.patch(\"tasks\", args.taskId, {\n      status: \"completed\",\n      completedAt: Date.now(),\n    });\n    return null;\n  },\n});\n\n\u002F\u002F GOOD: Patch directly without reading first when possible\nexport const updateNote = mutation({\n  args: { id: v.id(\"notes\"), content: v.string() },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    \u002F\u002F Patch directly - ctx.db.patch throws if document doesn't exist\n    await ctx.db.patch(\"notes\", args.id, { content: args.content });\n    return null;\n  },\n});\n\n\u002F\u002F GOOD: Use Promise.all for parallel independent updates\nexport const reorderItems = mutation({\n  args: { itemIds: v.array(v.id(\"items\")) },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const updates = args.itemIds.map((id, index) =>\n      ctx.db.patch(\"items\", id, { order: index }),\n    );\n    await Promise.all(updates);\n    return null;\n  },\n});\n```\n\n### TypeScript Best Practices\n\n```typescript\nimport { Id, Doc } from \".\u002F_generated\u002FdataModel\";\n\n\u002F\u002F Use Id type for document references\ntype UserId = Id\u003C\"users\">;\n\n\u002F\u002F Use Doc type for full documents\ntype User = Doc\u003C\"users\">;\n\n\u002F\u002F Define Record types properly\nconst userScores: Record\u003CId\u003C\"users\">, number> = {};\n```\n\n### Internal vs Public Functions\n\n```typescript\n\u002F\u002F Public function - exposed to clients\nexport const getUser = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.union(\n    v.null(),\n    v.object({\n      \u002F* ... *\u002F\n    }),\n  ),\n  handler: async (ctx, args) => {\n    \u002F\u002F ...\n  },\n});\n\n\u002F\u002F Internal function - only callable from other Convex functions\nexport const _updateUserStats = internalMutation({\n  args: { userId: v.id(\"users\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    \u002F\u002F ...\n  },\n});\n```\n\n## Examples\n\n### Complete CRUD Pattern\n\n```typescript\n\u002F\u002F convex\u002Ftasks.ts\nimport { query, mutation } from \".\u002F_generated\u002Fserver\";\nimport { v } from \"convex\u002Fvalues\";\nimport { ConvexError } from \"convex\u002Fvalues\";\n\nconst taskValidator = v.object({\n  _id: v.id(\"tasks\"),\n  _creationTime: v.number(),\n  title: v.string(),\n  completed: v.boolean(),\n  userId: v.id(\"users\"),\n});\n\nexport const list = query({\n  args: { userId: v.id(\"users\") },\n  returns: v.array(taskValidator),\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"tasks\")\n      .withIndex(\"by_user\", (q) => q.eq(\"userId\", args.userId))\n      .collect();\n  },\n});\n\nexport const create = mutation({\n  args: {\n    title: v.string(),\n    userId: v.id(\"users\"),\n  },\n  returns: v.id(\"tasks\"),\n  handler: async (ctx, args) => {\n    return await ctx.db.insert(\"tasks\", {\n      title: args.title,\n      completed: false,\n      userId: args.userId,\n    });\n  },\n});\n\nexport const update = mutation({\n  args: {\n    taskId: v.id(\"tasks\"),\n    title: v.optional(v.string()),\n    completed: v.optional(v.boolean()),\n  },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    const { taskId, ...updates } = args;\n\n    \u002F\u002F Remove undefined values\n    const cleanUpdates = Object.fromEntries(\n      Object.entries(updates).filter(([_, v]) => v !== undefined),\n    );\n\n    if (Object.keys(cleanUpdates).length > 0) {\n      await ctx.db.patch(\"tasks\", taskId, cleanUpdates);\n    }\n    return null;\n  },\n});\n\nexport const remove = mutation({\n  args: { taskId: v.id(\"tasks\") },\n  returns: v.null(),\n  handler: async (ctx, args) => {\n    await ctx.db.delete(\"tasks\", args.taskId);\n    return null;\n  },\n});\n```\n\n## Best Practices\n\n- Never run `npx convex deploy` unless explicitly instructed\n- Never run any git commands unless explicitly instructed\n- Always define return validators for functions\n- Use indexes for all queries that filter data\n- Make mutations idempotent to handle retries gracefully\n- Use ConvexError for user-facing error messages\n- Organize functions by domain (users.ts, tasks.ts, etc.)\n- Use internal functions for sensitive operations\n- Leverage TypeScript's Id and Doc types\n\n## Common Pitfalls\n\n1. **Using filter instead of withIndex** - Always define indexes and use withIndex\n2. **Missing return validators** - Always specify the returns field\n3. **Non-idempotent mutations** - Check current state before updating\n4. **Reading before patching unnecessarily** - Patch directly when possible\n5. **Not handling null returns** - Document IDs might not exist\n\n## References\n\n- Convex Documentation: https:\u002F\u002Fdocs.convex.dev\u002F\n- Convex LLMs.txt: https:\u002F\u002Fdocs.convex.dev\u002Fllms.txt\n- Best Practices: https:\u002F\u002Fdocs.convex.dev\u002Funderstanding\u002Fbest-practices\u002F\n- Error Handling: https:\u002F\u002Fdocs.convex.dev\u002Ffunctions\u002Ferror-handling\n- Write Conflicts: https:\u002F\u002Fdocs.convex.dev\u002Ferror#1\n",{"name":5,"next":44,"group":46,"workflows":47,"description":7,"prerequisites":49,"user-invocable":50},[45],"convex-component-authoring","build",[48],"full-startup",[19],true,"main","92dddf7f6e7b55d1424795ce11586b05dba9d8c8","skills\u002Fconvex-best-practices",3,"https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups","https:\u002F\u002Fgithub.com\u002FCheggin","reaganhsu.com","MTS @datacurve-ai, prev. founding eng @browser-use ","2026-04-24 08:33:47",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":50},[62,65,68],{"tool":63,"command":64},"npx","npx skills add Cheggin\u002Frequest-for-startups --skill convex-best-practices",{"tool":66,"command":67},"bunx","bunx skills add Cheggin\u002Frequest-for-startups --skill convex-best-practices",{"tool":69,"command":70},"pnpm","pnpm dlx skills add Cheggin\u002Frequest-for-startups --skill convex-best-practices","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fconvex-best-practices\u002FSKILL.md",[],[74,97,117,158,173,196],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":39},"01M6X7PHK069RZH25A3RXN5049","writer-memory","Agentic memory system for writers - track characters, relationships, scenes, and themes","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fwriter-memory\u002FSKILL.md",[],[81,82,83,84,85,86,87,88,89,90,91,31,92,93,94,95,96],"memory","writer","writer memory","system","characters","track","for","themes","memory system","scenes","relationships","export","status","validate","init","agentic",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":39},"01M6X7PC3G9228Z323X5YAKTVW","wiki","LLM Wiki — persistent markdown knowledge base that compounds across sessions (Karpathy model)","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fwiki\u002FSKILL.md",[],[99,104,105,106,107,108,109,110,111,112,113,114,115,31,116],"wiki lint","knowledge","model","llm wiki","markdown","wiki query","knowledge base","lint","sessions","karpathy","add","across","base",{"skillNo":118,"name":119,"nameZh":6,"description":120,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":121,"categories":122,"keywords":139,"publishedAt":39},"01M6X7P5XFW5C16H3JE4NFQ7MF","website-creation","Build production-quality SaaS websites with opinionated design presets. Use when creating any startup website. The user MUST pick a design style before building. Enforces shadcn\u002Fui, Figma design principles, specific CSS values per style, and anti-AI-writing. Load alongside anti-ai-writing skill. LIGHT MODE ONLY.","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fwebsite-creation\u002FSKILL.md",[123,128,131,136],{"categoryNo":124,"categoryName":125,"taxonomyType":126,"taxonomyTypeDesc":127},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":129,"categoryName":130,"taxonomyType":126,"taxonomyTypeDesc":127},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":132,"categoryName":133,"taxonomyType":134,"taxonomyTypeDesc":135},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",{"categoryNo":137,"categoryName":138,"taxonomyType":134,"taxonomyTypeDesc":135},"01JBSEEDCAT000000000000036","内容创作者",[140,141,142,143,144,145,146,29,147,148,149,150,151,152,153,154,155,156,157,32],"website creation","website","creation","when","design style","mode","brand-guidelines","ui","writing","design principles","only","pick","polish","audit","shadcn","figma","css","Anti-AI",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":164,"publishedAt":39},"01M6X7P3PCEAKA2SBETXHHTNBA","visual-verdict","Structured visual QA verdict for screenshot-to-reference comparisons","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-verdict\u002FSKILL.md",[],[165,166,167,87,168,169,170,171,172],"visual verdict","verdict","visual","visual qa","structured","reference","screenshot","qa",{"skillNo":174,"name":175,"nameZh":6,"description":176,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":177,"categories":178,"keywords":187,"publishedAt":39},"01M6X7NXEWWC4NFT0ZK1RRSGES","visual-qa-pipeline","Screenshot every page with Playwright, feed to visual QA agent for design evaluation, report results to Slack. Use after every build phase to verify UI matches the chosen design preset. Integrates with the Playwright skill and the website-creation preset system.","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-qa-pipeline\u002FSKILL.md",[179,182,185,186],{"categoryNo":180,"categoryName":181,"taxonomyType":126,"taxonomyTypeDesc":127},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":183,"categoryName":184,"taxonomyType":126,"taxonomyTypeDesc":127},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":124,"categoryName":125,"taxonomyType":126,"taxonomyTypeDesc":127},{"categoryNo":132,"categoryName":133,"taxonomyType":134,"taxonomyTypeDesc":135},[167,188,168,172,189,190,119,142,29,191,152,192,147,141,171,87,193,32,194,195],"pipeline","visual qa pipeline","slack","page","Evaluation","review","verify ui","phase",{"skillNo":197,"name":198,"nameZh":6,"description":199,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":200,"categories":201,"keywords":202,"publishedAt":39},"01M6X7NSNW00RQ8J531F52YHV9","verify","Verify that a change really works before you claim completion","https:\u002F\u002Fgithub.com\u002FCheggin\u002Frequest-for-startups\u002Fblob\u002Fmain\u002Fskills\u002Fverify\u002FSKILL.md",[],[198,203,204,205,206,207,188,208,209],"deploy-pipeline","true","you","claim","quality","deploy","change"]