Applies to all user-facing writing on the website (docs, marketing, blog). Internal code names are unaffected.
- The service that routes, schedules, and persists Actors is the control plane. Never "engine", "server", or "orchestrator".
- A process running the user's code with the Rivet SDK is a worker. Never "envoy", "runner", "node", "compute", or "data plane".
- "Actor" is always capitalized in prose: "Rivet Actor", "Actors", "an Actor's state", "per-Actor SQLite". Never "actor" or "actors" in user-facing copy, headings, alt text, or captions. Code identifiers, paths (
/actors/docs/), product IDs ("actors"), and CSS classes stay lowercase. Vendored product docs undervendor/*are synced from their own repos, so fix capitalization there upstream, not in the vendored copy. - Never use "agent" as a deployment noun. Rivet ships agentOS and Actors is "where agents live"; the collision is unrecoverable.
- "envoy" never appears on the website. Envoy Proxy is a top-tier CNCF project. Internal code keeps
pegboard-envoy/envoy-client. - Rivet Compute is a live Rivet Cloud feature, documented at
/docs/deploy/cloud/compute/. Where prose must name the managed offering, it is Rivet Cloud. When describing what Rivet Cloud runs for the customer, say "your backend", never "your workers". - Rivet Cloud docs live in the Deploy section at
/docs/deploy/cloud/, BYOC at/docs/deploy/byoc/; the pricing page is/pricing/. Dashboard links point athttps://dashboard.rivet.dev. - Positioning canon: the tagline is "Infrastructure for the agentic era." with the supporting line "Orchestrate agents. Operate their environment. Automate their work. Deploy what they build." The phrase "infrastructure for long-lived software" is retired.
- "Self-Host" names the section; "control plane" names the thing. Pages inside it say "deploy the control plane on Kubernetes".
- Do not rewrite blog or changelog posts to apply this terminology. They are dated records; dead links are handled by redirects.
- The site-wide docs overview is
/docs/; the Guides tab is/guides/(every product bundle'scontent/guides/andguidessidebar key, merged in product order with same-titled groups combined; the website owns only the overview insrc/content/guides/index.mdx); the Deploy tab is/docs/deploy/{self-host,byoc,cloud}/. Product documentation stays at/{product}/docs/and/{product}/integrations/. - The route prefixes live in
src/sitemap/deploy.tsandsrc/sitemap/guides.ts. Derive hrefs from them; never hand-write/orchestrate/,/{product}/self-host/, or/actors/learn/, which are redirects.
- A docs page that introduces a feature opens with a
## Quickstartcrash course: the shortest end-to-end path to a working result, as<Steps>with minimal code and no options, tradeoffs, or edge cases. Everything else goes below it. Pure reference pages, which a reader arrives at already knowing what they want, skip it.
- There is one shared copy of every guide at
/docs/deploy/self-host/, authored insrc/content/self-host/. Guides are product-agnostic; do not fork a guide per product or reintroduce per-product slots. - Prerequisites go in a
## Requirementsblock above## Steps, never as Step 1. ## Stepsis an H2 wrapping<Steps>. Four to six steps maximum, each titled with an imperative verb.- Every command shows its expected output. This replaces a prose verification step.
- Budget roughly two sentences per step. Anything needing a paragraph of why belongs in
## Optionsor the concept docs. - Never restate shared reference. Ports, env vars, and configuration live on one canonical page each; guides link to them.
- Use tabs for variants (Rivet Cloud vs self-hosted, and the product switcher), never a forked page.
- Pin versions in every snippet. No
:latest. ## Next stepscarries at most three links.- The control plane is stateful, so serverless platforms are worker-only. Adding a platform means updating
deployMatrix.ts, which feeds both the sidebar andgetStaticPaths. - Platform support is uniform across every product, including agentOS. agentOS runs inside Actors and the Actor supplies persistence, so it needs nothing extra from the host platform. Do not exclude it from serverless platforms.
- Worker guides inherit one shared architecture diagram from the template. Do not add a per-guide diagram; platform detail belongs in the steps.
- Diagrams are hand-authored inline SVG via the
creating-docs-diagramsskill, drawn in the figure accent (highlight, see Theme). Not Mermaid.
To add or update icons, see frontend/packages/icons/CLAUDE.md.
The product wordmarks in src/images/products/*-logo.svg are white-on-transparent: the alpha channel is the mark, so the file carries no color of its own. They are always painted as a masked element via wordmarkMaskStyle (src/lib/product-accent.ts), never as an <img>.
- Never render a naked mark. A wordmark always rides inside its tile:
rounded-[34.375%]at the SVG's inset-ring geometry, filled ink or the product accent. A bare mark dropped on a light surface — an<img>withbrightness-0, an invert filter, or a raw mask onpaper— is the failure mode this rule exists to prevent. It reads as a black outline box and matches nothing else on the site. - The mark inside the tile is white, never cream. Cream is for text and fills inside ink panels; on a mark it reads as a dirty off-white against the pure-white Rivet badge in the header.
- Ink tile (
bg-ink) is the default: product-page hero lockups (ProductLockup),/docscards (DocsLanding), inline product mentions, and any product list on a light surface. - Accent tile (
ProductBadgeinsrc/components/ProductBar.tsx) is the colored variant: header dropdowns, mobile sheet, product bar label, talk-to-an-engineer. Every place that lists products rendersProductBadgerather than hand-rolling the geometry, so the lockup cannot drift. - One sanctioned tile-less case: on the homepage stack plates (
StackSection) the mark is painted white directly on the product-accent field. The plate is the background — it is not a naked mark. - Secure Exec's mark is its own gothic wordmark (
secure-exec-logo.svg), filling the tile with no inset ring, because inside the ring it is illegible at product-bar size. It still rides in a tile like every other mark. - Rivet Cloud has no wordmark. It takes the
faCloudglyph — white inside an accent tile whereProductBadgesupplies one, otherwise bare in ink, sized down so it sits level with the neighboring tiles rather than outweighing them (its own hero, and the careers grid). Do not invent a wordmark for it.
Integration entries in website/src/data/registry.ts display icons on the registry page and detail pages. Each entry uses either an image (SVG file path) or an icon (Font Awesome icon).
image(SVG file inwebsite/public/images/registry/): Use for products and companies that have their own logo (e.g. Docker, Vercel, E2B).icon(Font Awesome from@rivet-gg/icons): Use for generic/non-product items that don't have a brand logo (e.g. Filesystem, Browser, SQLite).
When adding a new product integration:
- Search for the product's official SVG logo. Try these sources in order:
https://simpleicons.org/icons/{name}.svg(then apply the brand color)- The product's website favicon or press kit
- Their GitHub organization avatar
- Save the SVG to
website/public/images/registry/{slug}.svg. - Use actual brand colors. Do not convert logos to white/monochrome. Logos display on a dark background, so avoid dark/black logos. If a logo is black-only, find the dark-mode variant.
- The carousel selector at the top of the registry page applies a monochrome filter automatically. The colored version displays in the main card and detail pages.
Import from @rivet-gg/icons. The full Font Awesome Pro library is available. Common choices for registry items:
faFloppyDisk- filesystem/storagefaGlobe- web/browser/networkfaDatabase- databasefaSqlite/faPostgresql- specific databasesfaBrain- AI/memoryfaDesktop- local/desktopfaCode- code/interpreter
- Always store docs code examples under
examples/docs/and render them with<CodeSnippet>. Do not add inline fenced code blocks to docs MDX files. - Type-check all TypeScript code blocks in
website/src/content/docs/**/*.mdxbefore release, because any failing snippet fails the website build. - Document
onStateChangeas read-only againstc.state; usevarsfor callback counters or derived runtime-only values. - Connect page cards and sidebar entries come from
frontend/packages/shared-data/src/deploy.ts.
- Include all required imports.
- Define all referenced variables and types.
- Avoid placeholders or incomplete code that cannot compile.
- Use
@nocheckonly when a snippet intentionally documents API not available on this branch yet.
-
Use
<CodeGroup workspace>for any example that spans multiple files (for exampleregistry.ts+client.ts). -
Follow these rules for workspace code groups.
-
Store every file under
examples/docs/and render each one with<CodeSnippet file="..." title="..." />inside the group. -
Treat files as real modules in the same directory and use relative imports (for example
import type { registry } from "./registry"). -
Do not split related multi-file examples into separate non-workspace snippets.
-
If any code block fails type checking, the build fails.
- Marketing headings and card titles use
font-medium(h1 heroes, section h2s, h3/h4 card titles, FAQ headings, price figures). Do not introducefont-normalheadings. font-normalremains correct only for deliberate de-emphasis: tablethde-bolding, quietdtlabels, and input-like UI (TypesenseSearch).- Hero h1s and section h2s use the class constants in
src/components/marketing/typography.tsx(tracking-[-0.015em], h1leading-[1.06]). Do not hand-writetracking-tighton headings attext-2xlor larger;tracking-tightstays acceptable ontext-baseand smaller card titles. - Manrope is the only marketing typeface; JetBrains Mono covers code, terminal commands, keyboard keys, and tabular numeric data only — never titles, labels, or captions. No serif headings on marketing pages; the Learn section's serif treatment is the only exception.
- Section labels are quiet sans (
EYEBROW_CLASSoreditorial/Eyebrow):text-sm font-medium text-ink-faint, sentence case (text-cream/60inside ink panels). The mono uppercase letter-spaced eyebrow is retired, as are numbered markers ("01/02", "Fig. NN") anywhere in marketing UI. Plate and panel captions useCAPTION_CLASS(sans, sentence case, no figure numbers).
- Marketing pages and docs are light: cool porcelain (
paper,#EFEFEF) with apaper-deepradial pooling bottom-left (.depth-wash) and a fine grain (.paper-grain). Warmth comes from warm-blackinktext, classical imagery, and oil-paint textures, never from synthetic color gradients. Do not use the creammattoken as a surface/background design element on light surfaces (panels, dropdowns, badges, plate frames); usepaper/paper-mid/whiteorink-tint neutrals instead.creamstays valid only as the off-white text/fill inside darkinkpanels, and never on a product mark — those are white (see Product Marks). Docs paint the same porcelain field, render prose viaProse surface="paper", and usepinefor the active sidebar/TOC selected state; only the Learn section keeps a dark shell, and no other page may introduce a dark base. The one sanctioned exception is the Secure Exec overview (/secure-exec), ported from secureexec.dev with its own dark design: its body is scoped under.secure-exec-page, and it forces the shared header and footer dark withlight={false}onHeaderplusdarkChromeonBaseLayout. Its docs tab is normal light docs. Do not reusedarkChromeelsewhere. - Every page must look right in both light and dark theme. Dark mode is
html[data-theme="dark"](src/components/ThemeScript.astro,src/styles/theme.css, CSS-variable tokens intailwind.config.ts; the toggle storesrivet-themein localStorage). Before finishing any change that affects rendered UI, render the affected states in both themes and inspect them — do not sign off on a light-only screenshot. Use the tokens (paper,ink,ink-soft,pine, …) rather than hardcoded hex orwhite/blackso the retint is automatic; hand-drawn SVG diagrams, animations, hardcoded fills,invert/brightness-0filters, and imagery are the usual dark-mode failures. Assets that cannot retint through tokens are tracked inDARK_MODE_ASSETS.md; add any new one there with how it is handled.node scripts/check-theme.mjsagainst a dev server checks the CSS-handled cases. - Dark
inkpanels (editorial/InkPanel) are reserved for code, terminal, screenshot, and data moments. Code and data plates stay flat ink; the oil-texture backdrop (textureSrc) is for editorial moments only (CTA colophon, 404). - The brand accent is
accent-deep(#AB451F), the rust of the primary CTA — a fill color, chosen to carry white text. Diagrams and figures draw inhighlight, notaccent-deep: the same hue and chroma with luminance lifted for foreground marks,#B74B23on light (AA on paper and card for 12px figure labels) and#D36945on dark (whereaccent-deepdrops to ~3.3:1). It is the--runtime-highlighttoken intheme.css(183 75 35/211 105 69), exposed to Tailwind ashighlight(bg-highlight,text-highlight/60, …); canvas figures read the variable from computed style and re-read it ontheme-change. Use it for every dot, stroke, chip, and figure label on marketing pages. Do not draw diagrams in pine, sage, oraccent-deep. - Orange stays the spark: at most one
accent/ember CTA per page. White text sits only onaccent-deeporinkfills, never onaccent. Pine (#2E4034) is the structural color for links, eyebrows, and selected states; sage (#93A286) replaces it inside ink panels. - No drop shadows on marketing cards or imagery; depth comes from
border-ink/10..25hairlines,bg-white/55card fills, andpaper-mid/paper-deeplayering (inside ink panels:border-cream/10..15). Shadows stay acceptable on functional overlays (dropdowns, tooltips, modals) and the header's glass inset highlight. - Buttons use the constants in
src/components/marketing/typography.tsx— metricrounded-md px-4 py-2 text-sm font-mediumfor all. Primary accent =PRODUCT_HERO_PRIMARY_BUTTON_CLASS(accent-deep, the page's one ember); primary ink =PRIMARY_INK_BUTTON_CLASS; the only secondary =PRODUCT_HERO_SECONDARY_BUTTON_CLASS(border-ink/15 bg-white/55, filled — the borderlessborder-ink/20ghost is retired); light-on-ink primary =bg-white text-ink hover:bg-white/90. Do not hand-write button class strings. ink-fainttext is for captions and metadata at 12px+; body copy usesink-softorink.