⚠️ Warning: WIP Alpha⚠️
Atom is a module system for Nix that enforces bounded code structures, enabling complete static analysis without evaluation. While standard Nix code requires full evaluation to understand its structure, Atom-based modules can be analyzed and reasoned about statically, allowing tools to make strong associations about code relationships and dependencies before runtime.
As a standalone tool, Atom provides immediate value to Nix users through its module system. It also serves as the foundation for the broader Ekala project, where its static analyzability enables powerful developer tooling such as LSPs or the [eka][eka] evaluation frontend. This will also enable efficient caching strategies previously infeasible in the Nix ecosystem.
Modules in Atom are directories with a mod.nix
file containing an attribute set, with subdirectories of the same structure forming submodules. Features include:
- Explicit Scope: All other
.nix
files in the module directory are implicitly imported as module members with their associated scope. Manualimport
is prohibited, ensuring a consistent global namespace. - Predictable Composition: O(n) for shallow, O(n * log(m)) for deep nesting.
- Direct Type Declaration: Enables declaring code as its intended type without function wrappers. Enhances Nix's introspection capabilities, allowing complete Atom exploration in REPLs, while laying groundwork for future static analysis tooling.
- Public/Private Distinction: Capitalized members denote public exports; all others are private by default.
- Static File Access:
mod.outPath
provides access to non-Nix files, excluding submodules, offering an efficient file system API with a well-defined scope.
These features collectively provide a structured, introspectable, and efficient module system that enhances code organization and maintainability in Nix projects, while remaining otherwise unopinionated.
# string/mod.nix
{
ToLower = mod.toLowerCase;
Like = mod.like;
}
# string/toLowerCase.nix: mod.toLowerCase
str:
let
head = std.substring 0 1 str;
tail = std.substring 1 (-1) str;
in
"${mod.ToLower head}${tail}"
# parent/mod.nix
{
privateHelper = x: x * 2;
PublicFunc = x: x + 1;
}
# parent/child/mod.nix
{
UseParentPrivate = x: pre.privateHelper x;
UseParentPublic = x: pre.PublicFunc x;
}
# root/mod.nix
{
RootFunc = x: x * 3;
}
# nested/deep/mod.nix
{
UseRoot = x: atom.RootFunc x;
}
# utils/mod.nix
{
Double = x: std.mul 2 x;
IsEven = x: std.mod x 2 == 0;
}
The current in-repo manifest implementation is for demonstration purposes only. The canonical manifest validation layer exists in
eka
.
Each atom is defined by a TOML manifest file, enhancing dependency tracking and separation of concerns:
[atom]
name = "dev"
version = "0.1.0"
description = "Development environment"
[features]
default = []
[fetch.pkgs]
name = "nixpkgs"
import = true
args = [{}]
While it is conceptually useful to keep Atom minimal and in pure Nix, something like the code below should be implicit for user facing interfaces, e.g.
eka
.
let
atom = builtins.fetchGit "https://github.com/ekala-project/atom";
importAtom = import "${atom}/src/core/importAtom.nix";
in
importAtom {
features = [
# enabled flags
];
} ./src/dev.toml
Atom lays the groundwork for the Ekala platform, which builds upon the innovative store-based build and distribution model introduced by Nix.
The Ekala project, through the eka
CLI and its backend Eos API, aims to craft an open, unified platform that leverages the potential of this model to enhance software development, deployment, and system management at scale.
For details on eka
, see the eka README.
For ongoing discussions and updates, visit our Issues page.