Agent skill

Convex Realtime

by waynesutton in waynesutton/builder-skills

Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn.

Apache-2.0Auto-check passedFrontend & Design

Install Convex Realtime

skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install waynesutton/builder-skills convex-realtime --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/waynesutton/builder-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/convex-realtime .claude/skills/convex-realtime && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
convex-realtime
GitHub stars
406
Token cost
~2.6k tokens
SKILL.md length
910 words
Files
4 (incl. assets)
Skills in repo
17
Repo updated
First seen
Licence
Apache-2.0

At a glance

Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn.

  • Wiring the frontend to Convex
  • SKILL.md covers When to reach for this, How subscriptions work, useQuery and Mutations and optimistic updates, plus 7 more sections
  • Calls npm
  • Data does not update live

What it does

Convex Realtime is an agent skill from waynesutton/builder-skills. Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn. Use when wiring the frontend to Convex, when data does not update live, or when a page rerenders too much.

Its SKILL.md is about 2.6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 5 other files, including assets (for example `agents/openai.yaml`).

It sits in Frontend & Design, covering Realtime and WebSockets. The repository describes itself as: Builder skills for Convex apps. Convex patterns plus a PRD, task.md, changelog, and files.md workflow for Claude Code, Codex, Cursor, and OpenCode. The licence is Apache-2.0.

When your agent uses it

  • Wiring the frontend to Convex
  • Data does not update live
  • A page rerenders too much

Example prompts

  • “Use the convex-realtime skill to build reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live…”
  • “/convex-realtime”

Requirements

  • Node.js

What it can do on your machine

Read from SKILL.md and the folder at commit 82d1ce2. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • docs.convex.dev
    • convex.dev

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Convex Realtime loads about 2.6k tokens when it runs. Until then it costs about 69 tokens; SKILL.md has 910 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~69
When it runs · the whole SKILL.md, loaded when a task matches
~2.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from waynesutton/builder-skills at commit 82d1ce2, republished under its Apache-2.0 licence (© waynesutton). 910 words, ~2,612 tokens.

Download SKILL.mdSave it as .claude/skills/convex-realtime/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
convex-realtime
description
Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn. Use when wiring the frontend to Convex, when data does not update live, or when a page rerenders too much.

Convex realtime

Every useQuery is a live subscription. The one rule: keep the set of documents a query reads small and indexed, because that read set decides when the query reruns.

When to reach for this

  • Wiring a React component to Convex for the first time
  • Data changes on the server but the page does not update
  • A list or dashboard rerenders on every unrelated write
  • A "load more" list drops or duplicates rows when new data lands
  • Showing who is online or typing

How subscriptions work

useQuery opens a subscription over the client's websocket. The server runs the query, records its read set (every document and index range it touched), and pushes the result. When a mutation commits a write that overlaps that read set, the server reruns the query and pushes the new result. Nothing overlaps, nothing reruns. Results are cached per function and args, so two components calling useQuery(api.tasks.list, { userId }) share one subscription. All active subscriptions update together at the same database timestamp, so the UI never shows a half applied mutation. Queries must be deterministic for this to hold, which is why Date.now(), Math.random(), and fetch are not allowed inside them.

useQuery

undefined means loading. Pass "skip" instead of wrapping the hook in a condition.

typescript
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
import { Id } from "../convex/_generated/dataModel";

function TaskList({ userId }: { userId: Id<"users"> | null }) {
  const tasks = useQuery(api.tasks.list, userId ? { userId } : "skip");

  if (userId === null) return <p>Select a user</p>;
  if (tasks === undefined) return <p>Loading</p>;

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task._id}>{task.title}</li>
      ))}
    </ul>
  );
}

Backend queries return validated data and read through an index:

typescript
// convex/tasks.ts
import { query } from "./_generated/server";
import { v } from "convex/values";

export const list = query({
  args: { userId: v.id("users") },
  returns: v.array(
    v.object({
      _id: v.id("tasks"),
      _creationTime: v.number(),
      userId: v.id("users"),
      title: v.string(),
      completed: v.boolean(),
    }),
  ),
  handler: async (ctx, args) => {
    return await ctx.db
      .query("tasks")
      .withIndex("by_user", (q) => q.eq("userId", args.userId))
      .order("desc")
      .take(100);
  },
});

Mutations and optimistic updates

A plain useMutation call is enough for most UI. The subscription refreshes when the write commits, usually within a round trip. Add an optimistic update when that round trip is visible: toggles, reorders, chat sends.

