Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
66ef455
feat(website): serve the documentation at webjs.dev/docs
vivek7405 Jul 25, 2026
55f8916
fix(server): load a root middleware.ts, not only middleware.js
vivek7405 Jul 25, 2026
a0d88b9
docs: point every docs link at webjs.dev/docs
vivek7405 Jul 25, 2026
fb8c877
test: cover the docs merge across ssr, browser, and the redirect host
vivek7405 Jul 25, 2026
5f7dfd8
chore: drop the docs stylesheet build and DOCS_URL from deploy config
vivek7405 Jul 25, 2026
538a816
fix(website): keep the docs drawer clear of the shared header
vivek7405 Jul 25, 2026
377ee81
fix(website): make the docs sit on the site, not inside a panel on it
vivek7405 Jul 25, 2026
d4bd894
fix: resync the repo for the docs move and drop the router change
vivek7405 Jul 25, 2026
990f3a9
fix(website): give the docs their own metadata and fix mobile a11y
vivek7405 Jul 25, 2026
c2c185a
fix(website): restore the docs social card and scope the mobile CSS
vivek7405 Jul 25, 2026
84f307a
test(website): assert the docs social card fields at risk
vivek7405 Jul 25, 2026
bc6f528
fix(website): scroll only the docs nav, keeping the search box in place
vivek7405 Jul 25, 2026
030c02b
fix(website): derive the llms.txt order from the sidebar
vivek7405 Jul 25, 2026
4c8df81
fix(website): align the docs nav label and item padding
vivek7405 Jul 25, 2026
5c49e8f
fix(website): restore list markers the Tailwind preflight strips
vivek7405 Jul 25, 2026
ee69a64
fix(website): use a real ol for the route-resolution order
vivek7405 Jul 25, 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
2 changes: 1 addition & 1 deletion .agents/skills/webjs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Use this skill for end-to-end WebJs app work. It helps you choose the right laye

## Full Documentation

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://docs.webjs.dev.
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.
Comment thread
vivek7405 marked this conversation as resolved.

## What WebJs Is

Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/webjs/references/data-and-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const [updated] = await db.update(posts).set({ title }).where(eq(posts.id, id)).
await db.delete(posts).where(eq(posts.id, id));
```

A `.returning()` row is the table's own columns only, never `with` relations. When the caller wants a joined shape, re-read with `db.query.*` or splice the already-known related value in by hand. Full surface at https://docs.webjs.dev.
A `.returning()` row is the table's own columns only, never `with` relations. When the caller wants a joined shape, re-read with `db.query.*` or splice the already-known related value in by hand. Full surface at https://webjs.dev/docs.

## Input validation at the boundary

Expand Down Expand Up @@ -201,4 +201,4 @@ import type { Post } from '#db/schema.server.ts';
import { posts } from '#db/schema.server.ts';
```

