Skip to content

Commit 5e998fc

Browse files
authored
v0.8.1: grok 4.6, v2 endpoints extension, workflow UI improvements, logrocket, perf improvements
2 parents 48c59c8 + 3051954 commit 5e998fc

980 files changed

Lines changed: 85039 additions & 9658 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/ship/SKILL.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ improvement(scope): description for enhancements
100100
chore(scope): description for maintenance
101101
```
102102

103+
## What to Omit
104+
105+
The repo is public. Keep the title and description to the code change and its reasoning — never:
106+
107+
- Customer, company, or user names; workspace/user/org IDs; email addresses
108+
- Prod or staging operational data: log lines, DB rows, metrics, timestamps, incident details, canary/alert output
109+
- Infrastructure specifics: hostnames, ARNs, internal URLs, env var values, secret names
110+
111+
Describe the bug by its mechanism, not by how you found it. "Expired OAuth credentials fail to refresh in the worker" — not "the Sheets canary failed at 16:31Z for workspace abc-123".
112+
103113
## PR Description Format
104114

105115
Use this exact template in the user's voice (concise, bullet points):

.agents/skills/tool-registry-boundary/SKILL.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ If it fails, do not add the entry to an allowlist — there isn't one. Find the
6868

6969
Run it with `--verbose` to print per-route module counts, which is also the quickest way to see whether a change moved the graph.
7070

71+
The same command also ratchets those counts against `check-tool-registry-boundary.baseline.json`. `--check` (what CI runs) fails when an entry exceeds its baseline by more than `max(25 modules, 2%)`, naming the import chain responsible. This catches bloat the registry rule misses — a prefetch importing `listTables` cost the Tables page 444 modules without ever touching `@/tools/registry`.
72+
73+
Re-record with `--update-baseline` and commit the JSON when growth is deliberate. A *shrink* passes but is reported — re-record then too, or the win is silently spendable again.
74+
7175
## How to verify an edge actually got cut
7276

7377
Do not eyeball imports — the registry is reached through several redundant paths, so cutting one buys nothing while another survives. Walk the graph:

.agents/skills/v2-api-conventions/SKILL.md

Lines changed: 233 additions & 0 deletions
Large diffs are not rendered by default.

.claude/commands/ship.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ improvement(scope): description for enhancements
9999
chore(scope): description for maintenance
100100
```
101101

102+
## What to Omit
103+
104+
The repo is public. Keep the title and description to the code change and its reasoning — never:
105+
106+
- Customer, company, or user names; workspace/user/org IDs; email addresses
107+
- Prod or staging operational data: log lines, DB rows, metrics, timestamps, incident details, canary/alert output
108+
- Infrastructure specifics: hostnames, ARNs, internal URLs, env var values, secret names
109+
110+
Describe the bug by its mechanism, not by how you found it. "Expired OAuth credentials fail to refresh in the worker" — not "the Sheets canary failed at 16:31Z for workspace abc-123".
111+
102112
## PR Description Format
103113

104114
Use this exact template in the user's voice (concise, bullet points):

.claude/commands/tool-registry-boundary.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ If it fails, do not add the entry to an allowlist — there isn't one. Find the
6767

6868
Run it with `--verbose` to print per-route module counts, which is also the quickest way to see whether a change moved the graph.
6969

70+
The same command also ratchets those counts against `check-tool-registry-boundary.baseline.json`. `--check` (what CI runs) fails when an entry exceeds its baseline by more than `max(25 modules, 2%)`, naming the import chain responsible. This catches bloat the registry rule misses — a prefetch importing `listTables` cost the Tables page 444 modules without ever touching `@/tools/registry`.
71+
72+
Re-record with `--update-baseline` and commit the JSON when growth is deliberate. A *shrink* passes but is reported — re-record then too, or the win is silently spendable again.
73+
7074
## How to verify an edge actually got cut
7175

7276
Do not eyeball imports — the registry is reached through several redundant paths, so cutting one buys nothing while another survives. Walk the graph:

.claude/commands/v2-api-conventions.md

Lines changed: 232 additions & 0 deletions
Large diffs are not rendered by default.

.claude/rules/sim-architecture.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,27 @@ Use the `migrate-application-operation` skill before creating or migrating a pro
5757

5858
Every export of a `'use client'` module becomes a *client reference* on the server — server-evaluated code (RSC pages/layouts, `prefetch.ts`, route handlers, block definitions, triggers) can only *render* it as a component or pass it as a prop, never *call* it (doing so throws at runtime, e.g. `tableKeys.list is not a function`; `next build` does not catch it). Keep server-importable query primitives (key factories, fetchers, mappers, constants) in non-`'use client'` modules — see `.claude/rules/sim-queries.md`. Enforced by `scripts/check-client-boundary-imports.ts`.
5959

