13. Dependency policy
- Status: Accepted
- Date: 2026-09-02
Context
A language implementation that may be released publicly and depended upon should be deliberate about its dependency tree: every crate is attack surface, a compile-time cost, and a maintenance obligation. At the same time, reimplementing solved problems (terminal diagnostics, line editing, arg parsing) wastes effort and tends to produce worse results.
Decision
Dependencies are allowed, but each one is justified in
docs/internals/dependencies.md with: what it does, why not the standard
library, and what replacing it would cost. The bar:
crates/korrin(the published library) stays lean. A new runtime dependency needs a clear, load-bearing reason. As of M1:ariadne(diagnostic rendering),thiserror(error boilerplate),unicode-ident(identifier classification per UAX #31).crates/korrin-climay depend more freely on mature, widely-used crates for genuinely CLI concerns:clap,rustyline.- Dev-dependencies (
insta,proptest,assert_cmd,predicates) are unrestricted — they do not ship. - Prefer crates that are widely used, actively maintained, and
#![forbid(unsafe)]or close to it. Avoid crates that pull large transitive trees. - No dependency is added in the same change as the feature that needs it without a line in review calling it out.
unsafe_code is forbid across the workspace; if that ever needs to change it
requires its own ADR.
Consequences
- Slightly more friction to add a dependency; a short written justification each time.
- The published library's tree stays auditable.
- Some wheels may get partially reinvented if a dependency is judged too heavy. Accepted case by case.
Alternatives considered
- No third-party runtime dependencies at all. Purity that would cost a lot of
effort on diagnostic rendering for a worse result than
ariadne. - No policy, add what's convenient. How dependency trees become unauditable and how supply-chain incidents propagate.