# Architecture overview

Klyro uses Effect for application orchestration, dependency injection, typed
failures, and infrastructure services. Pure domain and rendering code stays
callable as ordinary functions, so compatibility decisions and generated
output remain deterministic. Using Effect Schema in core as the canonical
decoder does not require the resolver or renderer to run inside an Effect
runtime.

## Boundary map

| Area                        | Owns                                                                                           | Must not own                                                               |
| --------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `packages/core`             | Effect Schema definitions, decoded data types, resolver algorithms, invariants                 | Node I/O, CLI prompts, Compose filesystem writes, Effect runtime workflows |
| `packages/catalog`          | Plain provider descriptors, bindings, and curated deployment facts                             | Filesystem access, process execution, terminal presentation                |
| `packages/renderer-compose` | Pure `ResolvedStack`/profile to `DeploymentPlan` to `ArtifactSet` conversion                   | Node built-ins, environment reads, timestamps, randomness, writes          |
| `packages/platform-node`    | Effect application seams, Node filesystem/environment/process services, atomic artifact writes | Product-selection or compatibility decisions                               |
| `apps/cli`                  | Citty routing, Clack prompts, output formatting, exit-code mapping                             | Resolver rules, provider facts, filesystem implementation                  |

Two rules worth remembering: keep `effect/unstable/cli` and Zod out of the
repository, and do not introduce an Effect service for a pure catalog lookup
or serializer without a concrete dependency-substitution need.

## The standard workflow

```text
read source
  → decode and normalize
  → resolve capabilities and bindings
  → build DeploymentPlan
  → render the complete ArtifactSet in memory
  → inspect overwrite/path policy
  → write through FileSystem and ArtifactWriter
```

The render and preflight stages complete before mutation. Typed failures
retain their stable diagnostic code at each seam; raw Node errors are
normalized at the platform boundary.

## Testing the boundary

- Test schemas, resolver behavior, planner behavior, and rendering directly
  as pure functions over decoded values.
- Test platform workflows with injected filesystem, environment, and process
  layers; domain tests never rely on the host filesystem.
- Test CLI routing and prompts through the CLI adapter, then assert that the
  shared application workflow receives plain input data.

If you are adding a provider rather than changing infrastructure, start with
the checklist under [Providers](/integrations/providers/#adding-a-provider);
release mechanics live under [Releasing](/contributing/releasing/).