| name | services-layer |
| description | Whispering service boundaries: UI-free capabilities, explicit app inputs, Result-typed fallibility, direct Live objects, lifecycle-earned factories, and build-time #platform implementations. Use when creating or refactoring services, service contracts, platform variants, provider dispatch, or the $lib/services barrel. |
| metadata | {"author":"epicenter","version":"3.0"} |
Services Layer
Ground service guidance in apps/whispering/src/lib/services, its consumers,
and the #platform/* mappings in apps/whispering/package.json. Historical
examples and neighboring skills are leads, not current architecture.
Product Sentence
The service layer owns UI-free capabilities; callers inject app policy through
explicit inputs, fallible operations return Results, and platform selection has
one build-time owner.
Boundary
Services may perform IO and may own service-local runtime state. They are not
required to be pure functions. They must remain free of UI and app-owned policy:
- no runtime reads of Svelte stores,
settings, deviceConfig, toasts, or
report;
- accept credentials, model names, endpoints, paths, and user choices as inputs;
- return domain data and errors, not presentation copy or UI state;
- expose the same contract from both sides of a
#platform/* seam.
$lib/operations usually reads app settings, chooses providers, and composes
services. $lib/queries adds shared query identity and observable lifecycle only
when the UI needs it.
The transcription directory also holds provider registry data and the
UI-facing join. Those colocated metadata modules are not
service implementations; do not use them to weaken the service boundary.