# Sacred Computer — full doc bundle

> Concatenation of every AGENTS.md and SKILL.md in the sacred repo, in the same
> order as https://sacred.computer/llms.txt. Sacred Computer (React) and Simulacrum
> (CLI) are two halves of one framework — the React surface is documented in
> components/AGENTS.md, the CLI surface in scripts/cli/AGENTS.md and
> scripts/python/AGENTS.md.

---

# AGENTS.md

# 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.

The React side and the Simulacrum side share a single source of truth for the palette: `scripts/cli/colors.json`. The CSS surface drives the same colors via `--theme-*` custom properties in `global.css`.

## Repo map

- `app/` — Next.js App Router. `app/page.tsx` is the kitchen sink. `app/api/*` are tiny demo routes. `app/llm/[...path]/route.ts`, `app/llms.txt/route.ts`, and `app/llms-full.txt/route.ts` expose every `AGENTS.md` and `SKILL.md` as plain `text/markdown` URLs under `https://sacred.computer/llm/...` so external agents can fetch the sacred contract without `git clone`.
- `components/` — Sacred React components. `components/AGENTS.md` is the canonical catalog of every component (one entry per `.tsx`, with props, theming tokens, and CLI primitive equivalent) — read this first when picking a component, before grepping. `components/examples/` contains larger demo surfaces (AS400, MessagesInterface, CLITemplate, InvoiceTemplate, ResultsList, OneLineLoaders). `components/SimpleTable.tsx` is the fluid HTML table the CLI port examples use — its column/status contract maps one-to-one onto the CLI framework's `formatRow` + `cardHeaderRow` primitives. `components/Window.tsx` is the React peer of the CLI window primitive — wrap a CLI port surface in `<Window>` to render the same dialog frame the alt-screen CLI shows.
- `common/` — Constants and utilities shared across components.
- `modules/` — Stand-alone modules (snake game, chess, etc.).
- `scripts/cli/` — Simulacrum, the sacred CLI framework (CommonJS, zero dependencies). `lib/` is the framework, `lib/__tests__/` is the vitest suite (and the `dump_reference.js` 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.js` — Node orchestrator for `npm run test:python`. Probes for `python3`, regenerates the JS 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 new comments use `//NOTE(@YOUR_GITHUB_USERNAME): ...` (or `# NOTE(@YOUR_GITHUB_USERNAME): ...` in Python). Comments explain _why_, not _what_. Delete self-documenting comments on sight.
- The CLI framework is intentionally zero-dependency CommonJS so TypeScript templates can `require` it via `tsx` with no build step. Do not add ESM imports inside `scripts/cli/lib/*`.
- 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 `scripts/cli/lib/__tests__/*.test.mjs` (vitest, JS), `components/__tests__/*.test.mjs` (vitest, sync guard for the component catalog), `app/llm/__tests__/*.test.mjs` (vitest, sync guard for the `/llm/...` URL surface), and `scripts/python/sacred_cli/__tests__/test_*.py` (unittest, Python). The vitest suite uses `createRequire` so ESM tests can pull in CJS source modules. `npm test` runs both suites; `npm run test:js` and `npm run test:python` run them individually. Run `npm test` 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.

## Scripts

```sh
npm install             # install deps
npm run dev             # Next.js dev server on http://localhost:10000
npm test                # 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.js`) has its own keyboard system based on Node.js `process.stdin` raw mode. It handles `q`, `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.


---

# components/AGENTS.md

# AGENTS.md — components

Canonical catalog of every React component sacred ships under `components/`. One entry per `.tsx` file directly under `components/`. The `examples/`, `modals/`, `svg/`, `page/`, and `detectors/` subdirectories are intentionally excluded — those are demos, modal bodies, icons, and runtime detectors that compose this library, not the library itself.

The catalog is enforced by `components/__tests__/agents_md_sync.test.mjs`, which fails CI if a `.tsx` file is added under `components/` without a matching `## Heading` here, or vice versa. Adding a component without documenting it is a CI failure inside the same PR.

## How to read each entry

- **Path** — repo-relative path of the source file.
- **Purpose** — one factual sentence pulled from the source. The catalog never invents behavior.
- **Props** — copied verbatim from the `interface` / `type Props` block in the source. If the component uses `React.forwardRef`, the inner Props type is what is shown. Sacred components are deliberately untyped or loosely typed in places — the catalog reflects that, it does not normalize.
- **Theming tokens** — `var(--theme-*)`, `var(--ansi-*)`, `var(--color-*)`, `var(--font-*)`, and `var(--z-index-*)` references read from the matching `.module.css` file (or inline `style={{}}`). This is the contract that lets a port preserve colors across light/dark and the seven OKLCH tints. If a component has no `.module.css` and no inline tokens, the field reads `(none)`.
- **CLI primitive** — the equivalent in the sacred CLI framework (`scripts/cli/lib/*` / `scripts/python/sacred_cli/*`). Pulled from the four port skills' mapping tables. If there is no equivalent — typically because the CLI framework is layout-only and the React component is interactive, animated, or browser-specific — the field reads `(React-only)` plus a one-phrase reason.
- **Used by** — at least one concrete reference inside `app/page.tsx` (the kitchen sink) or `components/examples/*.tsx` so an agent can see the component in the wild.

The catalog is the **what**. The four `skills/port-sacred-terminal-ui-to-*/SKILL.md` files remain the **how** — they walk through the procedural side of porting and they keep their own (scoped) component mapping tables for the porting workflow they describe. If you are porting a screen, read the skill first; if you just need to know which sacred component renders X, read this catalog.

## Out of scope (gaps to fill in follow-up tasks)

- **Per-prop usage examples** — the catalog lists props but does not exhaustively show every meaningful prop combination. A "Storybook-lite" surface that embeds minimal usage snippets per component is a separate, larger task.
- **Raw `.tsx` source mirror** — an agent that has read this catalog may want to fetch the raw component source over HTTP. The `/llm/...` URL surface intentionally only exposes Markdown contracts (`AGENTS.md` and `SKILL.md`). A `/llm/components/<Name>.tsx.txt` mirror is a follow-up task with a broader allowlist; it is deliberately not part of the first ship so the public surface stays tight.

---

## Accordion

- **Path:** `components/Accordion.tsx`
- **Purpose:** Click-to-toggle collapsible section with a title row and a children body.
- **Props:**
  ```ts
  interface AccordionProps {
    defaultValue?: boolean;
    title: string;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** (React-only) The CLI framework renders flat pages — there is no folding section concept.
- **Used by:** `<Accordion defaultValue={true} title="ACTION BAR">` in the kitchen sink (`app/page.tsx`).

## ASCIICanvas

- **Path:** `components/ASCIICanvas.tsx`
- **Purpose:** Animated ASCII art rendered in a `<pre>` element using per-cell `<span>` elements with DOM diffing.
- **Props:**
  ```ts
  { rows?: number }
  ```
- **Theming tokens:** `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) The CLI framework is static — animation belongs on the React side.
- **Used by:** `<ASCIICanvas rows={20} />` in the "ASCII CANVAS" accordion in `app/page.tsx`.

## ActionBar

- **Path:** `components/ActionBar.tsx`
- **Purpose:** Horizontal toolbar of action items, each with optional hotkey and nested dropdown menu.
- **Props:**
  ```ts
  interface ActionBarProps {
    items: ActionBarItem[];
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border`
- **CLI primitive:** `buttonRow` plus repeated `button(hotkey, label)` calls. The CLI version is non-nested; nested dropdowns are React-only.
- **Used by:** `<ActionBar items={[ ... ]} />` inside the "ACTION BAR" accordion in `app/page.tsx`.

## ActionButton

- **Path:** `components/ActionButton.tsx`
- **Purpose:** Hotkey + label button pair, the React peer of the CLI `button` primitive.
- **Props:**
  ```ts
  interface ActionButtonProps {
    onClick?: () => void;
    hotkey?: any;
    children?: React.ReactNode;
    style?: any;
    rootStyle?: any;
    isSelected?: boolean;
  }
  ```
- **Theming tokens:** `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--font-family-mono`, `--font-size`
- **CLI primitive:** `button(hotkey, label)` in `scripts/cli/lib/button.js` (`button(hotkey, label)` in the Python mirror). Pair with `buttonRow(...)` to get the same left/right layout.
- **Used by:** `<ActionButton hotkey="ESC">EXIT</ActionButton>` in `components/examples/CLITemplate.tsx`, `components/examples/InvoiceTemplate.tsx`, `components/examples/ResultsList.tsx`, and the "ACTION BUTTONS" accordion in `app/page.tsx`. Every CLI port surface uses `ActionButton` (not `Button`) so it stays in lockstep with Simulacrum's `button(hotkey, label)` primitive.

## ActionListItem

- **Path:** `components/ActionListItem.tsx`
- **Purpose:** Menu row that renders as either an anchor or a button with a leading icon glyph.
- **Props:**
  ```ts
  interface ActionListItemProps {
    style?: React.CSSProperties;
    icon?: React.ReactNode;
    children?: React.ReactNode;
    href?: string;
    target?: string;
    onClick?: React.MouseEventHandler<HTMLDivElement | HTMLAnchorElement>;
    role?: string;
  }
  ```
- **Theming tokens:** `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardRow(formatRow([icon, label], colSpec, innerW), innerW)`. The CLI has no anchor concept — interactive items are wired through `createApp({ interactive, onKey })`.
- **Used by:** `<ActionListItem icon={'⭢'} href="https://internet.dev" target="_blank">` inside the navigation example in `app/page.tsx`.

