Skip to content
Merged
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
2 changes: 0 additions & 2 deletions .agents/skills/webjs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ Use this skill for end-to-end WebJs app work. It helps you choose the right laye

## Full Documentation

In a scaffolded app, `AGENTS.md` carries the build steps and a worked example of every common pattern (pages, layouts, form-bound actions with validation, queries, owner-scoped CRUD, `createAuth`, a component with signals, a test). Build from it first, and come here for a surface it does not show.

This skill is the quick guide. When you need the full API reference for a surface, load the matching file in `references/` (listed below). For even deeper framework detail, WebJs ships buildless, so the source you run IS the source you read: look in `node_modules/@webjsdev/{core,server,cli}/` (each package ships its own `AGENTS.md`). The complete hosted docs live at https://webjs.dev/docs.

## What WebJs Is
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/lib/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -1723,8 +1723,8 @@ ThemeToggle.register('theme-toggle');
`);
}
console.log(`For AI agents, read this before editing:
• Read AGENTS.md first: it carries the build steps and a worked example of
every common pattern. .agents/skills/webjs/ is the deeper reference.
• Read AGENTS.md, then .agents/skills/webjs/SKILL.md. The skill is the guide
to building a WebJs app and routes to focused references on demand.
• This scaffold is a minimal starting point, not a demo to prune. Grow the app
in place: add routes under app/, components under components/, and features
under modules/<feature>/, and keep server-only code behind .server.ts.
Expand Down
31 changes: 17 additions & 14 deletions packages/cli/templates/.agents/rules/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,33 @@

You are working on a WebJs app (AI-first, no-build, web-components-first). This
file is the WORKFLOW contract (git, tests, review). For HOW to build (routing,
components, actions, styling, the framework API), read `AGENTS.md`; the
deeper reference set is `.agents/skills/webjs/SKILL.md`. Full hosted docs are
at https://webjs.dev/docs.
components, actions, styling, the framework API), read
`.agents/skills/webjs/SKILL.md`, which routes to focused references on demand.
Read `AGENTS.md` first. Full hosted docs are at https://webjs.dev/docs.

## Grow the app in place (non-negotiable)

- **Clear the showcase, then build.** The scaffold is a starting point with a
browsable demo showcase plus a database wired up. A full-stack app ships a UI
feature gallery (`app/features/`, `app/examples/todo`); the api template ships
a backend-features showcase (`app/api/features/`), with logic in `modules/`.
Building a real app: run `npm run gallery:clear` to shed the showcase (it
keeps the agent docs and the database wiring, and resets to a clean base),
then regenerate the database and grow the app in place under `app/`,
`components/`, and `modules/<feature>/`. `AGENTS.md` carries the
template-specific build steps and the order to follow.
- **Study the shipped examples, then clear them and build.** The scaffold is a
starting point with a browsable showcase to learn the real idioms from, plus a
database wired up. A full-stack app ships a UI feature gallery (`app/features/`,
`app/examples/todo`); the api template ships a backend-features showcase
(`app/api/features/`), with logic in `modules/`. Building a real app: study the
parts that match your task (the skill teaches the same and SURVIVES the clear),
run `npm run gallery:clear` to shed the showcase (it keeps the agent skill and
the database wiring, and resets to a clean base), then regenerate the database
and grow the app in place under `app/`, `components/`, and `modules/<feature>/`.
`AGENTS.md` carries the full template-specific build playbook and the order to
follow.
- **Use the wired-up database (Drizzle), never JSON files.** For any data the app
stores, define a Drizzle table in `db/schema.server.ts`, then
`npm run db:generate` and `npm run db:migrate`. Never use a JSON file, a
module-scope array or Map, or localStorage as a database.
- **`app/` is routing-only.** Only routing files live in `app/` (page, layout,
route, middleware, metadata routes). Browser-safe helpers go in `lib/utils/`,
feature logic in `modules/`, server-only code behind `.server.ts`.
- **For a UI app, render and LOOK before calling it done.** Give the design
tokens in `public/input.css` a palette that fits the app, then open every
- **For a UI app, render and LOOK before calling it done.** Define design tokens
in `app/layout.ts` with a palette that fits the app
(`.agents/skills/webjs/references/styling.md` is the guide), then open every
route you changed in a real browser and play through its states.
`npm run check` and `npm run typecheck` pass even when a layout collapses, so
the browser is the real check.
Expand Down
7 changes: 0 additions & 7 deletions packages/cli/templates/.claude/hooks/nudge-uncommitted.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ fi
# Read stdin so we don't break Claude Code's hook contract.
cat /dev/stdin >/dev/null 2>&1 || true