typescript
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
import { Id } from "../convex/_generated/dataModel";

function useToggleTask(userId: Id<"users">) {
  return useMutation(api.tasks.toggle).withOptimisticUpdate(
    (localStore, args) => {
      const current = localStore.getQuery(api.tasks.list, { userId });
      if (current === undefined) return;
      localStore.setQuery(
        api.tasks.list,
        { userId },
        current.map((task) =>
          task._id === args.taskId
            ? { ...task, completed: !task.completed }
            : task,
        ),
      );
    },
  );
}

Inserting into a list works the same way. Build a temporary document with a placeholder _id and _creationTime: Date.now() (allowed here, this runs on the client), prepend it, and let the server result replace it. If the mutation throws, Convex rolls the local store back for you. Update every query the mutation affects, not just the one on screen, or the others will look stale until the server responds.

Pagination that stays live

typescript
// convex/messages.ts
import { query } from "./_generated/server";
import { v } from "convex/values";
import { paginationOptsValidator } from "convex/server";

export const listByChannel = query({
  args: { channelId: v.id("channels"), paginationOpts: paginationOptsValidator },
  // Return shape is fixed by .paginate(): { page, isDone, continueCursor }
  handler: async (ctx, args) => {
    return await ctx.db
      .query("messages")
      .withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
      .order("desc")
      .paginate(args.paginationOpts);
  },
});
typescript
import { usePaginatedQuery } from "convex/react";
import { api } from "../convex/_generated/api";
import { Id } from "../convex/_generated/dataModel";

function MessageList({ channelId }: { channelId: Id<"channels"> }) {
  const { results, status, loadMore } = usePaginatedQuery(
    api.messages.listByChannel,
    { channelId },
    { initialNumItems: 30 },
  );

  return (
    <div>
      {results.map((m) => (
        <p key={m._id}>{m.body}</p>
      ))}
      {status === "CanLoadMore" && (
        <button onClick={() => loadMore(30)}>Load more</button>
      )}
      {status === "LoadingMore" && <p>Loading</p>}
    </div>
  );
}

Each loaded page is its own subscription, so inserts and deletes anywhere in the list show up without refetching. status is LoadingFirstPage, CanLoadMore, LoadingMore, or Exhausted. For infinite scroll, call loadMore from an IntersectionObserver on a sentinel element when status === "CanLoadMore". Cursors come from .paginate() only. Do not build offset pagination by slicing a .collect() result.

Parallel loads with useQueries

Several useQuery calls in one component already load in parallel and stay consistent with each other. Reach for useQueries when the set of queries is dynamic, such as one query per id in a list.

typescript
import { useQueries } from "convex/react";
import { api } from "../convex/_generated/api";
import { Id } from "../convex/_generated/dataModel";

function Avatars({ userIds }: { userIds: Array<Id<"users">> }) {
  const users = useQueries(
    Object.fromEntries(
      userIds.map((userId) => [userId, { query: api.users.get, args: { userId } }]),
    ),
  );

  return (
    <div>
      {userIds.map((id) => {
        const user = users[id];
        if (user === undefined) return <span key={id}>...</span>;
        if (user instanceof Error) return <span key={id}>!</span>;
        return <img key={id} src={user.avatarUrl} alt={user.name} />;
      })}
    </div>
  );
}

Each value is undefined while loading, an Error on failure, or the query result.

Avoiding churn

Churn is a query rerunning for writes the component does not care about. Fix it on the server side first.

  • Narrow the read set. withIndex with an equality or range reads one slice. .filter() or a bare .query("table") reads the whole table, so any write to it reruns the query.
  • Return only what the component renders. A query that joins five tables reruns when any of the five change.
  • Never Date.now() in a query. Pass time as an argument and round it so the args stay stable: useQuery(api.tasks.overdue, { now: Math.floor(Date.now() / 60000) * 60000 }) reruns once a minute, not on every render.
  • Bound results with .take(n) or pagination. .collect() on a growing table is a growing read set.
  • Split hot fields into their own table. A lastSeen timestamp on the user document reruns every query that reads users. Put it in a presence table with its own query.
  • Debounce mutations from rapid input (typing, dragging) so the subscription is not flooded with intermediate states.
Show full SKILL.md (306 more words)Show less

Presence

Presence is a heartbeat mutation from each client plus a query over rows with a recent heartbeat, kept in a separate table so it does not touch anything else. Use the @convex-dev/presence component instead of building it. It handles heartbeats, disconnect cleanup, and a React hook.

