본문으로 건너뛰기
cccskills
무료GitHub에 공개

convex-create-component

Build reusable Convex backend components with their own database tables and a small API, the functions an app calls. It guides component structure, app integration, authentication boundaries, and checks for generated code and type errors.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

Builds reusable Convex components with isolated tables and app-facing APIs. Use for new components, reusable backend modules, integrations, or component boundary work.

연동 도구OpenAI
설치 방법 보기

이럴 때 유용합니다

  • Adding a local component to an existing Convex app
  • Extracting reusable backend logic
  • Building an integration with its own tables
  • Packaging backend features for multiple apps

포함된 파일(7)

  • SKILL.md10.3 KB
  • agents/openai.yaml504 B
  • assets/icon.svg485 B
  • references/advanced-patterns.md4.2 KB
  • references/hybrid-components.md1019 B
  • references/local-components.md1.1 KB
  • references/packaged-components.md1.8 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Convex Create Component

Create reusable Convex components with clear boundaries and a small app-facing API.

When to Use

  • Creating a new Convex component in an existing app
  • Extracting reusable backend logic into a component
  • Building a third-party integration that should own its own tables and workflows
  • Packaging Convex functionality for reuse across multiple apps

When Not to Use

  • One-off business logic that belongs in the main app
  • Thin utilities that do not need Convex tables or functions
  • App-level orchestration that should stay in convex/
  • Cases where a normal TypeScript library is enough

Workflow

  1. Ask the user what they are building and what the end goal is. If the repo already makes the answer obvious, say so and confirm before proceeding.
  2. Choose the shape using the decision tree below and read the matching reference file.
  3. Decide whether a component is justified. Prefer normal app code or a regular library if the feature does not need isolated tables, backend functions, or reusable persistent state.
  4. Make a short plan for:
    • what tables the component owns
    • what public functions it exposes
    • what data must be passed in from the app (auth, env vars, parent IDs)
    • what stays in the app as wrappers or HTTP mounts
  5. Create the component structure with convex.config.ts, schema.ts, and function files.
  6. Implement functions using the component's own ./_generated/server imports, not the app's generated files.
  7. Wire the component into the app with app.use(...). If the app does not already have convex/convex.config.ts, create it.
  8. Call the component from the app through components.<name> using ctx.runQuery, ctx.runMutation, or ctx.runAction.
  9. If React clients, HTTP callers, or public APIs need access, create wrapper functions in the app instead of exposing component functions directly.
  10. Run npx convex dev and fix codegen, type, or boundary issues before finishing.

Choose the Shape

Ask the user, then pick one path:

GoalShapeReference
Component for this app onlyLocalreferences/local-components.md
Publish or share across appsPackagedreferences/packaged-components.md
User explicitly needs local + shared library codeHybridreferences/hybrid-components.md
Not sureDefault to localreferences/local-components.md

Read exactly one reference file before proceeding.

Default Approach

Unless the user explicitly wants an npm package, default to a local component:

  • Put it under convex/components/<componentName>/
  • Define it with defineComponent(...) in its own convex.config.ts
  • Install it from the app's convex/convex.config.ts with app.use(...)
  • Let npx convex dev generate the component's own _generated/ files

Component Skeleton

A minimal local component with a table and two functions, plus the app wiring.

// convex/components/notifications/convex.config.ts
import { defineComponent } from "convex/server";

export default defineComponent("notifications");
// convex/components/notifications/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  notifications: defineTable({
    userId: v.string(),
    message: v.string(),
    read: v.boolean(),
  }).index("by_user_read", ["userId", "read"]),
});
// convex/components/notifications/lib.ts
import { v } from "convex/values";
import { mutation, query } from "./_generated/server.js";

export const send = mutation({
  args: { userId: v.string(), message: v.string() },
  returns: v.id("notifications"),
  handler: async (ctx, args) => {
    return await ctx.db.insert("notifications", {
      userId: args.userId,
      message: args.message,
      read: false,
    });
  },
});

export const listUnread = query({
  args: { userId: v.string() },
  returns: v.array(
    v.object({
      _id: v.id("notifications"),
      _creationTime: v.number(),
      userId: v.string(),
      message: v.string(),
      read: v.boolean(),
    }),
  ),
  handler: async (ctx, args) => {
    return await ctx.db
      .query("notifications")
      .withIndex("by_user_read", (q) =>
        q.eq("userId", args.userId).eq("read", false),
      )
      .collect();
  },
});
// convex/convex.config.ts
import { defineApp } from "convex/server";
import notifications from "./components/notifications/convex.config.js";

const app = defineApp();
app.use(notifications);

export default app;
// convex/notifications.ts  (app-side wrapper)
import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
import { components } from "./_generated/api";
import { getAuthUserId } from "@convex-dev/auth/server";

export const sendNotification = mutation({
  args: { message: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    await ctx.runMutation(components.notifications.lib.send, {
      userId,
      message: args.message,
    });
    return null;
  },
});

export const myUnread = query({
  args: {},
  handler: async (ctx) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    return await ctx.runQuery(components.notifications.lib.listUnread, {
      userId,
    });
  },
});

Note the reference path shape: a function in convex/components/notifications/lib.ts is called as components.notifications.lib.send from the app.