# A repository with no commit yet is a first build from the scaffold: the whole
# build is one logical unit (CLAUDE.md), committed once at the end, so nudging
# mid-build would only split it. The Stop hook still asks for that commit.
if ! git rev-parse --verify -q HEAD >/dev/null 2>&1; then
exit 0
fi

CHANGED=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')

if [ -z "$CHANGED" ] || [ "$CHANGED" -lt "$THRESHOLD" ]; then
Expand Down
129 changes: 70 additions & 59 deletions packages/cli/templates/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,82 @@
# AGENTS.md for {{APP_NAME}}

This is a WebJs app: server-rendered pages, web components for interactivity,
server actions, Drizzle, and no build step. WebJs is its own framework, not
React, Next.js or Lit, so write it from the patterns in this file rather than
from that memory. Read this whole file before you edit anything.
This is a WebJs app: AI-first, web-components-first, buildless, and
progressively enhanced. Read this whole file before you edit anything, then
follow it. The steps here are required, not optional.

{{PLAYBOOK}}
## Gather context BEFORE you build (required)

WebJs is its own framework. It is not React, Next, or Lit, so writing code from
that muscle memory produces broken WebJs code. Before you write or change
anything, gather context from these sources. Do not skip a step to save time.
This is what separates a working app from a broken one.

## Rules that hold everywhere
1. **Read the skill.** Start with `.agents/skills/webjs/SKILL.md`, then load the
`references/*.md` files it routes to for the surface you are touching. The
skill is the guide to building a WebJs app: it helps you choose the right
layer, reach for the right export, and avoid the mistakes Next.js or Lit
habits cause. Reading it is never wasted work: it survives the
gallery-clearing step in the playbook below.
2. **Study the shipped examples, then build on a clean slate.** The template
playbook below says what ships and the exact order to follow. The workflow
rules (git, tests, review) are in `.agents/rules/workflow.md`; follow them
too.
3. **Read the framework source for exact contracts.** WebJs is 100% buildless
native ES modules, so the source you run IS the source you read. When you
need a precise API signature or behavior, open the package source under
`node_modules/@webjsdev/*` directly (each package ships its own `AGENTS.md`).
The full hosted docs are at https://webjs.dev/docs.

{{PLAYBOOK}}

- Type every boundary from its source: rows are `typeof posts.$inferSelect`
(into browser code with `import type`), action inputs a named `interface`,
routing files `PageProps<'/posts/[id]'>` / `LayoutProps`, object props
`prop<Post>(Object)`. `unknown` only for an untrusted payload
narrowed on the next line. Never reach for `any`.
- Never add `'use server'` to a file only server code imports (the DB
connection, the schema).
- Store data with Drizzle in the wired-up database, never in a JSON file, an
in-memory array or localStorage. Every schema change is `npm run db:generate`
then `npm run db:migrate`, and the migrations are committed.
- TypeScript is erasable: no `enum`, `namespace`, parameter properties or
decorators. Never put a backtick inside an `html` template, even in a comment.
- Descriptive names (`formData`, `values`, `errors`, never `fd`, `v`, `e`) and a
one-line doc comment on every exported function.
- `npm run check` and `npm run typecheck` name the file and the fix; do what
they say.
## Type everything (all templates)

## Git
Full-stack type safety is what the `.server.ts` boundary buys you: a client
component importing a server action resolves to that action's real signature at
type-check time, with no build step and no code generation in between. So
DERIVE the type at every boundary instead of widening it:

Commit per logical unit (CLAUDE.md has the rule). When you build a whole app
from a spec in one session, the build is one unit: work on a feature branch
(commits to `main` are refused), and commit once at the end after the checks
pass (`git add -A && git commit -m "<imperative subject>"`). Team workflow
(pull requests, CI, worktrees) is in `.agents/rules/workflow.md`.
- A database row: `export type Todo = typeof todos.$inferSelect` in
`db/schema.server.ts` (`$inferInsert` for a write), carried into a
browser-shipped component with `import type` (erased before it reaches the
browser, so it does not trip the server-import boundary).
- An action's input: a named `interface`. Its result: `ActionResult<T>`.
Narrow with `if (result.success && result.data)`.
- Routing files: `PageProps<'/blog/[slug]'>`, `LayoutProps`,
`RouteHandlerContext`, all from `@webjsdev/core`. Run `npx webjsdev types`
for the typed `Route` union and per-route `params`.
- A reactive property: `prop<Student>(Object)`, `prop<Tag[]>(Array)`.

