Atom
An atom is a single Nu node. It has a kind, it has children (its direct children only), and it has its own properties and attributes: own mutation, what kind of atoms it accepts in each child slot, execution mode (sync vs async) etc.
When we say "a Query is X" or "a Command contributes WRITE", we are talking about atoms. The atom IS the unit of definition.
Properties of Atoms
- attributes (this atom's attributes like mutation, sort, execution mode, etc)
- children (other atoms)
- payload (extra arguments)
Composition
A composition is a collection of hierarchical atoms - the result of plugging atoms into other atoms' child slots, recursively. A composition isn't a separate entity; it's the structure that emerges from atoms wired together.
When we talk about a Nu composition's mutation, observability, or validity, we are talking about properties of the composition, derived by aggregating the atoms in it.
Why we keep them apart
Atom and composition answer different questions:
- Atom-level answers "what is this thing?" - kind, role, contributed mutation, accepted child kinds.
- Composition-level answers "what does this whole thing do?" - aggregated mutation, observability, validity.
Examples:
- "A Command contributes WRITE." (atom-level - own contribution via its slot annotations)
- "A Query atom can hold Query atoms as children." (atom-level - per-atom child slot rule)
- "A Flow with no Command in its subtree is meaningless." (composition-level - aggregated property)