services-layer
Services-layer enforces a consistent architecture using namespace exports and Result types to manage domain-specific error handling.
Install
mkdir -p .claude/skills/services-layer && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2304" && unzip -o skill.zip -d .claude/skills/services-layer && rm skill.zipInstalls to .claude/skills/services-layer
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Service layer patterns: defineErrors, namespace exports, Result types. Use when: "create a service", "service layer", creating services, defining domain-specific errors.Key capabilities
- →Define domain-specific error namespaces
- →Implement Result type return patterns
- →Create pure, testable business logic services
- →Extract error messages from unknown causes
How it works
It uses namespace exports and Result types to ensure business logic remains pure and error handling is consistent.
Inputs & outputs
When to use services-layer
- →Create a new business logic service
- →Define domain-specific error types
- →Implement uniform error handling
- →Decouple business logic from the UI
About this skill
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, orreport; - 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 provider-ui.ts join. Those colocated metadata modules are not
service implementations; do not use them to weaken the service boundary.
Model Fallibility Honestly
Use Result<T, E> for a public operation that can fail in ordinary runtime use.
Adapt throwing platform or library calls with the error-handling skill.
Do not fake a Result for an infallible in-memory action or cleanup. Current
examples include local shortcut register / unregister returning void and
listener setup returning a cleanup function.
export type DownloadService = {
downloadBlob(args: {
name: string;
blob: Blob;
}): Promise<Result<void, DownloadError>>;
};
Errors belong to the layer that understands the failure. Preserve lower-layer
tagged errors when composing services. Define a service-local variant only for
a failure the service itself owns. Use define-errors for variant shape and
message rules; use error-handling for adaptation and propagation.
Direct Object Or Factory
Default to a direct *ServiceLive object when construction has no input or
lifecycle. Current download, analytics, text, and transcription provider
implementations use this shape. Download, analytics, and text check their shared
platform contracts with satisfies <Service>.
Use a factory when it owns real construction inputs, replaceable dependencies, or stateful lifecycle. The browser and CPAL recorder factories earn their boundary because each creates recording sessions with stop, cancel, subscribe, and teardown behavior.
Do not add create* plus *Live mechanically for a stateless object.
Read service implementation patterns for the current direct-object example and the factory decision.
Platform And Runtime Selection
Use #platform/* imports for a capability with browser and Tauri
implementations. package.json#imports chooses the implementation at build
time; shared callers import one stable name and do not inspect
window.__TAURI_INTERNALS__.
Use the nullable #platform/tauri namespace for Tauri-only capabilities.
User-selected providers are runtime policy, not a platform seam. Keep the
dispatch in the consuming operation. Whispering transcription reads the
selected provider in $lib/operations/transcribe.ts; the query layer only
observes that operation.
Read service organization and platform variants when adding or moving a platform service.
Service Barrel
$lib/services/index.ts collects stable cross-platform capabilities:
export const services = {
analytics: AnalyticsServiceLive,
text: TextServiceLive,
blobs: BlobsLive,
blobSources: BlobSourcesLive,
download: DownloadServiceLive,
localShortcutManager: LocalShortcutManagerLive,
sound: PlaySoundServiceLive,
} as const;
Do not force every provider implementation into this barrel. A runtime operation may import its provider-specific services directly when it owns the dispatch table.
Final Check
- The service imports no UI or app-owned settings.
- Every app choice enters as an explicit input or is selected by the caller.
- Fallible public operations return Results; infallible operations stay plain.
- A factory owns construction or lifecycle, not convention alone.
- Platform choice happens through one
#platform/*mapping. - Runtime provider choice happens once at the consuming operation.
- Lower-layer errors pass through unless this service owns a new failure.
When not to use it
- →When importing UI code or reactive stores
- →When throwing exceptions instead of returning Results
Prerequisites
Limitations
- →Services cannot import settings directly
- →Requires specific error variant naming conventions
How it compares
It mandates explicit Result types and pure functions instead of relying on standard throw-catch exception handling.
Compared to similar skills
services-layer side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| services-layer (this skill) | 7 | 2mo | No flags | Advanced |
| software-architecture | 333 | 6mo | No flags | Intermediate |
| codex | 32 | 2mo | Review | Advanced |
| game-development | 70 | 6mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by EpicenterHQ
View all by EpicenterHQ →You might also like
software-architecture
davila7
Guide for quality focused software architecture. This skill should be used when users want to write code, design architecture, analyze code, in any case that relates to software development.
codex
Lucklyric
Invoke Codex CLI for complex coding tasks requiring high reasoning capabilities. This skill should be invoked when users explicitly mention "Codex", request complex implementation challenges, advanced reasoning, or need high-reasoning model assistance. Automatically triggers on codex-related requests and supports session continuation for iterative development.
game-development
davila7
Game development orchestrator. Routes to platform-specific skills based on project needs.
senior-fullstack
davila7
Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.
command-name
anthropics
This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.
python-project-structure
wshobson
Python project organization, module architecture, and public API design. Use when setting up new projects, organizing modules, defining public interfaces with __all__, or planning directory layouts.