## Before you build these, read the reference first
Never reach for `any` or a loose `as any` cast, and do not reach for `unknown`
either just because it looks safer. `unknown` is right for a payload nothing
has vouched for yet, narrowed on the very next line (a `route.ts` `await
req.json()`, an action's `export const validate` or a validator it delegates
to, a `catch` binding), and for a parameter of YOUR OWN helper that forwards
into an `html` template hole (a hole renders a string, a number, a
`TemplateResult`, or an array of those, so `TemplateResult` alone is too
narrow). That second case is about a value you accept, never one the framework
already types. Everywhere else it is a missing type, not a safe one: `unknown`
that survives into a return type, a component prop, a layout's `children`, or
an action signature is the shape to fix.
Nothing enforces this (both are valid TypeScript, so `webjs check` and `tsc`
pass either way), which is exactly why it is written down. The full ladder,
with an end-to-end example, is in
`.agents/skills/webjs/references/typescript.md`.

This file covers the common app. For any surface below, read the named
section of `.agents/skills/webjs/references/` BEFORE writing that part (one
`sed -n '/^## Heading/,/^## /p' <file>` call), because the API is WebJs's own
and guessing it from another framework is wrong.
Keep server-only code (database drivers, secrets, `node:*` builtins) in
`.server.ts` modules. There are exactly two kinds:

| Building | Read |
| --- | --- |
| Live updates beyond the example above (presence, two-way sockets) | `client-router-and-streaming.md` "WebSockets", `built-ins.md` "Broadcast" |
| Streaming beyond the example above (Suspense, cancellation) | `client-router-and-streaming.md` "Streaming (Suspense and RPC)" |
| Refreshing one region, or one element after a write (`<webjs-frame>`, `<webjs-stream>`) | `client-router-and-streaming.md` |
| File uploads and serving them (`FileStore`, `signedUrl`) | `built-ins.md` "File storage" |
| Caching, `revalidate`, `cache()`, rate limits | `built-ins.md` "Caching", "Rate limiting" |
| Middleware (`middleware.ts`, per segment) and JSON API routes (`route.ts`, `route()` adapter, CORS) | `routing-and-pages.md`, `data-and-actions.md` |
| SEO: `metadata`, `generateMetadata`, sitemap, robots, social images; the app icon | `routing-and-pages.md` "Metadata", "App icon and manifest" |
| Browser-only code (`window`, `localStorage`, timers) and component lifecycle, slots, context, directives | `components.md` |
| Optimistic updates | `optimistic-ui.md` |
| OAuth sign-in, cookie sessions, `forbidden()` / `unauthorized()` | `auth-and-sessions.md` |
| Env vars and secrets, boot-time code (`instrumentation.ts` `register()`) | `built-ins.md` "Environment variables", "Observability" |
| Scheduled jobs beyond the timer above | an external cron calling a `route.ts` with a secret |
| Email, payments, i18n | no built-in: use the provider's SDK from a server-only `.server.ts` utility called by actions; secrets from `process.env` |
| Browser and e2e tests | `testing.md` |
- A `.server.ts` file WITH `'use server';` as its first line is a server
action: WebJs exposes its exported async functions to browser code as RPC
calls, so browser modules may import it directly.
- A `.server.ts` file WITHOUT `'use server'` is a server-only utility:
importing it from a page, layout, or component CRASHES in the browser at
module load. Reach it only from `'use server'` actions, `route.ts` handlers,
or middleware. Never add `'use server'` to a file only other server code
imports (the DB connection, the schema).

## When you need more
## Data (all templates)

