You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .agents/skills/v2-api-conventions/SKILL.md
+17-4Lines changed: 17 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -149,6 +149,16 @@ Order matters because each layer is checked against the one before it.
149
149
3.**Route** with `defineV2JsonRoute`, declaring `contract`, `auth: v2ApiKeyAuth`, `operation`, `rateLimit`, `errorPolicy`, `mapInput`, `useCase`, `present`. Auth and rate limiting run before parsing.
150
150
4.**OpenAPI description** in `lib/api/contracts/v2/openapi/<domain>.ts`, then `bun run generate:openapi`. A description that claims behaviour the route does not have is the same class of bug as a wrong schema.
151
151
152
+
### Public descriptions
153
+
154
+
Use the [API description conventions](../../../apps/sim/lib/api/contracts/v2/openapi/README.md) when writing or auditing endpoint and field descriptions. Keep a short action-and-resource summary; use the description for behavior that changes the caller's choice, input, interpretation, or next action. Ordinary operations usually need one to three sentences, with no mandatory minimum.
155
+
156
+
Keep archive versus permanent-delete behavior, replacement versus partial-update semantics, partial success, retry safety, redaction, and asynchronous completion explicit. Verify these claims against the implementation. Describe observable behavior without exposing storage formats, locking mechanisms, internal identifiers, deployment architecture, or implementation history unless that detail changes how the caller must use the API.
157
+
158
+
Reuse wording across resource families when behavior matches: “Omitted fields remain unchanged,” “Archive,” and “permanently delete.” Prefer “during the request” or “asynchronously” to “settled inline.” Preserve real semantic differences; do not standardize them away.
159
+
160
+
Put field-specific rules in the source schema and reuse shared authentication and pagination wording. Shared schema descriptions also feed CLI help, so refer to related operation names rather than HTTP paths. Regenerate OpenAPI, CLI metadata, and CLI docs after changing their source descriptions; never hand-edit generated output.
161
+
152
162
## Rule 6 — a transient failure says when to come back
153
163
154
164
A response the caller is *expected* to retry must say how long to wait. Two statuses qualify, and both are wired:
@@ -186,11 +196,14 @@ Audited against the primary specs and against Stripe, GitHub, and Google's AIPs.
186
196
187
197
## Idempotency: at-most-once, not replay
188
198
189
-
`POST /workflows/{id}/execute` accepts `X-Run-Id`, a caller-supplied run identifier claimed through the `idempotency_key` table (`execution-id-claim.ts`). It is a **uniqueness claim, not an idempotency key**, and the distinction is deliberate and already published in the operation description:
199
+
`POST /workflows/{id}/execute` accepts `X-Run-Id` from API-key and OAuth callers; anonymous requests ignore it. It is a **uniqueness claim, not an idempotency key**:
200
+
201
+
- An available ID is claimed before execution starts.
202
+
- An already claimed ID returns **409** with `error.details.code: "RUN_ID_CONFLICT"`, the run id in `error.details.runId`, and an `X-Run-Id` response header. It never replays the earlier run's result. Get Workflow Run can retrieve an existing run, but a claim does not guarantee a retrievable run.
203
+
- IDs of runs that started remain reserved after their execution logs are deleted.
204
+
- An ambiguous enqueue can retain the claim indefinitely without creating a retrievable run. A **409** followed by **404** is an unresolved outcome, not proof that execution never started or that the ID will become reusable.
190
205
191
-
- First use wins and runs.
192
-
- Any reuse returns **409** with `error.details.code: "RUN_ID_CONFLICT"`, the run id in `error.details.runId`, and an `X-Run-Id` response header. It never replays the earlier run's result — the client recovers it by polling the runs resource.
193
-
- Claims are durable tombstones, so deleting execution logs cannot make an id reusable.
206
+
For an uncertain execution outcome, reuse the same run ID if retrying and check Get Workflow Run. Do not promise polling will eventually find a run. If the outcome cannot be verified, do not automatically restart with a fresh ID or an omitted header: either can start another execution. Failures before a run starts can release the claim, so phrase the conflict rule as an ID that is already claimed.
194
207
195
208
That makes the money path safe against double-execution **for callers that opt in**. What it is not: a Stripe-style `Idempotency-Key` that stores and replays the original status and body. Building that means a request fingerprint, a retention window, an in-flight-vs-completed distinction (the expired IETF draft would have these be 422 and 409 respectively), and somewhere to put a large synchronous execution body. It is a designed piece of work, not an increment — do not half-build it by aliasing the header name, which would invite clients written against Stripe semantics to treat our 409 as a hard failure.
Copy file name to clipboardExpand all lines: .claude/rules/emcn-components.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,6 +32,7 @@ The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items
32
32
-**`ChipDatePicker`** — chip-styled date field.
33
33
-**`ChipTimePicker`** — minute-granular time sibling of `ChipDatePicker`, a `ChipInput` that leniently parses typed input (`9:47`, `947`, `2:05pm`, `14:30`), commits on Enter/blur, and re-renders the canonical `9:47 AM` label.
34
34
-**`DropdownMenu`** — the canonical context/action menu (Radix-backed). Not a chip, but the standard menu for command/action lists; reach for it instead of a hand-rolled popover. Its surface intentionally diverges from the chip pill (`text-small`, `gap-2`) — keep them distinct. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
35
+
-**`useScrollEdges` + `scrollFadeClass` / `scrollFadeAttributes`** — the canonical scroll-region edge treatment. The hook reports which edges hide content (tracking scroll and resizes; pass the element itself, held in state, when the region mounts after its owner, e.g. inside a Radix portal); the class and attributes fade a fixed 12px band at an active edge only, so a list that fits or sits at its top is never fogged. A floating control over the top edge sets `--scroll-fade-inset` to its height. A region that scrolls sideways (a tab row, a chip strip) uses `useScrollEdges(ref, { axis: 'x' })` with `scrollFadeXClass`; the attributes helper is shared. Any divider beside the region belongs to the neighboring block (`border-b` above, `border-t` below), never to the masked element, and shows only while that edge is active. Never hand-roll a `mask-image` gradient for a scroll region.
35
36
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 18px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.
Copy file name to clipboardExpand all lines: .claude/rules/sim-styling.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,6 +60,10 @@ Use `DropdownMenuItemLabel` for a human label beside menu icons, checks, shortcu
60
60
61
61
Do not apply the fade universally to editable or mirrored input values, code, logs, paths, filenames that use intentional middle truncation, dense or virtualized grids, or a composite container that also holds icons/actions. Those keep their purpose-built overflow behavior. Multiline copy uses an intentional `line-clamp-*` treatment.
62
62
63
+
## Scroll Edges
64
+
65
+
A scroll region that can hide rows past an edge uses `useScrollEdges` with `scrollFadeClass` + `scrollFadeAttributes` from `@sim/emcn`: a 12px fade at an edge only while content is hidden beyond it, never at rest. The region's baseline padding lives on the scroll box itself (so rows pass through it under the fade), and the divider at that edge is drawn by the neighboring block, conditional on the same edge. Never hand-roll a `mask-image` gradient or a `scrollTop > 0` effect for this.
66
+
63
67
## Font Weight
64
68
65
69
Three steps, Tailwind's stock scale, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class only to step *up* from body.
@@ -70,7 +74,7 @@ Headings inherit their weight. Tailwind preflight resets `h1`–`h6` to `font-we
70
74
71
75
## Color Tokens
72
76
73
-
Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text-icon`; neutral borders and dividers `--border` (`--border-1` and `--border-muted` are legacy aliases resolving to it; `--divider` is retired); surfaces `--surface-5` (light) / `--surface-4` (dark); active row `--surface-active`; error `--text-error`. No focus rings on chip surfaces.
77
+
Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text-icon`; progress and completion (a checked step, a done state) `--brand-blue` — `--selection` stays the interactive highlight; neutral borders and dividers `--border` (`--border-1` and `--border-muted` are legacy aliases resolving to it; `--divider` is retired); surfaces `--surface-5` (light) / `--surface-4` (dark); active row `--surface-active`; error `--text-error`. No focus rings on chip surfaces.
0 commit comments