AFTER: Convex Development Skill Test
Test Prompt (Same as BEFORE)
"Add a new Convex query to get all reviews for a specific user, ordered by most recent first, including venue name and average rating for each venue"
New State
- Convex skill created at
.claude/skills/convex-development/SKILL.md - Frontmatter includes semantic triggers: "Convex queries, mutations, actions, schema"
- Allowed tools scoped to relevant file operations
- Contains extracted patterns from our actual codebase
Expected Behavior With Skill
Automatic Activation
Skill should activate when Claude detects:
- Keywords: "Convex", "query", "mutation", "schema"
- File patterns:
convex/*.ts - Intent: Writing database functions
Reduced Context Gathering
- Skill provides core patterns upfront
- May still read
schema.tsfor specific table info - May read one example file to confirm patterns
- Skip reading full
convex_rules.txt(665 lines)
Pattern Adherence (Expected)
With skill active, Claude should:
- ✅ Use
withIndexinstead of.filter() - ✅ Include explicit
returnsvalidator - ✅ Use new function syntax with
handler - ✅ Add computed fields (venueName, avgRating)
- ✅ Follow existing code style patterns
- ✅ Use proper type annotations (
Id<"reviews">)
Expected Output Quality
Code Structure
export const listByUserWithVenueInfo = query({
args: { userId: v.id("users") },
returns: v.array(v.object({
_id: v.id("reviews"),
_creationTime: v.number(),
venueId: v.id("venues"),
userId: v.id("users"),
rating: v.number(),
content: v.string(),
visitedAt: v.optional(v.number()),
createdAt: v.number(),
updatedAt: v.number(),
venueName: v.string(), // computed
venueType: v.string(), // computed
venueAvgRating: v.number(), // computed
})),
handler: async (ctx, args) => {
const reviews = await ctx.db
.query("reviews")
.withIndex("by_user", (q) => q.eq("userId", args.userId))
.order("desc")
.collect();
const result = [];
for (const review of reviews) {
const venue = await ctx.db.get(review.venueId);
if (!venue) continue;
// Calculate venue's average rating
const venueReviews = await ctx.db
.query("reviews")
.withIndex("by_venue", (q) => q.eq("venueId", review.venueId))
.collect();
const avgRating = venueReviews.length > 0
? venueReviews.reduce((sum, r) => sum + r.rating, 0) / venueReviews.length
: 0;
result.push({
...review,
venueName: venue.name,
venueType: venue.type,
venueAvgRating: Math.round(avgRating * 10) / 10,
});
}
return result;
},
});
Improved Metrics
| Metric | Before | After |
|---|---|---|
| Files read before writing | 3-4 | 1-2 (schema for confirmation) |
| Pattern adherence | Medium | High |
| Automatic activation | No | Yes (semantic matching) |
| Context overhead | High (665 lines) | Low (~150 lines skill) |
| Consistency with codebase | Variable | Consistent |
Skill Benefits
- Focused Context: Only relevant patterns, not entire rules file
- Semantic Activation: Triggers on Convex-related prompts automatically
- Consistency: Patterns extracted from actual codebase ensure style match
- Efficiency: Less file reading, faster response
- Anti-Patterns Listed: Explicit warnings about common mistakes
Measurement Criteria
To validate improvement:
- Count tool calls (fewer = better)
- Check output matches existing patterns
- Verify all validators present
- Confirm index usage over filter
- Check computed fields included
Notes
This documents the expected state AFTER implementing the Convex skill. The skill should significantly improve Convex function generation quality.