Ctrl K
ComunidadGuías…

AGENTS.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
## Engineering principles (apply to ALL code in this repo — not optional)

- **Hexagonal (ports & adapters).** The dependency arrow always points inward: **UI → application → domain**. The domain is the centre and stays pure and framework-free (`src/lib/domain/**` — no SvelteKit, no `fetch`, no IO, no stores, no global side effects). IO/UI/HTTP are adapters at the edges (`src/routes/**`, `src/lib/ui/**`, `src/lib/infrastructure/**`, HTTP clients). Side-effectful global bootstrap belongs at an edge, never inward — e.g. client UI config like `src/lib/ui/icons/offline.ts` is imported by the root layout, not reached into by the domain. Cross a boundary only through an explicit port (interface), never by reaching into another layer's internals.
- **Dependency inversion / reverse DI.** High-level policy depends on abstractions, not concretions. Define ports in the domain/application layer; wire concrete adapters at the composition root (`src/lib/composition/container.server.ts`, imported via `$composition`) — that root is the *only* module that `new`s an adapter or names a concrete infrastructure class. Never `new` an adapter elsewhere, and never import a route/store/UI from the domain.
- **Single Responsibility.** One reason to change per module/function. Use-cases live in `src/lib/application/use-cases/**` and each does one thing; keep pure helpers pure. A module's name should fully describe what it does (`offline.ts` makes icons render offline — and nothing else). Split a file the moment it grows a second responsibility.
- **Bounded contexts.** Respect context boundaries (experience, data, rules, users, framing, …). Each context owns its types and validates input at its edge (anti-corruption — see `parse-experience-*`, `parse-*-draft`). Don't share mutable internals across contexts; communicate through well-typed contracts. New features reuse the existing back API behind a strict bounded context rather than client shortcuts.
- **Clean code.** Small, well-named functions; no dead code or speculative abstractions; prefer pure functions; match the surrounding file's style and idioms; comments explain *why*, not *what*. **Always write code, identifiers, comments, commit messages, and committed docs in English — no exceptions.**


## Enterprise deployment & air-gap (read before adding any runtime dependency)

Lyriks ships as a **self-hosted, on-prem appliance** that must run **air-gapped with zero runtime egress**.
Protect this — it is a sales-critical, audited property (see `docs/`).

- **The platform is the product.** It runs on its own with PostgreSQL, the local coherence engine
  and the stub AI; the MCP gateway (`packages/mcp`) and the behaviour dashboard run beside it.
  Enterprise adds private components; everything here keeps working with `LYRIKS_BACK_URL` unset.
- **No new default egress.** Never introduce a runtime call to the public Internet that runs by default —
  no CDNs, web fonts, telemetry, or remote APIs. The AI backend is **opt-in / BYOK only** (default = local
  stub). Anything outbound must be optional and off by default.
- **Icons are bundled offline — do not regress this.** Icons render from
  `src/lib/ui/icons/lucide-offline.json` (registered by `src/lib/ui/icons/offline.ts`, imported in the root
  layout); the remote Iconify API is disabled. Only the **`lucide`** collection is used. After adding or
  removing any `lucide:*` icon, run **`pnpm icons:build`** to regenerate the committed subset. Never fetch
  icons from `api.iconify.design` at runtime.
- **Dependencies must be permissive, long-lived OSS.** Prefer well-stewarded MIT/BSD/Apache deps; avoid
  third-party copyleft runtime deps. `unspaghettit` (AGPL) is **first-party / vendor-owned** and run as an
  **isolated, runtime-optional subprocess** — keep that boundary; it is not a third-party copyleft risk.
- **Docs**: keep `docs/` in sync when the architecture, stack, or security posture changes. Never
  name specific prospects/customers in committed docs — keep them generic ("the customer").