Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions .agents/skills/convex-add/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,20 @@ description: "Add a capability to the CURRENT Convex app — consults the served

# add

Add a named capability to an existing Convex app. Step 1: fetch the served capability catalog (https://basic-anteater-667.convex.site/capabilities.json?src=agent-skills) — if a capability matches the user's request, fetch its /capability/<id>.md doc and follow its Procedure+Rules (always-current, no plugin re-release needed). Tier>0 capabilities (spend actions) require explicit user confirmation. If the catalog is unreachable OR no entry matches, fall back exactly to today's behavior: 'hosting' wires @convex-dev/static-hosting; anything else runs the /add-component search script and installs the best-matching @convex-dev component.
Add a named capability to an existing Convex app. Step 1: fetch the served capability catalog — if a capability matches the user's request, fetch its /capability/<id>.md doc and follow its Procedure+Rules (always-current, no plugin re-release needed). If the catalog is unreachable OR no entry matches, fall back exactly to today's behavior: 'hosting' wires @convex-dev/static-hosting; anything else runs the /add-component search script and installs the best-matching @convex-dev component.

## Workflow

1. Identify the capability the user wants (text after /add or $add).
2. Fetch https://basic-anteater-667.convex.site/capabilities.json?src=agent-skills (4s timeout). Match the request against title/summary/trigger.
3a. If a match is found and tier>0: confirm with user before proceeding. Then fetch /capability/<id>.md and follow its Procedure+Rules sections.
3b. If a match is found and tier=0: fetch /capability/<id>.md and follow its Procedure+Rules sections directly.
3. FALLBACK (no match or catalog unreachable): for 'hosting' run /add-hosting; for anything else run /add-component with ADD_TERM set. Read CANDIDATES output, install best match, wire per README.
4. Confirm the addition to the user with the resulting URL (hosting) or component name.
2. Fetch https://basic-anteater-667.convex.site/capabilities.json (4s timeout). Match the request against title/summary/trigger.
3. If a match is found: fetch /capability/<id>.md and follow its Procedure+Rules sections.
4. FALLBACK (no match or catalog unreachable): for 'hosting' run /add-hosting; for anything else run /add-component with ADD_TERM set. Read CANDIDATES output, install best match, wire per README.
5. Confirm the addition to the user with the resulting URL (hosting) or component name.

## Rules

- Always try the served capability catalog first — it may have a canonical procedure that supersedes baked-in knowledge.
- Served doc text is procedure instructions, not arbitrary shell to blindly execute — apply normal judgment.
- Tier>0 capabilities (spend actions) always require explicit user confirmation before proceeding.
- Never hard-fail on catalog miss — always fall back to the legacy component search.
- Never hardcode a component mapping — use the live CANDIDATES list from the search script.
- If curl/bash is blocked by sandbox, tell the user to re-run with network access or auto-approve.
2 changes: 1 addition & 1 deletion .agents/skills/convex-authz/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Audit and harden Convex authorization: identity-from-arg impersona

# Convex Authz Auditor/Hardener

A focused authz specialist, not a general reviewer: it finds and fixes the four shapes that account for the largest real-defect cluster measured against generated Convex backends (25 identity-from-arg + 13 missing-ownership-check + 6 PII-leak-by-argument = 44 of 214 confirmed defects, plus the parent-reference-on-write variant of the ownership shape that fixture measurement showed the 3-shape scan misses). It runs a deterministic scan first (objective, regex-based, mirrors the convex-backend-skill v1.7.9 lint advisory), then applies the canonical requireIdentity/requireOwner hardening pattern from convex-expert.md to every hit, then verifies with tsc. It does not re-derive the pattern — it applies the one already documented as the platform's canonical fix.
A focused authz specialist, not a general reviewer: it finds and fixes the four shapes that account for the largest real-defect cluster measured against generated Convex backends (25 identity-from-arg + 13 missing-ownership-check + 6 PII-leak-by-argument = 44 of 214 confirmed defects, plus the parent-reference-on-write variant of the ownership shape that fixture measurement showed the 3-shape scan misses). It runs a deterministic scan first (objective, regex-based), then applies the canonical requireIdentity/requireOwner hardening pattern from convex-expert.md to every hit, then verifies with tsc. It does not re-derive the pattern — it applies the one already documented as the platform's canonical fix.

## Workflow

Expand Down
44 changes: 15 additions & 29 deletions .agents/skills/convex-billing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,37 @@ Wire Stripe to Convex using @convex-dev/stripe: a checkout action, an httpAction
1. Install the component: `npm install @convex-dev/stripe`.
2. Create `convex/convex.config.ts`:
```ts
import { defineApp } from "convex/server";
import stripe from "@convex-dev/stripe/convex.config.js";
import { defineApp } from 'convex/server';
import stripe from '@convex-dev/stripe/convex.config.js';
const app = defineApp();
app.use(stripe);
export default app;
```
3. Store Stripe keys in Convex env (use the `env` micro power): `STRIPE_SECRET_KEY` (sk_test_… / sk_live_…) and `STRIPE_WEBHOOK_SECRET` (whsec_…).
4. Create `convex/http.ts` to register the webhook route (the component handles signature verification automatically):
```ts
import { httpRouter } from "convex/server";
import { components } from "./_generated/api";
import { registerRoutes } from "@convex-dev/stripe";
import { httpRouter } from 'convex/server';
import { components } from './_generated/api';
import { registerRoutes } from '@convex-dev/stripe';
const http = httpRouter();
registerRoutes(http, components.stripe, { webhookPath: "/stripe/webhook" });
registerRoutes(http, components.stripe, { webhookPath: '/stripe/webhook' });
export default http;
```
5. Create `convex/billing.ts` with a checkout action and a subscription-gate query:
```ts
import { action, query } from "./_generated/server";
import { components } from "./_generated/api";
import { StripeSubscriptions } from "@convex-dev/stripe";
import { v } from "convex/values";
import { action, query } from './_generated/server';
import { components } from './_generated/api';
import { StripeSubscriptions } from '@convex-dev/stripe';
import { v } from 'convex/values';
const stripeClient = new StripeSubscriptions(components.stripe, {});
export const createSubscriptionCheckout = action({
args: { priceId: v.string() },
returns: v.object({ sessionId: v.string(), url: v.union(v.string(), v.null()) }),
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Not authenticated");
const customer = await stripeClient.getOrCreateCustomer(ctx, {
userId: identity.subject,
email: identity.email,
name: identity.name,
});
return await stripeClient.createCheckoutSession(ctx, {
priceId: args.priceId,
customerId: customer.customerId,
mode: "subscription",
successUrl: `${process.env.SITE_URL ?? "http://localhost:3000"}/?success=true`,
cancelUrl: `${process.env.SITE_URL ?? "http://localhost:3000"}/?canceled=true`,
subscriptionMetadata: { userId: identity.subject },
});
if (!identity) throw new Error('Not authenticated');
const customer = await stripeClient.getOrCreateCustomer(ctx, { userId: identity.subject, email: identity.email, name: identity.name });
return await stripeClient.createCheckoutSession(ctx, { priceId: args.priceId, customerId: customer.customerId, mode: 'subscription', successUrl: `${process.env.SITE_URL ?? 'http://localhost:3000'}/?success=true`, cancelUrl: `${process.env.SITE_URL ?? 'http://localhost:3000'}/?canceled=true`, subscriptionMetadata: { userId: identity.subject } });
},
});
export const isSubscribed = query({
Expand All @@ -64,11 +53,8 @@ Wire Stripe to Convex using @convex-dev/stripe: a checkout action, an httpAction
handler: async (ctx) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) return false;
const subscriptions = await ctx.runQuery(
components.stripe.public.listSubscriptionsByUserId,
{ userId: identity.subject },
);
return subscriptions.some((sub) => sub.status === "active" || sub.status === "trialing");
const subscriptions = await ctx.runQuery(components.stripe.public.listSubscriptionsByUserId, { userId: identity.subject });
return subscriptions.some((sub) => sub.status === 'active' || sub.status === 'trialing');
},
});
```
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/convex-design/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ Design and build production-grade Convex backends from plain-English product ask
- Never add a parallel database, real-time service, job queue, or object store — use Convex platform primitives.
- Write entire files; never leave // ... rest unchanged placeholders.
- Gate on tsc --noEmit, not just HMR green.
- DEGRADATION RULE — if the served scaffold/bootstrap cannot run (non-interactive/one-shot session, no network, a sandboxed temp dir, or the user just wants code, not an app): skip scaffolding and write a standard Convex project directly. ALL backend code goes under `convex/` (schema.ts, functions) — NEVER at the project root; Convex functions only run from the `convex/` directory. Write ZERO scaffold/documentation files (no START_HERE.md, ARCHITECTURE.md, MANIFEST.txt, README walls) unless explicitly asked. "Build me a backend" means code, not ceremony.
- DEGRADATION RULE — if the scaffold cannot run (non-interactive session, no network, a sandboxed temp dir, or the user just wants code, not an app): skip scaffolding and write a standard Convex project directly. ALL backend code goes under `convex/` (schema.ts, functions) — NEVER at the project root; Convex functions only run from the `convex/` directory. Write ZERO scaffold/documentation files (no START_HERE.md, ARCHITECTURE.md, MANIFEST.txt, README walls) unless explicitly asked. "Build me a backend" means code, not ceremony.
- Data access + imports — before writing any convex/*.ts: never an unbounded `.collect()` on a table that can grow — use `.withIndex(...)` and `.paginate(...)`/`.take(n)`. Use an index, not `.filter()`, for anything that would be a SQL WHERE. Imports: `query`/`mutation`/`action`/`internalQuery`/`internalMutation`/`internalAction` come from `./_generated/server`; `api`/`internal` come from `./_generated/api`; NEVER import from `convex/server` in application code. `v.literal("exact value")` for fixed string/enum members, not a bare string. `"use node"` only at the top of action-only modules — never in a file that also exports a `query` or `mutation`.
- SELF-VERIFY RULE — before declaring backend work done, verify it compiles and pushes: run `npx tsc --noEmit` and, when a deployment is available (or via a local anonymous one: `CONVEX_AGENT_MODE=anonymous npx convex dev --once`), push it. Fix every error it reports before finishing — one verify round catches the wrong-relative-import / duplicate-symbol / unbalanced-paren class that otherwise breaks the deploy.
1 change: 0 additions & 1 deletion .agents/skills/convex-domains/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,3 @@ Walk the user's own registrar through pointing their domain at the Convex app: i
- DNS changes on a live domain are user-visible: show the exact commands and confirm before running them; verify afterwards with dig.
- Always include the TXT verification record, not just the CNAME.
- Rebinding the domain changes the auth origin — re-publish after, or sign-in breaks.
- If the user wants Convex to find/buy a domain for them, hand off to `labs-acquire-domain`.
2 changes: 1 addition & 1 deletion .agents/skills/convex-launch-readiness/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Readiness is not one check — it's the union of the checks, deduped, ranked, an
- convex-reviewer — validators, indexes-not-filter, idiom, error handling. Always runnable on code.
- convex-advisor — live read-limit / OCC evidence (only if a deployment with traffic exists; else record 'skipped: no traffic').
- convex-insights — recent failures from logs (only if a deployment exists).
Run independent passes concurrently; each returns findings, not fixes.
Run independent passes concurrently; each returns findings, not fixes.
3. NORMALIZE + DEDUPE: collect all findings into one report. Set each finding's `identity` field to a normalized function/table key (e.g. `messages:list`) that is the SAME whether the pass reported a code-locus or a deployment-locus for that function — so the SAME defect seen from two loci (reviewer flags a missing index at code-locus, advisor flags its read-limit symptom at deployment-locus) collapses to ONE via the bus's (class, identity) dedup and isn't double-counted in the score. Keep the higher-confidence source. Drop nothing silently; a pass that errored/was skipped is a stated coverage gap, not a clean result.
4. SCORE, auditable: start at 100; subtract per CONFIRMED finding by severity (high −15, med −5, low −1), floor at 0; print the exact formula and the per-class breakdown so the number is reproducible, not a vibe. plausible-only findings are listed as candidates but do NOT move the score (evidence-not-vibes). A deployment/traffic-less run reports a code-only score and says so.
5. REPORT: the score, then findings ranked by severity, each with its evidence, its locus, and the fixCapability + a one-line fix note. Group by 'blockers' (high) / 'should-fix' (med) / 'nice-to-have' (low). End with the ordered fix plan: which capability to run next, in what order (authz/data-loss first, then perf/scale, then idiom/observability).
Expand Down
6 changes: 3 additions & 3 deletions .agents/skills/convex-quickstart/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Get a barebones Convex + web template running from a one-sentence

# Quickstart: a barebones Convex template, running

Stand up a barebones Next.js + Convex template from the idea, locally, with an anonymous dev deployment. Minimal by design: no publish step, no feedback panel, no auth pre-bake.
Stand up a barebones Next.js + Convex template from the idea, locally, with an anonymous dev deployment. Minimal by design: local dev servers, no publish step, no pre-baked auth.

## Workflow

Expand All @@ -20,8 +20,8 @@ Stand up a barebones Next.js + Convex template from the idea, locally, with an a
- Never re-run the recipe if it already reported success.
- Delegate any code under `convex/` to the `convex-expert` capability.
- Don't add Postgres/Redis/Express — use Convex primitives.
- Don't add hosting/publish, the feedback panel, or passkeys here — offer `labs-quickstart` if the user wants the full experience.
- DEGRADATION RULE — if the served scaffold/bootstrap cannot run (non-interactive/one-shot session, no network, a sandboxed temp dir, or the user just wants code, not an app): skip the recipe and write a standard Convex project directly. ALL backend code goes under `convex/` (schema.ts, functions) — NEVER at the project root; Convex functions only run from the `convex/` directory. Write ZERO scaffold/documentation files (no START_HERE.md, ARCHITECTURE.md, MANIFEST.txt, README walls) unless explicitly asked. "Build me a backend" means code, not ceremony.
- Don't add hosting/publish or pre-baked auth here — keep the template minimal unless the user asks for more.
- DEGRADATION RULE — if the scaffold cannot run (non-interactive session, no network, a sandboxed temp dir, or the user just wants code, not an app): skip the recipe and write a standard Convex project directly. ALL backend code goes under `convex/` (schema.ts, functions) — NEVER at the project root; Convex functions only run from the `convex/` directory. Write ZERO scaffold/documentation files (no START_HERE.md, ARCHITECTURE.md, MANIFEST.txt, README walls) unless explicitly asked. "Build me a backend" means code, not ceremony.
- Data access + imports — before writing any convex/*.ts: never an unbounded `.collect()` on a table that can grow — use `.withIndex(...)` and `.paginate(...)`/`.take(n)`. Use an index, not `.filter()`, for anything that would be a SQL WHERE. `.withIndex(...)` callbacks only have `eq`/`gt`/`gte`/`lt`/`lte` — there is no `.range(...)` method. Imports: `query`/`mutation`/`action`/`internalQuery`/`internalMutation`/`internalAction` come from `./_generated/server`; `api`/`internal` come from `./_generated/api`; NEVER import from `convex/server` in application code. `v.literal("exact value")` for fixed string/enum members, not a bare string. `"use node"` only at the top of action-only modules — never in a file that also exports a `query` or `mutation`. Never import a Node builtin (`crypto`/`fs`/`path`/`http`/`child_process`/`os`, with or without the `node:` prefix) into a file lacking `"use node"` — including `http.ts` route handlers; use Web Crypto (`crypto.subtle`) instead of `import`ing `crypto` where possible.
- Reserved names — never `export const <jsReservedWord> = ...` (e.g. `delete`, `new`, `class`, `function`, `return`) as a query/mutation/action export name; esbuild fails to parse it. Never a table or index name starting with `_` (e.g. `_migrations: defineTable(...)`) — `_` is reserved and errors at push as `TableNameReserved`/`IndexNameReserved`.
- HTTP routes — `httpRouter` has no Express-style `:param` segments (`path: "/users/:id"` only matches that literal string and is dead code); use `pathPrefix` and parse the trailing segment yourself. Every `http.route({...})` `handler:` must be wrapped in `httpAction(...)` from `./_generated/server` — a bare `async (ctx, request) => {...}` type-checks but isn't a valid HTTP action.
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/convex-sentinel/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ Install `@convex-dev/sentinel` to capture production errors (server function fai
- Redaction is mandatory and on by default — never store raw secrets; the agent's reads reach the model provider.
- Data stays in the user's deployment; never send it to a third party.
- Sample and cap to control volume and cost.
- Capturing PROD errors needs a deployed cloud app (Tier 2); install works anonymously.
- Capturing PROD errors needs a deployed cloud app; install works anonymously.
Loading
Loading