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
10 changes: 8 additions & 2 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ This is a **Turborepo** monorepo with pnpm workspaces (`apps/*` and `packages/*`
│ ├── site/ # Prisma marketing site and multi-zone host (port 3000)
│ ├── docs/ # Prisma documentation site (Next.js 16 + Fumadocs, port 3001)
│ ├── blog/ # Prisma blog (Next.js + Fumadocs, port 3002)
│ └── eclipse/ # Eclipse design system showcase (Next.js + Fumadocs, port 3003)
│ ├── eclipse/ # Eclipse design system showcase (Next.js + Fumadocs, port 3003)
│ └── handbook/ # Builders Handbook (Next.js + Fumadocs, port 3004)
├── packages/
│ ├── ui/ # Shared UI components (@prisma-docs/ui, no build step)
│ └── eclipse/ # Eclipse design system (@prisma/eclipse, published, builds to dist/)
Expand All @@ -21,7 +22,7 @@ This is a **Turborepo** monorepo with pnpm workspaces (`apps/*` and `packages/*`
```

**Apps** - each pins its own dev port in its `dev` script, so `pnpm dev` at the root starts all
four side by side.
five side by side.

- **`site`** (apps/site, port 3000) - The prisma.io marketing site and the root zone of the
multi-zone setup. It has no `basePath`, serves its assets from `/site-static`, and owns the
Expand All @@ -36,6 +37,11 @@ four side by side.
(`output: "export"`, unoptimized images) and has no `basePath`, so it is not one of the zones
the site app rewrites into.

- **`handbook`** (apps/handbook, port 3004) - The Builders Handbook: MDX chapters in
`content/handbook/`, served under `basePath: "/handbook"` with assets at `/handbook-static`.
Content is dictated by Shane and structured by Claude; `apps/handbook/AUTHORING.md` is binding.
Not yet forwarded by the site app's rewrites.

**Packages:**

- **`@prisma-docs/ui`** (packages/ui) - Shared shadcn-style components, hooks, footer data, and
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This repository is a **pnpm monorepo** containing the Prisma documentation, blog
|------|--------------|
| `apps/docs` | Prisma documentation site (Next.js + Fumadocs) |
| `apps/blog` | Prisma blog |
| `apps/handbook` | Builders Handbook (Next.js + Fumadocs), chapters written by Shane, see `apps/handbook/AUTHORING.md` |
| `apps/eclipse` | Eclipse design system documentation |
| `packages/eclipse` | Eclipse design system component library (`@prisma/eclipse`) |
| `packages/ui` | Shared UI components and utilities (`@prisma-docs/ui`) |
Expand All @@ -36,13 +37,15 @@ This starts all apps via Turbo:
- **Docs** — http://localhost:3001
- **Blog** — http://localhost:3002
- **Eclipse** — http://localhost:3003
- **Handbook** — http://localhost:3004/handbook

To run a single app:

```bash
pnpm --filter docs dev # docs only
pnpm --filter blog dev # blog only
pnpm --filter eclipse dev # eclipse design system docs only
pnpm --filter handbook dev # builders handbook only
```

## Build
Expand Down
173 changes: 173 additions & 0 deletions apps/handbook/AUTHORING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Authoring the Builders Handbook

This file is the binding content spec. If a chapter contradicts it, the chapter is wrong.

## The one rule

**Shane writes the handbook. Claude structures it.** Every claim, opinion, example, number, and recommendation on a page came out of Shane's head first. Claude's job is to turn a raw brain-dump into readable chapters: order the thoughts, cut repetition, tighten sentences, apply the component vocabulary below, and flag gaps. Claude never fills a gap with invented content. A gap becomes a `TODO(shane):` comment in the MDX and a bullet in the review notes.

Claude is allowed to have ideas. Shane asked for them. They go in the chapter's private outline comment under a "Claude's suggestions" heading, clearly separate from "From your notes". A suggestion becomes content only when Shane says so, in his words. Names, numbers, quotes, and anecdotes are never suggested: those are asked for as questions.

The previous attempt at this book (`buildaproduct`) failed because the content was generated. Every rule below exists to stop that happening again.

## Workflow, chapter by chapter

1. **Dictate.** Shane brain-dumps into `notes/<part>/<chapter>.md`. Voice transcript, bullet spew, half sentences, all fine. Tangents welcome; they get cut later. Nothing in `notes/` is ever published or linted.
2. **Structure.** Claude reads the note and writes `content/handbook/<part>/<chapter>.mdx` with `status: structured`. Rules:
- Keep Shane's claims, order of importance, and voice. Rephrase for clarity; do not rephrase for smoothness.
- Keep his examples and numbers exactly. If a number is missing, `TODO(shane): number?`, not a plausible guess.
- Use only the components in this file.
- At the end of the MDX, add a private review-notes comment listing: what was cut, what was reordered, every TODO, and any place Claude was unsure it understood the point.

Private comments (outlines, review notes) use MDX comment syntax, wrapped so Prettier leaves them alone. Shane's editors format on save with Prettier, which rewrites a bare multi-line `{/* */}` into invalid MDX and takes every page down with a 500. HTML comments (`<!-- -->`) are not valid MDX at all. The blank lines around the markers are required:

```mdx
{/* prettier-ignore-start */}

{/*
OUTLINE (private, never published)

FROM YOUR NOTES
- ...

CLAUDE'S SUGGESTIONS
- ...

QUESTIONS FOR YOU
- ...
*/}

{/* prettier-ignore-end */}
```

A chapter that has been scoped but not written carries an outline comment in this shape and a one-line visible placeholder.
3. **Review.** Shane reads the diff, fixes what Claude got wrong, resolves TODOs, and flips `status: reviewed`.
4. **Publish.** Remove the `status` field. The badge disappears.

Chapter frontmatter:

```yaml
---
title: "3. Name of the chapter" # number in the title; the sidebar shows titles verbatim
description: One or two sentences. The chapter's promise, plainly.
status: stub | dictated | structured | reviewed # omit once published
readingTime: 12 # minutes, hand-set
---
```

Chapter numbering is manual and global across Parts. Renumber by hand when a chapter moves.

## Voice

- Light and easy reading. Not a textbook. `content/handbook/index.mdx` is the reference for tone: Shane wrote it himself.
- Talk to the reader as "you". "We" is fine for the handbook and the reader going through it together ("we'll step through..."). Warm is fine. An exclamation mark now and then is fine.
- Where one of Shane's own sentences breaks a rule in this file, Shane's sentence wins. The rules exist to stop Claude's defaults, not to edit Shane.
- Opinions stated as opinions. "Do X" beats "you may want to consider X." The book has a point of view because Shane does.
- Plain words. A tired non-native-English reader gets every sentence on first pass.
- Concrete over abstract. A number, a filename, a quote from a real person beats "many builders find."
- Short paragraphs. Three to five sentences. One idea each.
- Technical and non-technical readers share the text. Where they need different instructions, say so in one line and give both. Do not write two books.

## Banned on sight

Text that reads frictionless-smooth is a bug. Specifically banned in all prose, headings, captions, and code comments:

1. **Negation pivots.** "Not just X, it's Y." "This isn't about X, it's about Y." State it positively. One deliberate, load-bearing contrast per chapter at most.
2. **Rule-of-three cadence.** "Clear, concise, and compelling" as the default list shape. Vary: two items, four items, one flat statement. Three is fine when three is the count.
3. **Empty intensifiers.** delve, crucial, robust, seamless, leverage (verb), unlock, elevate, landscape, journey, game-changer, empower, supercharge, transformative, harness, navigate (metaphorical), tapestry. Say what the thing does.
4. **Reflexive hedging.** "It's important to note", "it's worth considering", both-sidesing where the book holds an opinion.
5. **Perfect parallelism in prose.** Every bullet opening with a bolded label and colon; uniform paragraph lengths; symmetric section shapes. Structured components (Playbook, Checklist) are UI and exempt. Running prose must be lumpier than the components.
6. **Grand openers and closers.** Throat-clearing intros, inspirational wrap-ups, "ultimately", "at the end of the day", any closing paragraph that restates the chapter.
7. **Em dashes.** Banned everywhere, including code comments and captions. Use a period, comma, colon, or parentheses. En dashes only for numeric ranges (10–15 min).
8. **Ceremonial metaphors.** "A testament to", "cornerstone", "the data tells a story", personified abstractions.
9. **Cryptic wordplay.** Headings or sentences that tease the point instead of stating it. "The menu changed" as a heading is out; "Pricing changed after month three" is in. Vivid is fine when the meaning is fully on the page.
10. **Invented specifics.** Any name, number, quote, or anecdote that is not in Shane's notes. This is the one that matters most.

## Chapter anatomy

Not every chapter has every part, and the order flexes. Playbooks and checklists are optional: use one only when the chapter has real steps or a real output. The fuller shape is:

1. **Title + description.** The description is the promise: what the reader can do after this chapter.
2. **Opening paragraphs.** Straight into the point. No "in this chapter we will."
3. **Body sections** under `##` headings. Readers skim; headings should make sense as a list on their own (that list is the right-hand TOC).
4. **One worked example**, threaded through as `:::example` callouts placed right after the concept they illustrate. Real, from Shane's experience, awkward parts included.
5. **Playbook**, if the chapter has actions. Numbered steps, one bounded action each, time estimate on every step.
6. **Checklist** at the end: what must be true before the next chapter is worth reading. Three to six items.

Target length: 600 to 900 words of prose. Components do not count toward the budget. A chapter that wants to run longer gets split into two pages.

## Component vocabulary

Callouts, directive syntax (preferred in source):

```mdx
:::note
Context the reader might want. Skipping it costs nothing.
:::

:::tip
A shortcut. Skipping it costs time.
:::

:::warning
Something that fails silently. Skipping it costs an afternoon.
:::

:::example
A beat from a real build. How it actually went.
:::
```

Custom title: `<Callout type="tip" title="Your label">...</Callout>`.

Code blocks: fenced, with a language. Add `title="path/to/file.ts"` for a filename tab. The copy button is automatic.

Playbook:

```mdx
<Playbook>
<Step title="One bounded action" time="~20 min">
Optional body. Prose, a code block, a short list.
</Step>
<Step title="Another action" time="an evening" />
</Playbook>
```

Checklist (interactive, persists per browser; `id` must be unique across the whole handbook and stable, or readers' ticks reset):

```mdx
<Checklist id="ch3-before-you-move-on" title="Before you move on">
<Check>Something that must be true.</Check>
<Check>Something else.</Check>
</Checklist>
```

Margin note (side commentary; floats to the gutter on wide screens, inset card elsewhere):

```mdx
<Aside label="Why">
One or two sentences. Must be skippable.
</Aside>
```

Footnotes: GitHub-style `[^1]` with the definition at the bottom of the file.

Tables: GitHub-style pipes. Keep them narrow; the reading column is 44rem.

## Files

```
apps/handbook/
├── AUTHORING.md # this file
├── notes/ # raw dictation, never published
│ └── <part>/<chapter>.md
├── content/handbook/ # published MDX
│ ├── meta.json # Part order
│ ├── index.mdx # landing / table of contents
│ └── <part>/
│ ├── meta.json # Part title + chapter order
│ └── <chapter>.mdx
└── src/components/handbook/ # Callout, Aside, Playbook, Checklist, ChapterMeta
```

Parts are folders. A Part's title lives in its `meta.json`. Chapter order within a Part is the `pages` array. Slugs are filenames; pick them once and do not rename (URLs are forever).
19 changes: 19 additions & 0 deletions apps/handbook/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# apps/handbook

The Builders Handbook. Read `AUTHORING.md` before writing or editing anything under `content/`.

Non-negotiable: **content comes from Shane's notes in `notes/`, never from Claude.** Claude structures, tightens, and applies the component vocabulary. A missing fact becomes `TODO(shane): ...` in the MDX, not a plausible sentence. The banned-phrasing list in `AUTHORING.md` applies to every word on every page, including code comments.

Shell and components live in `src/`; they follow `apps/docs` and `apps/eclipse` patterns (stock Fumadocs `DocsLayout`, Eclipse tokens, `@prisma-docs/ui` helpers). Port 3004, `basePath: "/handbook"`, `assetPrefix: "/handbook-static"`.

Commits in this repo need a type, a scope of `handbook`, and a Linear reference in the body. See the root `CONTRIBUTING.md`.

<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->
42 changes: 42 additions & 0 deletions apps/handbook/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Builders Handbook

A handbook for people who build software with AI, technical or not. Published by Prisma. Next.js + Fumadocs, one chapter per MDX file, served under `basePath: "/handbook"` as a multi-zone app alongside docs and blog.

**Content is written by Shane, structured with AI assistance.** Read `AUTHORING.md` before touching anything under `content/`.

## Run locally

```bash
pnpm install
pnpm --filter handbook dev
```

Runs on **http://localhost:3004/handbook** (site is 3000, docs 3001, blog 3002, eclipse 3003). `@prisma/eclipse` must be built first; `pnpm dev` at the root does that via Turbo, or run `pnpm --filter @prisma/eclipse build` once.

## Structure

- `content/handbook/` — published chapters. Parts are folders, each with a `meta.json`.
- `notes/` — Shane's raw dictation per chapter. Never published.
- `AUTHORING.md` — voice, banned phrasing, chapter anatomy, component vocabulary, dictation workflow.
- `src/components/handbook/` — `Callout`, `Aside`, `Playbook`/`Step`, `Checklist`/`Check`, `ChapterMeta`.
- `src/app/(handbook)/` — Fumadocs `DocsLayout` (sidebar + TOC) and the `[[...slug]]` page renderer.
- `source.config.ts` — MDX pipeline: directive callouts, Shiki via `@prisma-docs/ui`, frontmatter schema (`status`, `readingTime`).

## Wiring into prisma.io/handbook (not done yet)

When this goes public, `apps/site/next.config.mjs` needs the same treatment docs and blog get:

```js
const HANDBOOK_ORIGIN = process.env.NEXT_HANDBOOK_ORIGIN || "https://handbook.prisma.io";
// ...in rewrites().beforeFiles:
{ source: "/handbook", destination: `${HANDBOOK_ORIGIN}/handbook`, missing: [{ type: "host", value: HANDBOOK_ORIGIN_HOST }] },
{ source: "/handbook/:any*", destination: `${HANDBOOK_ORIGIN}/handbook/:any*`, missing: [...] },
{ source: "/handbook-static/:path*", destination: `${HANDBOOK_ORIGIN}/handbook-static/:path*`, missing: [...] },
```

plus a Vercel project for this app, `NEXT_HANDBOOK_ORIGIN` on the site project, and a CSP/security-headers block copied from `apps/blog/next.config.mjs`. Search, OG images, `llms.txt`, and sitemap are also deferred until there are real chapters.

## Related

- `ARCHITECTURE.md` at the repo root explains the multi-zone setup.
- `apps/docs` and `apps/blog` are the sibling zones this app copies its patterns from.
Loading
Loading