Keep the wire shape in a browser-safe `modules/<feature>/types.ts` with NO runtime import from a `.server.ts` file or from `db/`. Define a hand-written DTO, or a type-only derivation (`import type { Post } ...; export type PostFormatted = Omit<Post, 'createdAt'> & { createdAt: string }`). Never `export *` or a value re-export from a `.server.ts` in `types.ts`; that carries the runtime table bindings and breaks any component importing the types. Full reference at https://docs.webjs.dev.
Keep the wire shape in a browser-safe `modules/<feature>/types.ts` with NO runtime import from a `.server.ts` file or from `db/`. Define a hand-written DTO, or a type-only derivation (`import type { Post } ...; export type PostFormatted = Omit<Post, 'createdAt'> & { createdAt: string }`). Never `export *` or a value re-export from a `.server.ts` in `types.ts`; that carries the runtime table bindings and breaks any component importing the types. Full reference at https://webjs.dev/docs.
4 changes: 3 additions & 1 deletion .agents/skills/webjs/references/routing-and-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export async function POST(req: Request) {

Optional root-level plus per-segment. The default export is `async (req, next) => Response`. Return a Response to short-circuit, or call `next()` and post-process. Per-segment middleware applies to its subtree, outermost to innermost.

The root file sits beside `app/`, not inside it, and may be `middleware.ts` / `.js` / `.mts` / `.mjs` (`.ts` wins if more than one exists). A per-segment `app/<segment>/middleware.*` takes any of the same extensions.

## Metadata and `generateMetadata`

A page exports `metadata` (static) or `generateMetadata(ctx)` (request-scoped, takes precedence). Values flow into `<head>` at SSR and merge across nested layouts (deeper wins). Type both with `Metadata`; `MetadataContext` types the argument. The surface is Next.js-compatible.
Expand All @@ -108,7 +110,7 @@ export async function generateMetadata(ctx: MetadataContext): Promise<Metadata>
}
```

Common fields: `title` (string or `{ template, default, absolute }`), `description`, `keywords`, `metadataBase` (resolves relative URLs in `openGraph` / `twitter` / `alternates` / `icons`), `openGraph`, `twitter`, `robots`, `alternates.canonical`, `icons`, `manifest`, and `jsonLd` (schema.org structured data, single object or array, HTML-safe-escaped automatically). `viewport`, `themeColor`, and `colorScheme` may also be set via a split `export const viewport = { ... }`. `cacheControl` is emitted as a response HEADER (not a `<meta>`); pages default to `no-store`, and a `public` value enables conditional GET (a weak `ETag` + `304`). See https://docs.webjs.dev for the full field list.
Common fields: `title` (string or `{ template, default, absolute }`), `description`, `keywords`, `metadataBase` (resolves relative URLs in `openGraph` / `twitter` / `alternates` / `icons`), `openGraph`, `twitter`, `robots`, `alternates.canonical`, `icons`, `manifest`, and `jsonLd` (schema.org structured data, single object or array, HTML-safe-escaped automatically). `viewport`, `themeColor`, and `colorScheme` may also be set via a split `export const viewport = { ... }`. `cacheControl` is emitted as a response HEADER (not a `<meta>`); pages default to `no-store`, and a `public` value enables conditional GET (a weak `ETag` + `304`). See https://webjs.dev/docs for the full field list.

## Control-flow throws

Expand Down
14 changes: 10 additions & 4 deletions .claude/hooks/require-docs-with-src.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,16 @@ if [ -z "$src_touched" ]; then exit 0; fi
# Any documentation surface staged in the same commit? The curated set of
# real doc surfaces: AGENTS / CLAUDE / CONVENTIONS / README markdown at any
# depth (root, per-package, per-example), the skill at .agents/skills/webjs/,
# the docs site, the marketing website, and the scaffold templates. NOT every
# *.md, so a stray note cannot be staged to slip the gate.
# the marketing website (which carries the docs site at website/app/docs/),
# and the scaffold templates. NOT every *.md, so a stray note cannot be
# staged to slip the gate.
#
# `^docs/` is deliberately absent. That path used to BE the docs site, but
# since #1098 it holds a three-file redirect-only host, so accepting it would
# let a staged tsconfig satisfy the documentation gate. Its AGENTS.md still
# counts, via the markdown alternative above.
doc_staged=$(printf '%s\n' "$staged" | grep -E \
'(^|/)(AGENTS|CLAUDE|CONVENTIONS|README)\.md$|^\.agents/skills/webjs/|^docs/|^website/|^packages/cli/templates/' || true)
'(^|/)(AGENTS|CLAUDE|CONVENTIONS|README)\.md$|^\.agents/skills/webjs/|^website/|^packages/cli/templates/' || true)
Comment thread
vivek7405 marked this conversation as resolved.
if [ -n "$doc_staged" ]; then exit 0; fi

cat >&2 <<'EOF'
Expand All @@ -80,7 +86,7 @@ package.json webjs.* key, an html hole, a lifecycle hook, a convention, or
the behaviour of an already-documented feature), invoke the webjs-doc-sync
skill, then `git add` EVERY applicable surface and commit again:
AGENTS.md + .agents/skills/webjs/ agent reference (SKILL.md + references/)
docs/app/docs/<topic> the docs site
website/app/docs/<topic> the docs site (served at webjs.dev/docs)
README.md if a headline capability
website/ marketing copy, if headline
packages/cli/templates/ scaffold per-agent rule files
Expand Down
2 changes: 1 addition & 1 deletion .claude/hooks/route-skills.sh
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ if has '(doc|documentation) (gap|drift|sync|coverage|debt)' \
|| has '(missing|stale|outdated|out-of-date|out of date).{0,20}(doc|docs|documentation)' \
|| has 'did (we|you|i) (update|sync).{0,20}(doc|docs)' \
|| has '(audit|sweep|check).{0,40}(doc|docs|documentation)'; then
add_match "webjs-doc-sync: the request is about documentation sync, drift, or a doc gap. Invoke the webjs-doc-sync skill BEFORE editing any doc. It holds the authoritative map of EVERY surface (AGENTS.md + the skill at .agents/skills/webjs/, README, the docs site under docs/app/docs/, the marketing website/, and the scaffold templates' per-agent rule files) and the change-type to surface mapping, so no surface is silently skipped. File each confirmed gap via webjs-file-issue."
add_match "webjs-doc-sync: the request is about documentation sync, drift, or a doc gap. Invoke the webjs-doc-sync skill BEFORE editing any doc. It holds the authoritative map of EVERY surface (AGENTS.md + the skill at .agents/skills/webjs/, README, the docs site under website/app/docs/, the rest of the marketing website/, and the scaffold templates' per-agent rule files) and the change-type to surface mapping, so no surface is silently skipped. File each confirmed gap via webjs-file-issue."
Comment thread
vivek7405 marked this conversation as resolved.
fi

# --- webjs-scaffold-sync: keep every scaffold surface in sync -----------
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/webjs-blog-write/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ when_to_use: |
editing an existing blog post's prose in a non-trivial way
Do NOT trigger for: filing an issue (webjs-file-issue), syncing framework
API docs or the docs site (webjs-doc-sync), or the docs site's own
`docs/app/docs/**` pages (those are reference docs, not blog posts).
`website/app/docs/**` pages (those are reference docs, not blog posts).
---

# Write a webjs blog post
Expand Down Expand Up @@ -99,5 +99,5 @@ The test before you ship: read the draft aloud and ask whether the author would
## Related skills

- **webjs-file-issue**: file the tracking issue for the blog work before writing, and file a framework issue if dogfooding surfaces a real bug.
- **webjs-doc-sync**: for the framework's own reference docs (`AGENTS.md`, the skill at `.agents/skills/webjs/`, the docs site under `docs/app/docs/`). A blog post is not a doc-sync surface, and reference docs are not a blog. Keep them separate.
- **webjs-doc-sync**: for the framework's own reference docs (`AGENTS.md`, the skill at `.agents/skills/webjs/`, the docs site under `website/app/docs/`). A blog post is not a doc-sync surface, and reference docs are not a blog. Keep them separate.
- **webjs-list-todos**: to see what shipped work is open or recently done when hunting for a topic.
6 changes: 3 additions & 3 deletions .claude/skills/webjs-doc-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ applies, then update or consciously skip each.
relevant `references/` file.
2. **`README.md`** (repo root). Update when a headline capability changes (the
feature list, the quickstart, the runtime/template matrix).
3. **The docs site: `docs/app/docs/<topic>/page.tsx`.** This is the
user-facing documentation at docs.webjs.dev. Find the topic page(s) that cover
3. **The docs site: `website/app/docs/<topic>/page.tsx`.** This is the
user-facing documentation at webjs.dev/docs. Find the topic page(s) that cover
the area (`server-actions`, `routing`, `components`, `caching`, `configuration`,
`client-router`, `data-fetching`, ...) and update them. `llms.txt` /
`llms-full.txt` are generated LIVE from the doc pages (no build step), so they
Expand Down Expand Up @@ -90,7 +90,7 @@ applies, then update or consciously skip each.
be) described:
```sh
git grep -n -iE '<token1>|<token2>' -- \
AGENTS.md '.agents/skills/webjs/**' README.md 'docs/app/docs/**' \
AGENTS.md '.agents/skills/webjs/**' README.md 'website/app/docs/**' \
'website/**' 'packages/cli/templates/**' 'examples/**/CONVENTIONS.md'
```
3. For each surface in the mapping that applies, update it. For a behaviour
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/webjs-scaffold-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ it applies, then update or consciously skip each.
here, including the counterfactual (a per-template exclusion test).
6. **The framework docs that DESCRIBE the scaffold** (shared with doc-sync):
- Root `AGENTS.md` "Scaffolding" section.
- The docs site: `docs/app/docs/getting-started/page.ts` (+ `backend-only`,
- The docs site: `website/app/docs/getting-started/page.ts` (+ `backend-only`,
`ai-first`, `conventions` where they describe generated structure).
- `README.md` (the template matrix + the "scaffold is the tutorial" note).
7. **The CLI surface**: `packages/cli/` `--template` validation + `--help`/usage
Expand Down Expand Up @@ -185,7 +185,7 @@ it applies, then update or consciously skip each.
```sh
git grep -n -iE '<token1>|<token2>' -- \
'packages/cli/lib/**' 'packages/cli/templates/**' 'test/scaffolds/**' \
AGENTS.md README.md 'docs/app/docs/**'
AGENTS.md README.md 'website/app/docs/**'
```
3. Update every surface the mapping says applies. For a SCOPING or wording change
(e.g. "gallery is full-stack only" becoming "full-stack and saas"), the grep
Expand Down
10 changes: 5 additions & 5 deletions .claude/skills/webjs-start-work/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Doc drift is the #1 way a framework rots. Documentation MUST stay in sync with c
- `CHANGELOG.md` (per-package, under `changelog/<pkg>/<version>.md`). Generated automatically by the pre-commit hook on version-bump commits; review and add migration notes for breaking changes. Without a version bump, no changelog entry.
- `CLAUDE.md` (only if a Claude Code rule is specifically added; framework conventions go in AGENTS.md).
- `.github/*.md` (issue templates, PR templates, contributing) when a workflow rule shifts.
3. **User-facing docs site** under `docs/app/docs/<topic>/page.ts` (these are `.ts` files, not markdown, so they're excluded by the markdown query but they're the canonical user-facing reference). If the change is visible to a user reading the docs site, update the matching topic page. Add a new page if the surface is new and there's no obvious home.
3. **User-facing docs site** under `website/app/docs/<topic>/page.ts` (these are `.ts` files, not markdown, so they're excluded by the markdown query but they're the canonical user-facing reference). If the change is visible to a user reading the docs site, update the matching topic page. Add a new page if the surface is new and there's no obvious home.
4. **Scaffold templates** under `packages/cli/templates/` and the generators `packages/cli/lib/{create,api-gallery}.js`. Update if the change affects what `webjs create` generates. The scaffold ships a gallery index home + layout + db wiring, a densely-commented feature gallery (`packages/cli/templates/gallery/**`, demos under `app/features/` plus `app/examples/todo`) and the api showcase (`api-gallery.js`), plus one cross-agent skill at `.agents/skills/webjs/` (SKILL.md + references) that the agent grows in place; there are no per-agent rule files. A feature change that agents should know about lands in the skill; a generated-code change lands in the generators, verified with `generate + boot + webjs check`.
5. **The MCP server** (the standalone `@webjsdev/mcp` package, `packages/mcp/src/{mcp,mcp-docs,mcp-source}.js`, extracted from the CLI in #415; `webjs mcp` and `npx @webjsdev/mcp` both run it). The MCP is how AI agents learn and introspect webjs, so it must stay in lockstep with the surfaces it exposes. Update it whenever the change touches what it serves:
- **Introspection tools** (`list_routes` / `list_actions` / `list_components` / `check`): if you change the route table shape, the action/RPC-hash scheme, component registration, or a `webjs check` rule, update the matching tool projection so the MCP reports reality.
Expand Down Expand Up @@ -213,13 +213,13 @@ For each item above, explicitly answer one of:

The "every markdown file" rule is generative because new markdown files appear over a project's lifetime. A closed enumeration silently excludes them; the git query is the source of truth.

If you find yourself writing "N/A" for every item except tests, that is a smell. Most user-visible code changes touch at least one markdown file and the relevant `docs/app/docs/<topic>/page.ts` page.
If you find yourself writing "N/A" for every item except tests, that is a smell. Most user-visible code changes touch at least one markdown file and the relevant `website/app/docs/<topic>/page.ts` page.

### Concrete examples from recent PRs

- PR #110 (`fs.watch` + Web Crypto): updated `AGENTS.md` (no-build claim wording), `packages/server/AGENTS.md` (file watcher mention), `docs/app/docs/{configuration,deployment,no-build}/page.ts` (chokidar → fs.watch). Tests covered the watcher, the boundary, and the migration.
- PR #111 (module-graph asset gate): updated `AGENTS.md` (new invariant about the gate), `packages/server/AGENTS.md` (gate + guardrail invariants), `docs/app/docs/no-build/page.ts` (new "authorisation gate" subsection). Tests covered the gate end-to-end.
- PR #117 (core dist bundles): updated `docs/app/docs/no-build/page.ts` (the @webjsdev/core exception note), `packages/core/README.md` (tarball layout), `packages/core/AGENTS.md` (invariant 1 rewording), `packages/server/AGENTS.md` (importmap.js module-map entry).
- PR #110 (`fs.watch` + Web Crypto): updated `AGENTS.md` (no-build claim wording), `packages/server/AGENTS.md` (file watcher mention), `website/app/docs/{configuration,deployment,no-build}/page.ts` (chokidar → fs.watch). Tests covered the watcher, the boundary, and the migration.
- PR #111 (module-graph asset gate): updated `AGENTS.md` (new invariant about the gate), `packages/server/AGENTS.md` (gate + guardrail invariants), `website/app/docs/no-build/page.ts` (new "authorisation gate" subsection). Tests covered the gate end-to-end.
- PR #117 (core dist bundles): updated `website/app/docs/no-build/page.ts` (the @webjsdev/core exception note), `packages/core/README.md` (tarball layout), `packages/core/AGENTS.md` (invariant 1 rewording), `packages/server/AGENTS.md` (importmap.js module-map entry).

If a PR ships without ANY of those touches and the change is user-visible, the PR is incomplete; do not mark it ready for review (leave it draft until the surfaces are addressed).

Expand Down
Loading
Loading