typescript
// convex/convex.config.ts
import { defineApp } from "convex/server";
import presence from "@convex-dev/presence/convex.config";

const app = defineApp();
app.use(presence);
export default app;

Install with npm install @convex-dev/presence, then follow the package README for the server wrapper and the usePresence hook. If you must hand roll it, keep heartbeats in their own table, dedupe on the server with an early return when the last heartbeat is recent, and read with an index on roomId.

Common mistakes

MistakeWhy it breaksDo instead
if (userId) useQuery(...)hook order changes between rendersuseQuery(fn, userId ? args : "skip")
Treating undefined as emptyloading state renders as "no results"check === undefined first
Date.now() inside a querynondeterministic, breaks cachingpass now as an arg, rounded
.filter() on a large tablewhole table in the read setadd an index, use withIndex
.collect() for a feedread set grows with the table.take(n) or .paginate()
Optimistic update on one query onlyother views stale until the server respondsupdate every affected query in the callback
Offset pagination by slicing .collect()pages drift as rows insert.paginate() and usePaginatedQuery
lastSeen on the user documentevery user query reruns on each heartbeatseparate presence table or component

Checklist

  • Every useQuery handles undefined before reading the result
  • Conditional queries use "skip", not conditional hook calls
  • Every backend query has args and returns validators
  • Every query reads through withIndex, none use .filter() on a large table
  • No Date.now() or Math.random() inside any query
  • Lists that can grow use .paginate() and usePaginatedQuery
  • Optimistic updates touch every query the mutation changes
  • Hot fields like heartbeats live in their own table
  • Rapid input mutations are debounced on the client

Docs

© waynesutton, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 3 other files (assets) in skills/convex-realtime of waynesutton/builder-skills.

  • SKILL.md
  • agents/openai.yaml
  • assets/large-logo.png
  • assets/small-logo.svg

Open the folder on GitHubat commit 82d1ce2

Compare with similar skills

Convex Realtime next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Convex Realtime compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Convex Realtime this skillwaynesutton/builder-skills406—~2.6kAutomated safety check: PassApache-2.0
Hwc Navigation ContentTheHotwireClub/hotwire_club-skills148—~724Automated safety check: PassMIT
Update Project Docshoangsonww/Claude-Code-Agent-Monitor1.1k—~2.6kAutomated safety check: PassMIT
High Perf Browserwondelai/skills2.4k—~4kAutomated safety check: PassMIT
Trigger.dev Realtimepapermark/papermark9.2k—~1.7kAutomated safety check: PassCustom licence
Acarshub Design Languagesdr-enthusiasts/docker-acarshub117—~1.1kAutomated safety check: PassGPL-3.0

Similar skills

  • Hwc Navigation Content

    TheHotwireClub/hotwire_club-skills

    Build Hotwire navigation and content-discovery flows: Turbo Frame pagination, tabbed navigation, lazy loading, faceted filtering/search, cache lifecycle, scroll restoration, and visit/render control.

    148 GitHub stars~724 tokensUpdated 4 days ago
    Frontend & DesignAuto-check passed
  • Update Project Docs

    hoangsonww/Claude-Code-Agent-Monitor

    MANDATORY for every coding agent (Claude Code, Codex, or any other) — keep this repository's documentation in sync after any change to behavior, configuration, interfaces, events, schema, or features.

    1.1k GitHub stars~2.6k tokensUpdated today
    Frontend & DesignAuto-check passed
  • High Perf Browser

    wondelai/skills

    Optimize web performance through network protocols, resource loading, and browser rendering internals.

    2.4k GitHub stars~4k tokensUpdated 28 days ago
    Frontend & DesignAuto-check passed
  • Trigger.dev Realtime

    papermark/papermark

    Shows how to subscribe to Trigger.dev task runs from the backend and from React for progress indicators, live dashboards, AI response streams and approval waits.

    9.2k GitHub stars~1.7k tokensUpdated 1 mo ago
    Backend & APIsAuto-check passed
  • Acarshub Design Language

    sdr-enthusiasts/docker-acarshub

    Use ONLY when working in the docker-acarshub repository AND building UI -- React components, SCSS modules, theme variables, accessibility, mobile responsiveness, Catppuccin color usage, Zustand…

    117 GitHub stars~1.1k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Hwc Stimulus Fundamentals

    TheHotwireClub/hotwire_club-skills

    Cover Stimulus controller fundamentals: lifecycle hooks, values and valueChanged callbacks, targets and target callbacks, outlets, action parameters, keyboard events, and controller architecture…

    148 GitHub stars~701 tokensUpdated 4 days ago
    Backend & APIsAuto-check passed

