Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
waynesutton avatar

Function Creator

  • 2 installs
  • 627 repo stars
  • Updated May 20, 2026
  • waynesutton/markdown-site

Creates Convex queries, mutations, and actions with proper validation, authentication, and error handling for new API endpoints.

About

This skill generates secure, type-safe Convex queries, mutations, and actions following validation and auth best practices. A developer uses it when implementing new Convex API endpoints for reading data, writing data, or calling external services.

  • Distinguishes queries, mutations, and actions and their constraints
  • Adds validation, authentication, and error handling to functions

Function Creator by the numbers

  • 2 all-time installs (skills.sh)
  • Ranked #3,765 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/waynesutton/markdown-site --skill function-creator

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2
repo stars627
Last updatedMay 20, 2026
Repositorywaynesutton/markdown-site

What it does

Creates Convex queries, mutations, and actions with proper validation, authentication, and error handling for new API endpoints.

Files

SKILL.mdMarkdownGitHub ↗

Convex Function Creator

Generate secure, type-safe Convex functions following all best practices.

When to Use

  • Creating new query functions (read data)
  • Creating new mutation functions (write data)
  • Creating new action functions (external APIs, long-running)
  • Adding API endpoints to your Convex backend

Function Types

Queries (Read-Only)

  • Can only read from database
  • Cannot modify data or call external APIs
  • Cached and reactive
  • Run in transactions
import { query } from "./_generated/server";
import { v } from "convex/values";

export const getTask = query({
  args: { taskId: v.id("tasks") },
  returns: v.union(v.object({
    _id: v.id("tasks"),
    text: v.string(),
    completed: v.boolean(),
  }), v.null()),
  handler: async (ctx, args) => {
    return await ctx.db.get(args.taskId);
  },
});

Mutations (Transactional Writes)

  • Can read and write to database
  • Cannot call external APIs
  • Run in ACID transactions
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const createTask = mutation({
  args: {
    text: v.string(),
    priority: v.optional(v.union(
      v.literal("low"),
      v.literal("medium"),
      v.literal("high")
    )),
  },
  returns: v.id("tasks"),
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Not authenticated");

    return await ctx.db.insert("tasks", {
      text: args.text,
      priority: args.priority ?? "medium",
      completed: false,
      createdAt: Date.now(),
    });
  },
});

Actions (External + Non-Transactional)

  • Can call external APIs (fetch, AI, etc.)
  • Can call mutations via ctx.runMutation
  • Cannot directly access database
  • Use `"use node"` directive when needing Node.js APIs
"use node";

import { action } from "./_generated/server";
import { api } from "./_generated/api";
import { v } from "convex/values";
import OpenAI from "openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

export const generateTaskSuggestion = action({
  args: { prompt: v.string() },
  returns: v.string(),
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Not authenticated");

    const completion = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [{ role: "user", content: args.prompt }],
    });

    const suggestion = completion.choices[0].message.content;

    await ctx.runMutation(api.tasks.createTask, { text: suggestion });
    return suggestion;
  },
});

Note: Keep queries and mutations in files without "use node". Actions that need Node.js go in separate files with "use node".

Required Components

1. Argument Validation

Always define args with validators.

2. Return Type Validation

Always define returns.

3. Authentication Check

Always verify auth in public functions:

const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Not authenticated");

4. Authorization Check

Always verify ownership/permissions:

const task = await ctx.db.get(args.taskId);
if (!task) throw new Error("Task not found");
if (task.userId !== user._id) throw new Error("Unauthorized");

Internal Functions

For backend-only functions (called by scheduler, other functions):

import { internalMutation } from "./_generated/server";

export const processExpiredTasks = internalMutation({
  args: {},
  handler: async (ctx) => {
    const now = Date.now();
    const expired = await ctx.db
      .query("tasks")
      .withIndex("by_due_date", q => q.lt("dueDate", now))
      .collect();

    for (const task of expired) {
      await ctx.db.patch(task._id, { status: "expired" });
    }
  },
});

Checklist

  • [ ] args defined with validators
  • [ ] returns defined with validator
  • [ ] Authentication check (ctx.auth.getUserIdentity())
  • [ ] Authorization check (ownership/permissions)
  • [ ] All promises awaited
  • [ ] Indexed queries (no .filter() on queries)
  • [ ] Error handling with descriptive messages
  • [ ] Scheduled functions use internal.* not api.*
  • [ ] If using Node.js APIs: "use node" at top of file
  • [ ] If file has "use node": Only actions (no queries/mutations)

Source: https://github.com/get-convex/convex-agent-plugins

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.