From aa2ba373800e78bf4c7fe931e53c4add552e345b Mon Sep 17 00:00:00 2001 From: t Date: Thu, 8 Oct 2026 21:27:31 +0530 Subject: [PATCH] docs: revert the agent-doc dedupe and restore the full guidance Restores every rule #1632 collapsed into a pointer, in AGENTS.md, CONVENTIONS.md, workflow.md, CLAUDE.md, both playbooks and the skill, including the design-token bullet in workflow.md. The saving was about 1,500 tokens per build, small next to a visible drop in how apps look. The partial type-list restore from #1635 is replaced by the original text. --- .agents/skills/webjs/SKILL.md | 20 ++++++--- .../cli/templates/.agents/rules/workflow.md | 30 ++++++++++--- packages/cli/templates/AGENTS.md | 44 +++++++++++++++---- packages/cli/templates/CLAUDE.md | 11 +++-- packages/cli/templates/CONVENTIONS.md | 42 +++++++++++++----- .../templates/partials/agents-playbook-api.md | 20 ++++++--- .../partials/agents-playbook-fullstack.md | 28 ++++++++---- 7 files changed, 143 insertions(+), 52 deletions(-) diff --git a/.agents/skills/webjs/SKILL.md b/.agents/skills/webjs/SKILL.md index c0c865aca..29108b07f 100644 --- a/.agents/skills/webjs/SKILL.md +++ b/.agents/skills/webjs/SKILL.md @@ -104,12 +104,12 @@ Common bundles: 1. **Classify the change.** Route contract, data model, server mutation, auth, or only UI? 2. **Start from the server.** Add the page/route and its server action or query before wiring interactive UI. A page render or a `
` POST should already return correct HTML before any component hydrates. 3. **Put code in the narrowest owner.** Route-local first (`modules//`), promote to `lib/` or `components/` only when reuse is real. -4. **Keep server-only code behind `.server.ts`** (Core WebJs Rules 1 and 2). +4. **Keep server-only code behind `.server.ts`.** The DB driver, secrets, and `node:*` never belong in a page, layout, or component. 5. **Add interactivity per behaviour.** Reach for a component (and a signal or `@event`) only where the UI is genuinely interactive. A display-only component is elided from the browser. Then wrap the interactive part and STOP: the static markup around it stays in the page, where it costs nothing. 6. **Validate input at the boundary.** Declare `export const validate` on an action; the RPC and `route()` boundaries run it. 7. **Default mutations to optimistic UI** where the client can predict the result (`optimistic()` from `@webjsdev/core`). -8. **Type every boundary from its source, never `unknown` or `any`.** The row type comes from the schema (`typeof todos.$inferSelect`), the action's input from a named `interface` and its result from `ActionResult`, the routing files from `PageProps` / `LayoutProps` / `RouteHandlerContext`. `unknown` belongs on a payload nothing has vouched for yet that the next line narrows, and on a parameter of your own helper that forwards into an `html` template hole. Everywhere else, including a layout's `children`, it is a missing type. Carry a row type into a shipping component with `import type` (erased before the browser sees it). Nothing enforces this (both spellings are valid TypeScript, so `webjs check` and `tsc` pass either way), which is why it is written down. See `references/typescript.md`. -9. **Test the narrowest meaningful layer**, and look at any UI change in a real browser (see Testing Defaults). +8. **Type every boundary from its source, never `unknown` or `any`.** The row type comes from the schema (`typeof todos.$inferSelect`), the action's input from a named `interface` and its result from `ActionResult`, the routing files from `PageProps` / `LayoutProps` / `RouteHandlerContext`. `unknown` belongs on a payload nothing has vouched for yet that the next line narrows, and on a parameter of your own helper that forwards into an `html` template hole. Everywhere else, including a layout's `children`, it is a missing type. See `references/typescript.md`. +9. **Test the narrowest meaningful layer**, and render the app in a real browser for any UI change (static checks do not catch a collapsed layout). ## Project Layout @@ -137,7 +137,7 @@ App-internal imports use the `#` root alias (`import { db } from '#db/connection ## Core WebJs Rules (invariants) 1. Server-only code lives in `.server.ts`, `route.ts`, or `middleware.ts`. Never in a page, layout, or component (it crashes the browser at module load). -2. `'use server'` exports are `async` functions returning serializer-safe values, callable from browser code as RPC. Files without `'use server'` are server-only utilities: reach them only from `'use server'` actions, `route.ts`, or middleware. Never add `'use server'` to a file only other server code imports (the DB connection, the schema). +2. `'use server'` exports are `async` functions returning serializer-safe values. Files without `'use server'` are server-only utilities. 3. Custom element tag names contain a hyphen. Pass the tag to `Class.register('tag-name')`. 4. Event (`@`), property (`.`), and boolean (`?`) holes in `html` are UNQUOTED: `@click=${fn}`, never `@click="${fn}"`. 5. Signals are the default state primitive. Import `signal` / `computed` from `@webjsdev/core`, read via `signal.get()` inside `render()`. The base-class factory `WebComponent({ ... })` is only for values riding an HTML attribute or arriving via SSR hydration. @@ -147,7 +147,7 @@ App-internal imports use the `#` root alias (`import { db } from '#db/connection 9. No backtick characters inside an `html\`...\`` body, even in comments (it closes the literal and 500s). 10. TypeScript must be erasable (`erasableSyntaxOnly: true`): no `enum`, no value `namespace`, no constructor parameter properties, no legacy decorators. 11. Reactive properties are declared ONLY through the base-class factory `extends WebComponent({ count: Number })`. Never a `static properties` block, never a class-field initializer (it clobbers the reactive accessor). -12. A form that writes binds its action: ``, or a per-button `