AGENTS.md@apps/website · git:20261020.4efca9c · 2026-10-20 · sha256 168817a00bff7b64

AGENTS.md@apps/website git:20261020.4efca9cA

Immutable. This exact content never changes and is served at /api/v1/blob/168817a00bff7b64.

# Agent Instructions — `apps/website`

The hosted cloud's front page at `/`. Shared app rules:
[`apps/AGENTS.md`](../AGENTS.md).

- The page says the benefit, then proves it, and nothing else: the hero with
  the commands, then the showcase's steps, ending on the quickstart. Feature
  lists, ways in and roadmaps belong on the docs and zitadel.com.
- It ports `zitadel/new-website`'s narrative redesign
  (`docs/narrative-ia-proposal.md` on that repo's
  `claude/zitadel-narrative-redesign-377a49` branch) and follows that repo's
  `apps/website` (Next.js App Router, Tailwind 4, its `packages/theme`), so
  components move over unchanged. Keep the website's names in
  `app/globals.css` (`bg-background`, `text-foreground`, `text-accent`).
- It does not use `@zitadel/design-tokens`; only the login previews paint with
  them, on the login's own atoms.

## The fonts

- Load every face through `next/font/local` from `app/fonts/`, never
  `next/font/google`: its build-time download has failed builds.
- Each file is the latin subset Google Fonts serves `next/font/google`, byte
  for byte. Keep each SIL OFL license (`*-OFL.txt`) beside its file. APK
  Futural is licensed, not open.
- To update one, take the file under `/* latin */` from the stylesheet served
  to `next/font/google`'s user agent (Azeret Mono's family is
  `Azeret+Mono:wght@500`):

  ```sh
  curl -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' \
    'https://fonts.googleapis.com/css2?family=Arimo:wght@400..700&display=swap'
  ```

- `apps/docs/app/fonts/` holds the same Arimo file; update both.

## The theme

- Dark and light share one set of names in `app/globals.css`: add a color as
  a token with a value on both sides, never a `white`/`black` literal.
- `app/theme.ts` sets `data-theme` before the first paint, from the header
  toggle's choice or the system's; the login previews follow it.

## The logo and the favicons

- `app/logo.tsx` is the website's animated logo as inline SVG, its motion as
  CSS keyframes in `app/globals.css`. A hover plays it once to the end, and
  with `autoplay` it also plays now and then by itself (the header's and the
  footer's); never for reduced motion. Give each copy its own `id`.
- `apps/docs/components/logo.tsx` is a copy; change the copies together.
- `public/favicons/` and `public/favicon.ico` are the cloud's favicons: the
  console, the login UI and the docs link the same set, so a change here
  reaches them. A single `/favicon.ico` cannot replace the light/dark set.
- `layout.tsx` imports the share image (`app/og.jpg`) and sets no
  `metadataBase`: on Vercel, Next makes its URL absolute with the deployment's
  host. Render it from `scripts/og.html` at 1200×630 as a JPEG (quality 88),
  and change both when the hero's title, line or commands change.

## The commands and the showcase

- `app/commands.ts` feeds the hero and `/llms.txt`. The commands follow the
  README's quick start; never add `--force`. When that journey changes,
  change the commands and the showcase, and run them once against the
  published CLI.
- Steps 1 to 4 replay a recorded session (`app/showcase/sessions.ts`).
  Re-record rather than edit when what the CLI prints, the files setup writes
  or the flow format change.
- `login-preview.tsx` draws each login screen from `@zitadel/components`'
  atoms in the default template's English copy. When that copy or a step's
  fields change, change the screens.
- The previews' light-DOM chrome (`login-preview.module.css`) follows
  `packages/components/src/orchestrator/templates/layout-chrome.css`; follow
  its changes.
- The atoms load through one dynamic import once the first preview nears the
  viewport. `brand-tokens.ts` sets their `--zl-*` base layer from the
  package's `tokens` and `cssVars`, the light side from its `tokensCss`; JSX
  types are in `app/zl-elements.d.ts`.
- Every window is `app/window.tsx` and every command line
  `app/command-line.tsx`; colors come from the `@theme` in `app/globals.css`.
- Next resolves `@zitadel/components` to its `dist/`, so `build` and `dev`
  depend on `components:build` in moon and in turbo.

## Routing

The cloud routes only `/`, `/llms.txt`, `/_next/*`, `/favicon.ico` and
`/favicons/*` here (repo-root [`vercel.json`](../../vercel.json)).

- A new page or `public/` file needs a rewrite of its own in `vercel.json`, or
  the server answers it with a 404.
- Load every other asset from `/_next/`: fonts through `next/font`, images as
  imports. Never use Next's metadata files (`app/icon.svg`, `opengraph-image`),
  which Next serves at the root.
- Link another app with a plain `<a>` (`app/links.ts`), never `next/link`.
- `/llms.txt` (`app/llms.txt/route.ts`) links paths on the same host.

## Checks

```sh
moon run website:typecheck website:lint website:build
moon run website:start   # the build on port 3004
```

Vercel runs `turbo run build --filter=@zitadel/components`, then
`pnpm run build`; the Next build itself never goes through a task runner.