The reference set is `.agents/skills/webjs/` (`SKILL.md` routes to
`references/*.md`). Open one only for a surface this file does not show:
streaming and Suspense (`client-router-and-streaming.md`), optimistic UI
(`optimistic-ui.md`), caching, rate limits, file uploads, env vars
(`built-ins.md`), OAuth providers and sessions (`auth-and-sessions.md`),
browser and e2e tests (`testing.md`), deeper component topics such as slots,
shadow DOM, context and directives (`components.md`). The exact framework
source is under `node_modules/@webjsdev/*`, and the hosted docs are at
https://webjs.dev/docs.
Use the wired-up database (Drizzle) for every piece of data the app stores;
the playbook above has the modeling step. Never store app data in a JSON file,
an in-memory array, or localStorage.
30 changes: 16 additions & 14 deletions packages/cli/templates/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
# Committing per logical unit (this OVERRIDES Claude Code's default)

Claude Code's built-in default is to NEVER commit unless the user explicitly
asks. **For this project that default does NOT apply.** Commit per logical
unit (one feature, one fix, one rename, one doc rewrite) as soon as it is
complete and its checks pass, WITHOUT being asked, then push when there is a
remote. Git history is the user's revert and cherry-pick safety net.
asks. **For this project that default does NOT apply.** Commit and push per
logical unit (one feature, one fix, one rename, one doc rewrite) as soon as it
is complete, WITHOUT being asked. Do not save all the work for one commit at the
end. A finished implementation with zero commits is a mistake here, because git
history is the user's revert and cherry-pick safety net.

- Building a whole app from a spec in one session is ONE unit: build it,
verify it, then commit once. Later changes are one commit each.
- Never commit to `main`. Work on a feature branch (the pre-commit hook
refuses `main`).
- Imperative subject under 72 characters. No AI-attribution trailers
(`Co-Authored-By`, `Generated by`).
- After each completed unit whose tests pass, `git add` the related files and
`git commit` with an imperative subject under 72 chars, then push. If 5+ files
span more than one concern, you already waited too long.
- Never commit to `main`. Work on a feature branch (the
`.claude/hooks/guard-branch-context.sh` hook enforces this).
- No AI-attribution trailers (`Co-Authored-By`, `Generated by`).

Two hooks back this up: `.claude/hooks/nudge-uncommitted.sh` reminds you while
uncommitted changes pile up on a branch that already has commits, and
`.claude/hooks/commit-before-stop.sh` stops you from ending a turn with
uncommitted work on a feature branch.
See AGENTS.md "Git workflow" for the full contract. Two hooks back this up: the
`.claude/hooks/nudge-uncommitted.sh` PostToolUse hook reminds you while
uncommitted changes pile up during work, and the
`.claude/hooks/commit-before-stop.sh` Stop hook stops you from ending a turn
with a pile of uncommitted work still on a feature branch.
21 changes: 11 additions & 10 deletions packages/cli/templates/CONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Conventions for {{APP_NAME}}

The conventions for building a WebJs app live in **`AGENTS.md`**, which shows
every common pattern as a worked example. The deeper reference set is
`.agents/skills/webjs/` (`SKILL.md` routes to `references/*.md`), for the rarer
surfaces. This file is the short version.
The conventions for building a WebJs app live in the agent skill. **Read
`AGENTS.md` first, then `.agents/skills/webjs/SKILL.md`** (it routes to focused
references under `.agents/skills/webjs/references/`, loaded on demand). This file
is the short version.

## The essentials

Expand All @@ -17,12 +17,13 @@ surfaces. This file is the short version.
- **Use the wired-up database (Drizzle).** Define real models in
`db/schema.server.ts`, then `npm run db:generate` and `npm run db:migrate`.
Never persist to a JSON file, an in-memory array or Map, or localStorage.
- **The scaffold ships a demo showcase.** A full-stack app ships a UI feature
gallery (`app/features/`, `app/examples/todo`); the api template ships a
backend-features showcase (`app/api/features/`), with logic in `modules/`.
When you build a real app, run `npm run gallery:clear` first to shed the
showcase, then grow the app in place. `AGENTS.md` has the template-specific
build steps.
- **The scaffold ships a showcase to learn from.** A full-stack app ships a UI
feature gallery (`app/features/`, `app/examples/todo`); the api template ships
a backend-features showcase (`app/api/features/`), with logic in `modules/`.
When you build a real app, study the parts that match your task (the skill
teaches the same and survives the clear), run `npm run gallery:clear` to shed
the showcase, then grow the app in place. `AGENTS.md` has the full
template-specific playbook.
- **Derive types at every boundary.** Rows from `$inferSelect`, action inputs
from an `interface`, routing files from `PageProps` / `LayoutProps`. Never
`any`, and never `unknown` where a real type exists.
Expand Down
Loading
Loading