Files
correx/docs/decisions/adr-0002-kotlin-choice.md

57 lines
3.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: "Adr 0002 Kotlin Choice"
description: "Decision to implement in Kotlin"
depth: 2
links: ["../index.md", "./adr-0000-invariants.md"]
---
# ADR 0002: use kotlin as the primary implementation language
**status:** accepted
**date:** 07.05.2026 (May)
**deciders:** Kami
---
## context
Correx is a stateheavy, eventheavy, concurrencyheavy orchestration runtime. The language choice affects maintainability, type safety, concurrency model, and ecosystem compatibility for a localfirst tool.
## decision
We implement the core, orchestration, and infrastructure layers in **Kotlin** (JVM), using the following primary libraries:
* **coroutines** structured concurrency
* **kotlinx.serialization** event/artifact serialization
* **Exposed** typesafe SQL for persistence
* **Ktor** web/API server
* **Hoplite** / Typesafe Config configuration
Frontend interface uses **SvelteKit**; CLI uses **Clikt**.
## rationale
1. **Sealed hierarchies and data classes** map naturally to event types, artifact schemas, and validation outcomes.
2. **Coroutines** provide safe, cancellable concurrency that aligns with the session lifecycle (cancellation tokens, explicit scopes).
3. **Immutability by default** reduces accidental state mutation critical for event sourcing.
4. **Typesafe DSLs** enable clean definition of transitions, conditions, and tool contracts directly in config or code.
5. The existing team knows Java/Kotlin, reducing rampup.
6. Libraries like `kotlinx.serialization` give deterministic, reflectionfree serialization.
7. Strong typing prevents many categories of bugs that would be hard to catch in a dynamic language when dealing with complex state machines.
## alternatives considered
* **Python**: excellent for glue and rapid prototyping, but dynamic typing and global interpreter lock make deterministic concurrency, state integrity, and longterm maintenance riskier. Python was used in the failed `llm-pipeline` prototype and contributed to hidden mutable state issues.
* **TypeScript (Node.js)**: singlethreaded event loop simplifies some concurrency but lacks the typesafety and structured concurrency needed for complex orchestration state machines. Validation and serialization would rely on thirdparty libraries with varying degrees of strictness.
* **Rust**: performance and safety are excellent, but the borrow checker and ecosystem immaturity for LLM tooling would slow development significantly.
## consequences
* JVM startup overhead; acceptable for a tool that runs as a persistent server or longlived CLI.
* Requires Kotlin knowledge; mitigated by good documentation and a growing community.
* Interop with native libraries (e.g., llama.cpp) will be via JNI or external processes; we accept that complexity and encapsulate it in infrastructure providers.
* We must enforce module dependency rules (with tools like ArchUnit) to prevent core from depending on infrastructure.
## status
This decision is foundational and aligns with the architectural need for a “workflow engine” rather than a “scripting environment”.