Effect gives 14.ai typed schemas, retries, concurrency, dependency injection, and observability for production support agents.
2
The agent architecture separates small actions, deterministic workflows, and domain-specific sub-agents inside a planner that repeats until a task is complete.
3
Effect improves reliability and testing, but developers still need discipline because errors can disappear and service dependencies can become difficult to trace.
Summary
Michael Fester explains how 14.ai uses the Effect TypeScript library across its customer support platform. The system includes a React frontend, Effect-based RPC and HTTP services, data processing, PostgreSQL storage, and agent workflows built with a custom DSL. Agents plan tasks, select actions or workflows, and repeat until completion. Effect helps the team model schemas, errors, dependencies, retries, streaming, state transitions, and observability. Fester describes practical reliability measures such as switching LLM providers after failures, avoiding retries against providers known to be failing, duplicating token streams for users and storage, and injecting mock services during tests. He is also direct about the costs. Effect has a large learning curve, dependency injection can be hard to trace, and clean-looking code can hide swallowed errors. His advice is to adopt the library gradually, starting with one service or endpoint.
Effect fills gaps that plain TypeScript leaves around unreliable systems
Michael Fester says 14.ai uses Effect because its support platform depends on unreliable APIs, complex system dependencies, non-deterministic model output, and long-running workflows. TypeScript provides a useful foundation, but it does not solve these problems by itself. Effect adds type guarantees across the stack, composition primitives, concurrency, streaming, interruption, retries, structured error modeling, and dependency injection. OpenTelemetry makes observability easy. The library can also be introduced gradually into an existing codebase, which made it feel like a practical extension of TypeScript rather than a full rewrite.
The platform uses Effect across its frontend, services, data processing, and storage
14.ai uses Effect throughout its architecture. A React frontend powers dashboards, agent interfaces, knowledge management, insights, analytics, and SDKs. An internal RPC server handles application logic with Effect RPC and a modified TanStack Query on the frontend. The public API uses Effect HTTP, with OpenAPI documentation generated from annotated schemas. A data processing engine syncs CRM, document, and database data for analytics and reporting. PostgreSQL handles data and vector storage through Effect SQL. Effect schemas model the system and provide runtime validation, encoding, decoding, type-safe inputs and outputs, and generated documentation.
Agents are planners built from actions, workflows, and sub-agents
The support agents take a user input, create a plan, choose an action, workflow, or sub-agent, execute it, and repeat until the task is complete. Actions are small units such as fetching payment information or searching logs. Workflows are deterministic multi-step processes. Fester gives subscription cancellation as an example: the system can collect a reason, offer a retention option, check eligibility, and perform the cancellation. Sub-agents group related actions and workflows into larger domain modules, such as a billing agent or log retrieval agent.
A custom Effect-based DSL mixes deterministic and model-driven behavior
The team built a domain-specific language for workflows on top of Effect's functional, pipe-based system. It expresses branching, sequencing, retries, state transitions, and memory in a composable way. This lets the team combine deterministic workflow steps with non-deterministic LLM behavior. The separation gives small actions a focused role while allowing larger workflows and sub-agents to coordinate them.
Provider fallback and stream duplication address common production failures
For mission-critical systems, 14.ai can fall back to another LLM provider when one fails. Fester gives GPT-4 mini and Gemini Flash 2.0 as an example for tool calling. Retry policies track state, so the system avoids retrying providers that are already failing. When responses are streamed, the team duplicates the token stream. One copy goes to the user and another is stored for the platform. Fester says Effect's tools make this pattern straightforward.
Dependency injection makes failure testing and service replacement practical
14.ai uses dependency injection to replace LLM providers with mocks and simulate failure scenarios. Services can be swapped without changing the internals of the system. Fester also describes dependency injection as a major part of Effect's developer experience because services are supplied at system entry points, composed as needed, and overridden for tests. Required dependencies are present in the type-level model, so missing services are caught at compile time.
Schemas and guard rails improve consistency while adding a learning curve
Effect is schema-centric. The team defines input, output, and error types up front, then gets encoding, decoding, type safety, and automatic documentation from those schemas. Services are modular and composable, so implementations can be replaced without changing internal logic. Fester says these guard rails help engineers who are new to TypeScript avoid common mistakes. The tradeoff is a large ecosystem with many concepts and tools. Developers need time to get through the initial learning curve.
Effect can hide failures if developers do not inspect error handling carefully
Fester warns that Effect's clean happy-path code can create a false sense of safety. Errors may be caught somewhere upstream or out of sight, causing important failures to disappear silently. Dependency injection also becomes harder to follow when services are provided across several layers or subsystems. His conclusion is measured: Effect helps make systems predictable and resilient, but it does not remove the need for careful engineering.
The recommended adoption path starts with one service or endpoint
Teams do not need to adopt Effect everywhere on the first day. Fester recommends starting with one service or endpoint and expanding from there. He sees the library as especially useful for LLM and AI systems because they need to handle non-determinism while remaining predictable and observable. He also says developers do not need to be functional programming purists. The practical approach is to start small and allow the benefits to build over time.
"At the end of the day, Effect helps us build systems that are predictable and resilient, but it's not magic."06:27
Who should watch
You are building LLM-backed support or internal tools and need retries, provider fallback, streaming, and typed service boundaries.
Your TypeScript codebase has growing workflow dependencies and you are considering a gradual move toward Effect.
You want a candid account of Effect's costs, including swallowed errors, dependency tracing, and the initial learning curve.