www-sacred
internet-development/www-sacred/AGENTS.md
Orientation for any agent working in www-sacred. Read this before touching code. www-sacred (npm package srcl) is an open-source React component library with terminal aesthetics. It is consumed in two ways: Colors flow from one source: scripts/cli/colors.json. That file holds the terminal-tested palette. global.css mirrors it as --ansi-* primitives and builds --theme-* tokens on top. The OKLCH tint themes in global.css are a web-only derivation. When a color changes, it changes in colors.json first.
- Installs packages
What's in it
- AGENTS.md
- What this repo is
- Repo map
- Conventions
- The Fonts menu previews
- Changing the default font
- Scripts
- Where to start when porting
- Keyboard and hotkey system
- Architecture
- Where hotkeys are registered
- Where keyboard events are handled directly (onKeyDown / addEventListener)
- Integration with the CLI framework
- Working agreements
# AGENTS.md
Orientation for any agent working in `www-sacred`. Read this before touching code.
## What this repo is
`www-sacred` (npm package `srcl`) is an open-source React component library with terminal aesthetics. It is consumed in two ways:
1. **A Next.js 16 / React 19 site at `sacred.computer`** that renders every component in a kitchen sink at `app/page.tsx`.
2. **Simulacrum**, a zero-dependency CLI framework under `scripts/cli/lib/` (and a snake_case Python mirror under `scripts/python/sacred_cli/`) so the same layouts can render in a terminal.
Colors flow from one source: `scripts/cli/colors.json`. That file holds the terminal-tested palette. `global.css` mirrors it as `--ansi-*` primitives and builds `--theme-*` tokens on top. The OKLCH tint themes in `global.css` are a web-only derivation. When a color changes, it changes in `colors.json` first.
## Repo map
- `app/` — Next.js App Router. `app/page.tsx` is the kitchen sink. The `/llm/*` routes serve docs as markdown and component source as plain text so agents can fetch them without cloning.
- `components/` — Sacred React components. Read `components/AGENTS.md` first when picking a component. `components/examples/` has larger demo surfaces. `SimpleTable` is the table for CLI ports (maps onto `formatRow` + `cardHeaderRow`). `Window` is the React peer of the CLI window frame.
- `common/` — Constants and utilities shared across components.
- `modules/` — Stand-alone, dependency-free modules: the vendored `hotkeys/` library plus a few vendored Node helpers (`cors.ts`, `vary.ts`, `object-assign.ts`).
- `scripts/cli/` — Simulacrum, the sacred CLI framework (TypeScript, zero dependencies, run via `tsx`). `lib/` is the framework, `lib/__tests__/` is the vitest suite (and the `dump_reference.ts` fixture generator), `templates/` is the canonical TS template, `colors.json` is the shared palette.
- `scripts/python/` — Simulacrum's Python mirror. `sacred_cli/` is the package, `sacred_cli/__tests__/` is the unittest suite (and the parity test against the JS fixture), `templates/` is the canonical Python template.
- `scripts/test_python.ts` — TypeScript orchestrator for `npm run test:python`. Probes for `python3`, regenerates the TS fixture, then invokes `python3 -m unittest discover`. Skips with a warning if `python3` is missing.
- `skills/` — Four porting skills (TS CLI, Python CLI, React-to-React, hostile React host). Read `skills/*/SKILL.md` before porting.
- `.workdir/` — Read-only reference material from sibling projects. Never edit, never ship.
## Conventions
- All comments use `//NOTE(jimmylee): ...` in TS/JS/CSS (no space after `//`, no `@`) and `# NOTE(jimmylee): ...` in Python. Comments explain _why_, not _what_. If the code reads clearly on its own, write no comment — and delete self-documenting comments on sight.
- The CLI framework is intentionally zero-dependency TypeScript, run via `tsx` with no build step.
- The Python framework mirrors the JS framework one-to-one but uses snake_case. The same `colors.json` is the single source of truth — do not duplicate the palette. The two runtimes are locked into byte-identical output by the parity suite under `scripts/python/sacred_cli/__tests__/test_parity.py`. When you change a JS module, port the change to its Python mirror in the same PR — `npm test` will fail otherwise.
- React example components in `components/examples/*` should only depend on sacred's existing primitives (`Card`, `SimpleTable`, `Button`, `RowSpaceBetween`, etc.). The CLI port examples (`CLITemplate`, `InvoiceTemplate`, `ResultsList`) use `SimpleTable`, not `DataTable`, because `SimpleTable`'s column + status contract maps one-to-one onto `formatRow` and `cardHeaderRow`. Do not import from `scripts/cli/lib/*` from React — that code is Node-only and uses `process.stdout`.
- Tests live in four places: `scripts/cli/lib/__tests__/` (CLI framework), `components/__tests__/` (catalog sync guards), `app/llm/__tests__/` (URL surface), and `scripts/python/sacred_cli/__tests__/` (Python + parity). The sync guards keep docs, props, theming tokens, palette colors, and URL surfaces honest against the source. `npm test` runs everything. Run it before opening a PR.
- Sacred CLI ports are static — no animation diffing system. The React side keeps its existing animation primitives (canvas snake, canvas platformer, etc.). The one exception is `OneLineLoaders.tsx` because the spinners are the entire point of that component.
## The Fonts menu previews
The Fonts menu in `components/page/DefaultActionBar.tsx` previews each font in its own typeface on hover/keyboard focus. The pieces fit together like this — keep them in sync when touching any of them:
- The `.font-use-*` rules in `global-fonts.css` only define `--font-family-mono`; a class on its own changes nothing. The `[role='menuitem']:hover/:focus-visible` rule at the top of that file is what applies the variable, letting each menu label (a `<span className="font-use-...">` wrapping the same class its `onClick` passes to `onHandleFontChange`) preview its font without duplicating family names in TSX. The default entry's label uses `font-use-fira-code`, which is intentionally never wired to a click handler (see `components/__tests__/font_sync.test.mjs`).
- Previews are hover/focus-only so the woffs download lazily, one per hovered row, instead of all of them when the menu opens.
- The focus half of the rule must stay `:focus-visible`, not `:focus`: `DropdownMenuTrigger` programmatically focuses the first menu item on open, and with `:focus` the first row (Cascadia Mono) rendered permanently in its own font as if hovered. `:focus-visible` skips that programmatic/mouse focus but still previews while arrow-keying through the menu.
- The preview rule is built so previews cannot resize the open menu: the pinned `line-height` stops vertical growth; `font-size-adjust: 0.5` (a typical monospace x-height ratio) normalizes visual size across fonts with wildly different metrics — a neutral value picked to sit each preview inside its row rather than matched to any one font, so a decorative-metric face (e.g. Mekzantine's tall x) does not upscale out of its row; `contain: inline-size` keeps a wide preview from widening the menu, clipping an over-wide label at the row edge instead.
## Changing the default font
The default font (applied on first mount, before anyone opens the Fonts menu) is a convention spread across four coupled spots — change all four in the same PR or `npm test` fails:
1. `global.css` — the base `--font-family-mono` declaration is the real default. Selecting the default in the menu calls `onHandleFontChange('')`, which strips every `font-use-*` class off `<body>` and falls back to this value. It currently names `'FiraCode-Regular'` (whose `@font-face` lives in `global-fonts.css`).
2. `components/page/DefaultActionBar.tsx` — the default's menu row is wired to `onHandleFontChange('')` (not to its own class) and carries the `[DEFAULT]` tag in its label. Its `<span>` still uses the matching `font-use-*` class so the row previews the default font on hover. Every *other* font's row wires `onHandleFontChange('font-use-<name>')`.
3. `components/__tests__/font_sync.test.mjs` — `DEFAULT_SELECTOR` names the default's `font-use-*` class. That class is the one selector exempt from the "referenced by exactly one menu entry" rule: it must stay in `global-fonts.css` and must *not* be wired to any `onClick`.
4. When you promote a font to default, the font it replaces must gain a normal wired menu row (`onHandleFontChange('font-use-<name>')`), or the test flags its now-unreferenced CSS rule as an unreachable font.
- `contain` also removes a row's own width contribution, so hovering the widest row would shrink the menu — which is why `components/DropdownMenuTrigger.tsx` locks the menu's natural width (`elementRef.current.style.width = ...`) when it opens. That line exists for the previews; do not remove it as a cleanup.
## Scripts
```sh
npm install # install deps
npm run dev # Next.js dev server on http://localhost:10000
npm test # tsc --noEmit + JS vitest suite + Python unittest + parity suite (chained)
npm run test:js # only the JS vitest suite
npm run test:python # only the Python suite (skips with a warning if python3 missing)
npm run cli:typescript # render the canonical TS CLI template (alt screen, ESC to quit)
npm run cli:python # render the canonical Python CLI template (alt screen, ESC to quit)
```
## Where to start when porting
- **React → CLI (TS):** read `skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md` and `scripts/cli/templates/template.ts`.
- **React → CLI (Python):** read `skills/port-sacred-terminal-ui-to-python/SKILL.md` and `scripts/python/templates/template.py`.
- **CLI → React (sacred host):** read `skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md` and any of the `components/examples/CLITemplate.tsx` / `InvoiceTemplate.tsx` / `ResultsList.tsx` files.
- **Sacred → foreign React app:** read `skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md`.
## Keyboard and hotkey system
Sacred uses a vendored copy of [react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook) at `modules/hotkeys/`. The module is self-contained CommonJS-compatible React code — no npm dependency. It provides `useHotkeys`, `HotkeysProvider`, `isHotkeyPressed`, and `useRecordHotkeys`.
### Architecture
- **`modules/hotkeys/parse-hotkeys.ts`** — parses key strings (`ctrl+a`, `ArrowDown`, `esc`) into a `Hotkey` descriptor with modifier flags (`alt`, `ctrl`, `meta`, `shift`, `mod`) and non-modifier key names. `mod` is a platform-aware shortcut: meta on macOS, ctrl elsewhere.
- **`modules/hotkeys/validators.ts`** — matching logic: `isHotkeyMatchingKeyboardEvent` compares a live `KeyboardEvent` against a parsed `Hotkey`, respecting modifier state. Guards (`isHotkeyEnabledOnTag`, `isKeyboardEventTriggeredByInput`) suppress hotkeys when focus is inside form elements unless explicitly opted in.
- **`modules/hotkeys/use-hotkeys.ts`** — the main hook. Attaches `keydown`/`keyup` listeners to either a ref'd DOM node or `document`. Supports `scopes` for conditional activation, `enableOnFormTags` / `enableOnContentEditable` overrides, `preventDefault`, and `keyup`-only mode.
- **`modules/hotkeys/hotkeys-provider.tsx`** — React context for scope management (`enableScope`, `disableScope`, `toggleScope`) and a registry of all bound hotkeys via `BoundHotkeysProxyProvider`. `HotkeysProvider` is mounted at the app root in `components/Providers.tsx`, activating scope-based hotkey gating for the entire tree.
- **`modules/hotkeys/is-hotkey-pressed.ts`** — global `Set<string>` tracking all currently held keys via document-level `keydown`/`keyup` listeners. Used by `useHotkeys` for multi-key combination matching. Handles the macOS meta-key quirk (clears non-modifier keys when meta is released).
- **`modules/hotkeys/use-record-hotkeys.ts`** — records key combinations pressed by the user into a `Set<string>`, useful for UI that lets users define their own shortcuts.
- **`modules/hotkeys/use-deep-equal-memo.ts`** — memoization helper using `Utilities.deepEqual` to prevent unnecessary re-renders when options objects are structurally equal.
### Where hotkeys are registered
| Component | Hotkeys | Purpose |
| --- | --- | --- |
| `components/page/DefaultActionBar.tsx` | `ArrowDown`, `ArrowUp`, `ArrowRight`, `ArrowLeft`, `Enter`, `Space`, `ctrl+g`, `Escape` | Global focus navigation across all focusable elements + debug grid toggle + dismiss topmost modal |
| `components/DropdownMenuTrigger.tsx` | Configurable via `hotkey` prop (e.g. `ctrl+o`, `ctrl+a`, `ctrl+t`) | Opens/closes a dropdown menu |
| `components/DropdownMenu.tsx` | `Escape` | Closes the active dropdown (fallback for when focus is outside the menu container) |
| `components/modals/ModalError.tsx` | `enter` | Closes the error modal |
| `components/modals/ModalChess.tsx` | `enter` | Closes the chess modal |
### Where keyboard events are handled directly (onKeyDown / addEventListener)
| Component | Keys | Purpose |
| --- | --- | --- |
| `components/DropdownMenu.tsx` | `ArrowDown`, `ArrowUp`, `Enter`, `Space`, `Escape` | Menu item navigation with focus wrapping, activation, and dismiss |
| `components/DataTable.tsx` | `Enter`, arrow keys | Cell navigation and activation within the gradient table |
| `components/ListItem.tsx` | `Enter`, arrow keys | Item activation and sequential focus traversal |
| `components/Select.tsx` | `Enter`, `Space`, `Escape`, arrow keys | Open/close listbox, navigate and select options, dismiss |
| `components/Input.tsx` | Native `onKeyDown` passthrough | Delegates to consumer callback |
| `components/TextArea.tsx` | Native `onKeyDown` passthrough | Delegates to consumer callback |
| `components/Checkbox.tsx` | Native `onKeyDown` via `<input>` | Standard checkbox toggling |
| `components/RadioButton.tsx` | Native `onKeyDown` via `<input>` | Standard radio selection |
| `components/ActionButton.tsx` | `Enter`, `Space` (inline) | Click activation for keyboard users |
| `components/ActionListItem.tsx` | `Enter`, `Space` (inline) | Click activation for keyboard users |
| `components/Accordion.tsx` | `Enter`, `Space` (inline) | Toggle open/close for keyboard users |
| `components/TreeView.tsx` | `Enter`, `Space` (inline) | Toggle expand/collapse for keyboard users |
| `components/CanvasPlatformer.tsx` | Arrow keys, `Space` (window listener) | Player movement and jumping |
| `components/CanvasSnake.tsx` | Arrow keys (window listener) | Snake direction control |
| `components/DOMSnake.tsx` | Arrow keys (window listener) | Snake direction control |
### Integration with the CLI framework
The CLI framework (`scripts/cli/lib/app.ts`) has its own keyboard system based on Node.js `process.stdin` raw mode. It handles `Ctrl-C`, `Escape` (quit), arrow keys (pagination/selection), and `Enter` (selection confirm). This is completely separate from the React hotkey module — the two systems share concepts but no code.
## Working agreements
- Don't commit unless the user explicitly asks. Sacred ships releases manually.
- Don't add features the task didn't ask for. If you find a tangential bug, surface it instead of fixing it silently.
- Don't import from `.workdir/` at runtime. It is reference material only.
- Don't break the kitchen sink. After any component change, render `app/page.tsx` mentally (or in `npm run dev`) and confirm nothing regresses.
More agent context in internet-development/www-sacred
6 other files this repository gives its agents.
AGENTS.md
Skill
- fast-typescript-checkskills/fast-typescript-check/SKILL.md
- port-sacred-terminal-ui-to-hostile-react-codebaseskills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md
- port-sacred-terminal-ui-to-pythonskills/port-sacred-terminal-ui-to-python/SKILL.md
- port-sacred-terminal-ui-to-react-using-same-conventionsskills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md
- port-sacred-terminal-ui-to-typescript-cliskills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