60+
## The app/worker runtime boundary
61+
62+
Server code runs in two runtimes with **different environments**. The app container loads the
63+
full env from `SIM_ENV_SECRET_ID` (Secrets Manager). Trigger.dev workers — which execute
64+
workflows, so every block handler and every tool call — get their env from the Trigger.dev
65+
dashboard, and `trigger.config.ts` syncs only `DB_APP_NAME`. The repo cannot see what the
66+
dashboard holds.
67+
68+
So before replacing a worker's HTTP call to our own API with an in-process call, ask what env
69+
that work reads *on the app side*. Anything gated by a `require*Capability` helper is the sharp
70+
case: those **throw** when the variable is absent (`requireOAuthClientCapability`
71+
`EnvCapabilityConfigurationError`), and the throw may be caught and reported as something
72+
unrelated. OAuth token refresh is the known example — moving it into the worker turns every
73+
expired credential into `Failed to refresh access token`, while a still-valid token hides the
74+
bug entirely, so it surfaces hours later and only for whoever's token lapsed first.
75+
76+
An in-process conversion is safe when the same work already runs in that runtime (the agent
77+
block has always called `executeProviderRequest` in-process, so router and evaluator joining it
78+
is proven), or when the caller and the callee are both the app (a route calling a lib module, an
79+
RSC prefetch reading the data layer). It is not safe on reasoning alone.
80+
6081
## Feature Organization
6182

6283
Features live under `app/workspace/[workspaceId]/`:

.claude/rules/sim-queries.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,22 @@ const handler = useCallback(() => {
143143
}, [data])
144144
```
145145

146+
## Server prefetching
147+
148+
A server prefetch fills the *same* cache key a client hook fills, so it must be indistinguishable from a client fetch. Five rules:
149+
150+
1. **Read the data layer, never our own API over HTTP.** A server-to-server call to `/api/...` costs a round trip and a second authentication for data the process can already read. Where the route runs an application use case, call that same use case with a principal from the same auth policy the route declares — not a manager underneath it.
151+
2. **Match the wire shape the hook caches.** The hook's data is whatever `requestJson(contract, …)` produced, so the seed must equal it. Two traps: a contract field declared `z.coerce.date()` means the hook holds a `Date` where raw route JSON holds a string; a passthrough response schema (`z.custom`) means the hook caches route JSON *verbatim*, so seeding raw rows leaks `Date`s and server-only fields. When the route projects before responding, share that projection — have the route and the prefetch call one function.
152+
3. **Prove the viewer.** Data-layer reads carry no authorization; the route used to provide it. Resolve the viewer (`getWorkspaceHostContextForViewer`, already `cache`d by the layout so it costs nothing) and return early on failure, caching nothing — the client fetch then reaches the route for the real 403. Never widen what a viewer can see.
153+
4. **Always `await`.** Only a settled query is dehydrated, so an unawaited prefetch is silently dropped from the payload and the pane waterfalls anyway.
154+
5. **Don't repeat what the layout already seeded.** `getQueryClient()` builds a new client per server call, so a page re-seeding a layout key is a genuine second read — and `HydrationBoundary` defers an already-seen query to an effect, which SSR never runs, so it never reaches the server render either.
155+
156+
Reuse the hook's exported `staleTime` constant and its key factory; `dehydrate` carries neither options nor `staleTime`, and freshness is per-observer.
157+
158+
Seed with `setQueryData` only when the prefetch must be able to *decline* to create an entry (an empty list that has to fall through to a route's creation path). `prefetchQuery` and `ensureQueryData` always create one.
159+
160+
Keep prefetch imports light. A page prefetch's imports land in that route's server graph, so pulling a barrel to reach one function can drag thousands of modules behind it — `bun run check:tool-registry-boundary` gates this per page.
161+
146162
## Boundary Types
147163

148164
- Hooks import named type aliases from `@/lib/api/contracts/**` (e.g., `import { listEntitiesContract, type EntityList } from '@/lib/api/contracts/entities'`). Never write `z.input<...>` / `z.output<...>` in hooks, and never `import { z } from 'zod'` in client code.

.cursor/commands/ship.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ improvement(scope): description for enhancements
9494
chore(scope): description for maintenance
9595
```
9696

97+
## What to Omit
98+
99+
The repo is public. Keep the title and description to the code change and its reasoning — never:
100+
101+
- Customer, company, or user names; workspace/user/org IDs; email addresses
102+
- Prod or staging operational data: log lines, DB rows, metrics, timestamps, incident details, canary/alert output
103+
- Infrastructure specifics: hostnames, ARNs, internal URLs, env var values, secret names
104+
105+
Describe the bug by its mechanism, not by how you found it. "Expired OAuth credentials fail to refresh in the worker" — not "the Sheets canary failed at 16:31Z for workspace abc-123".
106+
97107
## PR Description Format
98108

99109
Use this exact template in the user's voice (concise, bullet points):

.cursor/commands/tool-registry-boundary.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ If it fails, do not add the entry to an allowlist — there isn't one. Find the
6363

6464
Run it with `--verbose` to print per-route module counts, which is also the quickest way to see whether a change moved the graph.
6565

66+
The same command also ratchets those counts against `check-tool-registry-boundary.baseline.json`. `--check` (what CI runs) fails when an entry exceeds its baseline by more than `max(25 modules, 2%)`, naming the import chain responsible. This catches bloat the registry rule misses — a prefetch importing `listTables` cost the Tables page 444 modules without ever touching `@/tools/registry`.
67+
68+
Re-record with `--update-baseline` and commit the JSON when growth is deliberate. A *shrink* passes but is reported — re-record then too, or the win is silently spendable again.
69+
6670
## How to verify an edge actually got cut
6771

6872
Do not eyeball imports — the registry is reached through several redundant paths, so cutting one buys nothing while another survives. Walk the graph:

0 commit comments

Comments
 (0)