Critical Rules

  • Keep authentication in the app, because ctx.auth is not available inside components.
  • Keep environment access in the app, because component functions cannot read process.env.
  • Pass parent app IDs across the boundary as strings, because Id types become plain strings in the app-facing ComponentApi.
  • Do not use v.id("parentTable") for app-owned tables inside component args or schema, because the component has no access to the app's table namespace.
  • Import query, mutation, and action from the component's own ./_generated/server, not the app's generated files.
  • Do not expose component functions directly to clients. Create app wrappers when client access is needed, because components are internal and need auth/env wiring the app provides.
  • If the component defines HTTP handlers, mount the routes in the app's convex/http.ts, because components cannot register their own HTTP routes.
  • If the component needs pagination, use paginator from convex-helpers instead of built-in .paginate(), because .paginate() does not work across the component boundary.
  • Define indexes for queried fields instead of using Convex .filter() after a database query.
  • Add args and returns validators to all public component functions, because the component boundary requires explicit type contracts.

Patterns

Authentication and environment access

// Bad: component code cannot rely on app auth or env
const identity = await ctx.auth.getUserIdentity();
const apiKey = process.env.OPENAI_API_KEY;
// Good: the app resolves auth and env, then passes explicit values
const userId = await getAuthUserId(ctx);
if (!userId) throw new Error("Not authenticated");

await ctx.runAction(components.translator.translate, {
  userId,
  apiKey: process.env.OPENAI_API_KEY,
  text: args.text,
});

Client-facing API

// Bad: assuming a component function is directly callable by clients
export const send = components.notifications.send;
// Good: re-export through an app mutation or query
export const sendNotification = mutation({
  args: { message: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    await ctx.runMutation(components.notifications.lib.send, {
      userId,
      message: args.message,
    });
    return null;
  },
});

IDs across the boundary

// Bad: parent app table IDs are not valid component validators
args: {
  userId: v.id("users"),
}
// Good: treat parent-owned IDs as strings at the boundary
args: {
  userId: v.string(),
}

Advanced Patterns

For additional patterns including function handles for callbacks, deriving validators from schema, static configuration with a globals table, and class-based client wrappers, see references/advanced-patterns.md.

Validation

Try validation in this order:

  1. npx convex codegen --component-dir convex/components/<name>
  2. npx convex codegen
  3. npx convex dev

Important:

  • Fresh repos may fail these commands until CONVEX_DEPLOYMENT is configured.
  • Until codegen runs, component-local ./_generated/* imports and app-side components.<name>... references will not typecheck.
  • If validation blocks on Convex login or deployment setup, stop and ask the user for that exact step instead of guessing.

Reference Files

Read exactly one of these after the user confirms the goal:

  • references/local-components.md
  • references/packaged-components.md
  • references/hybrid-components.md

Official docs: Authoring Components

Checklist

  • Asked the user what they want to build and confirmed the shape
  • Read the matching reference file
  • Confirmed a component is the right abstraction
  • Planned tables, public API, boundaries, and app wrappers
  • Component lives under convex/components/<name>/ (or package layout if publishing)
  • Component imports from its own ./_generated/server
  • Auth, env access, and HTTP routes stay in the app
  • Parent app IDs cross the boundary as v.string()
  • Public functions have args and returns validators
  • Ran npx convex dev and fixed codegen or type issues

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Review code using shared OpenClaw instructions and a Python helper, while also following the target repository’s review requirements. This skill points to a common installation that supplies the actual review procedure.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Reviewing code with shared OpenClaw instructions
  • Applying repository-specific review requirements
  • Keeping shared review instructions up to date
openclaw/clawhub9.5천2026년 10월 19일 업데이트

Create and manage Axiom alert rules and notification destinations through its API. Connect alerts to email, Slack, or webhooks, check monitor history, and adjust thresholds and evaluation schedules to address excessive or missing alerts.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Set up error alerts and notification destinations
  • Tune monitors that send too many alerts
  • Investigate monitors that never trigger
openclaw/clawhub9.5천2026년 10월 19일 업데이트

axiom-sre

무료

Investigate production incidents and bugs using logs, metrics, and code evidence. The skill guides hypothesis testing, root cause analysis, fix validation, and reusable investigation notes, with access to configured observability tools such as Axiom.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Investigate production outages and rising error rates
  • Trace causes using logs, metrics, and code
  • Reproduce bugs and validate minimal fixes
openclaw/clawhub9.5천2026년 10월 19일 업데이트

Design and build Axiom dashboards from logs or metrics, the numerical measurements of system behavior. Create charts, filters, and layouts for monitoring and reporting, or migrate existing Splunk and Grafana panels while validating queries against available data.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Build a service health monitoring dashboard
  • Create interactive filters for investigating logs
  • Migrate dashboards from Splunk or Grafana
openclaw/clawhub9.5천2026년 10월 19일 업데이트

Drafts, previews, sends, and records emails for existing ClawHub content rights cases. It supports publisher removal notices and requester updates, requires approval of the final draft, and preserves the exact correspondence in the case record.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Preparing a skill removal notice for a publisher
  • Sending a requester a progress update or closure note
  • Preserving sent correspondence in an existing rights case
openclaw/clawhub9.5천2026년 10월 19일 업데이트

Apply ClawHub-specific rules when developing with Convex, including deployment targeting, runtime checks, data migrations, search performance, and skill statistics. It also directs specialized work to the appropriate companion skills.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Changing Convex functions or schemas
  • Planning production data migrations
  • Reviewing search query performance
openclaw/clawhub9.5천2026년 10월 19일 업데이트

openclaw의 스킬 모두 보기

이 스킬의 문제 신고