More from waynesutton/builder-skills

All 17 skills in this repo
  • Convex Agents

    waynesutton/builder-skills

    Builds AI agents on the Convex agent component: threads, messages, tools that call queries and mutations, streaming, RAG with vector search, and workflows for multi step jobs.

    406 GitHub stars~2.2k tokensUpdated 11 days ago
    Auto-check passed
  • Convex Best Practices

    waynesutton/builder-skills

    Production patterns for Convex apps and the rules the @convex-dev/eslint-plugin enforces: validators, indexes, idempotent mutations, avoiding OCC conflicts, thin function wrappers, error handling.

    406 GitHub stars~2.6k tokensUpdated 11 days ago
    Auto-check passed
  • Convex Component Authoring

    waynesutton/builder-skills

    Creates reusable Convex components with defineComponent, a clean client wrapper, their own schema, and an npm publish setup.

    406 GitHub stars~2.6k tokensUpdated 11 days ago
    Auto-check passed
  • Convex Cron Jobs

    waynesutton/builder-skills

    Schedules work in Convex: cron jobs in convex/crons.ts, one off scheduled functions with runAfter and runAt, batching large jobs, and cancelling or inspecting the queue.

    406 GitHub stars~2k tokensUpdated 11 days ago
    Auto-check passed
  • Convex HTTP Actions

    waynesutton/builder-skills

    Adds HTTP endpoints in convex/http.ts: webhook receivers with signature checks, REST style routes, CORS, auth headers, streaming responses, and file uploads over HTTP.

    406 GitHub stars~2.6k tokensUpdated 11 days ago
    Auto-check passed
  • Convex Migrations

    waynesutton/builder-skills

    Changes a live Convex schema without downtime: make a field optional, backfill in batches, flip the validator, then clean up.

    406 GitHub stars~2.1k tokensUpdated 11 days ago
    Auto-check passed

Questions about Convex Realtime

What does Convex Realtime do?

Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn. Convex Realtime is an agent skill from waynesutton/builder-skills. Builds reactive UIs on Convex subscriptions: useQuery patterns, optimistic updates, pagination that stays live, presence, and avoiding subscription churn.

When should I use Convex Realtime?

Convex Realtime fits situations like: wiring the frontend to Convex; data does not update live; A page rerenders too much.

How do I install Convex Realtime in Claude Code?

Run `npx skills add waynesutton/builder-skills --skill convex-realtime -a claude-code`. Or copy the skill folder (skills/convex-realtime in waynesutton/builder-skills) into .claude/skills/convex-realtime in your project. Claude Code loads it when a task matches its description.

How do I install Convex Realtime in Codex?

Run `npx skills add waynesutton/builder-skills --skill convex-realtime -a codex`. Or copy the skill folder (skills/convex-realtime in waynesutton/builder-skills) into .agents/skills/convex-realtime in your project. Codex loads it when a task matches its description.

Can I use Convex Realtime in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add waynesutton/builder-skills --skill convex-realtime -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/convex-realtime, .gemini/skills/convex-realtime, .github/skills/convex-realtime and .opencode/skills/convex-realtime in your project.

What does Convex Realtime need to run?

Going by SKILL.md and its folder, Convex Realtime needs the command-line tools its instructions call (npm). Our summary lists: Node.js.

Does Convex Realtime access the network?

SKILL.md names 2 domains. As links in the text: docs.convex.dev and convex.dev. This is read from the text; nothing was executed.

Is Convex Realtime safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Convex Realtime use?

Convex Realtime is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Convex Realtime use?

About 2.6k tokens (SKILL.md is roughly 10k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Convex Realtime?

Skills that share tags, products or a category with Convex Realtime: Hwc Navigation Content (TheHotwireClub/hotwire_club-skills, 148 stars), Update Project Docs (hoangsonww/Claude-Code-Agent-Monitor, 1.1k stars), High Perf Browser (wondelai/skills, 2.4k stars) and Trigger.dev Realtime (papermark/papermark, 9.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Convex Realtime?

waynesutton (a GitHub user) maintains it in waynesutton/builder-skills, which has 406 GitHub stars. The repository holds 17 skills in this directory. The repository was last updated on September 28, 2026.

Source: waynesutton/builder-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.