ADR-002: YAML + TypeScript
Status
Section titled “Status”Accepted — March 2025
Context
Section titled “Context”Healthcare integration requires two fundamentally different kinds of authoring:
- Declarative configuration — what connects to what, which protocol, which port, how many retries, where to store messages.
- Imperative logic — transform message A into message B, validate that a field exists, filter messages by type, enrich data from an external API.
Legacy engines like Mirth Connect, Rhapsody, and Cloverleaf conflate both in a GUI. Configuration and logic are stored in a proprietary database, exported as opaque XML blobs, and impossible to meaningfully diff, review, or version control. This creates serious problems:
- No Git workflow — changes cannot be tracked, reviewed, or rolled back with standard tools.
- No CI/CD — automated testing and deployment require fragile API calls to a running engine instance.
- No collaboration — two engineers cannot work on the same channel simultaneously without conflict.
- No AI assistance — LLMs cannot generate or modify proprietary XML formats reliably.
The broader infrastructure world solved this years ago. Terraform, Kubernetes, Docker Compose, GitHub Actions, and Ansible all use YAML for declarative configuration. It is the lingua franca of Infrastructure-as-Code. Developers know it, tools support it, and AI models generate it with high accuracy.
For imperative logic, TypeScript has become the most productive language for data transformation:
- A powerful type system catches errors at compile time, not when a message fails at 2 AM.
- The npm ecosystem has mature libraries for every healthcare data format.
- IDE support (autocompletion, inline errors, hover documentation) is best-in-class.
- AI assistants generate TypeScript better than almost any other language — it is structured, well-documented, and predictable.
Decision
Section titled “Decision”We enforce a strict separation of concerns:
- YAML for all configuration — channel definitions, source/destination endpoints, protocol settings, runtime configuration, environment profiles, scheduling, retry policies.
- TypeScript for all logic — transformers, validators, filters, pre-processors, post-processors, custom functions.
YAML describes what the integration does. TypeScript implements how it does it.
YAML configuration example
Section titled “YAML configuration example”channel: name: ADT-to-FHIR description: Transforms ADT messages to FHIR Patient resources source: type: mllp port: 6661 destinations: - name: FHIR Server type: http url: https://fhir.hospital.org/Patient transformer: adt-to-fhir.tsTypeScript transformer example
Section titled “TypeScript transformer example”import { Message } from "@intuware/types";
export default function transform(msg: Message): Message { const patient = msg.get("PID"); return { resourceType: "Patient", name: [{ family: patient.field(5).component(1) }], birthDate: patient.field(7).toString(), };}JSON Schema support
Section titled “JSON Schema support”Every YAML configuration file has a corresponding JSON Schema. This enables:
- IDE autocompletion — VS Code, JetBrains, and Cursor suggest valid keys and values as you type.
- Validation — configuration errors are caught before deployment, not at runtime.
- AI generation — LLMs can use the schema as context to generate valid YAML with high accuracy.
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Standard developer workflow — channels live in Git repositories. Changes go through pull requests. Code review works naturally. CI/CD pipelines validate and deploy automatically.
- AI-friendly by design — LLMs generate and modify both YAML configuration and TypeScript logic with high accuracy. Schema-guided generation reduces hallucination.
- Type safety — TypeScript catches field access errors, type mismatches, and missing properties at compile time. A transformer that references
PID.5.1on a message type that doesn’t have it fails at build time, not at 2 AM in production. - Full npm ecosystem — transformers can import
node-hl7-client,@types/fhir,xml2js,csv-parse,zod,date-fns, or any other npm package. No custom plugin system or SDK required. - Readable diffs — YAML and TypeScript produce clean, meaningful diffs in Git. Reviewers can see exactly what changed in a channel configuration or transformer.
- Onboarding speed — new developers can read and understand a channel’s behavior by looking at two files: a YAML config and a TypeScript transformer. No GUI navigation, no database queries.
Negative
Section titled “Negative”- Two languages — developers must know both YAML and TypeScript. However, both are among the most widely known formats in software engineering, and healthcare integration engineers increasingly have this skillset.
- YAML indentation sensitivity — a misplaced space can change the meaning of a YAML file silently. This is mitigated by JSON Schema validation, linting in CI, and IDE support that highlights errors inline.
- File management — large deployments may have dozens of YAML and TypeScript files. This requires good project structure conventions (which intu provides via
intu initscaffolding).
Alternatives Considered
Section titled “Alternatives Considered”| Alternative | Why we rejected it |
|---|---|
| JSON for configuration | More verbose than YAML, does not support comments, less readable for humans. JSON is excellent for machine interchange but poor for hand-authored configuration. |
| JavaScript (not TypeScript) | No type safety, weaker IDE support, more runtime errors. TypeScript’s type system is especially valuable in healthcare where message schemas are complex and field access errors are common. |
| Domain-specific language (DSL) | Higher learning curve, smaller ecosystem, no existing IDE support or AI training data. Every DSL eventually wants to be a general-purpose language — TypeScript already is one. |
| GUI-first with code export | Loses the code-first philosophy. Exported code is typically unreadable and unmaintainable. GUI-generated configuration cannot be meaningfully reviewed in a pull request. |
| TOML for configuration | Less expressive than YAML for nested structures. Smaller ecosystem of tooling and schema support. Less familiar to the Kubernetes/DevOps audience we target. |