Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2800238
Add host-created events with per-night URLs
cursoragent Aug 17, 2026
6b8beb5
Drop restating comments on the event API
cursoragent Aug 17, 2026
1f56b82
Fix featured persistence, schema migration, loading links, and slug trim
cursoragent Aug 17, 2026
6a0ec06
Fix Convex preview: make eventId optional and install AI files
cursoragent Aug 17, 2026
da87bcc
Fix npm lockfile, Convex start sync, and unused indexes
cursoragent Aug 17, 2026
b27bf0d
Fix seed backfill collisions, reserved slugs, and copy capacity
cursoragent Aug 18, 2026
2abb220
Keep orphan backfill from exceeding event capacity
cursoragent Aug 18, 2026
1bda3ea
Recover public seed without a host visit
cursoragent Aug 18, 2026
850ddb1
Add open-night list and a collision-safe signup move
cursoragent Aug 18, 2026
87ab0fc
Give hosts nav, route codes, and date/time when pickers
cursoragent Aug 18, 2026
a4968b8
Show other rooms and make wrong-talk signups movable
cursoragent Aug 18, 2026
a0be749
Make a moved signup re-enter the target night's funnel
cursoragent Aug 20, 2026
1edd07b
Hold picker state as date and time keys, never parse the string
cursoragent Aug 20, 2026
396d826
Derive header links from one night context and share the move control
cursoragent Aug 20, 2026
edabc97
Keep host when and move from writing defaults on first tap
cursoragent Aug 20, 2026
d636659
Keep unparsed when from saving a fallback picker date
cursoragent Aug 20, 2026
212f568
Prompt for a date instead of preselecting the fallback Thursday
cursoragent Aug 20, 2026
d5d1f0e
Add shadcn calendar, popover, and button in the film palette
cursoragent Aug 20, 2026
be33a7e
Open the when date on a calendar instead of a 16-day list
cursoragent Aug 20, 2026
30063ad
Show host identity in the public chrome
cursoragent Aug 20, 2026
8289dd0
Raise nav pill contrast on the dark hero
cursoragent Aug 20, 2026
8c7b47e
Pin the calendar's today to the venue date
cursoragent Aug 20, 2026
de4b556
Give hosts a guest QR instead of route codes, and any doors time
cursoragent Aug 20, 2026
6457508
Let hosts change a night's slots after posting it
cursoragent Aug 20, 2026
3f2415d
Archive AiOS SF and seed a distinct HTW night
cursoragent Aug 31, 2026
4b1c13e
Drive apply and board copy from the event
cursoragent Aug 31, 2026
0982ce3
Let agents open a guest harness without Clerk
cursoragent Aug 31, 2026
d654c0f
Forward the harness pathname on the request
cursoragent Aug 31, 2026
5d5b6c3
Stop HostDesk remounts from restaging the featured night
cursoragent Aug 31, 2026
c98f993
Merge remote harness pathname fix into seed review fixes
cursoragent Aug 31, 2026
95cbf61
Cut the header down to Board, slot, and Desk
cursoragent Aug 31, 2026
5e63adb
Hide archived nights from public guest slugs
cursoragent Sep 1, 2026
6b5023f
Keep archived night slugs reachable for room QRs
cursoragent Sep 1, 2026
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
26 changes: 26 additions & 0 deletions .agents/skills/convex-add/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: convex-add
description: "Add a capability to the CURRENT Convex app — consults the served Convex capability catalog for always-current procedures (billing, crons, auth, agent, search, …); falls back to built-in hosting or @convex-dev component search. TRIGGER when the user runs /add, or asks to add hosting/publishing or any backend capability to an existing Convex app."
---

<!-- GENERATED from convex-agents content/capabilities/add.json — do not edit by hand. -->