## AlertBanner

- **Path:** `components/AlertBanner.tsx`
- **Purpose:** Full-width inline notification banner for advisory or warning copy.
- **Props:**
  ```ts
  interface AlertBannerProps {
    style?: any;
    children?: any;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-border-subdued`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardTop('!', innerW)` + `cardRow(text, innerW)` + `cardBot(innerW)` — sacred CLI ships no dedicated banner glyph; an unlabeled card row is the convention.
- **Used by:** `<AlertBanner>When things reach the extreme, they alternate to the opposite.</AlertBanner>` in `app/page.tsx`.

## Avatar

- **Path:** `components/Avatar.tsx`
- **Purpose:** Square portrait image (or initials placeholder) with optional inline label and external link.
- **Props:**
  ```ts
  interface AvatarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'className' | 'children'> {
    src?: string;
    href?: string;
    target?: string;
    style?: React.CSSProperties;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-window-shadow`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI is text-only; portraits do not exist there.
- **Used by:** `<Avatar src="..." href="https://internet.dev" target="_blank" />` inside the "AVATARS" accordion in `app/page.tsx`.

## Badge

- **Path:** `components/Badge.tsx`
- **Purpose:** Inline label chip used for short status / version markers next to titles.
- **Props:**
  ```ts
  interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`
- **CLI primitive:** Plain string concatenated into a `cardRow`. The CLI framework has no badge glyph because monospace runs are already labeled at column boundaries.
- **Used by:** `<Badge>{Package.version}</Badge>` inside the navigation strip in `app/page.tsx`.

## BarLoader

- **Path:** `components/BarLoader.tsx`
- **Purpose:** Fill-style progress bar with optional auto-advancing interval mode.
- **Props:**
  ```ts
  interface BarLoaderProps {
    intervalRate?: number;
    progress?: number;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Sacred CLI ports are static — there is no animation diff loop. If you want a CLI progress indicator, render a single `cardRow` with the percentage at draw time.
- **Used by:** `<BarLoader intervalRate={1000} />` and `<BarLoader progress={50} />` inside the "BAR LOADERS" accordion in `app/page.tsx`.

## BarProgress

- **Path:** `components/BarProgress.tsx`
- **Purpose:** Character-based progress bar that fills its container width with a configurable glyph.
- **Props:**
  ```ts
  interface BarProgressProps {
    intervalRate?: number;
    progress?: number;
    fillChar?: string;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`
- **CLI primitive:** (React-only) Same reason as BarLoader — the CLI is static.
- **Used by:** `<BarProgress intervalRate={500} fillChar="█" />` inside `components/examples/OneLineLoaders.tsx`.

## Block

- **Path:** `components/Block.tsx`
- **Purpose:** Inline span block used as a 1ch placeholder or measurement spacer in monospace layouts.
- **Props:**
  ```ts
  interface BlockProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A single space inside a `cardRow`. The CLI lays out by character grid, so a `<Block>` is implicit.
- **Used by:** `<Block style={{ opacity: 0 }} />` as a sizing spacer in `app/page.tsx`.

## BlockLoader

- **Path:** `components/BlockLoader.tsx`
- **Purpose:** Single-glyph spinner cycling through a Unicode box-drawing or block animation sequence.
- **Props:**
  ```ts
  interface BlockLoaderProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {
    mode?: number;
  }
  ```
- **Theming tokens:** `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Sacred CLI ports are static. `OneLineLoaders.tsx` is the explicit React-side carve-out for spinners.
- **Used by:** `<BlockLoader mode={0} />` (and modes 1-11) inside the "BLOCK LOADERS" accordion in `app/page.tsx`.

## BreadCrumbs

- **Path:** `components/BreadCrumbs.tsx`
- **Purpose:** Linked breadcrumb trail with visual separators between hierarchy levels.
- **Props:**
  ```ts
  interface BreadCrumbsProps {
    items: BreadCrumbsItem[];
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** A `cardRow` with `path / segments / joined / by / slashes`. The CLI has no link concept.
- **Used by:** `<BreadCrumbs items={[...]} />` inside the "BREADCRUMBS" accordion in `app/page.tsx`.

## Button

- **Path:** `components/Button.tsx`
- **Purpose:** Two-theme HTML `<button>` (PRIMARY / SECONDARY) with disabled-state styling.
- **Props:**
  ```ts
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
    theme?: 'PRIMARY' | 'SECONDARY';
    isDisabled?: boolean;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border`, `--theme-button`, `--theme-button-background`, `--theme-button-foreground`, `--theme-button-text`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`
- **CLI primitive:** `button(hotkey, label)` (no theme variants — CLI buttons are uniform).
- **Used by:** `<Button>Primary Button</Button>` inside the "BUTTONS" accordion in `app/page.tsx`. Use `ActionButton` instead when porting CLI screens.

## ButtonGroup

- **Path:** `components/ButtonGroup.tsx`
- **Purpose:** Horizontal cluster of `ActionButton`s with selected-state highlighting and optional nested dropdown items.
- **Props:** _(untyped — `props.items: { body, hotkey?, selected?, onClick?, items?, openHotkey? }[]`, `props.isFull?: boolean`)_
- **Theming tokens:** (none)
- **CLI primitive:** `buttonRow(button(...), button(...), innerW)` repeated for each pair.
- **Used by:** `<ButtonGroup items={[{ body: '16 PX', selected: true }, { body: '32 PX' }, { body: '42 PX' }]} />` inside the "BUTTON GROUP" accordion in `app/page.tsx`.

## CanvasPlatformer

- **Path:** `components/CanvasPlatformer.tsx`
- **Purpose:** ASCII-grid 2D platformer mini-game with gravity, block placement, keyboard controls, and touch region controls for mobile (left third = move left, right third = move right, center = jump, multi-touch supported). Renders via pre/span grid with DOM diffing instead of canvas.
- **Props:**
  ```ts
  interface PlatformerProps {
    rows?: number;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-text`, `--theme-focused-foreground`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Sacred CLI ports are static; no animation diffing.
- **Used by:** `<CanvasPlatformer rows={12} />` inside the ModalCanvasPlatformer modal triggered from `app/page.tsx`.

## CanvasSnake

- **Path:** `components/CanvasSnake.tsx`
- **Purpose:** ASCII-grid Snake mini-game with directional input (keyboard arrows and swipe gestures on mobile) and food collection. Renders via pre/span grid with DOM diffing instead of canvas.
- **Props:**
  ```ts
  interface SnakeProps {
    rows?: number;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-focused-foreground`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Same reason as CanvasPlatformer.
- **Used by:** `<CanvasSnake rows={12} />` inside the ModalCanvasSnake modal triggered from `app/page.tsx`.

## Card

- **Path:** `components/Card.tsx`
- **Purpose:** Box-drawing card with a title bar and three corner modes (`default`, `'left'`, `'right'`).
- **Props:**
  ```ts
  interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
    title?: string | any;
    mode?: string | any;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardTop(title, innerW)` + `cardRow(content, innerW)` + `cardBot(innerW)` (`scripts/cli/lib/card.js`).
- **Used by:** `<Card title="EXAMPLE">...</Card>` repeated throughout `app/page.tsx`, and `<Card title="SACRED CLI / TEMPLATE" mode="left">` in `components/examples/CLITemplate.tsx`.

## CardDouble

- **Path:** `components/CardDouble.tsx`
- **Purpose:** Card variant with a double-stroke outer border, used for nested or emphasis groupings.
- **Props:**
  ```ts
  interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
    title?: string | any;
    mode?: string | any;
    style?: any;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The sacred CLI framework only ships single-border cards in `scripts/cli/lib/card.js`.
- **Used by:** `<CardDouble title={entry[0]}>...</CardDouble>` inside `components/ComboBox.tsx`.

## Checkbox

- **Path:** `components/Checkbox.tsx`
- **Purpose:** Custom-styled checkbox with click + keyboard toggling and a children label slot.
- **Props:**
  ```ts
  interface CheckboxProps {
    style?: React.CSSProperties;
    checkboxStyle?: React.CSSProperties;
    name: string;
    defaultChecked?: boolean;
    onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
    tabIndex?: number;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** `cardRow('[x] label', innerW)` rendered manually by the template; sacred CLI ships no checkbox primitive yet.
- **Used by:** `<Checkbox name="1">...</Checkbox>` inside the "CHECKBOX" accordion in `app/page.tsx`.

## Chessboard

- **Path:** `components/Chessboard.tsx`
- **Purpose:** 8×8 grid renderer that draws Unicode chess pieces from a 2D position array.
- **Props:**
  ```ts
  interface ChessboardProps {
    board: string[][];
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-focused-foreground-subdued`, `--theme-focused-foreground`, `--theme-line-height-base`
- **CLI primitive:** (React-only) The CLI framework has no grid primitive; a CLI port would render the board with eight `cardRow` calls of joined glyphs.
- **Used by:** `<Chessboard board={Constants.CHESSBOARD_DEFAULT_POSITIONS} />` inside the "CHESSBOARD" accordion in `app/page.tsx`.

## CodeBlock

- **Path:** `components/CodeBlock.tsx`
- **Purpose:** Pre-formatted source code block with line numbers and a fixed monospace style.
- **Props:**
  ```ts
  interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`
- **CLI primitive:** A `cardRow` per line of source. The CLI has no syntax highlighting because the framework is colorless except for status columns.
- **Used by:** `<CodeBlock>...</CodeBlock>` inside the "CODE BLOCK" accordion in `app/page.tsx`.

## ComboBox

- **Path:** `components/ComboBox.tsx`
- **Purpose:** Searchable input + filtered result cards combo, optionally backed by a dataset.
- **Props:**
  ```ts
  interface ComboBoxProps {
    data: string[][];
    label?: string;
  }
  ```
- **Theming tokens:** (inherited from `Input` and `CardDouble`)
- **CLI primitive:** `createApp({ interactive: { count, onSelect } })` plus `cardSelectRow` for each filtered row. Sacred CLI's interactive selection lifecycle is the equivalent.
- **Used by:** `<ComboBox data={Constants.LANDSCAPES} label="SEARCH THE WORLD" />` inside the "COMBO BOX" accordion in `app/page.tsx`.

## ContentFluid

- **Path:** `components/ContentFluid.tsx`
- **Purpose:** Block container that expands to the full available width, used as the page-content shell.
- **Props:**
  ```ts
  interface ContentFluidProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** `getInnerWidth(termW)` plus the surrounding window frame in `scripts/cli/lib/window.js` — the CLI framework computes width once and the templates fill it.
- **Used by:** `<ContentFluid>...</ContentFluid>` wraps the kitchen sink page body in `app/page.tsx`.

## DataTable

- **Path:** `components/DataTable.tsx`
- **Purpose:** Gradient-tinted interactive data table that animates background fill on cell change.
- **Props:**
  ```ts
  interface TableProps {
    data: string[][];
  }
  ```
- **Theming tokens:** `--theme-focused-foreground-subdued`, `--theme-focused-foreground`
- **CLI primitive:** (React-only) The CLI port story uses `SimpleTable` instead because `SimpleTable`'s column + status contract maps one-to-one onto `formatRow`. `DataTable`'s gradient backgrounds are not part of the CLI surface — do not use it for CLI ports.
- **Used by:** `<DataTable data={Constants.SAMPLE_TABLE_DATA_CHANGE_ME} />` inside the "DATA TABLE" accordion in `app/page.tsx`.

## DatePicker

- **Path:** `components/DatePicker.tsx`
- **Purpose:** Calendar widget with month navigation and day cell selection in a 7-column grid.
- **Props:**
  ```ts
  interface DatePickerProps {
    year?: number;
    month?: number;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** (React-only) No date grid in the CLI framework yet — a port would render rows of `formatRow` cells.
- **Used by:** `<DatePicker year={2012} month={12} />` inside the "DATE PICKER" accordion in `app/page.tsx`.

## DebugGrid

- **Path:** `components/DebugGrid.tsx`
- **Purpose:** Hidden character-grid overlay for visualizing alignment during layout work.
- **Props:** _(no props)_
- **Theming tokens:** `--theme-border`
- **CLI primitive:** (React-only) The CLI framework already snaps to character columns by definition.
- **Used by:** `<DebugGrid />` rendered above the kitchen sink in `app/page.tsx`.

## DefaultMetaTags

- **Path:** `components/DefaultMetaTags.tsx`
- **Purpose:** Static `<head>` metadata block for viewport, language, and favicon defaults.
- **Props:** _(no props)_
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) HTML metadata has no CLI analogue.
- **Used by:** `app/head.tsx` for the kitchen sink page.

## Dialog

- **Path:** `components/Dialog.tsx`
- **Purpose:** Lightweight modal dialog with a title slot, body slot, and OK/Cancel actions.
- **Props:**
  ```ts
  interface DialogProps {
    title?: React.ReactNode;
    children?: React.ReactNode;
    style?: React.CSSProperties;
    onConfirm?: () => void;
    onCancel?: () => void;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-border`, `--theme-text`
- **CLI primitive:** A bordered card plus a `buttonRow(button('ESC','cancel'), button('↵','ok'), innerW)`.
- **Used by:** `<Dialog title="FAREWELL">...</Dialog>` inside the "DIALOG" accordion in `app/page.tsx`.

## Divider

- **Path:** `components/Divider.tsx`
- **Purpose:** Horizontal rule with three styles: single, double, and gradient.
- **Props:**
  ```ts
  interface DividerProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
    type?: string | any;
    style?: any;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A `cardRow` of `'─'` glyphs (or `'═'` for double) at full inner width. The CLI framework has no dedicated divider helper.
- **Used by:** `<Divider type="DOUBLE" />` inside the "DIVIDERS" accordion in `app/page.tsx`.

## DOMSnake

- **Path:** `components/DOMSnake.tsx`
- **Purpose:** DOM-grid Snake mini-game (sibling of `CanvasSnake`) using CSS cells instead of canvas pixels.
- **Props:**
  ```ts
  interface SnakeGameProps {
    width?: number;
    height?: number;
    startSpeed?: number;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`
- **CLI primitive:** (React-only) Animation game.
- **Used by:** `<DOMSnake />` inside the "DOM SNAKE" accordion in `app/page.tsx`.

## Drawer

- **Path:** `components/Drawer.tsx`
- **Purpose:** Collapsible sidebar drawer with a single toggle button and an animated hide/show state.
- **Props:**
  ```ts
  interface DrawerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'> {
    children?: React.ReactNode;
    defaultValue?: boolean;
  }
  ```
- **Theming tokens:** `--theme-background-input`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI alt-screen is a single window; there is no drawer concept.
- **Used by:** `<Drawer>...</Drawer>` inside the "DRAWER" accordion in `app/page.tsx`.

## DropdownMenu

- **Path:** `components/DropdownMenu.tsx`
- **Purpose:** Floating list of action items with `role="menu"`, arrow-key navigation with focus wrapping, Enter/Space activation, and Escape to dismiss. Each item receives `role="menuitem"`.
- **Props:**
  ```ts
  interface DropdownMenuProps extends React.HTMLAttributes<HTMLDivElement> {
    onClose?: (event?: MouseEvent | TouchEvent | KeyboardEvent) => void;
    items?: DropdownMenuItemProps[];
  }
  ```
- **Theming tokens:** `--theme-background-modal-footer`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Sacred CLI's `createApp({ interactive: { count, onSelect } })` lifecycle plus `cardSelectRow` is the closest equivalent.
- **Used by:** Wired through `DropdownMenuTrigger` inside the "DROPDOWN MENU" accordion in `app/page.tsx`.

## DropdownMenuTrigger

- **Path:** `components/DropdownMenuTrigger.tsx`
- **Purpose:** Wrapper that opens an associated `DropdownMenu` on click or hotkey, dismisses on outside click, and returns focus to the trigger element when the menu closes.
- **Props:**
  ```ts
  interface DropdownMenuTriggerProps {
    children: React.ReactElement<React.HTMLAttributes<HTMLElement>>;
    items: any;
    hotkey?: string;
  }
  ```
- **Theming tokens:** `--z-index-page-dropdown-menus`
- **CLI primitive:** (React-only) Hover/click trigger interaction is browser-specific.
- **Used by:** `<DropdownMenuTrigger items={...}>...</DropdownMenuTrigger>` inside the "DROPDOWN MENU" accordion in `app/page.tsx`.

## Grid

- **Path:** `components/Grid.tsx`
- **Purpose:** Responsive multi-column grid container that wraps its children in a flexible grid track.
- **Props:**
  ```ts
  interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Multiple `cardRow(formatRow(...), innerW)` calls — the CLI framework treats every layout as a single column, multiple rows.
- **Used by:** `<Grid>...</Grid>` wraps the navigation strip near the top of `app/page.tsx`.

## HoverComponentTrigger

- **Path:** `components/HoverComponentTrigger.tsx`
- **Purpose:** Wrapper that pops a tooltip or popover on hover/click with auto-positioning and outside-click dismissal.
- **Props:**
  ```ts
  interface HoverComponentTriggerProps {
    children: React.ReactElement<React.HTMLAttributes<HTMLElement>>;
    text: string;
    component: 'popover' | 'tooltip';
  }
  ```
- **Theming tokens:** `--z-index-page-popover`, `--z-index-page-tooltips`
- **CLI primitive:** (React-only) Hover-driven UI is browser-specific.
- **Used by:** `<HoverComponentTrigger text="..." component="tooltip">` inside the "TOOLTIP" accordion in `app/page.tsx`.

## Indent

- **Path:** `components/Indent.tsx`
- **Purpose:** Wrapper that applies a left padding to its children for nested content blocks.
- **Props:**
  ```ts
  interface IndentProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** Manual `' '.repeat(N)` prefix inside `cardRow`. The CLI framework leaves indentation up to the template.
- **Used by:** `<Indent>...</Indent>` inside the "AVATARS" accordion in `app/page.tsx`.

## Input

- **Path:** `components/Input.tsx`
- **Purpose:** Single-line text input with a custom caret glyph, password masking, and optional label.
- **Props:**
  ```ts
  type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
    caretChars?: string | any;
    label?: string | any;
    isBlink?: boolean;
  };
  ```
- **Theming tokens:** `--theme-background-input`, `--theme-background`, `--theme-border`, `--theme-focused-foreground`, `--theme-overlay`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI templates capture keystrokes through `createApp({ onKey })` and compose their own input strings — sacred CLI ships no boxed input primitive.
- **Used by:** `<Input label="MULTIPLE INPUTS" autoComplete="off" isBlink={false} name="input_test_empty" />` inside the "INPUT" accordion in `app/page.tsx`.

## ListItem

- **Path:** `components/ListItem.tsx`
- **Purpose:** Keyboard-focusable list row with Enter / arrow-key navigation between siblings.
- **Props:** _(untyped — accepts standard `<li>` HTML attributes)_
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** `cardRow` with manual prefix glyphs.
- **Used by:** Inside `Navigation` and `BreadCrumbs` examples in `app/page.tsx`.

## MatrixLoader

- **Path:** `components/MatrixLoader.tsx`
- **Purpose:** Matrix-rain effect rendered via pre/span grid with DOM diffing. Configurable direction and Greek/Katakana glyph mode.
- **Props:**
  ```ts
  interface MatrixLoaderProps {
    rows?: number;
    direction?: undefined | 'top-to-bottom' | 'left-to-right';
    mode?: undefined | 'greek' | 'katakana';
  }
  ```
- **Theming tokens:** `--theme-text`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Animation surface.
- **Used by:** `<MatrixLoader rows={32} mode="katakana" />` inside the ModalMatrixModes modal triggered from `app/page.tsx`.

## Message

- **Path:** `components/Message.tsx`
- **Purpose:** Chat message bubble (left-tail) for outgoing user messages.
- **Props:** _(untyped — accepts an optional children prop)_
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A `cardRow` per wrapped line with no special styling.
- **Used by:** `<Message>...</Message>` inside `components/examples/MessagesInterface.tsx`.

## MessageViewer

- **Path:** `components/MessageViewer.tsx`
- **Purpose:** Chat message bubble (right-tail) for incoming messages from another participant.
- **Props:** _(untyped — accepts an optional children prop)_
- **Theming tokens:** `--theme-focused-foreground`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Same as `Message` — a `cardRow` per wrapped line.
- **Used by:** `<MessageViewer>...</MessageViewer>` inside `components/examples/MessagesInterface.tsx`.

## ModalStack

- **Path:** `components/ModalStack.tsx`
- **Purpose:** Stacked modal overlay container that manages z-index ordering and backdrop blur.
- **Props:** _(no props)_
- **Theming tokens:** `--z-index-page-modals`
- **CLI primitive:** (React-only) The CLI alt-screen has a single layer.
- **Used by:** Mounted by `Providers` for any `ModalTrigger` in the kitchen sink.

## ModalTrigger

- **Path:** `components/ModalTrigger.tsx`
- **Purpose:** Injects an `onClick` into its child via `React.cloneElement` that opens a modal component, chaining with any existing `onClick` the child already has. Keyboard-accessible because the child's own `onKeyDown` handler (which calls `onClick`) fires the injected callback directly.
- **Props:**
  ```ts
  interface ModalTriggerProps {
    children: React.ReactElement<{ onClick?: React.MouseEventHandler }>;
    modal: React.ComponentType<any>;
    modalProps?: Record<string, any>;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) See `ModalStack`.
- **Used by:** `<ModalTrigger modal={ModalCreateAccount}>` inside the "MODAL" accordion in `app/page.tsx`.

## Navigation

- **Path:** `components/Navigation.tsx`
- **Purpose:** Top navigation bar with logo, left/right slot rails, and a center children slot.
- **Props:**
  ```ts
  interface NavigationProps extends React.HTMLAttributes<HTMLElement> {
    children?: React.ReactNode;
    logoHref?: string;
    logoTarget?: React.HTMLAttributeAnchorTarget;
    onClickLogo?: React.MouseEventHandler<HTMLButtonElement>;
    logo?: React.ReactNode;
    left?: React.ReactNode;
    right?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--font-size`
- **CLI primitive:** A `buttonRow(left, right, innerW)` plus a leading `cardRow` for the title.
- **Used by:** Top of the kitchen sink in `app/page.tsx` (search for `<Navigation`).

## NumberRangeSlider

- **Path:** `components/NumberRangeSlider.tsx`
- **Purpose:** Range slider with a labeled current value and configurable min/max/step bounds.
- **Props:**
  ```ts
  interface RangerProps {
    defaultValue?: number;
    max?: number;
    min?: number;
    step?: number;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Pointer-driven slider — port to a discrete `formatRow` of step labels if you need a CLI version.
- **Used by:** `<NumberRangeSlider defaultValue={50} />` inside the "NUMBER RANGE SLIDER" accordion in `app/page.tsx`.

## Popover

- **Path:** `components/Popover.tsx`
- **Purpose:** Generic floating panel container reused by `DropdownMenu` and `HoverComponentTrigger`.
- **Props:**
  ```ts
  interface PopoverProps extends React.HTMLAttributes<HTMLDivElement> {}
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) See `DropdownMenu`.
- **Used by:** Mounted by `HoverComponentTrigger` in the "POPOVER" accordion in `app/page.tsx`.

## Providers

- **Path:** `components/Providers.tsx`
- **Purpose:** Top-level context provider wrapping the app in `HotkeysProvider` and `ModalProvider`.
- **Props:**
  ```ts
  interface ProvidersProps {
    children: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) Sacred CLI is a single process; there is no provider tree.
- **Used by:** `app/layout.tsx`.

## RadioButton

- **Path:** `components/RadioButton.tsx`
- **Purpose:** Custom-styled radio input with click + arrow-key selection inside a `RadioButtonGroup`.
- **Props:**
  ```ts
  interface RadioButtonProps {
    style?: React.CSSProperties;
    name: string;
    value: string;
    selected?: boolean;
    onSelect?: (value: string) => void;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardSelectRow(content, innerW, isSelected)` driven by `createApp({ interactive: { count, onSelect } })`.
- **Used by:** Inside `RadioButtonGroup` in the "RADIO BUTTON" accordion in `app/page.tsx`.

## RadioButtonGroup

- **Path:** `components/RadioButtonGroup.tsx`
- **Purpose:** Container that owns the selected value across a list of `RadioButton` siblings.
- **Props:**
  ```ts
  interface RadioButtonGroupProps {
    options: { value: string; label: string }[];
    defaultValue?: string;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** Same as `RadioButton` — `createApp` with `interactive: { count, onSelect, persist: true }`.
- **Used by:** `<RadioButtonGroup options={[...]} defaultValue="..." />` in the "RADIO BUTTON" accordion in `app/page.tsx`.

## Row

- **Path:** `components/Row.tsx`
- **Purpose:** Block-level row container with focus styling.
- **Props:**
  ```ts
  type RowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A single `cardRow(content, innerW)`.
- **Used by:** `<Row>...</Row>` near the top of `app/page.tsx`.

## RowEllipsis

- **Path:** `components/RowEllipsis.tsx`
- **Purpose:** Row container with `text-overflow: ellipsis` for single-line truncation.
- **Props:**
  ```ts
  type RowEllipsisProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** `truncateVisible(line, innerW)` from `scripts/cli/lib/ansi.js`.
- **Used by:** `<RowEllipsis>...</RowEllipsis>` inside list-item rows in `app/page.tsx`.

## RowSpaceBetween

- **Path:** `components/RowSpaceBetween.tsx`
- **Purpose:** Flexbox row that pushes its first and last child to opposite ends.
- **Props:**
  ```ts
  type RowSpaceBetweenProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** `buttonRow(left, right, innerW)` in `scripts/cli/lib/button.js`.
- **Used by:** `<RowSpaceBetween><span><ActionButton hotkey="ESC">EXIT</ActionButton></span><span><ActionButton hotkey="↵">SELECT</ActionButton></span></RowSpaceBetween>` in `components/examples/CLITemplate.tsx`, with the same shape repeated in `components/examples/InvoiceTemplate.tsx` (ESC EXIT / ↵ SUBMIT) and `components/examples/ResultsList.tsx` (ESC EXIT / ← PREV → NEXT).

## Select

- **Path:** `components/Select.tsx`
- **Purpose:** Custom dropdown select with keyboard navigation and styled option list.
- **Props:**
  ```ts
  interface SelectProps {
    name: string;
    options: string[];
    placeholder?: string;
    defaultValue?: string;
    onChange?: (selectedValue: string) => void;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-border`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`, `--z-index-page-select`
- **CLI primitive:** `createApp({ interactive: { count, onSelect } })` plus `cardSelectRow`.
- **Used by:** `<Select name="select_test" options={[...]} />` inside the "SELECT" accordion in `app/page.tsx`.

## SidebarLayout

- **Path:** `components/SidebarLayout.tsx`
- **Purpose:** Two-column layout with a draggable sidebar handle and optional reversed column order.
- **Props:**
  ```ts
  interface SidebarLayoutProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'> {
    children?: React.ReactNode;
    sidebar?: React.ReactNode;
    defaultSidebarWidth?: number;
    isShowingHandle?: boolean;
    isReversed?: boolean;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`
- **CLI primitive:** (React-only) The CLI uses a single full-width window — there is no resizable sidebar.
- **Used by:** `<SidebarLayout sidebar={...}>...</SidebarLayout>` inside the "SIDEBAR LAYOUT" accordion in `app/page.tsx`.

## SimpleTable

- **Path:** `components/SimpleTable.tsx`
- **Purpose:** Fluid HTML table that mirrors the CLI framework's `formatRow` + `cardHeaderRow` contract one-to-one. First row is the header. Status coloring fires on `ACTIVE`/`OPEN`/`APPROVED` (bold green) and `CLOSED`/`PAID`/`SUSPENDED` (gray). Use this table — not `DataTable` — for any CLI port surface. The table is wrapped in a `scrollWrapper` div with `overflow-x: auto` so it scrolls horizontally inside its container on narrow viewports instead of forcing page-level scroll.
- **Props:**
  ```ts
  interface SimpleTableProps {
    data: string[][];
    align?: ('left' | 'right')[];
  }
  ```
- **Theming tokens:** `--ansi-10-lime`, `--ansi-240-gray-35`, `--ansi-248-gray-66`, `--color-white`
- **CLI primitive:** `cardHeaderRow(formatRow(TH, COL_SPEC, innerW), innerW)` for the header plus `cardRow(formatRow(row, COL_SPEC, innerW), innerW)` for each body row. The status set is the contract — `ACTIVE`/`OPEN`/`APPROVED` and `CLOSED`/`PAID`/`SUSPENDED`.
- **Used by:** `<SimpleTable data={PRIMITIVES} />` in `components/examples/CLITemplate.tsx`, `<SimpleTable data={LINE_ITEMS} align={LINE_ITEM_ALIGN} />` in `components/examples/InvoiceTemplate.tsx`, `<SimpleTable data={RESULTS} />` in `components/examples/ResultsList.tsx`.

## Table

- **Path:** `components/Table.tsx`
- **Purpose:** Semantic `<table>` wrapper that renders a `<tbody>` shell for sacred-styled tables.
- **Props:**
  ```ts
  type TableProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** (none)
- **CLI primitive:** A column of `cardRow(formatRow(...))` calls — there is no separate `<table>` analogue in the CLI.
- **Used by:** `<Table>...</Table>` inside the navigation strip in `app/page.tsx`.

## TableColumn

- **Path:** `components/TableColumn.tsx`
- **Purpose:** Semantic `<td>` wrapper used inside `Table`/`TableRow`.
- **Props:**
  ```ts
  type TableColumnProps = React.HTMLAttributes<HTMLTableCellElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--font-size`
- **CLI primitive:** A single cell inside `formatRow`.
- **Used by:** Inside `<TableRow>` in the navigation strip in `app/page.tsx`.

## TableRow

- **Path:** `components/TableRow.tsx`
- **Purpose:** Semantic `<tr>` wrapper with focus styling for keyboard navigation.
- **Props:**
  ```ts
  type TableRowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A single row inside `formatRow`.
- **Used by:** `<TableRow>...</TableRow>` inside `<Table>` in the navigation strip in `app/page.tsx`.

## Text

- **Path:** `components/Text.tsx`
- **Purpose:** Semantic `<p>` paragraph wrapper for body copy.
- **Props:**
  ```ts
  interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** `wordWrap(text, contentW)` in `scripts/cli/lib/card.js`, fed into a sequence of `cardRow` calls.
- **Used by:** `<Text>...</Text>` inside the navigation strip in `app/page.tsx`.

## TextArea

- **Path:** `components/TextArea.tsx`
- **Purpose:** Multi-line text input with auto-resizing height, custom caret, and an optional autoplay typewriter mode.
- **Props:**
  ```ts
  type TextAreaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
    autoPlay?: string;
    autoPlaySpeedMS?: number;
    isBlink?: boolean;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI captures keystrokes through `createApp({ onKey })`.
- **Used by:** `<TextArea autoPlay="..." />` inside the "TEXT AREA" accordion in `app/page.tsx`.

## Tooltip

- **Path:** `components/Tooltip.tsx`
- **Purpose:** Generic short-text tooltip container, mounted by `HoverComponentTrigger`.
- **Props:**
  ```ts
  interface TooltipProps extends React.HTMLAttributes<HTMLDivElement> {}
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`
- **CLI primitive:** (React-only) Hover-driven UI is browser-specific.
- **Used by:** Mounted via `<HoverComponentTrigger component="tooltip">` in the "TOOLTIP" accordion in `app/page.tsx`.

## TreeView

- **Path:** `components/TreeView.tsx`
- **Purpose:** Hierarchical file/folder tree with expand/collapse toggles and Unicode branch glyphs.
- **Props:**
  ```ts
  interface TreeViewProps {
    children?: React.ReactNode;
    defaultValue?: boolean;
    depth?: number;
    isFile?: boolean;
    isLastChild?: boolean;
    isRoot?: boolean;
    parentLines?: boolean[];
    style?: any;
    title: string;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A sequence of `cardRow` calls with manually composed `'├──'` / `'└──'` glyphs.
- **Used by:** `<TreeView title="root">...</TreeView>` inside the "TREE VIEW" accordion in `app/page.tsx`.

## Window

- **Path:** `components/Window.tsx`
- **Purpose:** Terminal-window frame for sacred React surfaces — slight off-background body fill plus a `1ch` right + 1-row bottom drop shadow (intentionally a step darker than the body so the panel reads as "lifted") that mirrors Simulacrum's window primitive. Uses a responsive `min-width: min(24ch, 100%)` so the window shrinks gracefully on narrow viewports (320px and up) without forcing horizontal scroll.
- **Props:**
  ```ts
  type WindowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-window-background`, `--theme-window-shadow`, `--theme-line-height-base`
- **CLI primitive:** `getInnerWidth(termW)` + `wrapLine` / `wrapLineTop` / `shadowBottomRow` in `scripts/cli/lib/window.js`. Wrapping a CLI-port React surface in `<Window>` is the React-side equivalent of running the screen inside the Simulacrum alt-screen window frame.
- **Used by:** `<Window>...</Window>` wraps the cards + button row in `components/examples/CLITemplate.tsx`, `components/examples/InvoiceTemplate.tsx`, `components/examples/ResultsList.tsx`, `components/examples/AS400.tsx`, `components/examples/Denabase.tsx`, `components/examples/DashboardRadar.tsx`, and `components/examples/MessagesInterface.tsx`, plus the standalone "WINDOW" accordion in `app/page.tsx`.
- **Drop shadow spacing:** Window's bottom drop shadow (1 row) extends below the component's bounding box. When a Window-wrapped component sits inside an Accordion or any container that clips or collapses whitespace, add a double `<br />` after the component so the shadow has room to render. Single `<br />` clips the shadow.


---

# scripts/cli/AGENTS.md

# AGENTS.md — scripts/cli

Simulacrum, the sacred CLI framework. Zero-dependency CommonJS. Imported by `scripts/cli/templates/*.ts` (via `tsx`) and mirrored in Python under `scripts/python/sacred_cli/`.

## Why CommonJS

`tsx` runs TypeScript with no build step, and `require()` against a CJS module means TypeScript consumes it through type erasure. Adding ESM here would force a build step or `--experimental-vm-modules`. Don't do it.

## Layout

- `colors.json` — sacred palette. Single source of truth, also loaded by the Python mirror.
- `lib/ansi.js` — ANSI escapes, hex helpers (`fgHex`/`bgHex`), padding (`padR`/`padL`), gradient text, visible-length math (`strip`/`visLen`/`truncateVisible`), color constants (`COLORS`).
- `lib/window.js` — window frame: margin (2ch), shadow (1ch right + 1 row bottom), `getInnerWidth`, `wrapLine`/`wrapLineTop`/`shadowBottomRow`/`wrapLines`, `bgTerm`/`bgWin`/`bgShd`, `MIN_TERM_W`/`MIN_INNER_W`.
- `lib/card.js` — box-drawing card (`B`, `cardTop`, `cardRow`, `cardSelectRow`, `cardHeaderRow`, `cardBot`, `wordWrap`).
- `lib/table.js` — `formatRow(vals, colSpec, innerW)`, `kvTable`, `kvTableGradient`. Status coloring fires when a column has `status: true` (`ACTIVE`/`OPEN`/`APPROVED` → bold green, `CLOSED`/`PAID`/`SUSPENDED` → gray).
- `lib/button.js` — `button(hotkey, label)` and `buttonRow(left, right, innerW)`.
- `lib/app.js` — lifecycle: alt screen, raw mode, resize debounce, pagination, optional row selection. Exports `createApp({ build, totalPages, interactive, onKey }).start()`.

## What this framework deliberately does NOT have

- **No animation diffing.** Sacred CLI ports are static. The React side handles animation via `<ASCIICanvas>` and the canvas modules. If you find yourself adding a frame loop here, stop and use the React side instead.
- **No mode loader, no plugin system.** Templates wire data and call `createApp`. Anything more belongs in the template.
- **No third-party deps.** `package.json`'s only role here is to expose the `cli:typescript` and `cli:python` scripts. The framework itself never imports from `node_modules`.

## Tests

`__tests__/*.test.mjs` cover the framework. Tests are `.mjs` so they can use `vitest`'s ESM imports while pulling the CJS source through `createRequire`. Run with `npm test` (which also runs the Python parity suite) or `npm run test:js` to skip Python. Add a test alongside the module you change.

## Parity fixture

`__tests__/dump_reference.js` is a tiny Node script that pipes a fixed dataset through every public primitive (`cardTop`, `cardRow`, `cardHeaderRow`, `cardBot`, `cardSelectRow`, `formatRow`, `kvTable`, `kvTableGradient`, `button`, `buttonRow`, `wrapLine`/`wrapLineTop`/`shadowBottomRow`, `wordWrap`) and prints the result as JSON on stdout. The output is the source-of-truth fixture that the Python parity test (`scripts/python/sacred_cli/__tests__/test_parity.py`) loads. `npm run test:python` regenerates the fixture before running the Python suite, so any drift between the JS framework and the Python mirror produces a hard test failure within a single PR cycle.

If you change a primitive's output, the fixture changes automatically — port the change into the Python mirror in the same PR, never edit the JSON by hand.

## Templates

`templates/template.ts` is the canonical TypeScript template. It is the reference for the `port-sacred-terminal-ui-to-typescript-cli` skill. Keep it short, opinionated, and runnable: `npm run cli:typescript` must always work.


---

# scripts/python/AGENTS.md

# AGENTS.md — scripts/python

Python mirror of Simulacrum (the sacred CLI framework). Mirrors `scripts/cli/lib/*` one-to-one but with snake_case symbol names so the Python surface is idiomatic. The package is `sacred_cli` so Python imports stay obviously sacred-flavored.

## Why a Python mirror

The CLI framework is small enough that maintaining a parallel Python implementation is cheap, and porting React → Python is easier when the source-of-truth API is identical to the JS version. Both runtimes load the **same** `scripts/cli/colors.json`, so terminal output is byte-identical between `npm run cli:typescript` and `npm run cli:python` modulo numeric formatting.

## Layout

- `sacred_cli/__init__.py` — re-exports the public surface so templates can `from sacred_cli import ...`.
- `sacred_cli/ansi.py` — mirrors `scripts/cli/lib/ansi.js`. Loads colors via `os.path.join(_HERE, "..", "..", "cli", "colors.json")` — do not duplicate the palette. `_js_round` (private helper) reproduces JavaScript's `Math.round` semantics so byte-level parity holds against the JS framework; do **not** replace it with Python's banker-rounding `round()`.
- `sacred_cli/window.py` — mirrors `window.js`. `get_inner_width`, `wrap_line`, `wrap_line_top`, `shadow_bottom_row`, `wrap_lines`.
- `sacred_cli/card.py` — mirrors `card.js`. `card_top`, `card_row`, `card_select_row`, `card_header_row`, `card_bot`, `word_wrap`. `B` is a dict instead of a JS object.
- `sacred_cli/table.py` — mirrors `table.js`. `format_row`, `kv_table`, `kv_table_gradient`.
- `sacred_cli/button.py` — mirrors `button.js`. `button`, `button_row`.
- `sacred_cli/app.py` — mirrors `app.js`. `create_app(*, build, total_pages=1, interactive=None, on_key=None)` using `termios`/`tty` for POSIX raw mode.
- `sacred_cli/__tests__/` — unittest suite. One file per module (`test_ansi.py`, `test_window.py`, `test_card.py`, `test_table.py`, `test_button.py`) plus `test_parity.py` that asserts byte-identical output against the JS reference fixture under `fixtures/reference.json`. `_bootstrap.py` adds `scripts/python/` to `sys.path` so `import sacred_cli` works under `unittest discover` regardless of cwd. We use the `__tests__/` directory name to mirror the JS test layout under `scripts/cli/lib/__tests__/`.
- `templates/template.py` — canonical Python template, runs with `npm run cli:python`.

## Naming convention

| JavaScript | Python |
| --- | --- |
| `cardTop` | `card_top` |
| `cardRow` | `card_row` |
| `cardSelectRow` | `card_select_row` |
| `cardHeaderRow` | `card_header_row` |
| `cardBot` | `card_bot` |
| `formatRow` | `format_row` |
| `kvTable` | `kv_table` |
| `kvTableGradient` | `kv_table_gradient` |
| `buttonRow` | `button_row` |
| `wordWrap` | `word_wrap` |
| `createApp` | `create_app` |

`button(hotkey, label)` and `COLORS` keep the same name in both runtimes.

## Platform support

The Python lifecycle uses `termios` + `tty` for raw mode, so it runs on macOS / Linux. Windows users would need a `msvcrt` shim that the sacred port does not currently provide. If you add one, mirror the JS lifecycle byte-for-byte rather than introducing platform branches inside `app.py`. (The parity test suite intentionally does not exercise `app.py` — it only covers the layout primitives, which are platform-agnostic.)

## Tests

`npm run test:python` regenerates the JS reference fixture (via `node scripts/cli/lib/__tests__/dump_reference.js`) and then runs `python3 -m unittest discover -s sacred_cli/__tests__ -t .`. The `npm test` script chains the JS suite and the Python suite, so a single command catches both kinds of regression. If `python3` is not on PATH, the runner prints a warning and exits 0 — sacred contributors on minimal containers can still run `npm test`.

When the parity test fails, the cause is almost always a JS module that changed without a matching Python port. Open the failing assertion (e.g. `test_format_row_status`), read the JS source side-by-side with the Python mirror, and port the change. Re-run `npm test` — the fixture regenerates automatically.

## What this mirror deliberately does NOT have

- No third-party Python deps. Stdlib only. The mirror exists so a Python team can ship a sacred-styled CLI without `pip install` overhead. The test suite uses `unittest` from the stdlib for the same reason.
- No `pytest`. The JS suite is `vitest`; the Python suite is `unittest`. Both runtimes lean on their stdlib-equivalent test runner so there is nothing to install.


---

# skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md

# Skill: Port Sacred Terminal UI to a Hostile React Codebase

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md

Take a sacred React component (or a sacred screen that mirrors a Simulacrum CLI surface) and graft it into a foreign React codebase that already ships its own design system, build pipeline, and CSS toolchain — without breaking the host or polluting it with sacred-specific globals.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it to know which sacred component you are about to graft into the host.

## When to use

Use this skill when the target repository:

- Already has its own CSS reset, theme tokens, or design system (Tailwind, MUI, Chakra, ShadCN, custom)
- Uses a build tool that conflicts with sacred's CSS Modules (`vite`, `webpack`, `rollup`, `parcel`, `metro`)
- Refuses to take sacred's `global.css` as-is because it would clobber the host's typography, color tokens, or layout primitives
- Has a hostile lint config (`no-default-export`, `no-css-modules`, `no-unused-vars` on `style` props, etc.)

If you control both repos and the host has no design system, prefer `port-sacred-terminal-ui-to-react-using-same-conventions` instead — it gives you the full sacred theming for free.

## Core principle

**Isolate, don't inherit.** Sacred's terminal aesthetic must be opt-in inside one container element, not bleed into the host. You will:

1. Scope every CSS rule under a single container class.
2. Inline the ANSI palette as CSS custom properties on that container.
3. Replace sacred's CSS Modules with whatever the host supports (CSS Modules, Tailwind, vanilla-extract, etc.).
4. Keep the React component file's structure identical so future updates from sacred can be diffed cleanly.

## Step-by-step

### 1. Pick a single root class name

Every sacred selector must live under one root. Pick a host-friendly name:

```tsx
<div className="sacred-root theme-dark tint-yellow">
  <Card title="STATUS">...</Card>
</div>
```

### 2. Inline the palette

Copy the relevant `--ansi-*`, `--color-*`, and `--theme-*` tokens from `global.css` into a host-controlled CSS file scoped to `.sacred-root`:

```css
.sacred-root {
  /* NOTE(@YOUR_GITHUB_USERNAME): Pinned ANSI palette — do not inherit host theme tokens. */
  --color-black: #000000;
  --color-white: #ffffff;
  --color-brand: #e4f221;
  --theme-background: var(--color-black);
  --theme-text: var(--color-white);
  --theme-border: #3a3a3a;
  /* ... */

  background: var(--theme-background);
  color: var(--theme-text);
  font-family: 'GeistMono-Regular', Consolas, monospace;
  font-variant-numeric: tabular-nums lining-nums;
}
```

Sacred's tints (`tint-green`, `tint-blue`, etc.) work the same way — copy the OKLCH math from `global.css` and scope it under `.sacred-root.theme-dark.tint-green`.

### 3. Translate CSS Modules

Sacred uses `Foo.module.css`. If the host blocks CSS Modules, translate the rules into the host's equivalent:

| Host system | Translation strategy |
| --- | --- |
| Tailwind | Map each `--theme-*` token to a Tailwind theme extension, then use `bg-[var(--theme-background)]` etc. |
| vanilla-extract | Copy each `.foo` rule into a `style({ ... })` block |
| Stitches/Emotion/styled-components | Wrap the CSS in `styled.div\`...\`` blocks |
| Plain CSS | Inline the CSS Modules content into a single scoped stylesheet |

In every case, every selector must start with `.sacred-root` so the host's other components are unaffected.

### 4. Eject sacred dependencies

Sacred React components import from `@components/...` via `tsconfig.json` paths. The host won't have that alias. Either:

- Add the alias to the host's `tsconfig.json` (cleanest), or
- Rewrite `@components/Card` to a relative path inside the host's `src/`

Sacred avoids runtime dependencies, so there is nothing else to port — no React Query, no Redux, no animation libraries.

### 5. Avoid global side effects

Sacred's `global.css` resets `box-sizing`, margins, padding, and list styles for every element. **Do not** import `global.css` into the host. Re-create only the rules you need under the `.sacred-root` selector. The host's reset stays untouched.

### 6. Confirm theming

Wrap your sacred container in a host-managed theme switcher and verify:

```tsx
<div className={`sacred-root theme-${theme} tint-${tint}`}>
  <Card title="STATUS">...</Card>
</div>
```

If the host already has dark mode, you have two options:

- **Mirror** the host's dark mode by deriving `theme-dark` from the host theme context
- **Independent** sacred theming via its own state — recommended when the sacred surface is a "console" or "debugger" overlay

## Don'ts

- **Do not** import `global.css` into the host. It breaks `body`, `ul`, `ol`, and many other elements.
- **Do not** re-export sacred's `Button`, `Input`, or other primitives with the same name as a host primitive — you will collide. Prefix them: `SacredButton`, `SacredInput`.
- **Do not** ship `scripts/cli/lib/*` into the React bundle. It is Node-only and uses `process.stdout`.
- **Do not** rewrite sacred components to consume host theme tokens. The whole point of this skill is to keep sacred isolated so future sacred releases drop in cleanly.

## Smoke test

1. Render your sacred-rooted component in the host app.
2. Switch the host's theme and confirm sacred does not change (or does change, intentionally, if you wired it).
3. Inspect the host's other components and confirm none of them have new margin/padding/font-family from sacred's reset.
4. Run `git diff` against the previous host build and confirm no host CSS rule changed.

## Reference: minimum sacred surface

A useful "first port" is the `Card` + `DataTable` + `Button` triple. That gives you:

- Box-drawing borders
- Header/data row alignment with status coloring
- Hotkey + label button row

That's enough for a status console, an audit log, or a debugger overlay. Add more sacred primitives (`BarLoader`, `BarProgress`, `Block`, `Text`) one at a time, scoping each new selector under `.sacred-root`.


---

# skills/port-sacred-terminal-ui-to-python/SKILL.md

# Skill: Port Sacred Terminal UI to Python

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-python/SKILL.md

Take a React `Window*.tsx` (or any sacred component) and produce a terminal CLI screen written in Python that uses **Simulacrum's** Python mirror in `scripts/python/sacred_cli/`. Simulacrum is the sacred CLI framework — the JavaScript half lives in `scripts/cli/lib/`, the Python half is a one-to-one snake_case mirror.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before identifying which React surface you are porting from.

## When to use

Use this skill whenever you want a Python CLI version of an existing sacred React surface. Sacred ships a Python port of the layout primitives (one-to-one with the JavaScript framework) so the same React component can render identically from either runtime.

## What you ship

A single `.py` file under `scripts/python/templates/` that:

1. Has a `python3` shebang and `if __name__ == "__main__":` entry point.
2. Imports primitives from `sacred_cli` (the package lives in `scripts/python/sacred_cli/`).
3. Calls `create_app(build=build).start()` with a `build(page, inner_w, selected_row)` function that returns `list[str]`.

## Reference implementation

Read these files before starting:

- `scripts/python/templates/template.py` — canonical example (run with `npm run cli:python`)
- `scripts/python/sacred_cli/__init__.py` — public surface re-exports
- `scripts/python/sacred_cli/ansi.py` — ANSI escapes, hex helpers, padding, gradient text
- `scripts/python/sacred_cli/window.py` — window frame (margin + window bg + shadow)
- `scripts/python/sacred_cli/card.py` — box-drawing card borders and word wrap
- `scripts/python/sacred_cli/table.py` — `format_row`, `kv_table`, `kv_table_gradient`
- `scripts/python/sacred_cli/button.py` — `button`, `button_row`
- `scripts/python/sacred_cli/app.py` — lifecycle: alt screen, raw mode, resize, paging, selection
- `scripts/cli/colors.json` — sacred-themed color palette (the Python ANSI module loads this same JSON)

## Naming convention

The Python port mirrors the JavaScript framework one-to-one but uses **snake_case**:

| JavaScript                                 | Python                                        |
| ------------------------------------------ | --------------------------------------------- |
| `cardTop(title, innerW)`                   | `card_top(title, inner_w)`                    |
| `cardRow(content, innerW)`                 | `card_row(content, inner_w)`                  |
| `cardSelectRow(content, innerW, selected)` | `card_select_row(content, inner_w, selected)` |
| `cardHeaderRow(content, innerW)`           | `card_header_row(content, inner_w)`           |
| `cardBot(innerW)`                          | `card_bot(inner_w)`                           |
| `formatRow(vals, colSpec, innerW)`         | `format_row(vals, col_spec, inner_w)`         |
| `kvTable(pairs)`                           | `kv_table(pairs)`                             |
| `kvTableGradient(pairs)`                   | `kv_table_gradient(pairs)`                    |
| `buttonRow(left, right, innerW)`           | `button_row(left, right, inner_w)`            |
| `wordWrap(text, maxW)`                     | `word_wrap(text, max_w)`                      |
| `createApp({ build })`                     | `create_app(build=build)`                     |

`button(hotkey, label)` and the COLORS dict keep the same names because they have no JS-specific casing.

## ColSpec reference

```py
COL_SPEC = [
    {"width": 14, "align": "left"},
    {"width": 12, "align": "left", "grow": True},
    {"width": 8, "align": "right", "status": True, "gap": 2},
]
```

Status coloring: `ACTIVE`/`OPEN`/`APPROVED` → bold green; `CLOSED`/`PAID`/`SUSPENDED` → gray. The framework handles this automatically when `status: True`.

## Step-by-step

1. **Read the React file.** Identify cards, tables, paragraphs, and button rows. Skip the `<ASCIICanvas>` (CLI is static).
2. **Extract data.** Move table rows into module-level lists at the top of your `.py` file.
3. **Define COL_SPECS.** One per table. Mark a single column with `"grow": True`.
4. **Write `build(page, inner_w, selected_row)`.** Append `card_top` → rows → `card_bot` for each section. End with `button_row(...)`.
5. **Run `npm run cli:python`.** Verify margins, shadow, and inner padding match the React component.
6. **Add interactivity (optional).** Pass `interactive={"count": 5, "on_select": fn, "persist": True}` to `create_app` and use `card_select_row(content, inner_w, i == selected_row)`.
7. **Add pagination (optional).** Pass `total_pages=N` (or a callable) and slice your data by `page` inside `build`.

## Formatting rules

- Shebang `#!/usr/bin/env python3`.
- Comments use `# NOTE(your_github_username): ...`.
- Column headers are `UPPER_SNAKE_CASE`.
- Dates are ISO 8601 (`2026-04-08T09:00:00`).
- Currency uses commas (`$18,920.50`).
- Never hardcode hex colors — read from `scripts/cli/colors.json` via `sacred_cli.COLORS`.
- Python templates run on POSIX terminals (macOS / Linux); the lifecycle uses `termios` raw mode. Windows users need a `msvcrt` shim that the sacred port does not currently provide.

## Smoke test

After writing the file:

```sh
npm test                # JS framework unit tests + Python parity suite
npm run cli:python      # your screen renders, ESC quits cleanly
```

If you see garbled output, your terminal probably does not support 24-bit true color — the sacred palette assumes `\x1b[38;2;R;G;Bm` works.

## Verifying parity

The Python framework is a one-to-one mirror of the JavaScript framework. The two runtimes are locked into byte-identical output by a parity test suite under `scripts/python/sacred_cli/__tests__/`:

```sh
npm run test:python     # only the Python suite
npm test                # JS suite + Python suite (chained)
```

`npm run test:python` first regenerates the JS reference fixture (`scripts/python/sacred_cli/__tests__/fixtures/reference.json`) via `node scripts/cli/lib/__tests__/dump_reference.js`, then runs `python3 -m unittest discover` against `sacred_cli/__tests__`. The fixture is checked into the repo so the Python test never has to shell out — regeneration is just a guard against stale snapshots.

If `python3` is not on PATH, the runner prints a warning and exits 0. Sacred contributors on minimal containers can still run `npm test` without installing Python.

### When the parity test fails

A failing parity test almost always means **a JS module was changed without porting the change to its Python mirror.** To fix:

1. Read the failing assertion (e.g. `test_format_row_status`).
2. Open the corresponding JS module (`scripts/cli/lib/table.js`) and the Python mirror (`scripts/python/sacred_cli/table.py`) side-by-side.
3. Port the JS change into the Python file. Snake-case the symbol names per the naming table above.
4. Re-run `npm test`. The fixture is regenerated automatically — no manual step needed.

If you genuinely need to update the contract on **both** sides, edit the JS module first, then run `npm test` to see what the parity fixture now looks like, and only then port the new behavior into Python. Never edit the fixture JSON by hand.

The unit tests under `scripts/python/sacred_cli/__tests__/` (one file per module: `test_ansi.py`, `test_window.py`, `test_card.py`, `test_table.py`, `test_button.py`) mirror the JS tests in `scripts/cli/lib/__tests__/`. When you add a new JS test, add the equivalent Python test in the same file so the assertion sets stay synchronized.


---

# skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md

# Skill: Port Sacred Terminal UI to React Using Same Conventions

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md

Take a CLI screen written for **Simulacrum** — the sacred CLI framework (`scripts/cli/templates/*.ts` or `scripts/python/templates/*.py`) — and produce a React component that lives inside `components/examples/` (or `components/`) using only sacred's existing primitives — `Window`, `Card`, `SimpleTable`, `ActionButton`, `RowSpaceBetween`, `BarLoader`, etc.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before picking a component to render.

## When to use

Use this skill whenever you have a CLI screen and want a sacred React surface that mirrors it without the canvas-based animation. This is the inverse of `port-sacred-terminal-ui-to-typescript-cli` and `port-sacred-terminal-ui-to-python`.

## Reference primitives

These are the React components that sacred ships and that the CLI framework maps onto. Read them before writing the port:

| Sacred React component | CLI primitive | What it renders |
| --- | --- | --- |
| `components/Card.tsx` | `cardTop`/`cardRow`/`cardBot` | Box-drawing card with title bar |
| `components/CardDouble.tsx` | (no equivalent) | Double-bordered card with left/right titles |
| `components/SimpleTable.tsx` | `formatRow` + `cardHeaderRow`/`cardRow` | Fluid HTML table with header background and status coloring — the canonical React surface for CLI port examples |
| `components/DataTable.tsx` | (no direct equivalent) | Sacred's gradient-tinted table — heavier, used outside CLI ports |
| `components/Button.tsx` | `button` + `buttonRow` | Hotkey + label button pair |
| `components/BarLoader.tsx` | (one-line loader) | Single-row progress fill |
| `components/RowSpaceBetween.tsx` | `buttonRow(left, right, innerW)` | Left/right justified row |
| `components/Block.tsx` | `cardRow(text, innerW)` with word wrap | Padded text block |
| `components/Text.tsx` | gradient or plain text | Typography wrapper |

## Step-by-step

1. **Read the CLI screen.** Identify each `cardTop`/`cardRow`/`cardBot` block and each `buttonRow`. Each block becomes one `<Card>` element.
2. **Create the React file.** Drop it in `components/examples/` if it is a demo, or `components/` if it is a reusable surface. Use `'use client'` only if you need browser APIs (most ports do not).
3. **Map cards to `<Card title="...">`.** Wrap content children in `<Card>`. Card renders the title bar, the framework only adds borders.
4. **Map data tables to `<SimpleTable data={[...]} />`.** First row is the header, subsequent rows are data. `SimpleTable` is a fluid HTML table with the same column + status contract as the CLI framework's `formatRow` (`ACTIVE`/`OPEN`/`APPROVED` → bold green, `CLOSED`/`PAID`/`SUSPENDED` → gray). Use `align={['left','right',...]}` to mirror per-column alignment from the CLI's `colSpec`. Do **not** use the heavier `DataTable` here — its gradient backgrounds are not part of the CLI surface.
5. **Map button rows to `<RowSpaceBetween>`.** Left and right buttons go in the slots provided. Use `<Button theme="SECONDARY">ESC EXIT</Button>` so the React buttons match the CLI button row visually.
6. **Skip the animation header.** Sacred's React UI has its own animation surfaces (`canvas-platformer`, `canvas-snake`); do not re-port the CLI's static layout into one of those. The point is **layout parity**, not animation parity.
7. **Inherit theming.** Sacred's `global.css` already drives every `--theme-*` token from the active light/dark/tint theme. Do not import `scripts/cli/colors.json` from React — the React side picks up the same ANSI palette through the CSS custom properties (`var(--theme-background)` etc.).

## What NOT to do

- **Do not** re-implement the box-drawing borders in HTML/CSS — `Card` already does this.
- **Do not** copy `scripts/cli/lib/*` into the React tree. The CLI framework is for terminals; the React tree uses CSS Modules.
- **Do not** import `scripts/cli/colors.json` from a React file. The browser palette comes from CSS custom properties — the JSON is the authoritative source for the ANSI palette but it is consumed indirectly through `global.css`.
- **Do not** add an `<ASCIICanvas>` from `.workdir/` — sacred has its own animations and porting that canvas duplicates state machines.

## Layout expectations

Sacred React components are width-fluid: use them in `<ContentFluid>` or `<Block>` containers and let CSS Grid / Flexbox do the work. The CLI framework's "innerW" concept is replaced by browser layout, so you do not need to compute column widths yourself — DataTable and Card handle their own padding.

## Smoke test

After writing the component:

```sh
npm test     # CLI framework tests still pass (sanity check)
npm run dev  # render the React surface in the browser
```

Visit the page that renders your component and confirm:

- Card titles match the CLI `cardTop` titles exactly
- SimpleTable rows match the CLI `formatRow` outputs (same order, same labels, same status colors)
- Buttons match the CLI `button(hotkey, label)` pairs
- The screen reads the same in light, dark, and every tinted theme (the global CSS handles this for free)

If anything diverges, trust the CLI screen — it is the source of truth for layout because the CLI framework forces explicit widths and the React side fills in around it.


---

# skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md

# Skill: Port Sacred Terminal UI to TypeScript CLI

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md

Take a React `Window*.tsx` (or any sacred component) and produce a terminal CLI screen written in TypeScript that uses **Simulacrum** — the sacred CLI framework in `scripts/cli/lib/`.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before identifying which React surface you are porting from.

## When to use

Use this skill whenever you want a CLI version of an existing sacred React surface. Sacred ships a small zero-dependency layout framework that maps every React `<Card>` / `<DataTable>` / `<TerminalButton>` concept onto a CLI primitive. The output is identical to the React component minus the canvas-based animations — sacred renders are static.

## What you ship

A single `.ts` file under `scripts/cli/templates/` that:

1. Uses `tsx` as a shebang or `npm run cli:typescript` as the entry point.
2. `require`s the framework primitives (the framework is CommonJS so TypeScript consumes it via `require` for type erasure with no build step).
3. Calls `createApp({ build }).start()` with a `build(page, innerW, selectedRow)` function that returns `string[]`.

## Reference implementation

Read these files before starting:

- `scripts/cli/templates/template.ts` — canonical example (run with `npm run cli:typescript`)
- `scripts/cli/lib/ansi.js` — ANSI escapes, hex helpers, padding, gradient text
- `scripts/cli/lib/window.js` — window frame (margin + window bg + shadow)
- `scripts/cli/lib/card.js` — box-drawing card borders and word-wrap
- `scripts/cli/lib/table.js` — `formatRow`, `kvTable`, `kvTableGradient`
- `scripts/cli/lib/button.js` — `button`, `buttonRow`
- `scripts/cli/lib/app.js` — lifecycle: alt screen, raw mode, resize, paging, selection
- `scripts/cli/colors.json` — sacred-themed color palette (single source of truth)

## React-to-CLI concept map

| React surface                             | CLI primitive                                            | Notes                                                                       |
| ----------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------- |
| `<Card title="T">`                        | `cardTop('T', innerW)` + `cardBot(innerW)`               | Top + bottom borders                                                        |
| Content `<div>` inside `<Card>`           | `cardRow(text, innerW)`                                  | 2ch left indent, padded to inner width                                      |
| `unstyledTableFixedKey` + `gradientText`  | `kvTableGradient([[k, v]])`                              | 24ch key column, gradient on value                                          |
| `<thead><tr><td>`                         | `cardHeaderRow(formatRow(TH, COL_SPEC, innerW), innerW)` | `#585858` background                                                        |
| `<tbody><tr><td>`                         | `cardRow(formatRow(row, COL_SPEC, innerW), innerW)`      | Per-cell alignment, status coloring                                         |
| `styles.statusAuthenticated/Disconnected` | `colSpec: { status: true }`                              | `ACTIVE`/`OPEN`/`APPROVED` → bold green; `CLOSED`/`PAID`/`SUSPENDED` → gray |
| `<TerminalButton hotkey="ESC">`           | `button('ESC', 'exit')`                                  | Hotkey + label background pair                                              |
| `flexRowLeft / flexRowRight`              | `buttonRow(left, right, innerW)`                         | Left + right justify with windowBg gap                                      |
| Word-wrapped paragraph                    | `wordWrap(text, innerW - 6)`                             | Card padding is 3ch each side                                               |
| Animated `<ASCIICanvas>` header           | _omit_                                                   | Sacred CLI ports are static; the React side keeps the animation             |

## ColSpec reference

```ts
type ColSpec = {
  width: number;
  align?: 'left' | 'right';
  grow?: boolean; // one column per spec absorbs extra width
  status?: boolean; // ACTIVE/OPEN/APPROVED → bold green; CLOSED/PAID/SUSPENDED → gray
  gap?: number; // inter-column spacing (default 1ch)
};
```

## Step-by-step

1. **Read the React file.** Identify cards, tables, paragraphs, and button rows. Skip the `<ASCIICanvas>` (CLI is static).
2. **Extract data.** Move table rows into `const` arrays at the top of your TS file. If the React component already imports JSON, share the same JSON.
3. **Define COL_SPECS.** One per `<table>`. Mark a single column with `grow: true`.
4. **Write `build(page, innerW, selectedRow)`.** Push `cardTop` → rows → `cardBot` for each section. Append `buttonRow(...)` last.
5. **Run `npm run cli:typescript`.** Verify margins, shadow, and inner padding match the React component.
6. **Add interactivity (optional).** Pass `interactive: { count, onSelect, persist: true }` to `createApp` and use `cardSelectRow(content, innerW, i === selectedRow)`.
7. **Add pagination (optional).** Pass `totalPages: N` (or `() => N`) and slice your data by `page` inside `build`.

## Formatting rules

- File starts with `#!/usr/bin/env -S npx tsx`.
- Comments use `//NOTE(your_github_username): ...`.
- Column headers are `UPPER_SNAKE_CASE`.
- Dates are ISO 8601 (`2026-04-08T09:00:00`).
- Currency uses commas (`$18,920.50`).
- Never hardcode hex colors — read from `scripts/cli/colors.json` via the framework.

## Smoke test

After writing the file:

```sh
npm test                  # JS framework + Python parity suite (chained)
npm run cli:typescript    # your screen renders, ESC quits cleanly
```

If `npm test` fails, the framework is broken — fix it before continuing. If your screen flickers on resize, you forgot to wrap content in `cardRow`/`cardSelectRow` (the framework relies on padded rows for the in-place redraw).

If a JS module changes the bytes coming out of any primitive, the parity test in `scripts/python/sacred_cli/__tests__/test_parity.py` will fail until the Python mirror under `scripts/python/sacred_cli/` is updated to match. Port the change to both runtimes in the same PR — see `skills/port-sacred-terminal-ui-to-python/SKILL.md` § "Verifying parity".

