Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .claude/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a codex
Project install goes to .agents/skills/; add -g for ~/.codex/skills/.
Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .agents/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a cursor
Project install goes to .agents/skills/; add -g for ~/.cursor/skills/.
Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .cursor/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a gemini-cli
Project install goes to .agents/skills/; add -g for ~/.gemini/skills/.
Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .gemini/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a github-copilot
Project install goes to .agents/skills/; add -g for ~/.copilot/skills/.
Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .github/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add waynesutton/builder-skills --skill convex-realtime -a opencode
OpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
Install the "convex-realtime" agent skill from https://github.com/waynesutton/builder-skills/tree/main/skills/convex-realtime into .opencode/skills/convex-realtime/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "convex-realtime", then confirm the skill loads.
OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
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.
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:
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.
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
Mistake
Why it breaks
Do instead
if (userId) useQuery(...)
hook order changes between renders
useQuery(fn, userId ? args : "skip")
Treating undefined as empty
loading state renders as "no results"
check === undefined first
Date.now() inside a query
nondeterministic, breaks caching
pass now as an arg, rounded
.filter() on a large table
whole table in the read set
add an index, use withIndex
.collect() for a feed
read set grows with the table
.take(n) or .paginate()
Optimistic update on one query only
other views stale until the server responds
update every affected query in the callback
Offset pagination by slicing .collect()
pages drift as rows insert
.paginate() and usePaginatedQuery
lastSeen on the user document
every user query reruns on each heartbeat
separate 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
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
Skill
Stars
Used in
Tokens
Auto-check
Licence
Repo updated
Convex Realtime this skillwaynesutton/builder-skills
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.
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.
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…
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.
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.
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.
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.