This document provides guidelines for AI agents (Claude, Copilot, Cursor, etc.) working on the Morphir-Elm codebase.
DO NOT add AI agents as co-authors to git commits.
This project is governed by the FINOS EasyCLA. Adding AI agents as co-authors (e.g., Co-Authored-By: Claude <noreply@anthropic.com>) will cause CLA verification failures and block contributions.
When committing:
- Commits should only be attributed to human contributors who have signed the CLA
- Never include
Co-Authored-Bylines for AI assistants - The human developer is responsible for reviewing and taking ownership of all changes
Morphir is a multi-language system for capturing business logic in a technology-agnostic manner. This repository (morphir-elm) provides:
- Elm frontend: Parses Elm source code into Morphir IR (Intermediate Representation)
- Code generators: Transpile Morphir IR to Scala, TypeScript, Spark, and other targets
- CLI tools:
morphir-elm(v1) andmorphir(v2) command-line interfaces - TypeScript SDK: Type-safe API for working with Morphir IR
- Development tools: Web-based visualization and debugging
- mise - Polyglot tool version manager for Node.js and Bun
- Bun - Fast JavaScript runtime used for task execution
- Tasks are TypeScript files in
.mise/tasks/
- Elm - Primary language for business logic and frontend tooling
- TypeScript - CLI tooling (cli2/) and SDK (morphir-ts/)
- JavaScript - CLI v1 and generated outputs
mise run build # Build all components
mise run test # Run all tests
mise run build:cli # Build CLI v1
mise run build:cli2 # Build CLI v2See DEVELOPING.md for full build system documentation.
Morphir is built on functional programming principles. When contributing code, adhere to these practices:
- Prefer immutable data structures
- Avoid mutating state; create new values instead
- Use
constoverletin TypeScript; avoidvarentirely
- Functions should be deterministic (same input → same output)
- Avoid side effects where possible
- Isolate side effects at the edges of the system
- Leverage Elm's type system fully - if it compiles, it should work
- Use TypeScript's strict mode; avoid
anytypes - Model invalid states as unrepresentable through types
- Build complex behavior from simple, composable functions
- Prefer small, focused functions over large monolithic ones
- Use pipelines and function composition
Morphir's core purpose is functional domain modeling - capturing business domains in a pure, technology-agnostic way. When working on Morphir:
- Model the business domain, not the technical implementation
- Use ubiquitous language from the business domain
- Types should reflect real business concepts
- Use sum types (union types) to model choices:
type Result a = Ok a | Err String - Use product types (records) to model combinations of data
- Make illegal states unrepresentable
- The IR is the central artifact - a typed AST of business logic
- It captures what the logic does, not how it's implemented
- Generators translate IR to target languages while preserving semantics
Morphir.SDKprovides pure functional building blocks- Functions should work identically across all target platforms
- Avoid platform-specific behavior in SDK modules
- Follow elm-format conventions (enforced automatically)
- Use descriptive type aliases for domain concepts
- Prefer pattern matching over conditionals
- Document public APIs with doc comments
- Use strict TypeScript configuration
- Prefer functional patterns:
map,filter,reduceover loops - Use
readonlyfor immutable properties - Model errors as values (Result/Either types) rather than exceptions
- Keep functions small and focused
- Name things based on what they represent, not how they work
- Write self-documenting code; add comments only for non-obvious "why"
- Elm tests: Run with
mise run test:unit(uses elm-test) - Integration tests: Run with
mise run test:integration - TypeScript tests:
bun:testfor both unit and integration suites — import viaimport { describe, it, expect } from 'bun:test'
When adding features:
- Add Elm tests for new SDK functions
- Add integration tests for new CLI commands or generators
- Test edge cases and error conditions
When making architectural decisions:
- Preserve IR semantics - Changes to IR structure affect all generators
- Maintain backward compatibility - Existing morphir.json files should continue to work
- Keep generators consistent - Similar business logic should produce similar output across targets
- Favor correctness over performance - Morphir prioritizes semantic accuracy
- Morphir Documentation
- Elm Guide
- Morphir SDK Reference
- DEVELOPING.md - Build system and development workflow