# add

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 (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.
- 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.
32 changes: 32 additions & 0 deletions .agents/skills/convex-advisor/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: convex-advisor
description: "Read the Convex deployment's 72h insights (read limits, OCC contention), root-cause each event in code, report evidence-backed perf/cost findings with fixes."
---

<!-- GENERATED from convex-agents content/capabilities/convex-advisor.json — do not edit by hand. -->

# Live-deployment advisor

Static review guesses; the deployment KNOWS. The official Convex MCP ships an `insights` tool with typed 72h health events per function — documentsReadLimit / bytesReadLimit (hard limit hits), documentsReadThreshold / bytesReadThreshold (approaching), occFailedPermanently / occRetried (write contention) — each carrying evidence (table_name, bytes_read, documents_read, occ document id + retry count). The advisor turns each event into a root-caused finding by reading the flagged function's actual code, and emits findings on the findings bus (specs/finding.schema.json) so fixers can be dispatched and launch-readiness can score.

## Workflow

1. GUARD: run deploy-guard step 0-1 — identify + announce the deployment being read. Reading insights/logs on prod is allowed read-only; never enable mutating prod access for an advisory pass.
2. GATHER (deterministic, via the official Convex MCP): `status` → deployment selector; `insights` → the typed 72h events; `tables` → schema + row counts; `functionSpec` → the public/internal surface. The `insights` tool is only available on cloud dev/prod deployments when logged in as a user (not on previews or deploy-key-scoped contexts) and needs ~72h of traffic; if it returns nothing or is unavailable, say so and fall back to offering convex-reviewer — do NOT invent findings.
3. ROOT-CAUSE each insight event by reading the flagged function's code:
- bytesReadThreshold/Limit or documentsReadThreshold/Limit → look for `.collect()` / unindexed `.filter()` / missing pagination on the named table; the fix is an index + `.withIndex`, `.take(n)`, or `.paginate` (convex-expert patterns), or an aggregate component for counting shapes.
- occRetried / occFailedPermanently → look for read-modify-write hotspots on the named document (shared counters, status toggles); the fix is @convex-dev/sharded-counter, narrowing the read set, or moving contention to a workpool.
- repeated failures in `logs` (status: failure) → classify: crash loop in a cron, validator rejections, unhandled error shapes.
4. EMIT findings per specs/finding.schema.json: class perf/correctness/cost, severity from the insight kind (limit hits = high, thresholds = med, retried = med, permanent OCC failure = high), locus {kind: deployment, functionId, tableName}, evidence {kind: insight-event, detail: the raw event}, confidence: confirmed (the event happened — it is not a hypothesis), fixCapability + autofixable where the repair is mechanical.
5. REPORT: findings ranked by severity, each with (a) the runtime evidence in one line ('messages:list read 4.2MB from messages 31× yesterday'), (b) the code-level root cause with file:line, (c) the concrete fix and which capability applies it. Offer to apply fixes; apply only on confirmation, then re-run `insights` after traffic to verify the trend, or re-run the static check immediately.
6. Scope discipline: this is a health/perf/cost pass. Route authz findings to convex-authz, code-idiom findings to convex-reviewer, error triage to sentinel — emit a pointer finding rather than duplicating their work.

## Rules

- Evidence-not-vibes: every finding cites a real insight event, log line, or table stat — if the deployment has no evidence, the advisor has no findings (offer convex-reviewer instead).
- Read-only by construction: an advisory pass never mutates any deployment and never enables prod mutation flags (deploy-guard discipline applies).
- Root-cause in the code before reporting: an insight event names the symptom; the finding must name the line and the mechanism.
- Emit on the findings bus (specs/finding.schema.json), confidence: confirmed — runtime events are facts, not hypotheses.
- Severity from the event kind: limit-hit / permanent-OCC-failure = high; threshold / retried = med.
- Stay in lane: perf/cost/health only — hand authz to convex-authz, style to convex-reviewer, error triage to sentinel.
- Prefer component fixes over hand-rolls when they match (sharded-counter for OCC on counters, aggregate for count scans) — same bias as suggest.
23 changes: 23 additions & 0 deletions .agents/skills/convex-agent/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: convex-agent
description: "Add an AI agent / RAG backend (@convex-dev/agent) to the Convex app."
---

<!-- GENERATED from convex-agents content/capabilities/agent.json — do not edit by hand. -->

# Add an AI agent / RAG backend

Install @convex-dev/agent for durable threads, message history, tool-calls, and vector search/RAG — the backend for an in-app AI agent.

## Workflow

1. Install @convex-dev/agent + add to convex.config.ts.
2. Define the agent (model, tools, instructions); store the LLM key via the `env` micro power.
3. Create threads + stream messages; persist history in Convex.
4. For RAG: embed docs into a vector index and retrieve in the tool.

## Rules

- Keep the LLM API key in Convex env (use the `env` micro power), never client-side.
- Run model calls in actions ('use node' if the SDK needs it).
- Persist threads/messages in Convex for durability + reactivity.
29 changes: 29 additions & 0 deletions .agents/skills/convex-auth/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: convex-auth
description: "Add authentication (passkeys/OAuth) to the current Convex app, including the auth.config.ts wiring."
---

<!-- GENERATED from convex-agents content/capabilities/auth.json — do not edit by hand. -->

# Add sign-in to the app

Install and wire @convex-dev/auth for the current app: a provider (passkeys by default, or OAuth/password), the server config, the client hooks, and a sign-in UI — correctly, including the auth.config.ts that's the #1 real-world auth footgun.

## Workflow

1. Install @convex-dev/auth (pinned build) and add it to convex.config.ts. With pnpm, also `pnpm add jose` (it won't hoist otherwise); you need it for step 3.
2. Add the provider in convex/auth.ts (Passkey by default; Password or OAuth like Google on request).
3. Generate the auth keys HEADLESSLY. Do NOT run the interactive `npx @convex-dev/auth` wizard: it needs a login/TTY and hangs in non-interactive, anonymous, or CI runs (the #1 auth time-sink). Generate JWT_PRIVATE_KEY + JWKS deterministically with `jose`:
node -e 'import("jose").then(async({generateKeyPair,exportPKCS8,exportJWK})=>{const k=await generateKeyPair("RS256",{extractable:true});const priv=await exportPKCS8(k.privateKey);const pub=await exportJWK(k.publicKey);process.stdout.write(JSON.stringify({JWT_PRIVATE_KEY:priv.trimEnd().replace(/\n/g," "),JWKS:JSON.stringify({keys:[{use:"sig",...pub}]})}))})' > .auth-keys.json
Then set JWT_PRIVATE_KEY and JWKS (from .auth-keys.json) plus SITE_URL on the deployment. Prefer the Convex MCP `envSet` tool, one call per var, to avoid shell-quoting the multi-line key. CLI fallback: use the NAME=VALUE form (`npx convex env set "JWT_PRIVATE_KEY=$JWT"`), NEVER `env set JWT_PRIVATE_KEY "$JWT"` (the value starts with `-----BEGIN` and the CLI parses the leading `-` as an unknown flag). SITE_URL is the dev URL (e.g. http://localhost:3000). Delete .auth-keys.json after.
4. Write convex/auth.config.ts (the silently-always-signed-out bug lives here if it's wrong).
5. Wire the client: ConvexAuthProvider, the sign-in component, and route guards. If you import shadcn/ui primitives (button, input, textarea, label, and so on), add them first with `npx shadcn@latest add <name>`; a missing @/components/ui/* is a hard build error.
6. Verify a sign-in round-trips before declaring done.

## Rules

- Generate JWT_PRIVATE_KEY/JWKS with `jose` (extractable RS256; PKCS8 newlines to spaces; JWKS = {keys:[{use:"sig", ...publicJwk}]}). Do NOT run the interactive `npx @convex-dev/auth` wizard: it hangs headless/anonymous. Set the vars via the MCP `envSet` tool or the NAME=VALUE CLI form.
- Always write auth.config.ts: a missing/incorrect one makes the app silently always-signed-out with no error.
- Passkeys by default; only switch to password/OAuth on explicit request.
- Install any shadcn/ui primitive you import up front (`npx shadcn@latest add ...`); a missing @/components/ui/* is a hard build failure.
- Verify a real sign-in works before finishing.
36 changes: 36 additions & 0 deletions .agents/skills/convex-authz/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: convex-authz
description: "Audit and harden Convex authorization: identity-from-arg impersonation, missing per-document ownership checks, PII-leaking public queries, and writes into containers the caller doesn't own. Deterministic scan + canonical requireIdentity/requireOwner fix + tsc verify. Use for 'secure my app' / 'audit auth' / 'who can access this data', not generic code review."
---

<!-- GENERATED from convex-agents content/capabilities/convex-authz.json — do not edit by hand. -->

# 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), 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

0. MANDATORY FIRST STEP — check the auth foundation exists before injecting any ctx.auth enforcement: (1) is there an auth.config.ts with a provider? (2) is there a users/identities table keyed to the auth subject (tokenIdentifier/identity.subject)? If EITHER is missing, DO NOT add requireIdentity/requireOwner — on a foundationless app ctx.auth.getUserIdentity() always returns null (enforcement is non-functional: every call 401s, or worse, the check is bypassed/miscompared against a non-subject field like an email string) and a reviewer correctly flags that as a NEW authz defect, not a fix. Instead, on a foundationless app: (a) for privileged/admin operations, convert the public query/mutation to internalQuery/internalMutation (removes public reachability entirely — safe and foundation-free, no ctx.auth needed), and (b) tell the user: 'this app has no auth foundation; run `/add auth` or the auth setup first, then re-run convex-authz to add per-user ownership checks.' Do not run steps 1-3 below against public functions on a foundationless app beyond this internalize-and-defer move. Only when the foundation exists (both auth.config.ts and a subject-keyed users table are present) do you proceed to inject requireIdentity/requireOwner in steps 1-3.
1. SCAN (deterministic, objective-first): for every convex/**/*.ts file (skip convex/_generated/ and .d.ts), grep for the four shapes:
(a) identity-from-arg: a public `query(`/`mutation(` object whose `args` block declares `userId`/`actorId`/`ownerId`/`authorId`/`accountId` typed `v.id(...)`, where the function's whole block (args + handler) has zero `ctx.auth` reference. Regex: `/\b(userId|actorId|ownerId|authorId|accountId)\s*:\s*v\.id\(/` inside an `args: { ... }` block paired with an absent `/\bctx\.auth\b/` anywhere in the enclosing `(query|mutation)\(\s*\{ ... }` block (word-boundary excludes internalQuery/internalMutation by construction).
(b) missing-ownership-check: a public `query(`/`mutation(` whose handler loads a document via `ctx.db.get(args.<xId>)` (an `_id`-typed arg) and then calls `ctx.db.patch`/`ctx.db.delete`/`ctx.db.replace` on that same id, or returns the doc's fields directly, with no comparison of any `<doc>.<ownerField>` against an identity value anywhere in the block (no `===`/`!==` involving `identity.subject` or a `ctx.auth` derived value).
(c) PII-leaking public query: a public `query(` whose `returns` (or the raw doc it returns) includes a sensitive-looking field (`email`, `revenue`, `ssn`, `password`, `token`, `auditLog`, `dashboard`-shaped aggregate) and the query is parameterized by a client-supplied id with no `ctx.auth` check gating access to that id's own scope.
(d) parent-reference ownership on write: a public `mutation(` whose args include a `v.id(...)` of a parent/container table (`projectId`, `boardId`, `teamId`, `orgId`, `listId`, `folderId`, `conversationId`, `accountId`, ...) that the handler uses as a foreign key in a `ctx.db.insert`/`ctx.db.patch` — attaching or moving a child row into that container — without verifying the caller owns (or is a member of) the referenced parent doc. Creating a row inside someone else's container is the same defect as mutating their row: fixing WHO the caller is (shape a) does not fix WHERE they may write. After handling shapes a-c, re-audit every REMAINING `v.id(...)` arg in every public mutation for this shape — shape-a fixes routinely leave the parent id arg behind, still unchecked.
Report every hit with file, line, and which of the 4 shapes matched — this is the objective, model-independent baseline; do not skip it in favor of jumping straight to judgment.
2. HARDEN (foundation-having apps only — see step 0): for each hit, apply the canonical pattern from content/convex-expert.md verbatim — do not invent a new helper. Add (if absent) `convex/model/auth.ts` exporting `requireIdentity(ctx)` (throws 401 if `ctx.auth.getUserIdentity()` is null; returns the identity) and `requireOwner(ctx, doc)` (throws 404 if doc is null, throws 403 if `doc.ownerId !== identity.subject`, else returns doc). Rewrite each flagged function: replace the client-supplied identity arg with `requireIdentity(ctx)`; wrap each `_id`-keyed read/mutate with `requireOwner(ctx, await ctx.db.get(args.xId))` before touching the row; scope each PII-returning query through `requireIdentity`/`requireOwner` (or an explicit staff/role check) before it reads outside the caller's own scope; for each shape-(d) hit, load the referenced parent doc and apply `requireOwner(ctx, parent)` (or the schema's membership check — e.g. `participantIds.includes(user._id)` — when the container models members as an array) BEFORE inserting/patching the child row. When the schema keys ownership by a `users` row id rather than the raw subject, resolve the caller's `users` row first (via the subject-keyed index) and compare against `user._id` — comparing an `Id<"users">` field to `identity.subject` never matches and silently breaks enforcement. Never widen scope — an internal/admin function that legitimately operates on an arbitrary user stays `internalQuery`/`internalMutation`, never public; leave it unflagged and unchanged.
3. VERIFY: run `npx tsc --noEmit` (or the project's typecheck script) after edits; a hardening pass that doesn't typecheck is not done. Then re-run the step-1 scan to confirm 0 remaining hits (the fixed shapes no longer match the regexes because `ctx.auth` now appears in-block and ownership comparisons now exist).
4. Report findings grouped by the 4 rule shapes with file:line, explain why each is exploitable (who could impersonate whom / read whose data), and show the concrete diff applied (or, on a foundationless app, the internalize-and-defer diff plus the auth-setup nudge) — never just describe the fix in prose.

## Rules

- MANDATORY FIRST STEP: before injecting requireIdentity/requireOwner, verify the auth foundation exists — an auth.config.ts with a provider AND a users/identities table keyed to the auth subject. If either is missing, do not add ctx.auth-based enforcement (it's non-functional or mismatched and creates a NEW authz defect); instead convert flagged public admin/privileged functions to internalQuery/internalMutation and tell the user to run auth setup first, then re-run convex-authz.
- Scan objectively before judging — run the 4 deterministic greps first; don't skip straight to LLM judgment, and don't let a clean scan stop you from still eyeballing internal/admin exemptions.
- Identity always comes from ctx.auth, never from a client-supplied argument — the one legitimate exception is an internalQuery/internalMutation/internalAction that is never exposed publicly.
- Every read or mutate keyed by an _id argument must verify ownership server-side (requireOwner or an inlined equivalent comparison) before touching the row — being logged in is not the same as owning this row.
- Any v.id(...) argument a public mutation uses as a foreign key when inserting or moving a row must have the referenced parent's ownership (or membership) verified against the caller first — creating a child row inside someone else's project/board/account is the same defect as mutating their row, and it survives an identity-from-arg fix unless checked separately.
- Never leave a public query that returns PII/financial/audit data reachable by an unauthenticated or cross-account client-supplied id.
- Reuse requireIdentity/requireOwner from content/convex-expert.md verbatim — do not fork a parallel helper or invent new error semantics.
- Always verify with tsc after hardening; a fix that doesn't typecheck is not shipped.
- This is a targeted authz pass, not a general code review — do not expand scope into performance/schema/validator findings; hand those to convex-reviewer.
- SKIP entirely when there is no convex/ directory in the project.
Loading